чување 23e9021005c75757e2bdd28d1949eaeec25ea92a
родитељ 71387db6bdac2bb8dafd73fbe37dc5ace75d0e74
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Tue, 20 Jul 2021 13:48:06 +0200
Removed libunistring as a dependency
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | .gitignore | | | 6 | ++++-- |
| M | CHANGES | | | 5 | +++++ |
| M | TODO | | | 2 | +- |
| M | all.do | | | 3 | +-- |
| A | default.h.do | | | 13 | +++++++++++++ |
| M | defs.h | | | 106 | ++++++++++++++++++++++++++++--------------------------------------------------- |
| M | table.c | | | 1375 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
| M | table.do | | | 10 | ++++++++-- |
| A | utf8.c | | | 161 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | utf8.h | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
| A | version.h.in | | | 4 | ++++ |
измењених датотека: 11, додавања: 981(+), брисања: 744(-)
diff --git a/.gitignore b/.gitignore
@@ -14,11 +14,13 @@
*.swp
*.did
nohup.out
-highlight.css
+*.gz
+*.xz
*.png
+*.1
table
table.1
-*.gz
date
version
+version.h
diff --git a/CHANGES b/CHANGES
@@ -1,5 +1,9 @@
Changelog
=========
+* v0.3
+
+ - Removed libunistring as a dependency
+
* v0.2
@@ -35,3 +39,4 @@
- Better UTF-8 substring code based on screen columns
+
diff --git a/TODO b/TODO
@@ -1,7 +1,7 @@
TODO
====
- [ ] Move away from libunistring
+ [x] Move away from libunistring
Legend
diff --git a/all.do b/all.do
@@ -1,3 +1,2 @@
-redo-ifchange table
-redo-ifchange table.1.gz table.pdf
+redo-ifchange version.h table table.1.gz table.pdf
diff --git a/default.h.do b/default.h.do
@@ -0,0 +1,13 @@
+if [ -r $1.in ]; then
+ redo-ifchange $1.in version date
+ read VERSION <version
+ read DATE <date
+ sed -e "s/%VERSION%/$VERSION/g" \
+ -e "s/%DATE%/$DATE/g" <$1.in
+else
+ if [ -f $2.def.h ]; then
+ redo-ifchange $2.def.h
+ cat $2.def.h > $3
+ fi
+fi
+
diff --git a/defs.h b/defs.h
@@ -1,38 +1,8 @@
-/*
- * table - Command line utility to format and display CSV.
- * Copyright (C) 2020 Страхиња Радић
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef __DEFS_H
-#define __DEFS_H
+/* See the file LICENSE for copyright and license details. */
#define _POSIX_C_SOURCE 200809L
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistr.h>
-#include <unistdio.h>
-#include <uniwidth.h>
-
-#define PROGRAMNAME "table"
-#define VERSION "0.2.2"
+#include "utf8.h"
#define BUFSIZE 4096
#define SMALL_BUFSIZE 256
@@ -77,65 +47,63 @@ enum
TABLE_INNER_DOUBLE_DOUBLE
};
-static const uint8_t* table_symbols[][9] =
+static const u32* table_symbols[][9] =
{
- [TABLE_SYMBOLS_ASCII] = {
- // ascii
- (uint8_t*)"+", (uint8_t*)"-", (uint8_t*)"+",
- (uint8_t*)"|", (uint8_t*)" ", (uint8_t*)"|",
- (uint8_t*)"+", (uint8_t*)"-", (uint8_t*)"+",
- },
- [TABLE_SYMBOLS_SINGLE] = {
- // single
- (uint8_t*)"\u250c", (uint8_t*)"\u2500", (uint8_t*)"\u2510",
- (uint8_t*)"\u2502", (uint8_t*)" ", (uint8_t*)"\u2502",
- (uint8_t*)"\u2514", (uint8_t*)"\u2500", (uint8_t*)"\u2518",
- },
- [TABLE_SYMBOLS_DOUBLE] = {
- // double
- (uint8_t*)"\u2554", (uint8_t*)"\u2550", (uint8_t*)"\u2557",
- (uint8_t*)"\u2551", (uint8_t*)" ", (uint8_t*)"\u2551",
- (uint8_t*)"\u255a", (uint8_t*)"\u2550", (uint8_t*)"\u255d",
- }
+ [TABLE_SYMBOLS_ASCII] = {
+ // ascii
+ (u32*)L"+", (u32*)L"-", (u32*)L"+",
+ (u32*)L"|", (u32*)L" ", (u32*)L"|",
+ (u32*)L"+", (u32*)L"-", (u32*)L"+",
+ },
+ [TABLE_SYMBOLS_SINGLE] = {
+ // single
+ (u32*)L"\u250c", (u32*)L"\u2500", (u32*)L"\u2510",
+ (u32*)L"\u2502", (u32*)L" ", (u32*)L"\u2502",
+ (u32*)L"\u2514", (u32*)L"\u2500", (u32*)L"\u2518",
+ },
+ [TABLE_SYMBOLS_DOUBLE] = {
+ // double
+ (u32*)L"\u2554", (u32*)L"\u2550", (u32*)L"\u2557",
+ (u32*)L"\u2551", (u32*)L" ", (u32*)L"\u2551",
+ (u32*)L"\u255a", (u32*)L"\u2550", (u32*)L"\u255d",
+ }
};
-static const uint8_t* table_inner_symbols[][3] =
+static const u32* table_inner_symbols[][3] =
{
[TABLE_INNER_ASCII_ASCII] = {
// ascii -> ascii
- (uint8_t*)"+",
- (uint8_t*)"|",
- (uint8_t*)"+",
+ (u32*)L"+",
+ (u32*)L"|",
+ (u32*)L"+",
},
[TABLE_INNER_SINGLE_SINGLE] = {
// single -> single
- (uint8_t*)"\u252c",
- (uint8_t*)"\u2502",
- (uint8_t*)"\u2534",
+ (u32*)L"\u252c",
+ (u32*)L"\u2502",
+ (u32*)L"\u2534",
},
[TABLE_INNER_SINGLE_DOUBLE] = {
// single -> double
- (uint8_t*)"\u2565",
- (uint8_t*)"\u2551",
- (uint8_t*)"\u2568",
+ (u32*)L"\u2565",
+ (u32*)L"\u2551",
+ (u32*)L"\u2568",
},
[TABLE_INNER_DOUBLE_SINGLE] = {
// double -> single
- (uint8_t*)"\u2564",
- (uint8_t*)"\u2502",
- (uint8_t*)"\u2567",
+ (u32*)L"\u2564",
+ (u32*)L"\u2502",
+ (u32*)L"\u2567",
},
[TABLE_INNER_DOUBLE_DOUBLE] = {
// double -> double
- (uint8_t*)"\u2566",
- (uint8_t*)"\u2551",
- (uint8_t*)"\u2569",
+ (u32*)L"\u2566",
+ (u32*)L"\u2551",
+ (u32*)L"\u2569",
}
};
-#endif
-
diff --git a/table.c b/table.c
@@ -1,748 +1,787 @@
-/*
- * table - Command line utility to format and display CSV.
- * Copyright (C) 2020 Страхиња Радић
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- */
+/* See the file LICENSE for copyright and license details. */
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include "defs.h"
+#include "version.h"
#define CHECKEXITNOMEM(ptr) { if (!ptr) exit(error(ENOMEM, \
- (uint8_t*)"Memory allocation failed (out of memory?)")); }
+ "Memory allocation failed (out of memory?)")); }
#define CALLOC(ptr, ptrtype, nmemb) { ptr = calloc(nmemb, sizeof(ptrtype)); \
- CHECKEXITNOMEM(ptr) }
+ CHECKEXITNOMEM(ptr) }
#define REALLOC(ptr, ptrtype, newsize) { ptrtype* newptr = realloc(ptr, newsize); \
- CHECKEXITNOMEM(newptr) \
- ptr = newptr; }
+ CHECKEXITNOMEM(newptr) \
+ ptr = newptr; }
#define REALLOCARRAY(ptr, membtype, newcount) \
- REALLOC(ptr, membtype, sizeof(membtype) * newcount)
+ REALLOC(ptr, membtype, sizeof(membtype) * newcount)
#define CHECKCOPY(token, ptoken, token_size, parg) { \
- if (ptoken + 2 > token + token_size) \
- { \
- size_t old_size = token_size; \
- token_size += BUFSIZE; \
- REALLOC(token, char, token_size) \
- ptoken = token + old_size - 1; \
- } \
- *ptoken++ = *parg++; }
+ if (ptoken + 2 > token + token_size) \
+ { \
+ size_t old_size = token_size; \
+ token_size += BUFSIZE; \
+ REALLOC(token, char, token_size) \
+ ptoken = token + old_size - 1; \
+ } \
+ *ptoken++ = *parg++; }
#define CHECKSET(format, pformat, format_size, num) { \
- if (pformat + 2 > format + format_size) \
- { \
- size_t old_size = format_size; \
- format_size += BUFSIZE; \
- REALLOC(format, ULONG, format_size) \
- pformat = format + old_size - 1; \
- } \
- *pformat++ = num; }
-
-size_t colno = 0;
-size_t lineno = 0;
-int current_symbol_set = TABLE_SYMBOLS_DOUBLE;
-int current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE;
-size_t current_table_column = 0;
-size_t current_rune_column = 0;
-size_t table_columns = 0;
-size_t rune_columns = 80;
-size_t tab_length = 8;
-ucs4_t delimiter = ',';
-ULONG* format = NULL;
-size_t format_size = 0;
-ULONG format_value = 0;
-BOOL border_mode = FALSE;
-BOOL handle_ansi = TRUE;
-BOOL msdos = FALSE;
-BOOL expand_tabs = FALSE;
+ if (pformat + 2 > format + format_size) \
+ { \
+ size_t old_size = format_size; \
+ format_size += BUFSIZE; \
+ REALLOC(format, ULONG, format_size) \
+ pformat = format + old_size - 1; \
+ } \
+ *pformat++ = num; }
+
+size_t colno = 0;
+size_t lineno = 0;
+int current_symbol_set = TABLE_SYMBOLS_DOUBLE;
+int current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE;
+size_t current_table_column = 0;
+size_t current_rune_column = 0;
+size_t table_columns = 0;
+size_t rune_columns = 80;
+size_t tab_length = 8;
+u32 delimiter = L',';
+ULONG* format = NULL;
+size_t format_size = 0;
+ULONG format_value = 0;
+BOOL border_mode = FALSE;
+BOOL handle_ansi = TRUE;
+BOOL msdos = FALSE;
+BOOL expand_tabs = FALSE;
int
version()
{
- printf("%s v%s\n", PROGRAMNAME, VERSION);
- return 0;
+ printf("%s v%s\n", PROGRAMNAME, VERSION);
+ return 0;
}
int
usage()
{
- printf("Usage: %s [-b|--border-mode] [-c <cols>|--columns=<cols>] [-d"
- " <delim>|--delimiter=<delim>] [-f <format>|--format=<format>]"
- " [-h|--help] [-m|--msdos] [-n|--no-ansi]"
- " [-s <set>|--symbols=<set>] [-t|--expand-tabs] [-v|--version]\n",
- PROGRAMNAME);
- return 0;
+ printf("Usage: %s [-b|--border-mode] [-c <cols>|--columns=<cols>] [-d"
+ " <delim>|--delimiter=<delim>] [-f <format>|--format=<format>]"
+ " [-h|--help] [-m|--msdos] [-n|--no-ansi]"
+ " [-s <set>|--symbols=<set>] [-t|--expand-tabs] [-v|--version]\n",
+ PROGRAMNAME);
+ return 0;
}
int
-error(int code, uint8_t* fmt, ...)
+error(int code, char* fmt, ...)
{
- uint8_t buf[BUFSIZE];
- va_list args;
- va_start(args, fmt);
- u8_vsnprintf(buf, sizeof(buf), (const char*)fmt, args);
- va_end(args);
- fprintf(stderr, "%s: %s\n", PROGRAMNAME, buf);
- return code;
+ char buf[BUFSIZE];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), (const char*)fmt, args);
+ va_end(args);
+ fprintf(stderr, "%s: %s\n", PROGRAMNAME, buf);
+ return code;
}
char*
substr(const char* src, int start, int finish)
{
- int len = strlen(src);
- if (finish > len)
- finish = len;
- int substr_len = finish-start;
- if (substr_len < 0)
- substr_len = 0;
- char* result = NULL;
- CALLOC(result, char, substr_len+1)
- char* presult = result;
- for (int i = start; i < finish && *(src+i) != '\0'; i++)
- *presult++ = *(src+i);
- *presult = 0;
-
- return result;
+ int len = strlen(src);
+ if (finish > len)
+ finish = len;
+ int substr_len = finish-start;
+ if (substr_len < 0)
+ substr_len = 0;
+ char* result = NULL;
+ CALLOC(result, char, substr_len+1)
+ char* presult = result;
+ for (int i = start; i < finish && *(src+i) != '\0'; i++)
+ *presult++ = *(src+i);
+ *presult = 0;
+
+ return result;
}
BOOL
startswith(const char* s, const char* what)
{
- if (!s || !what)
- return 0;
+ if (!s || !what)
+ return 0;
- char* subs = substr(s, 0, strlen(what));
- BOOL result = !strcmp(subs, what);
+ char* subs = substr(s, 0, strlen(what));
+ BOOL result = !strcmp(subs, what);
- free(subs);
+ free(subs);
- return result;
+ return result;
}
int
set_symbol_set(char* arg, int* current_symbol_set,
- int* current_inner_symbol_set)
+ int* current_inner_symbol_set)
{
- if (!strcmp(arg, "aa"))
- {
- *current_symbol_set = TABLE_SYMBOLS_ASCII;
- *current_inner_symbol_set = TABLE_INNER_ASCII_ASCII;
- }
- else if (!strcmp(arg, "ss"))
- {
- *current_symbol_set = TABLE_SYMBOLS_SINGLE;
- *current_inner_symbol_set = TABLE_INNER_SINGLE_SINGLE;
- }
- else if (!strcmp(arg, "sd"))
- {
- *current_symbol_set = TABLE_SYMBOLS_SINGLE;
- *current_inner_symbol_set = TABLE_INNER_SINGLE_DOUBLE;
- }
- else if (!strcmp(arg, "ds"))
- {
- *current_symbol_set = TABLE_SYMBOLS_DOUBLE;
- *current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE;
- }
- else if (!strcmp(arg, "dd"))
- {
- *current_symbol_set = TABLE_SYMBOLS_DOUBLE;
- *current_inner_symbol_set = TABLE_INNER_DOUBLE_DOUBLE;
- }
- else
- {
- return error(1, (uint8_t*)"Invalid symbol set: %s", arg);
- }
- return 0;
+ if (!strcmp(arg, "aa"))
+ {
+ *current_symbol_set = TABLE_SYMBOLS_ASCII;
+ *current_inner_symbol_set = TABLE_INNER_ASCII_ASCII;
+ }
+ else if (!strcmp(arg, "ss"))
+ {
+ *current_symbol_set = TABLE_SYMBOLS_SINGLE;
+ *current_inner_symbol_set = TABLE_INNER_SINGLE_SINGLE;
+ }
+ else if (!strcmp(arg, "sd"))
+ {
+ *current_symbol_set = TABLE_SYMBOLS_SINGLE;
+ *current_inner_symbol_set = TABLE_INNER_SINGLE_DOUBLE;
+ }
+ else if (!strcmp(arg, "ds"))
+ {
+ *current_symbol_set = TABLE_SYMBOLS_DOUBLE;
+ *current_inner_symbol_set = TABLE_INNER_DOUBLE_SINGLE;
+ }
+ else if (!strcmp(arg, "dd"))
+ {
+ *current_symbol_set = TABLE_SYMBOLS_DOUBLE;
+ *current_inner_symbol_set = TABLE_INNER_DOUBLE_DOUBLE;
+ }
+ else
+ {
+ return error(1, "Invalid symbol set: %s", arg);
+ }
+ return 0;
}
int
set_columns(const char* arg, size_t* cols)
{
- size_t c = strtol(arg, NULL, 10);
- if (errno == EINVAL || errno == ERANGE)
- return error(1, (uint8_t*)"Invalid numeric value: %s", arg);
- else
- *cols = c;
- return 0;
+ size_t c = strtol(arg, NULL, 10);
+ if (errno == EINVAL || errno == ERANGE)
+ return error(1, "Invalid numeric value: %s", arg);
+ else
+ *cols = c;
+ return 0;
}
int
-set_delimiter(uint8_t* arg, ucs4_t* delimiter)
+set_delimiter(u8* arg, u32* delimiter)
{
- size_t arg_len = u8_strlen(arg);
- size_t delimiter_len = 0;
- uint8_t* parg = arg;
- ucs4_t uch;
-
- while (parg && *parg)
- {
- delimiter_len = u8_mbtouc(&uch, parg, arg_len);
- if (uch != (ucs4_t)'"' && uch != (ucs4_t)'\'')
- {
- *delimiter = uch;
- return 0;
- }
- parg += delimiter_len;
- }
-
- return -1;
+ size_t delimiter_len = 0;
+ u8* parg = arg;
+ u32 uch;
+
+ while (parg && *parg)
+ {
+ u8_char_to_u32(&uch, parg, &delimiter_len);
+ if (uch != (u32)L'"' && uch != (u32)L'\'')
+ {
+ *delimiter = uch;
+ return 0;
+ }
+ parg += delimiter_len;
+ }
+
+ return -1;
}
int
set_format(const char* arg, ULONG** format, size_t* format_size)
{
- const char* parg = arg;
- ULONG* pformat = NULL;
- char* token = NULL;
- size_t token_size = BUFSIZE;
- char* ptoken = NULL;
- ULONG num;
-
- CALLOC(token, char, token_size)
- ptoken = token;
- *format_size = SMALL_BUFSIZE;
- CALLOC(*format, ULONG, *format_size)
- pformat = *format;
-
- while (*parg)
- {
- if (!((*parg >= '0' && *parg <= '9') || *parg == ':'))
- {
- free(token);
- free(*format);
- *format = NULL;
- return 1;
- }
- if (*parg == ':')
- {
- if (parg == arg || !*(parg+1))
- {
- free(token);
- free(*format);
- *format = NULL;
- return 2;
- }
- *ptoken = 0;
- num = strtol(token, NULL, 10);
- if (errno)
- {
- perror("strtol");
- free(token);
- free(*format);
- *format = NULL;
- return 3;
- }
- CHECKSET(*format, pformat, *format_size, num)
- *token = 0;
- ptoken = token;
- parg++;
- }
- else
- CHECKCOPY(token, ptoken, token_size, parg)
- }
- if (*token)
- {
- *ptoken = 0;
- num = strtol(token, NULL, 10);
- if (errno)
- {
- perror("strtol");
- free(token);
- free(*format);
- *format = NULL;
- return 3;
- }
- CHECKSET(*format, pformat, *format_size, num)
- }
-
- free(token);
-
- return 0;
+ const char* parg = arg;
+ ULONG* pformat = NULL;
+ char* token = NULL;
+ size_t token_size = BUFSIZE;
+ char* ptoken = NULL;
+ ULONG num;
+
+ CALLOC(token, char, token_size)
+ ptoken = token;
+ *format_size = SMALL_BUFSIZE;
+ CALLOC(*format, ULONG, *format_size)
+ pformat = *format;
+
+ while (*parg)
+ {
+ if (!((*parg >= '0' && *parg <= '9') || *parg == ':'))
+ {
+ free(token);
+ free(*format);
+ *format = NULL;
+ return 1;
+ }
+ if (*parg == ':')
+ {
+ if (parg == arg || !*(parg+1))
+ {
+ free(token);
+ free(*format);
+ *format = NULL;
+ return 2;
+ }
+ *ptoken = 0;
+ num = strtol(token, NULL, 10);
+ if (errno)
+ {
+ perror("strtol");
+ free(token);
+ free(*format);
+ *format = NULL;
+ return 3;
+ }
+ CHECKSET(*format, pformat, *format_size, num)
+ *token = 0;
+ ptoken = token;
+ parg++;
+ }
+ else
+ CHECKCOPY(token, ptoken, token_size, parg)
+ }
+ if (*token)
+ {
+ *ptoken = 0;
+ num = strtol(token, NULL, 10);
+ if (errno)
+ {
+ perror("strtol");
+ free(token);
+ free(*format);
+ *format = NULL;
+ return 3;
+ }
+ CHECKSET(*format, pformat, *format_size, num)
+ }
+
+ free(token);
+
+ return 0;
}
/* Return number of columns based on the input line */
size_t
-number_of_columns(const uint8_t* input, ucs4_t delimiter)
+number_of_columns(const u8* input, u32 delimiter)
{
- ucs4_t uch;
- size_t ch_len = 0;
- size_t result = 1;
- const uint8_t* pinput = NULL;
- size_t input_len = 0;
-
- if (!input)
- return result;
-
- input_len = u8_strlen(input);
- pinput = input;
-
- while (pinput && *pinput)
- {
- ch_len = u8_mbtouc(&uch, pinput, input_len);
- if (uch == delimiter)
- result++;
- pinput += ch_len;
- }
-
- return result;
+ u32 uch;
+ size_t ch_len = 0;
+ size_t result = 1;
+ const u8* pinput = NULL;
+
+ pinput = input;
+
+ if (!input)
+ return result;
+
+ while (pinput && *pinput)
+ {
+ u8_char_to_u32(&uch, pinput, &ch_len);
+ if (uch == delimiter)
+ result++;
+ pinput += ch_len;
+ }
+
+ return result;
}
UINT round_div(UINT a, UINT b)
{
- return (a + (b/2)) / b;
+ return (a + (b/2)) / b;
}
BOOL
within_column(size_t column_start)
{
- return format
- ? (current_rune_column <
- column_start + *(format+current_table_column))
- : (current_rune_column <
- column_start + format_value);
+ return format
+ ? (current_rune_column <
+ column_start + *(format+current_table_column))
+ : (current_rune_column <
+ column_start + format_value);
}
int
main(int argc, char** argv)
{
- char* arg;
- Command cmd = CMD_NONE;
- char* filename = NULL;
-
- while ((arg = *++argv))
- {
- if (*arg == '-')
- {
- arg++;
- char c = *arg++;
- if (c == '-')
- {
- if (!strcmp(arg, "version"))
- cmd = CMD_VERSION;
- else if (startswith(arg, "border-mode"))
- {
- arg += strlen("border-mode");
- border_mode = TRUE;
- }
- else if (startswith(arg, "columns="))
- {
- arg += strlen("columns=");
- if (set_columns(arg, &rune_columns))
- return error(EINVAL, (uint8_t*)"Invalid argument: '%s'",
- arg);
- }
- else if (startswith(arg, "delimiter="))
- {
- arg += strlen("delimiter=");
- if (set_delimiter((uint8_t*)arg, &delimiter))
- return error(EINVAL, (uint8_t*)"Invalid argument: '%s'",
- arg);
- }
- else if (startswith(arg, "expand-tabs"))
- {
- arg += strlen("expand-tabs");
- expand_tabs = TRUE;
- }
- else if (startswith(arg, "format="))
- {
- arg += strlen("format=");
- set_format(arg, &format, &format_size);
- }
- else if (startswith(arg, "msdos"))
- {
- arg += strlen("msdos");
- msdos = TRUE;
- }
- else if (startswith(arg, "no-ansi"))
- {
- arg += strlen("no-ansi");
- handle_ansi = FALSE;
- }
- else if (startswith(arg, "symbols="))
- {
- arg += strlen("symbols=");
- if (set_symbol_set(arg, ¤t_symbol_set,
- ¤t_inner_symbol_set))
- return error(EINVAL, (uint8_t*)"Invalid argument: '%s'",
- arg);
- }
- else if (!strcmp(arg, "help"))
- return usage();
- else
- {
- error(EINVAL, (uint8_t*)"Invalid argument: --%s", arg);
- return usage();
- }
- }
- else
- {
- switch (c)
- {
- case 'b':
- border_mode = TRUE;
- break;
- case 'c':
- cmd = CMD_COLUMNS;
- break;
- case 'd':
- cmd = CMD_DELIMITER;
- break;
- case 'f':
- cmd = CMD_FORMAT;
- break;
- case 'h':
- return usage();
- break;
- case 'm':
- msdos = TRUE;
- break;
- case 'n':
- handle_ansi = FALSE;
- break;
- case 's':
- cmd = CMD_SYMBOLS;
- break;
- case 't':
- expand_tabs = TRUE;
- break;
- case 'v':
- cmd = CMD_VERSION;
- break;
- default:
- error(EINVAL, (uint8_t*)"Invalid argument: -%c", c);
- return usage();
- }
- }
- }
- else
- {
- if (cmd == CMD_COLUMNS)
- {
- if (set_columns(arg, &rune_columns))
- return error(EINVAL, (uint8_t*)"Invalid argument: '%s'", arg);
- }
- else if (cmd == CMD_DELIMITER)
- {
- if (set_delimiter((uint8_t*)arg, &delimiter))
- return error(EINVAL, (uint8_t*)"Invalid argument: '%s'", arg);
- }
- else if (cmd == CMD_FORMAT)
- {
- if (set_format(arg, &format, &format_size))
- return error(EINVAL, (uint8_t*)"Invalid argument: '%s'", arg);
- }
- else if (cmd == CMD_SYMBOLS)
- {
- if (set_symbol_set(arg, ¤t_symbol_set,
- ¤t_inner_symbol_set))
- return error(EINVAL, (uint8_t*)"Invalid argument: '%s'", arg);
- }
- else
- filename = arg;
- cmd = CMD_NONE;
- }
- }
-
- if (cmd == CMD_VERSION)
- return version();
-
- FILE* input = NULL;
- if (filename)
- {
- input = fopen(filename, "r");
- if (!input)
- return error(ENOENT, (uint8_t*)"File not found: %s", filename);
- }
- else
- input = stdin;
-
- uint8_t* line = NULL;
- size_t pline_len = 0;
- uint8_t* pline = NULL;
- BOOL quote = FALSE;
- ucs4_t uch;
- size_t ch_len = 0;
- size_t output_lines = 0;
- size_t column_start = 0;
-
- CALLOC(line, uint8_t, BUFSIZE)
-
- while (!feof(input))
- {
- char* eol = NULL;
- if (!fgets((char*)line, sizeof(uint8_t) * BUFSIZE-1, input))
- break;
-
- eol = strchr((char*)line, '\n');
- if (eol)
- {
- if (msdos && *line != '\n' && *(eol-1) == '\r')
- *(eol-1) = 0;
- *eol = 0;
- }
-
- if (!*line)
- continue;
-
- quote = FALSE;
- pline = line;
- colno = 0;
- current_rune_column = 0;
-
- /* Top border */
- if (lineno == 0)
- {
- if (!border_mode)
- table_columns = number_of_columns(line, delimiter);
- else
- table_columns = 1;
-
- /* Sanity check */
- if (rune_columns < table_columns+2)
- rune_columns = table_columns+2;
-
- if (format && !border_mode)
- {
- ULONG* pformat = format;
- ULONG format_sum = 0;
- while (*pformat)
- format_sum += *pformat++;
- pformat = format;
- while (*pformat && format_sum)
- {
- *pformat = round_div((rune_columns-table_columns-2)
- * (*pformat), format_sum);
- pformat++;
- }
- }
- else
- format_value = (rune_columns-table_columns-2) / table_columns;
-
- current_table_column = 0;
- column_start = 0;
- while (current_table_column < table_columns)
- {
- if (current_rune_column == 0)
- {
- printf("%s", table_symbols[current_symbol_set][0]);
- column_start++;
- }
- else if (!within_column(column_start))
- {
- if (current_table_column == table_columns-1)
- {
- printf("%s", table_symbols[current_symbol_set][2]);
- current_table_column++;
- }
- else
- {
- printf("%s", table_inner_symbols[current_inner_symbol_set][0]);
- column_start++;
- if (format)
- column_start += *(format+current_table_column);
- else
- column_start += format_value;
- current_table_column++;
- }
- }
- else
- printf("%s", table_symbols[current_symbol_set][1]);
- current_rune_column++;
- }
- printf("\n");
- output_lines++;
- }
-
- /* Inner rows */
- current_table_column = 0;
- current_rune_column = 0;
- column_start = 0;
-
- printf("%s", table_symbols[current_symbol_set][3]);
-
- if (handle_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
-
- while (pline && *pline)
- {
- if (*pline == '"')
- {
- quote = !quote;
- pline++;
- colno++;
- }
- else
- {
- uint8_t* pch_end;
- pline_len = u8_strlen(line);
- ch_len = u8_mbtouc(&uch, pline, pline_len);
- if (border_mode)
- {
- pch_end = pline + ch_len;
- if (within_column(column_start))
- {
- while (pline != pch_end)
- printf("%c", *pline++);
- current_rune_column++;
- }
- pline = pch_end;
- colno += ch_len;
- }
- else if (ch_len <= 0)
- {
- if (within_column(column_start))
- {
- printf("%c", *pline++);
- current_rune_column++;
- }
- colno++;
- }
- else if (uch == '\t' && expand_tabs)
- {
- while (within_column(column_start))
- {
- printf(" ");
- current_rune_column++;
- if (current_rune_column % tab_length == 0)
- break;
- }
- pline++;
- colno++;
- }
- else if (uch == delimiter && !quote
- && current_table_column < table_columns-1)
- {
- if (handle_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_OFF);
-
- while (within_column(column_start))
- {
- printf(" ");
- current_rune_column++;
- }
- column_start++;
- if (format)
- column_start += *(format+current_table_column);
- else
- column_start += format_value;
- if (current_table_column != table_columns-1)
- {
- printf("%s", table_inner_symbols[current_inner_symbol_set][1]);
- current_rune_column++;
- current_table_column++;
- }
-
- if (handle_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_ON);
-
- pline += ch_len;
- colno += ch_len;
- }
- else
- {
- pch_end = pline + ch_len;
- if (within_column(column_start))
- {
- while (pline != pch_end)
- printf("%c", *pline++);
- current_rune_column++;
- }
- pline = pch_end;
- colno += ch_len;
- }
- }
- }
-
- if (handle_ansi && lineno == 0)
- printf("%s", ANSI_SGR_BOLD_OFF);
-
- while (current_table_column < table_columns-1)
- {
- while (within_column(column_start))
- {
- printf(" ");
- current_rune_column++;
- }
- printf("%s", table_inner_symbols[current_inner_symbol_set][1]);
- column_start++;
- if (format)
- column_start += *(format+current_table_column);
- else
- column_start += format_value;
- current_table_column++;
- current_rune_column++;
- }
- while (within_column(column_start))
- {
- printf(" ");
- current_rune_column++;
- }
-
- printf("%s\n", table_symbols[current_symbol_set][5]);
-
- output_lines++;
- lineno++;
- }
-
- fclose(input);
- free(line);
-
- /* Bottom border */
- if (output_lines)
- {
- current_table_column = 0;
- current_rune_column = 0;
- column_start = 0;
- while (current_table_column < table_columns)
- {
- if (current_rune_column == 0)
- {
- printf("%s", table_symbols[current_symbol_set][6]);
- column_start++;
- }
- else if (!within_column(column_start))
- {
- if (current_table_column == table_columns-1)
- {
- printf("%s", table_symbols[current_symbol_set][8]);
- current_table_column++;
- }
- else
- {
- printf("%s", table_inner_symbols[current_inner_symbol_set][2]);
- column_start++;
- if (format)
- column_start += *(format+current_table_column);
- else
- column_start += format_value;
- current_table_column++;
- }
- }
- else
- printf("%s", table_symbols[current_symbol_set][7]);
- current_rune_column++;
- }
- printf("\n");
- output_lines++;
- }
-
- if (format)
- free(format);
-
- return 0;
+ char* arg;
+ Command cmd = CMD_NONE;
+ char* filename = NULL;
+
+ while ((arg = *++argv))
+ {
+ if (*arg == '-')
+ {
+ arg++;
+ char c = *arg++;
+ if (c == '-')
+ {
+ if (!strcmp(arg, "version"))
+ cmd = CMD_VERSION;
+ else if (startswith(arg, "border-mode"))
+ {
+ arg += strlen("border-mode");
+ border_mode = TRUE;
+ }
+ else if (startswith(arg, "columns="))
+ {
+ arg += strlen("columns=");
+ if (set_columns(arg, &rune_columns))
+ return error(EINVAL, "Invalid argument: '%s'",
+ arg);
+ }
+ else if (startswith(arg, "delimiter="))
+ {
+ arg += strlen("delimiter=");
+ if (set_delimiter((u8*)arg, &delimiter))
+ return error(EINVAL, "Invalid argument: '%s'",
+ arg);
+ }
+ else if (startswith(arg, "expand-tabs"))
+ {
+ arg += strlen("expand-tabs");
+ expand_tabs = TRUE;
+ }
+ else if (startswith(arg, "format="))
+ {
+ arg += strlen("format=");
+ set_format(arg, &format, &format_size);
+ }
+ else if (startswith(arg, "msdos"))
+ {
+ arg += strlen("msdos");
+ msdos = TRUE;
+ }
+ else if (startswith(arg, "no-ansi"))
+ {
+ arg += strlen("no-ansi");
+ handle_ansi = FALSE;
+ }
+ else if (startswith(arg, "symbols="))
+ {
+ arg += strlen("symbols=");
+ if (set_symbol_set(arg, ¤t_symbol_set,
+ ¤t_inner_symbol_set))
+ return error(EINVAL, "Invalid argument: '%s'",
+ arg);
+ }
+ else if (!strcmp(arg, "help"))
+ return usage();
+ else
+ {
+ error(EINVAL, "Invalid argument: --%s", arg);
+ return usage();
+ }
+ }
+ else
+ {
+ switch (c)
+ {
+ case 'b':
+ border_mode = TRUE;
+ break;
+ case 'c':
+ cmd = CMD_COLUMNS;
+ break;
+ case 'd':
+ cmd = CMD_DELIMITER;
+ break;
+ case 'f':
+ cmd = CMD_FORMAT;
+ break;
+ case 'h':
+ return usage();
+ break;
+ case 'm':
+ msdos = TRUE;
+ break;
+ case 'n':
+ handle_ansi = FALSE;
+ break;
+ case 's':
+ cmd = CMD_SYMBOLS;
+ break;
+ case 't':
+ expand_tabs = TRUE;
+ break;
+ case 'v':
+ cmd = CMD_VERSION;
+ break;
+ default:
+ error(EINVAL, "Invalid argument: -%c", c);
+ return usage();
+ }
+ }
+ }
+ else
+ {
+ if (cmd == CMD_COLUMNS)
+ {
+ if (set_columns(arg, &rune_columns))
+ return error(EINVAL, "Invalid argument: '%s'", arg);
+ }
+ else if (cmd == CMD_DELIMITER)
+ {
+ if (set_delimiter((u8*)arg, &delimiter))
+ return error(EINVAL, "Invalid argument: '%s'", arg);
+ }
+ else if (cmd == CMD_FORMAT)
+ {
+ if (set_format(arg, &format, &format_size))
+ return error(EINVAL, "Invalid argument: '%s'", arg);
+ }
+ else if (cmd == CMD_SYMBOLS)
+ {
+ if (set_symbol_set(arg, ¤t_symbol_set,
+ ¤t_inner_symbol_set))
+ return error(EINVAL, "Invalid argument: '%s'", arg);
+ }
+ else
+ filename = arg;
+ cmd = CMD_NONE;
+ }
+ }
+
+ if (cmd == CMD_VERSION)
+ return version();
+
+ FILE* input = NULL;
+ if (filename)
+ {
+ input = fopen(filename, "r");
+ if (!input)
+ return error(ENOENT, "File not found: %s", filename);
+ }
+ else
+ input = stdin;
+
+ u8* line = NULL;
+ u8* pline = NULL;
+ BOOL quote = FALSE;
+ u32 uch;
+ u8 u8ch[7];
+ size_t u8len = 0;
+ size_t ch_len = 0;
+ size_t output_lines = 0;
+ size_t column_start = 0;
+
+ CALLOC(line, u8, BUFSIZE)
+
+ while (!feof(input))
+ {
+ char* eol = NULL;
+ if (!fgets((char*)line, BUFSIZE-1, input))
+ break;
+
+ eol = strchr((char*)line, '\n');
+ if (eol)
+ {
+ if (msdos && *line != '\n' && *(eol-1) == '\r')
+ *(eol-1) = 0;
+ *eol = 0;
+ }
+
+ if (!*line)
+ continue;
+
+ quote = FALSE;
+ pline = line;
+ colno = 0;
+ current_rune_column = 0;
+
+ /* Top border */
+ if (lineno == 0)
+ {
+ if (!border_mode)
+ table_columns = number_of_columns(line, delimiter);
+ else
+ table_columns = 1;
+
+ /* Sanity check */
+ if (rune_columns < table_columns+2)
+ rune_columns = table_columns+2;
+
+ if (format && !border_mode)
+ {
+ ULONG* pformat = format;
+ ULONG format_sum = 0;
+ while (*pformat)
+ format_sum += *pformat++;
+ pformat = format;
+ while (*pformat && format_sum)
+ {
+ *pformat = round_div((rune_columns-table_columns-2)
+ * (*pformat), format_sum);
+ pformat++;
+ }
+ }
+ else
+ format_value = (rune_columns-table_columns-2) / table_columns;
+
+ current_table_column = 0;
+ column_start = 0;
+ while (current_table_column < table_columns)
+ {
+ if (current_rune_column == 0)
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[
+ current_symbol_set][0]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ column_start++;
+ }
+ else if (!within_column(column_start))
+ {
+ if (current_table_column == table_columns-1)
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[
+ current_symbol_set][2]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ current_table_column++;
+ }
+ else
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_inner_symbols[
+ current_inner_symbol_set][0]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ column_start++;
+ if (format)
+ column_start += *(format+current_table_column);
+ else
+ column_start += format_value;
+ current_table_column++;
+ }
+ }
+ else
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[
+ current_symbol_set][1]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ }
+ current_rune_column++;
+ }
+ printf("\n");
+ output_lines++;
+ }
+
+ /* Inner rows */
+ current_table_column = 0;
+ current_rune_column = 0;
+ column_start = 0;
+
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[current_symbol_set][3]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+
+ if (handle_ansi && lineno == 0)
+ printf("%s", ANSI_SGR_BOLD_ON);
+
+ while (pline && *pline)
+ {
+ if (*pline == '"')
+ {
+ quote = !quote;
+ pline++;
+ colno++;
+ }
+ else
+ {
+ u8* pch_end;
+ u8_char_to_u32(&uch, pline, &ch_len);
+ if (border_mode)
+ {
+ pch_end = pline + ch_len;
+ if (within_column(column_start))
+ {
+ while (pline != pch_end)
+ printf("%c", *pline++);
+ current_rune_column++;
+ }
+ pline = pch_end;
+ colno += ch_len;
+ }
+ else if (ch_len <= 0)
+ {
+ if (within_column(column_start))
+ {
+ printf("%c", *pline++);
+ current_rune_column++;
+ }
+ colno++;
+ }
+ else if (uch == (u32)L'\t' && expand_tabs)
+ {
+ while (within_column(column_start))
+ {
+ printf(" ");
+ current_rune_column++;
+ if (current_rune_column % tab_length == 0)
+ break;
+ }
+ pline++;
+ colno++;
+ }
+ else if (uch == delimiter && !quote
+ && current_table_column < table_columns-1)
+ {
+ if (handle_ansi && lineno == 0)
+ printf("%s", ANSI_SGR_BOLD_OFF);
+
+ while (within_column(column_start))
+ {
+ printf(" ");
+ current_rune_column++;
+ }
+ column_start++;
+ if (format)
+ column_start += *(format+current_table_column);
+ else
+ column_start += format_value;
+ if (current_table_column != table_columns-1)
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_inner_symbols[
+ current_inner_symbol_set][1]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ current_rune_column++;
+ current_table_column++;
+ }
+
+ if (handle_ansi && lineno == 0)
+ printf("%s", ANSI_SGR_BOLD_ON);
+
+ pline += ch_len;
+ colno += ch_len;
+ }
+ else
+ {
+ pch_end = pline + ch_len;
+ if (within_column(column_start))
+ {
+ while (pline != pch_end)
+ printf("%c", *pline++);
+ current_rune_column++;
+ }
+ pline = pch_end;
+ colno += ch_len;
+ }
+ }
+ }
+
+ if (handle_ansi && lineno == 0)
+ printf("%s", ANSI_SGR_BOLD_OFF);
+
+ while (current_table_column < table_columns-1)
+ {
+ while (within_column(column_start))
+ {
+ printf(" ");
+ current_rune_column++;
+ }
+ u8len = u32_char_to_u8(u8ch,
+ *table_inner_symbols[
+ current_inner_symbol_set][1]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ column_start++;
+ if (format)
+ column_start += *(format+current_table_column);
+ else
+ column_start += format_value;
+ current_table_column++;
+ current_rune_column++;
+ }
+ while (within_column(column_start))
+ {
+ printf(" ");
+ current_rune_column++;
+ }
+
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[current_symbol_set][5]);
+ u8ch[u8len] = 0;
+ printf("%s\n", u8ch);
+
+ output_lines++;
+ lineno++;
+ }
+
+ fclose(input);
+ free(line);
+
+ /* Bottom border */
+ if (output_lines)
+ {
+ current_table_column = 0;
+ current_rune_column = 0;
+ column_start = 0;
+ while (current_table_column < table_columns)
+ {
+ if (current_rune_column == 0)
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[
+ current_symbol_set][6]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ column_start++;
+ }
+ else if (!within_column(column_start))
+ {
+ if (current_table_column == table_columns-1)
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[
+ current_symbol_set][8]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ current_table_column++;
+ }
+ else
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_inner_symbols[
+ current_inner_symbol_set][2]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ column_start++;
+ if (format)
+ column_start += *(format+current_table_column);
+ else
+ column_start += format_value;
+ current_table_column++;
+ }
+ }
+ else
+ {
+ u8len = u32_char_to_u8(u8ch,
+ *table_symbols[
+ current_symbol_set][7]);
+ u8ch[u8len] = 0;
+ printf("%s", u8ch);
+ }
+ current_rune_column++;
+ }
+ printf("\n");
+ output_lines++;
+ }
+
+ if (format)
+ free(format);
+
+ return 0;
}
diff --git a/table.do b/table.do
@@ -1,3 +1,9 @@
-redo-ifchange table.o table.c defs.h
-${TABLE_CC:-gcc} -g -Wall -std=c99 -o $3 table.o -lunistring
+for f in *.h.in; do
+ echo $f | sed -e's/\.in$//g'
+done | xargs redo-ifchange
+for f in *.h *.c; do
+ echo $f
+ echo $f | sed -e's/\.c$/.o/g'
+done | xargs redo-ifchange
+${TABLE_CC:-gcc} -g -Wall -std=c99 -o $3 table.o utf8.o
diff --git a/utf8.c b/utf8.c
@@ -0,0 +1,161 @@
+/* See the file LICENSE for copyright and license details. */
+
+#include "utf8.h"
+
+/*
+ * 00000000 -- 0000007F: 0xxxxxxx
+ * (2^7 = 128 chars)
+ * 00000080 -- 000007FF: 110xxxxx 10xxxxxx
+ * (2^5 = 32 chars)
+ * 00000800 -- 0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
+ * (2^4 = 16 chars)
+ * 00010000 -- 001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * (2^3 = 8 chars)
+ * 00200000 -- 007FFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * (2^2 = 4 chars)
+ * 00800000 -- 00FFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 10xxxxxx
+ * (2^1 = 2 chars)
+ */
+
+const int
+utf_length_table[256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 32 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 128 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 160 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 192 */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 224 */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1, /* 256 */
+};
+
+const int
+extract_masks[6] = {
+ XMASK1, XMASK2, XMASK3, XMASK4, XMASK5, XMASK6
+};
+
+int
+u8_char_to_u32(u32* to, const u8 *from, size_t* from_delta)
+{
+ const u8* pfrom = from;
+ if (!from)
+ return 1;
+ *from_delta = 0;
+ int len = utf_length_table[*from];
+ *to = *from & extract_masks[len-1];
+ for (int i = 1; i < len; i++)
+ {
+ pfrom = from + i;
+ if (!*pfrom)
+ return 1;
+ *to <<= 6;
+ *to |= *pfrom & XMASKR;
+ }
+ *from_delta = len;
+
+ return 0;
+}
+
+size_t
+u32_char_to_u8(u8 *to, const u32 from)
+{
+ size_t len = 0;
+ u8 start = 0;
+ u32 cfrom = from;
+ if (from >= BOUND6)
+ {
+ start = START6;
+ len = 6;
+ }
+ else if (from >= BOUND5)
+ {
+ start = START5;
+ len = 5;
+ }
+ else if (from >= BOUND4)
+ {
+ start = START4;
+ len = 4;
+ }
+ else if (from >= BOUND3)
+ {
+ start = START3;
+ len = 3;
+ }
+ else if (from >= BOUND2)
+ {
+ start = START2;
+ len = 2;
+ }
+ else
+ {
+ start = START1;
+ len = 1;
+ }
+ for (int i = len-1; i > 0; i--)
+ {
+ to[i] = STARTR | (cfrom & XMASKR);
+ cfrom >>= 6;
+ }
+ to[0] = start | cfrom;
+ return len;
+}
+
+int
+u8_to_u32(u32 *to, const u8 *from, size_t* from_delta)
+{
+ const u8* pfrom = from;
+ u32* pto = to;
+ if (!from)
+ return 1;
+ size_t delta = 0;
+ *from_delta = 0;
+ while (*pfrom)
+ {
+ int result = u8_char_to_u32(pto, pfrom, &delta);
+ if (result)
+ return result;
+ pto++;
+ pfrom += delta;
+ *from_delta += delta;
+ }
+ *pto = 0;
+ return 0;
+}
+
+size_t
+u32_to_u8(u8 *to, const u32* from)
+{
+ u8* pto = to;
+ const u32* pfrom = from;
+ size_t len = 0;
+ if (!from)
+ return 0;
+ while (*pfrom)
+ {
+ size_t delta = u32_char_to_u8(pto, *pfrom);
+ pto += delta;
+ len += delta;
+ pfrom++;
+ }
+ return len;
+}
+
+size_t
+u32_strlen(const u32* s)
+{
+ const u32* ps = s;
+ while (ps && *ps)
+ ps++;
+ return ps - s;
+}
+
diff --git a/utf8.h b/utf8.h
@@ -0,0 +1,40 @@
+/* See the file LICENSE for copyright and license details. */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define XMASK1 0x7F /* b01111111 */
+#define XMASK2 0x1F /* b00011111 */
+#define XMASK3 0x0F /* b00001111 */
+#define XMASK4 0x07 /* b00000111 */
+#define XMASK5 0x03 /* b00000011 */
+#define XMASK6 0x01 /* b00000001 */
+
+#define XMASKR 0x3F /* b00111111 */
+
+/*
+#define BOUND1 0x0*/
+#define BOUND2 0x80
+#define BOUND3 0x800
+#define BOUND4 0x10000
+#define BOUND5 0x200000
+#define BOUND6 0x800000
+
+#define START1 0x00 /* b0xxxxxxx */
+#define START2 0xC0 /* b110xxxxx */
+#define START3 0xE0 /* b1110xxxx */
+#define START4 0xF0 /* b11110xxx */
+#define START5 0xF8 /* b111110xx */
+#define START6 0xFC /* b1111110x */
+
+#define STARTR 0x80 /* b10xxxxxx */
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+
+int u8_char_to_u32(u32* to, const u8* from, size_t* from_delta);
+size_t u32_char_to_u8(u8* to, const u32 from);
+int u8_to_u32(u32* to, const u8* from, size_t* from_delta);
+size_t u32_to_u8(u8* to, const u32* from);
+size_t u32_strlen(const u32* s);
+
diff --git a/version.h.in b/version.h.in
@@ -0,0 +1,4 @@
+#define PROGRAMNAME "table"
+#define DATE "%DATE%"
+#define VERSION "%VERSION%"
+