diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2022-10-26 23:57:45 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2022-10-26 23:57:45 -0400 |
commit | 5baaec22352873767dbf253dc6deec4f55049886 (patch) | |
tree | 11ce974b1664be6cff5208da1fa91923bc7e4a24 | |
parent | f28f138c997a944c4144de10046f15191ecd88d9 (diff) | |
download | sayeth-5baaec22352873767dbf253dc6deec4f55049886.tar.gz |
Wide character support -- from hellwchar
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | draw.c | 107 | ||||
-rw-r--r-- | driver.c | 47 | ||||
-rw-r--r-- | main.c | 63 | ||||
-rw-r--r-- | sayeth.h | 22 |
5 files changed, 140 insertions, 101 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 673e65d..f80bc24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ if (MSVC) add_compile_options(/W4 /WX) else() # lots of warnings and all warnings as errors - add_compile_options(-Wall -Wextra -pedantic -Werror) + add_compile_options(-Wall -Wextra -pedantic) endif() add_executable(sayeth main.c driver.c draw.c) @@ -2,20 +2,22 @@ #include <stdio.h> #include <string.h> #include <stdarg.h> +#include <wchar.h> #include "sayeth.h" size_t START_Y_BOX = 0; size_t START_Y_CARET = 0; size_t START_Y_DATA = 0; -const char *A_TAB = " "; -char wspace = ' '; -char box_top_left = '\0'; -char box_top = '\0'; -char box_top_right = '\0'; -char box_side = '\0'; -char box_bottom_left = '\0'; -char box_bottom = '\0'; -char box_bottom_right = '\0'; +const wchar_t *A_TAB = L" "; +wchar_t wspace = L' '; +wchar_t box_top_left = L'\0'; +wchar_t box_top = L'\0'; +wchar_t box_top_right = L'\0'; +wchar_t box_side = L'\0'; +wchar_t box_bottom_left = L'\0'; +wchar_t box_bottom = L'\0'; +wchar_t box_bottom_right = L'\0'; +extern int do_fill; void box_draw_top(size_t y, size_t longest) { repchar(wspace, y); @@ -41,20 +43,20 @@ void box_draw_end_line(size_t longest, size_t len) { repchar(box_side, 1); } -int box_printf(const char *fmt, ...) { +int box_printf(const wchar_t *fmt, ...) { int count; va_list list; va_start(list, fmt); size_t len = 0; - char data[INPUT_BUFSIZ] = {0}; - char output[INPUT_BUFSIZ] = {0}; - count = vsnprintf(data, sizeof(data) - 1, fmt, list); + wchar_t data[INPUT_BUFSIZ] = {0}; + wchar_t output[INPUT_BUFSIZ] = {0}; + count = vswprintf(data, sizeof(data) - 1, fmt, list); // convert tabs to spaces - for (size_t i = 0, n = 0; i < strlen(data) && n < sizeof(output); i++, n++) { - if (data[i] == '\t') { - strcat(&output[n], A_TAB); - n = n + strlen(A_TAB) - 1; + for (size_t i = 0, n = 0; i < wcslen(data) && n < sizeof(output); i++, n++) { + if (data[i] == L'\t') { + wcscat(&output[n], A_TAB); + n = n + wcslen(A_TAB) - 1; continue; } output[n] = data[i]; @@ -63,10 +65,10 @@ int box_printf(const char *fmt, ...) { size_t longest = get_longest_line(output); box_draw_top(START_Y_BOX, longest); - puts(""); + wprintf(L"\n"); - for (size_t i = 0; i < strlen(output); i++) { - if (i == strlen(output) - 1) { + for (size_t i = 0; i < wcslen(output); i++) { + if (i == wcslen(output) - 1) { box_draw_end_line(longest, len); continue; } @@ -77,36 +79,36 @@ int box_printf(const char *fmt, ...) { if (output[i] == '\n') { box_draw_end_line(longest, len); - putc('\n', stdout); + putwc('\n', stdout); len = 0; continue; } - putc(output[i], stdout); + putwc(output[i], stdout); len++; } - puts(""); + wprintf(L"\n"); box_draw_bottom(START_Y_BOX, longest); va_end(list); return count; } -void caret_draw(char *data, size_t indent, size_t attached) { - if (!strlen(data)) +void caret_draw(wchar_t *data, size_t indent, size_t attached) { + if (!wcslen(data)) return; if (!attached) repchar(wspace, START_Y_BOX); - for (size_t i = 0; i < strlen(data); i++) { - if (data[i] == '\\' && isalpha(data[i + 1])) { + for (size_t i = 0; i < wcslen(data); i++) { + if (data[i] == L'\\' && isalpha(data[i + 1])) { i++; switch (data[i]) { case 'n': - putc('\n', stdout); - if (i == strlen(data) - 1) + putwc(L'\n', stdout); + if (i == wcslen(data) - 1) continue; repchar(wspace, indent); continue; @@ -114,25 +116,46 @@ void caret_draw(char *data, size_t indent, size_t attached) { continue; } } - putc(data[i], stdout); + putwc(data[i], stdout); } } +size_t count_lines(wchar_t *s) { + size_t count = 0; + wchar_t *ptr = s; -void data_draw(char *data, size_t indent) { + while (*ptr != L'\0') { + if (*ptr == L'\n') + count++; + ptr++; + } + return count; +} + +void data_draw(wchar_t *data, size_t indent) { size_t len = 0; - for (size_t i = 0; i < strlen(data); i++) { - if (len == 0) { - repchar(wspace, indent); + wchar_t *inbuf = wcsdup(data); + size_t longest = get_longest_line(inbuf); + size_t lines = count_lines(inbuf); + wchar_t buf[DATA_BUFSIZ] = {0}; + + wchar_t *token = NULL; + wchar_t *ptr; + token = wcstok(inbuf, L"\n", &ptr); + for (size_t i = 0; token != NULL; i++) { + memset(buf, '\0', sizeof(buf)); + for (size_t y = 0; y < indent; y++) { + buf[y] = wspace; } - - if (data[i] == '\n') { - putc('\n', stdout); - len = 0; - continue; + wcscat(buf, token); + len = wcslen(buf); + if (i < lines) { + for (size_t y = len; y < longest + (indent * 2); y++) { + buf[y] = wspace; + } + wcscat(buf, L"\n"); } - - putc(data[i], stdout); - len++; + wprintf(L"%S", buf); + token = wcstok(NULL, L"\n", &ptr); } } @@ -1,8 +1,10 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <wchar.h> #include "sayeth.h" +extern int do_fill; extern size_t START_Y_BOX; extern size_t START_Y_CARET; extern size_t START_Y_DATA; @@ -35,52 +37,52 @@ struct Driver *driver_load(char *filename) { } for (size_t i = 0; i < 9; i++) { - char buf[INPUT_BUFSIZ] = {0}; + wchar_t buf[INPUT_BUFSIZ] = {0}; ssize_t lastpos = ftell(fp); - if (fgets(buf, sizeof(buf) - 1, fp) == NULL) { + if (fgetws(buf, sizeof(buf) - 1, fp) == NULL) { break; } - if (!strlen(buf) || buf[0] == '#') { + if (!wcslen(buf) || buf[0] == '#') { i--; continue; } - buf[strlen(buf) - 1] = '\0'; + buf[wcslen(buf) - 1] = '\0'; switch (i) { case 0: - driver->name = strdup(buf); + driver->name = wcsdup(buf); if (!driver->name) { fclose(fp); return NULL; } break; case 1: - driver->box_indent = strtol(buf, NULL, 10); + driver->box_indent = wcstol(buf, NULL, 10); break; case 2: - driver->box_elements = strdup(buf); + driver->box_elements = wcsdup(buf); if (!driver->box_elements) { fclose(fp); return NULL; } break; case 3: - driver->caret_pos = strtol(buf, NULL, 10); + driver->caret_pos = wcstol(buf, NULL, 10); break; case 4: - driver->caret_indent = strtol(buf, NULL, 10); + driver->caret_indent = wcstol(buf, NULL, 10); break; case 5: - driver->caret_attached = strtol(buf, NULL, 10); + driver->caret_attached = wcstol(buf, NULL, 10); break; case 6: - driver->caret = strdup(buf); + driver->caret = wcsdup(buf); if (!driver->caret) { fclose(fp); return NULL; } break; case 7: - driver->data_indent = strtol(buf, 0, 10); + driver->data_indent = wcstol(buf, 0, 10); break; case 8: driver->data = calloc(DATA_BUFSIZ, sizeof(*driver->data)); @@ -88,9 +90,12 @@ struct Driver *driver_load(char *filename) { fclose(fp); return NULL; } - // rewind to beginning of the data section fseek(fp, lastpos, SEEK_SET); - fread(driver->data, 1, DATA_BUFSIZ - 1, fp); + wint_t c = 0; + size_t n = 0; + while ((c = fgetwc(fp)) != WEOF) { + driver->data[n++] = (wchar_t) c; + } break; default: break; @@ -129,7 +134,7 @@ int driver_register(struct Driver *driver) { return 0; } -void drivers_free() { +void drivers_free(void) { for (size_t i = 0; i < drivers_alloc; i++) { if (drivers[i]) { if (drivers[i]->name) @@ -145,8 +150,8 @@ void drivers_free() { } free(drivers); } -void driver_run(struct Driver *driver, char *input) { - char *elem = driver->box_elements; +void driver_run(struct Driver *driver, wchar_t *input) { + wchar_t *elem = driver->box_elements; box_top_left = elem[0]; box_top = elem[1]; box_top_right = elem[2]; @@ -159,7 +164,7 @@ void driver_run(struct Driver *driver, char *input) { START_Y_DATA = driver->data_indent; if (!driver->caret_pos) { - box_printf("%s", input); + box_printf(L"%S", input); caret_draw(driver->caret, START_Y_CARET, driver->caret_attached); } @@ -169,13 +174,13 @@ void driver_run(struct Driver *driver, char *input) { if (driver->caret_pos) { caret_draw(driver->caret, START_Y_CARET, driver->caret_attached); - box_printf("%s", input); + box_printf(L"%S", input); } } -struct Driver *driver_lookup(char *name) { +struct Driver *driver_lookup(wchar_t *name) { for (size_t i = 0; drivers[i] != NULL; i++) { - if (!strcmp(drivers[i]->name, name)) { + if (!wcscmp(drivers[i]->name, name)) { return drivers[i]; } } @@ -5,9 +5,12 @@ #include <dirent.h> #include <errno.h> #include <limits.h> +#include <wchar.h> +#include <locale.h> #include "config.h" #include "sayeth.h" +int do_fill = 1; extern char wspace; extern struct Driver **drivers; extern size_t drivers_alloc; @@ -18,9 +21,9 @@ extern size_t drivers_used; * @param ch character to repeat * @param limit number of times to repeat */ -void repchar(char ch, size_t limit) { +void repchar(wchar_t ch, size_t limit) { while (limit > 0) { - putc(ch, stdout); + putwc(ch, stdout); limit--; } } @@ -30,34 +33,30 @@ void repchar(char ch, size_t limit) { * @param s the string * @return longest line */ -size_t get_longest_line(char *s) { +size_t get_longest_line(wchar_t *s) { size_t *lengths; - size_t len; - size_t linecount; + size_t linecount = 0; size_t longest; - char *ch = s; + wchar_t *ch = s; + wchar_t *buf = wcsdup(s); - linecount = 0; - while (*ch != '\0') { - if (*ch == '\n') - linecount++; - ch++; - } + wchar_t *token = NULL; + wchar_t *ptr; + token = wcstok(buf, L"\n", &ptr); + if (token) linecount++; + for (; (token = wcstok(NULL, L"\n", &ptr)) != NULL; linecount++); + wcscpy(buf, s); lengths = calloc(linecount + 1, sizeof(*lengths)); if (!lengths) { return ULONG_MAX; } - len = 0; - for (size_t i = 0, line = 0; i < strlen(s); i++) { - if (s[i] == '\n') { - lengths[line] = len; - line++; - len = 0; - continue; - } - len++; + token = wcstok(buf, L"\n", &ptr); + for (size_t i = 0; token != NULL; i++) { + size_t len = wcslen(token); + lengths[i] = len; + token = wcstok(NULL, L"\n", &ptr); } longest = lengths[0]; @@ -67,6 +66,7 @@ size_t get_longest_line(char *s) { } } free(lengths); + free(buf); return longest; } @@ -82,8 +82,9 @@ void usage(char *prog) { } int main(int argc, char *argv[]) { - char driver_name[255] = {0}; - char input[INPUT_BUFSIZ] = {0}; + setlocale(LC_ALL, ""); + char *driver_name = calloc(255, sizeof(*driver_name)); + char *input = calloc(INPUT_BUFSIZ, sizeof(*input)); struct Driver *driver = NULL; char *driver_dir = getenv("SAYETH_DRIVERS"); if (!driver_dir) { @@ -176,14 +177,24 @@ int main(int argc, char *argv[]) { input[strlen(input)] = '\n'; } - driver = driver_lookup(driver_name); + size_t reqsize = 0; + wchar_t wdriver_name[INPUT_BUFSIZ] = {0}; + wchar_t winput[INPUT_BUFSIZ] = {0}; + mbstate_t mbs; + memset(&mbs, 0, sizeof(mbs)); + mbsrtowcs(wdriver_name, &driver_name, 255 - 1, &mbs); + mbsrtowcs(winput, &input, INPUT_BUFSIZ - 1, &mbs); + //reqsize = wcstombs(input, NULL, 0); + //wcstombs(input, winput, reqsize); + + driver = driver_lookup(wdriver_name); if (!driver) { fprintf(stderr, "Driver not found\n"); exit(1); } - driver_run(driver, input); - puts(""); + driver_run(driver, winput); + wprintf(L"\n"); drivers_free(); free(driver_dir); return 0; @@ -12,9 +12,9 @@ #define DRIVERS_ALLOC_DEFAULT 128 struct Driver { - char *name; // Driver name (passed to '-d' argument) + wchar_t *name; // Driver name (passed to '-d' argument) size_t box_indent; // Shift box n columns to the right - char *box_elements; // Border characters + wchar_t *box_elements; // Border characters // top left, top, top right, sides, bottom left, bottom, bottom right // e.g. "/-\|\-/' /* @@ -25,7 +25,7 @@ struct Driver { size_t caret_pos; // Above or below the box size_t caret_indent; // Shift caret n columns to the right size_t caret_attached; // Inject a new line *after* art data, or not? - char *caret; // Caret characters + wchar_t *caret; // Caret characters // e.g. "\n \ |\n \ |\n \|\n" /* * \ | @@ -33,24 +33,24 @@ struct Driver { * \| */ size_t data_indent; // Shift art data n columns to the right - char *data; // Art data (up to size: DATA_BUFSIZ - 1) + wchar_t *data; // Art data (up to size: DATA_BUFSIZ - 1) }; -void repchar(char ch, size_t limit); -size_t get_longest_line(char *s); +void repchar(wchar_t ch, size_t limit); +size_t get_longest_line(wchar_t *s); struct Driver *driver_load(char *filename); -struct Driver *driver_lookup(char *name); +struct Driver *driver_lookup(wchar_t *name); int driver_register(struct Driver *driver); -void driver_run(struct Driver *driver, char *input); +void driver_run(struct Driver *driver, wchar_t *input); void drivers_free(void); void box_draw_top(size_t y, size_t longest); void box_draw_bottom(size_t y, size_t longest); void box_draw_next_line(size_t y); void box_draw_end_line(size_t longest, size_t len); -int box_printf(const char *fmt, ...); +int box_printf(const wchar_t *fmt, ...); -void caret_draw(char *data, size_t indent, size_t attached); -void data_draw(char *data, size_t indent); +void caret_draw(wchar_t *data, size_t indent, size_t attached); +void data_draw(wchar_t *data, size_t indent); #endif //SAYETH_SAYETH_H |