From: Michael Göhler Date: Sun, 8 Feb 2015 16:53:39 +0000 (+0100) Subject: Merge pull request #79 from visit1985/wchar_support X-Git-Url: https://git.danieliu.xyz/?p=smdp.git;a=commitdiff_plain;h=80d361502cd01220458e3961dd380f6a26ea682a;hp=09d6bd1a8a33fac75a999f0822ec10cb77fbc072 Merge pull request #79 from visit1985/wchar_support wchar support + line by line support --- diff --git a/include/cstack.h b/include/cstack.h index fd6c60d..230fcdd 100644 --- a/include/cstack.h +++ b/include/cstack.h @@ -41,21 +41,21 @@ #include "common.h" typedef struct _cstack_t { - char *content; + wchar_t *content; size_t alloc; size_t size; int head; - void (*push)(struct _cstack_t *self, char c); - char (*pop)(struct _cstack_t *self); - bool (*top)(struct _cstack_t *self, char c); + void (*push)(struct _cstack_t *self, wchar_t c); + wchar_t (*pop)(struct _cstack_t *self); + bool (*top)(struct _cstack_t *self, wchar_t c); bool (*empty)(struct _cstack_t *self); void (*delete)(struct _cstack_t *self); } cstack_t; cstack_t *cstack_init(); -void cstack_push(cstack_t *self, char c); -char cstack_pop(cstack_t *self); -bool cstack_top(cstack_t *self, char c); +void cstack_push(cstack_t *self, wchar_t c); +wchar_t cstack_pop(cstack_t *self); +bool cstack_top(cstack_t *self, wchar_t c); bool cstack_empty(cstack_t *self); void cstack_delete(cstack_t *self); diff --git a/include/cstring.h b/include/cstring.h index d0a7c1c..f9225be 100644 --- a/include/cstring.h +++ b/include/cstring.h @@ -42,19 +42,19 @@ #define REALLOC_ADD 10 typedef struct _cstring_t { - char *text; + wchar_t *value; size_t size; size_t alloc; - void (*expand)(struct _cstring_t *self, char x); - void (*expand_arr)(struct _cstring_t *self, char *x); + void (*expand)(struct _cstring_t *self, wchar_t x); + void (*expand_arr)(struct _cstring_t *self, wchar_t *x); void (*strip)(struct _cstring_t *self, int pos, int len); void (*reset)(struct _cstring_t *self); void (*delete)(struct _cstring_t *self); } cstring_t; cstring_t *cstring_init(); -void cstring_expand(cstring_t *self, char x); -void cstring_expand_arr(cstring_t *self, char *x); +void cstring_expand(cstring_t *self, wchar_t x); +void cstring_expand_arr(cstring_t *self, wchar_t *x); void cstring_strip(cstring_t *self, int pos, int len); void cstring_reset(cstring_t *self); void cstring_delete(cstring_t *self); diff --git a/include/markdown.h b/include/markdown.h index f38a646..da8805e 100644 --- a/include/markdown.h +++ b/include/markdown.h @@ -53,6 +53,7 @@ enum line_bitmask { IS_UNORDERED_LIST_3, IS_UNORDERED_LIST_EXT, IS_CENTER, + IS_STOP, IS_EMPTY }; @@ -70,6 +71,7 @@ typedef struct _slide_t { struct _slide_t *prev; struct _slide_t *next; int lines; + int stop; } slide_t; typedef struct _deck_t { diff --git a/include/parser.h b/include/parser.h index 477342d..67d15d4 100644 --- a/include/parser.h +++ b/include/parser.h @@ -40,6 +40,11 @@ #include "markdown.h" #include "cstack.h" +#if defined( CYGWIN ) +#undef WEOF +#define WEOF (0xffff) +#endif // defined( CYGWIN ) + #define EXPAND_TABS 4 #define CODE_INDENT 4 #define UNORDERED_LIST_MAX_LEVEL 3 @@ -48,8 +53,6 @@ deck_t *markdown_load(FILE *input); int markdown_analyse(cstring_t *text, int prev); void markdown_debug(deck_t *deck, int debug); void adjust_line_length(line_t *line); -bool is_utf8(char ch); -int length_utf8(char ch); int next_nonblank(cstring_t *text, int i); int prev_blank(cstring_t *text, int i); int next_blank(cstring_t *text, int i); diff --git a/include/url.h b/include/url.h index 1bd3950..c2c386f 100644 --- a/include/url.h +++ b/include/url.h @@ -24,21 +24,21 @@ */ typedef struct _url_t { - char *link_name; - char *target; + wchar_t *link_name; + wchar_t *target; int x; int y; struct _url_t *next; } url_t; void url_init(void); -int url_add(const char *link_name, int link_name_length, const char *target, int target_length, int x, int y); -char * url_get_target(int index); -char * url_get_name(int index); +int url_add(const wchar_t *link_name, int link_name_length, const wchar_t *target, int target_length, int x, int y); +wchar_t* url_get_target(int index); +wchar_t* url_get_name(int index); int url_get_amount(void); void url_purge(void); void url_dump(void); -int url_count_inline(const char *line); -int url_len_inline(const char *text); +int url_count_inline(const wchar_t *line); +int url_len_inline(const wchar_t *value); #endif // !defined( URL_H ) diff --git a/include/viewer.h b/include/viewer.h index d921247..81f23ec 100644 --- a/include/viewer.h +++ b/include/viewer.h @@ -32,6 +32,9 @@ * */ +#define _GNU_SOURCE // enable ncurses wchar support +#define _XOPEN_SOURCE_EXTENDED 1 // enable ncurses wchar support + #if defined( WIN32 ) #include #else @@ -54,7 +57,7 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reload, int noreload); void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colors); -void inline_display(WINDOW *window, const char *c, const int colors); +void inline_display(WINDOW *window, const wchar_t *c, const int colors); void fade_out(WINDOW *window, int trans, int colors, int invert); void fade_in(WINDOW *window, int trans, int colors, int invert); int int_length (int val); diff --git a/src/Makefile b/src/Makefile index fd31fd8..8b75f8f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,6 +33,8 @@ endif ifeq ($(OS),Windows_NT) ifeq (,$(findstring CYGWIN,$(UNAME_S))) CPPFLAGS += -DWIN32 + else + CPPFLAGS += -DCYGWIN endif endif diff --git a/src/cstack.c b/src/cstack.c index 4763b5b..df27ff4 100644 --- a/src/cstack.c +++ b/src/cstack.c @@ -19,6 +19,7 @@ * */ +#include #include // fprintf #include // malloc, realloc @@ -42,24 +43,24 @@ cstack_t *cstack_init() { return stack; } -void cstack_push(cstack_t *self, char c) { +void cstack_push(cstack_t *self, wchar_t c) { if(self->size + sizeof(c) > self->alloc) { - self->alloc += (sizeof(char)); + self->alloc += (sizeof(wchar_t)); if((self->content = realloc(self->content, self->alloc)) == NULL) { fprintf(stderr, "%s\n", "cstack_push() failed to reallocate memory."); exit(EXIT_FAILURE); } } self->content[++self->head] = c; - self->size += (sizeof(char)); + self->size += (sizeof(wchar_t)); } -char cstack_pop(cstack_t *self) { - self->size -= (sizeof(char)); +wchar_t cstack_pop(cstack_t *self) { + self->size -= (sizeof(wchar_t)); return self->content[self->head--]; } -bool cstack_top(cstack_t *self, char c) { +bool cstack_top(cstack_t *self, wchar_t c) { return self->head >= 0 && self->content[self->head] == c; } diff --git a/src/cstring.c b/src/cstring.c index 558a786..c200572 100644 --- a/src/cstring.c +++ b/src/cstring.c @@ -19,7 +19,7 @@ * */ -#include // strlen, memmove +#include // wcslen, wcscat, wmemmove #include // fprintf #include // malloc, realloc @@ -28,7 +28,7 @@ cstring_t *cstring_init() { cstring_t *x = NULL; if((x = malloc(sizeof(cstring_t))) != NULL) { - x->text = NULL; + x->value = NULL; x->size = x->alloc = 0; x->expand = cstring_expand; x->expand_arr = cstring_expand_arr; @@ -42,51 +42,51 @@ cstring_t *cstring_init() { return x; } -void cstring_expand(cstring_t *self, char x) { - if(self->size + sizeof(x) + sizeof(char) > self->alloc) { - self->alloc += (REALLOC_ADD * sizeof(char)); - if((self->text = realloc(self->text, self->alloc)) == NULL) { +void cstring_expand(cstring_t *self, wchar_t x) { + if((self->size + 2) * sizeof(wchar_t) > self->alloc) { + self->alloc += (REALLOC_ADD * sizeof(wchar_t)); + if((self->value = realloc(self->value, self->alloc)) == NULL) { fprintf(stderr, "%s\n", "cstring_expand() failed to reallocate memory."); exit(EXIT_FAILURE); } } - self->text[self->size] = x; - self->text[self->size+1] = '\0'; - self->size = strlen(self->text); + self->value[self->size] = x; + self->value[self->size+1] = L'\0'; + self->size = wcslen(self->value); } -void cstring_expand_arr(cstring_t *self, char *x) { - if(self->size + strlen(x) + sizeof(char) > self->alloc) { - self->alloc = ((strlen(x) + self->size + 1) * sizeof(char)); - if((self->text = realloc(self->text, self->alloc)) == NULL) { - fprintf(stderr, "%s\n", "cstring_expand() failed to reallocate memory."); +void cstring_expand_arr(cstring_t *self, wchar_t *x) { + if((self->size + wcslen(x) + 1) * sizeof(wchar_t) > self->alloc) { + self->alloc = ((self->size + wcslen(x) + 1) * sizeof(wchar_t)); + if((self->value = realloc(self->value, self->alloc)) == NULL) { + fprintf(stderr, "%s\n", "cstring_expand_arr() failed to reallocate memory."); exit(EXIT_FAILURE); } } - self->text = strcat(self->text, x); - self->size = strlen(self->text); - self->text[self->size+1] = '\0'; + self->value = wcscat(self->value, x); + self->size = wcslen(self->value); + self->value[self->size+1] = L'\0'; } void cstring_strip(cstring_t *self, int pos, int len) { if(pos + len >= self->size) { if(pos <= self->size) { - self->text[pos] = '\0'; + self->value[pos] = L'\0'; self->size = pos; } return; } - memmove(&self->text[pos], &self->text[pos+len], self->size - pos - len+1); + wmemmove(&self->value[pos], &self->value[pos+len], self->size - pos - len+1); self->size -= len; } void cstring_reset(cstring_t *self) { - free(self->text); - self->text = NULL; + free(self->value); + self->value = NULL; self->size = self->alloc = 0; } void cstring_delete(cstring_t *self) { - free(self->text); + free(self->value); free(self); } diff --git a/src/main.c b/src/main.c index 37af9bc..e762fbb 100644 --- a/src/main.c +++ b/src/main.c @@ -19,6 +19,7 @@ #include #include +#include // setlocale #include #include #include @@ -82,6 +83,9 @@ int main(int argc, char *argv[]) { } } + // set locale to read and display UTF-8 correctly in ncurses + setlocale(LC_CTYPE, "en_US.UTF8"); + // open file or set input to STDIN char *file = NULL; FILE *input; diff --git a/src/markdown.c b/src/markdown.c index 05c77be..dd1ea48 100644 --- a/src/markdown.c +++ b/src/markdown.c @@ -43,7 +43,7 @@ slide_t *new_slide() { slide_t *x = malloc(sizeof(slide_t)); x->line = NULL; x->prev = x->next = NULL; - x->lines = 0; + x->lines = x->stop = 0; return x; } diff --git a/src/parser.c b/src/parser.c index f835a5c..5ca7ea2 100644 --- a/src/parser.c +++ b/src/parser.c @@ -25,13 +25,15 @@ #include #include #include +#include +#include #include #include "parser.h" deck_t *markdown_load(FILE *input) { - int c = 0; // char + wchar_t c = L'\0'; // char int i = 0; // increment int hc = 0; // header count int lc = 0; // line count @@ -48,13 +50,13 @@ deck_t *markdown_load(FILE *input) { // initialize bits as empty line SET_BIT(bits, IS_EMPTY); - while ((c = fgetc(input)) != EOF) { + while ((c = fgetwc(input)) != WEOF) { if (ferror(input)) { fprintf(stderr, "markdown_load() failed to read input: %s\n", strerror(errno)); exit(EXIT_FAILURE); } - if(c == '\n') { + if(c == L'\n') { // markdown analyse prev = bits; @@ -66,6 +68,14 @@ deck_t *markdown_load(FILE *input) { // clear text (text->reset)(text); + } else if(line && CHECK_BIT(bits, IS_STOP)) { + + // set stop bit on last line + SET_BIT(line->bits, IS_STOP); + + // clear text + (text->reset)(text); + // if text is markdown hr } else if(CHECK_BIT(bits, IS_HR) && CHECK_BIT(line->bits, IS_EMPTY)) { @@ -107,21 +117,21 @@ deck_t *markdown_load(FILE *input) { line->offset = next_nonblank(text, 0); // adjust line length dynamicaly - excluding markup - if(line->text->text) + if(line->text->value) adjust_line_length(line); // new text text = cstring_init(); } - } else if(c == '\t') { + } else if(c == L'\t') { // expand tab to spaces for (i = 0; i < EXPAND_TABS; i++) { - (text->expand)(text, ' '); + (text->expand)(text, L' '); } - } else if(c == '\\') { + } else if(c == L'\\') { // add char to line (text->expand)(text, c); @@ -130,35 +140,14 @@ deck_t *markdown_load(FILE *input) { // and do not increase line count if(next_nonblank(text, 0) < CODE_INDENT) { - c = fgetc(input); + c = fgetwc(input); (text->expand)(text, c); - - if(is_utf8(c)) { - - // if utf-8 char > 1 byte add remaing to line - for(i = 0; i < length_utf8(c) - 1; i++) { - c = fgetc(input); - (text->expand)(text, c); - } - } - } - } else if(isprint(c) || isspace((unsigned char) c)) { + } else if(iswprint(c) || iswspace(c)) { // add char to line (text->expand)(text, c); - - } else if(is_utf8(c)) { - - // add char to line - (text->expand)(text, c); - - // if utf-8 char > 1 byte add remaing to line - for(i = 0; i < length_utf8(c) - 1; i++) { - c = fgetc(input); - (text->expand)(text, c); - } } } (text->delete)(text); @@ -168,13 +157,13 @@ deck_t *markdown_load(FILE *input) { // detect header line = deck->slide->line; - if(line && line->text->size > 0 && line->text->text[0] == '%') { + if(line && line->text->size > 0 && line->text->value[0] == L'%') { // assign header to deck deck->header = line; // find first non-header line - while(line && line->text->size > 0 && line->text->text[0] == '%') { + while(line && line->text->size > 0 && line->text->value[0] == L'%') { hc++; line = line->next; } @@ -319,7 +308,7 @@ int markdown_analyse(cstring_t *text, int prev) { const int unordered_list_offset = unordered_list_level_offset[unordered_list_level]; // return IS_EMPTY on null pointers - if(!text || !text->text) { + if(!text || !text->value) { SET_BIT(bits, IS_EMPTY); return bits; } @@ -327,13 +316,22 @@ int markdown_analyse(cstring_t *text, int prev) { // count leading spaces offset = next_nonblank(text, 0); + // IS_STOP + if((offset < CODE_INDENT || !CHECK_BIT(prev, IS_CODE)) && + (!wcsncmp(&text->value[offset], L"
", 4) || + !wcsncmp(&text->value[offset], L"
", 4) || + !wcsncmp(&text->value[offset], L"^", 1))) { + SET_BIT(bits, IS_STOP); + return bits; + } + // strip trailing spaces - for(eol = text->size; eol > offset && isspace((unsigned char) text->text[eol - 1]); eol--); + for(eol = text->size; eol > offset && iswspace(text->value[eol - 1]); eol--); // IS_UNORDERED_LIST_# if(text->size >= offset + 2 && - (text->text[offset] == '*' || text->text[offset] == '-') && - text->text[offset + 1] == ' ') { + (text->value[offset] == L'*' || text->value[offset] == L'-') && + iswspace(text->value[offset + 1])) { // if different from last lines offset if(offset != unordered_list_offset) { @@ -400,21 +398,22 @@ int markdown_analyse(cstring_t *text, int prev) { // IS_CODE if(offset >= CODE_INDENT && (CHECK_BIT(prev, IS_EMPTY) || - CHECK_BIT(prev, IS_CODE))) { + CHECK_BIT(prev, IS_CODE) || + CHECK_BIT(prev, IS_STOP))) { SET_BIT(bits, IS_CODE); } else { // IS_QUOTE - if(text->text[offset] == '>') { + if(text->value[offset] == L'>') { SET_BIT(bits, IS_QUOTE); } // IS_CENTER if(text->size >= offset + 3 && - text->text[offset] == '-' && - text->text[offset + 1] == '>' && - text->text[offset + 2] == ' ') { + text->value[offset] == L'-' && + text->value[offset + 1] == L'>' && + iswspace(text->value[offset + 2])) { SET_BIT(bits, IS_CENTER); // remove start tag @@ -422,31 +421,31 @@ int markdown_analyse(cstring_t *text, int prev) { eol -= 3; if(text->size >= offset + 3 && - text->text[eol - 1] == '-' && - text->text[eol - 2] == '<' && - text->text[eol - 3] == ' ') { + text->value[eol - 1] == L'-' && + text->value[eol - 2] == L'<' && + iswspace(text->value[eol - 3])) { // remove end tags (text->strip)(text, eol - 3, 3); // adjust end of line - for(eol = text->size; eol > offset && isspace((unsigned char) text->text[eol - 1]); eol--); + for(eol = text->size; eol > offset && iswspace(text->value[eol - 1]); eol--); } } for(i = offset; i < eol; i++) { - if(text->text[i] == ' ') { + if(iswspace(text->value[i])) { spaces++; } else { - switch(text->text[i]) { - case '=': equals++; break; - case '#': hashes++; break; - case '*': stars++; break; - case '-': minus++; break; - case '\\': other++; i++; break; + switch(text->value[i]) { + case L'=': equals++; break; + case L'#': hashes++; break; + case L'*': stars++; break; + case L'-': minus++; break; + case L'\\': other++; i++; break; default: other++; break; } } @@ -454,23 +453,23 @@ int markdown_analyse(cstring_t *text, int prev) { // IS_H1 if(equals > 0 && - hashes + stars + minus + spaces + other == 0) { + hashes + stars + minus + spaces + other == 0) { SET_BIT(bits, IS_H1); } - if(text->text[offset] == '#' && - text->text[offset+1] == ' ') { + if(text->value[offset] == L'#' && + iswspace(text->value[offset+1])) { SET_BIT(bits, IS_H1); SET_BIT(bits, IS_H1_ATX); } // IS_H2 if(minus > 0 && - equals + hashes + stars + spaces + other == 0) { + equals + hashes + stars + spaces + other == 0) { SET_BIT(bits, IS_H2); } - if(text->text[offset] == '#' && - text->text[offset+1] == '#' && - text->text[offset+2] == ' ') { + if(text->value[offset] == L'#' && + text->value[offset+1] == L'#' && + iswspace(text->value[offset+2])) { SET_BIT(bits, IS_H2); SET_BIT(bits, IS_H2_ATX); } @@ -501,7 +500,7 @@ void markdown_debug(deck_t *deck, int debug) { line_t *header; if(debug == 1) { - fprintf(stderr, "headers: %i\nslides: %i\n", deck->headers, deck->slides); + fwprintf(stderr, L"headers: %i\nslides: %i\n", deck->headers, deck->slides); } else if(debug > 1) { @@ -510,12 +509,12 @@ void markdown_debug(deck_t *deck, int debug) { header = deck->header; while(header && header->length > 0 && - header->text->text[0] == '%') { + header->text->value[0] == L'%') { // skip descriptor word (e.g. %title:) offset = next_blank(header->text, 0) + 1; - fprintf(stderr, "header: %s\n", &header->text->text[offset]); + fwprintf(stderr, L"header: %S\n", &header->text->value[offset]); header = header->next; } } @@ -529,17 +528,17 @@ void markdown_debug(deck_t *deck, int debug) { sc++; if(debug == 1) { - fprintf(stderr, " slide %i: %i lines\n", sc, slide->lines); + fwprintf(stderr, L" slide %i: %i lines\n", sc, slide->lines); } else if(debug > 1) { // also print bits and line length - fprintf(stderr, " slide %i:\n", sc); + fwprintf(stderr, L" slide %i:\n", sc); line = slide->line; lc = 0; while(line) { lc++; - fprintf(stderr, " line %i: bits = %i, length = %i\n", lc, line->bits, line->length); + fwprintf(stderr, L" line %i: bits = %i, length = %i\n", lc, line->bits, line->length); line = line->next; } } @@ -550,22 +549,22 @@ void markdown_debug(deck_t *deck, int debug) { void adjust_line_length(line_t *line) { int l = 0; - const static char *special = "\\*_`"; // list of interpreted chars - const char *c = &line->text->text[line->offset]; + const static wchar_t *special = L"\\*_`"; // list of interpreted chars + const wchar_t *c = &line->text->value[line->offset]; cstack_t *stack = cstack_init(); // for each char in line for(; *c; c++) { // if char is in special char list - if(strchr(special, *c)) { + if(wcschr(special, *c)) { // closing special char (or second backslash) if((stack->top)(stack, *c)) { - if(*c == '\\') l++; + if(*c == L'\\') l++; (stack->pop)(stack); // treat special as regular char - } else if((stack->top)(stack, '\\')) { + } else if((stack->top)(stack, L'\\')) { l++; (stack->pop)(stack); @@ -576,7 +575,7 @@ void adjust_line_length(line_t *line) { } else { // remove backslash from stack - if((stack->top)(stack, '\\')) + if((stack->top)(stack, L'\\')) (stack->pop)(stack); l++; } @@ -592,38 +591,22 @@ void adjust_line_length(line_t *line) { (stack->delete)(stack); } -bool is_utf8(char ch) { - return (ch & 0x80) != 0x00; -} - -int length_utf8(char ch) { - - int i = 0; // increment - - while(is_utf8(ch)) { - i++; - ch <<= 1; - } - - return i; -} - int next_nonblank(cstring_t *text, int i) { - while ((i < text->size) && isspace((unsigned char) (text->text)[i])) + while ((i < text->size) && iswspace((text->value)[i])) i++; return i; } int prev_blank(cstring_t *text, int i) { - while ((i > 0) && !isspace((unsigned char) (text->text)[i])) + while ((i > 0) && !iswspace((text->value)[i])) i--; return i; } int next_blank(cstring_t *text, int i) { - while ((i < text->size) && !isspace((unsigned char) (text->text)[i])) + while ((i < text->size) && !iswspace((text->value)[i])) i++; return i; diff --git a/src/url.c b/src/url.c index 1aa2de6..25c60c3 100644 --- a/src/url.c +++ b/src/url.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include "url.h" @@ -39,7 +39,7 @@ void url_init(void) { init_ok = 1; } -int url_add(const char *link_name, int link_name_length, const char *target, int target_length, int x, int y) { +int url_add(const wchar_t *link_name, int link_name_length, const wchar_t *target, int target_length, int x, int y) { if (!init_ok) return -1; url_t *tmp = NULL; @@ -60,14 +60,14 @@ int url_add(const char *link_name, int link_name_length, const char *target, int assert(tmp); } - tmp -> link_name = calloc(link_name_length+1, sizeof(char)); + tmp -> link_name = calloc(link_name_length+1, sizeof(wchar_t)); assert(tmp->link_name); - strncpy(tmp->link_name, link_name, link_name_length); + wcsncpy(tmp->link_name, link_name, link_name_length); tmp->link_name[link_name_length] = '\0'; - tmp->target = calloc(target_length+1, sizeof(char)); + tmp->target = calloc(target_length+1, sizeof(wchar_t)); assert(tmp->target); - strncpy(tmp->target, target, target_length); + wcsncpy(tmp->target, target, target_length); tmp->target[target_length] = '\0'; tmp->x = x; @@ -79,7 +79,7 @@ int url_add(const char *link_name, int link_name_length, const char *target, int return index_max-1; } -char * url_get_target(int index) { +wchar_t * url_get_target(int index) { if (!init_ok) return NULL; url_t *tmp = list; @@ -96,7 +96,7 @@ char * url_get_target(int index) { } else return NULL; } -char * url_get_name(int index) { +wchar_t * url_get_name(int index) { url_t *tmp = list; while (index > 0 && tmp && tmp->next) { @@ -158,9 +158,9 @@ int url_get_amount(void) { return index_max; } -int url_count_inline(const char *line) { +int url_count_inline(const wchar_t *line) { int count = 0; - const char *i = line; + const wchar_t *i = line; for (; *i; i++) { if (*i == '\\') { @@ -168,9 +168,9 @@ int url_count_inline(const char *line) { } else if ( *i == '[' && *(i+1) != ']') { while (*i && *i != ']') i++; i++; - if (*i == '(' && strchr(i, ')')) { + if (*i == '(' && wcschr(i, ')')) { count ++; - i = strchr(i, ')'); + i = wcschr(i, ')'); } } } @@ -178,9 +178,9 @@ int url_count_inline(const char *line) { return count; } -int url_len_inline(const char *text) { +int url_len_inline(const wchar_t *value) { int count = 0; - const char *i = text; + const wchar_t *i = value; for (; *i; i++) { if (*i == '\\') { @@ -188,7 +188,7 @@ int url_len_inline(const char *text) { } else if ( *i == '[' && *(i+1) != ']') { while (*i && *i != ']') i++; i++; - if (*i == '(' && strchr(i, ')')) { + if (*i == '(' && wcschr(i, ')')) { while (*i && *i != ')') { count++; i++; diff --git a/src/viewer.c b/src/viewer.c index 3e391b1..5ca04a5 100644 --- a/src/viewer.c +++ b/src/viewer.c @@ -22,10 +22,10 @@ */ #include // isalnum -#include // setlocale -#include // strchr +#include // wcschr +#include // iswalnum +#include // strcpy #include // usleep - #include "viewer.h" // color ramp for fading from black to color @@ -73,6 +73,7 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa int max_lines = 0; // max lines per slide int max_cols = 0; // max columns per line int offset; // text offset + int stop = 0; // passed stop bits per slide // header line 1 is displayed at the top int bar_top = (deck->headers > 0) ? 1 : 0; @@ -83,9 +84,6 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa slide_t *slide = deck->slide; line_t *line; - // set locale to display UTF-8 correctly in ncurses - setlocale(LC_CTYPE, ""); - // init ncurses initscr(); @@ -95,11 +93,11 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa while(line && line->text) { - if (line->text->text) - lc += url_count_inline(line->text->text); + if (line->text->value) + lc += url_count_inline(line->text->value); - if (line->text->text) - line->length -= url_len_inline(line->text->text); + if (line->text->value) + line->length -= url_len_inline(line->text->value); if(line->length > COLS) { i = line->length; @@ -117,8 +115,8 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa endwin(); // print error - fprintf(stderr, "Error: Terminal width (%i columns) too small. Need at least %i columns.\n", COLS, i); - fprintf(stderr, "You may need to shorten some lines by inserting line breaks.\n"); + fwprintf(stderr, L"Error: Terminal width (%i columns) too small. Need at least %i columns.\n", COLS, i); + fwprintf(stderr, L"You may need to shorten some lines by inserting line breaks.\n"); // no reload return 0; @@ -154,8 +152,8 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa endwin(); // print error - fprintf(stderr, "Error: Terminal height (%i lines) too small. Need at least %i lines.\n", LINES, max_lines + bar_top + bar_bottom); - fprintf(stderr, "You may need to add additional horizontal rules (---) to split your file in shorter slides.\n"); + fwprintf(stderr, L"Error: Terminal height (%i lines) too small. Need at least %i lines.\n", LINES, max_lines + bar_top + bar_bottom); + fwprintf(stderr, L"You may need to add additional horizontal rules (---) to split your file in shorter slides.\n"); // no reload return 0; @@ -269,9 +267,9 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa line = deck->header; offset = next_blank(line->text, 0) + 1; // add text to header - mvwprintw(stdscr, - 0, (COLS - line->length + offset) / 2, - "%s", &line->text->text[offset]); + mvwaddwstr(stdscr, + 0, (COLS - line->length + offset) / 2, + &line->text->value[offset]); } // setup footer @@ -279,10 +277,11 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa line = deck->header->next; offset = next_blank(line->text, 0) + 1; // add text to left footer - mvwprintw(stdscr, - LINES - 1, 3, - "%s", &line->text->text[offset]); + mvwaddwstr(stdscr, + LINES - 1, 3, + &line->text->value[offset]); } + // add slide number to right footer mvwprintw(stdscr, LINES - 1, COLS - int_length(deck->slides) - int_length(sc) - 6, @@ -293,20 +292,34 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa wrefresh(stdscr); line = slide->line; - l = 0; + l = stop = 0; // print lines while(line) { add_line(content, l, (COLS - max_cols) / 2, line, max_cols, colors); + + // raise stop counter if we pass a line having a stop bit + if(CHECK_BIT(line->bits, IS_STOP)) + stop++; + l += (line->length / COLS) + 1; line = line->next; + + // only stop here if we didn't stop here recently + if(stop > slide->stop) + break; } - int i, ymax; - getmaxyx( content, ymax, i ); - for (i = 0; i < url_get_amount(); i++) { - mvwprintw(content, ymax - url_get_amount() - 1 + i, 3, - "[%d] %s", i, url_get_target(i)); + // print pandoc URL references + // only if we already printed all lines of the current slide + if(!line) { + int i, ymax; + getmaxyx( content, ymax, i ); + for (i = 0; i < url_get_amount(); i++) { + mvwprintw(content, ymax - url_get_amount() - 1 + i, 3, + "[%d] ", i); + waddwstr(content, url_get_target(i)); + } } // make content visible @@ -327,7 +340,7 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa i = 0; switch(c) { - // show previous slide + // show previous slide or stop bit case KEY_UP: case KEY_LEFT: case KEY_PPAGE: @@ -336,15 +349,23 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa case 263: // BACKSPACE (getty) case 'h': case 'k': - if(slide->prev) { - slide = slide->prev; - sc--; + if(stop > 1 || (stop == 1 && !line)) { + // show current slide again + // but stop one stop bit earlier + slide->stop--; } else { - fade = false; + if(slide->prev) { + // show previous slide + slide = slide->prev; + sc--; + } else { + // do nothing + fade = false; + } } break; - // show next slide + // show next slide or stop bit case KEY_DOWN: case KEY_RIGHT: case KEY_NPAGE: @@ -352,11 +373,19 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa case ' ': // SPACE case 'j': case 'l': - if(slide->next) { - slide = slide->next; - sc++; + if(stop && line) { + // show current slide again + // but stop one stop bit later (or at end of slide) + slide->stop++; } else { - fade = false; + if(slide->next) { + // show next slide + slide = slide->next; + sc++; + } else { + // do nothing + fade = false; + } } break; @@ -459,7 +488,7 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colors) { - if(!line->text->text) { + if(!line->text->value) { return; } @@ -487,7 +516,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo "%s", prompt); if(!CHECK_BIT(line->bits, IS_CODE)) - inline_display(window, &line->text->text[offset], colors); + inline_display(window, &line->text->value[offset], colors); // IS_UNORDERED_LIST_2 } else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_2)) { @@ -506,7 +535,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo "%s", prompt); if(!CHECK_BIT(line->bits, IS_CODE)) - inline_display(window, &line->text->text[offset], colors); + inline_display(window, &line->text->value[offset], colors); // IS_UNORDERED_LIST_1 } else if(CHECK_BIT(line->bits, IS_UNORDERED_LIST_1)) { @@ -524,7 +553,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo "%s", prompt); if(!CHECK_BIT(line->bits, IS_CODE)) - inline_display(window, &line->text->text[offset], colors); + inline_display(window, &line->text->value[offset], colors); } // IS_CODE @@ -538,8 +567,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo wattron(window, COLOR_PAIR(CP_BLACK)); // print whole lines - wprintw(window, - "%s", &line->text->text[offset]); + waddwstr(window, &line->text->value[offset]); } if(!CHECK_BIT(line->bits, IS_UNORDERED_LIST_1) && @@ -549,7 +577,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo // IS_QUOTE if(CHECK_BIT(line->bits, IS_QUOTE)) { - while(line->text->text[offset] == '>') { + while(line->text->value[offset] == '>') { // print a reverse color block if(colors) { wattron(window, COLOR_PAIR(CP_BLACK)); @@ -562,11 +590,11 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo // find next quote or break offset++; - if(line->text->text[offset] == ' ') + if(line->text->value[offset] == ' ') offset = next_word(line->text, offset); } - inline_display(window, &line->text->text[offset], colors); + inline_display(window, &line->text->value[offset], colors); } else { // IS_CENTER @@ -588,19 +616,18 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo wattron(window, A_UNDERLINE); // skip hashes - while(line->text->text[offset] == '#') + while(line->text->value[offset] == '#') offset = next_word(line->text, offset); // print whole lines - wprintw(window, - "%s", &line->text->text[offset]); + waddwstr(window, &line->text->value[offset]); wattroff(window, A_UNDERLINE); // no line-wide markdown } else { - inline_display(window, &line->text->text[offset], colors); + inline_display(window, &line->text->value[offset], colors); } } } @@ -615,10 +642,10 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo wattroff(window, A_UNDERLINE); } -void inline_display(WINDOW *window, const char *c, const int colors) { - const static char *special = "\\*_`!["; // list of interpreted chars - const char *i = c; // iterator - const char *start_link_name, *start_url; +void inline_display(WINDOW *window, const wchar_t *c, const int colors) { + const static wchar_t *special = L"\\*_`!["; // list of interpreted chars + const wchar_t *i = c; // iterator + const wchar_t *start_link_name, *start_url; int length_link_name, url_num; cstack_t *stack = cstack_init(); @@ -627,29 +654,29 @@ void inline_display(WINDOW *window, const char *c, const int colors) { for(; *i; i++) { // if char is in special char list - if(strchr(special, *i)) { + if(wcschr(special, *i)) { // closing special char (or second backslash) // only if not followed by :alnum: if((stack->top)(stack, *i) && - (!isalnum((int)i[1]) || *(i + 1) == '\0' || *i == '\\')) { + (!iswalnum(i[1]) || *(i + 1) == L'\0' || *i == L'\\')) { switch(*i) { // print escaped backslash - case '\\': - wprintw(window, "%c", *i); + case L'\\': + waddnwstr(window, i, 1); break; // disable highlight - case '*': + case L'*': if(colors) wattron(window, COLOR_PAIR(CP_WHITE)); break; // disable underline - case '_': + case L'_': wattroff(window, A_UNDERLINE); break; // disable inline code - case '`': + case L'`': if(colors) wattron(window, COLOR_PAIR(CP_WHITE)); break; @@ -659,8 +686,8 @@ void inline_display(WINDOW *window, const char *c, const int colors) { (stack->pop)(stack); // treat special as regular char - } else if((stack->top)(stack, '\\')) { - wprintw(window, "%c", *i); + } else if((stack->top)(stack, L'\\')) { + waddnwstr(window, i, 1); // remove backslash from stack (stack->pop)(stack); @@ -672,17 +699,18 @@ void inline_display(WINDOW *window, const char *c, const int colors) { // and of cause after another emphasis markup //TODO this condition looks ugly if(i == c || - *(i - 1) == ' ' || - ((*(i - 1) == '_' || *(i - 1) == '*') && ((i - 1) == c || *(i - 2) == ' ')) || - *i == '\\') { + iswspace(*(i - 1)) || + ((iswspace(*(i - 1)) || *(i - 1) == L'*' || *(i - 1) == L'_') && + ((i - 1) == c || iswspace(*(i - 2)))) || + *i == L'\\') { // url in pandoc style - if ((*i == '[' && strchr(i, ']')) || - (*i == '!' && *(i + 1) == '[' && strchr(i, ']'))) { + if ((*i == L'[' && wcschr(i, L']')) || + (*i == L'!' && *(i + 1) == L'[' && wcschr(i, L']'))) { - if (*i == '!') i++; + if (*i == L'!') i++; - if (strchr(i, ']')[1] == '(') { + if (wcschr(i, L']')[1] == L'(') { i++; // turn higlighting and underlining on @@ -695,9 +723,9 @@ void inline_display(WINDOW *window, const char *c, const int colors) { // print the content of the label // the label is printed as is do { - wprintw(window, "%c", *i); + waddnwstr(window, i, 1); i++; - } while (*i != ']'); + } while (*i != L']'); length_link_name = i - 1 - start_link_name; @@ -706,9 +734,9 @@ void inline_display(WINDOW *window, const char *c, const int colors) { start_url = i; - while (*i != ')') i++; + while (*i != L')') i++; - url_num = url_add(start_link_name, length_link_name, start_url, i - start_url, 0,0); + url_num = url_add(start_link_name, length_link_name, start_url, i - start_url, 0, 0); wprintw(window, " [%d]", url_num); @@ -722,16 +750,16 @@ void inline_display(WINDOW *window, const char *c, const int colors) { } else switch(*i) { // enable highlight - case '*': + case L'*': if(colors) wattron(window, COLOR_PAIR(CP_RED)); break; // enable underline - case '_': + case L'_': wattron(window, A_UNDERLINE); break; // enable inline code - case '`': + case L'`': if(colors) wattron(window, COLOR_PAIR(CP_BLACK)); break; @@ -742,17 +770,17 @@ void inline_display(WINDOW *window, const char *c, const int colors) { (stack->push)(stack, *i); } else { - wprintw(window, "%c", *i); + waddnwstr(window, i, 1); } } } else { // remove backslash from stack - if((stack->top)(stack, '\\')) + if((stack->top)(stack, L'\\')) (stack->pop)(stack); // print regular char - wprintw(window, "%c", *i); + waddnwstr(window, i, 1); } } @@ -760,16 +788,16 @@ void inline_display(WINDOW *window, const char *c, const int colors) { while(!(stack->empty)(stack)) { switch((stack->pop)(stack)) { // disable highlight - case '*': + case L'*': if(colors) wattron(window, COLOR_PAIR(CP_WHITE)); break; // disable underline - case '_': + case L'_': wattroff(window, A_UNDERLINE); break; // disable inline code - case '`': + case L'`': if(colors) wattron(window, COLOR_PAIR(CP_WHITE)); break; diff --git a/utf8.md b/utf8.md new file mode 100644 index 0000000..32c357d --- /dev/null +++ b/utf8.md @@ -0,0 +1,57 @@ +%title: UTF-8 Test Presentation + +_Tables:_ + +┍━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━┑ +│ Cell 1 │ Cell 2 │ Cell 3 │ Cell 4 │ +├──────────┼──────────┼──────────┼──────────┤ +│ Cell 5 │ Cell 6 │ Cell 7 │ Cell 8 │ +┕━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━┙ + +--- + +_Greek:_ + +Apò mēkhanês Theós + +ἀπὸ μηχανῆς Θεός + +--- + +_Chinese:_ + +bù zuō sǐ jiù bú huì sǐ + +不作死就不会死 + +--- + +_Japanese:_ + +Saru mo ki kara ochiru + +猿も木から落ちる。 + +--- + +_ASCII art:_ + + ██████████████ + ██▓▓▓▓▓▓▓▓▓ M ▓████ + ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██ + ██████░░░░██░░██████ + ██░░░░████░░██░░░░░░░░██ + ██░░░░████░░░░██░░░░░░██ + ████░░░░░░██████████ + ██░░░░░░░░░░░░░██ + ██░░░░░░░░░██ + ██░░░░░░██ + ██▓▓████▓▓▓█ + ██▓▓▓▓▓▓████▓▓█ + ██▓▓▓▓▓▓███░░███░ + ██░░░░░░███████ + ██░░░░███████ + ██████████ + ██▓▓▓▓▓▓▓▓▓██ + █████████████ +