replace pseudo UTF-8 with real wide character support
authorMichael Göhler <somebody.here@gmx.de>
Sat, 31 Jan 2015 23:28:38 +0000 (00:28 +0100)
committerMichael Göhler <somebody.here@gmx.de>
Sun, 8 Feb 2015 16:48:02 +0000 (17:48 +0100)
include/cstack.h
include/cstring.h
include/parser.h
include/url.h
include/viewer.h
src/cstack.c
src/cstring.c
src/main.c
src/parser.c
src/url.c
src/viewer.c

index fd6c60d..230fcdd 100644 (file)
 #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);
 
index d0a7c1c..d74cd80 100644 (file)
 #define REALLOC_ADD 10
 
 typedef struct _cstring_t {
-    char *text;
+    wchar_t *text;
     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);
index 477342d..23cd12f 100644 (file)
@@ -48,8 +48,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);
index 1bd3950..e48e194 100644 (file)
  */
 
 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 *text);
 
 #endif // !defined( URL_H )
index d921247..81f23ec 100644 (file)
@@ -32,6 +32,9 @@
  *
  */
 
+#define _GNU_SOURCE              // enable ncurses wchar support
+#define _XOPEN_SOURCE_EXTENDED 1 // enable ncurses wchar support
+
 #if defined( WIN32 )
 #include <curses.h>
 #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);
index 4763b5b..df27ff4 100644 (file)
@@ -19,6 +19,7 @@
  *
  */
 
+#include <wchar.h>
 #include <stdio.h> // fprintf
 #include <stdlib.h> // 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;
 }
 
index 558a786..1570786 100644 (file)
@@ -19,7 +19,7 @@
  *
  */
 
-#include <string.h> // strlen, memmove
+#include <wchar.h> // wcslen, wcscat, wmemmove
 #include <stdio.h> // fprintf
 #include <stdlib.h> // malloc, realloc
 
@@ -42,41 +42,41 @@ 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));
+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->text = realloc(self->text, 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->text[self->size+1] = L'\0';
+    self->size = wcslen(self->text);
 }
 
-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));
+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->text = realloc(self->text, self->alloc)) == NULL) {
-            fprintf(stderr, "%s\n", "cstring_expand() failed to reallocate memory.");
+            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->text = wcscat(self->text, x);
+    self->size = wcslen(self->text);
+    self->text[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->text[pos] = L'\0';
             self->size = pos;
         }
         return;
     }
-    memmove(&self->text[pos], &self->text[pos+len], self->size - pos - len+1);
+    wmemmove(&self->text[pos], &self->text[pos+len], self->size - pos - len+1);
     self->size -= len;
 }
 
index 37af9bc..e762fbb 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <errno.h>
 #include <getopt.h>
+#include <locale.h> // setlocale
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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;
index f835a5c..4d48e33 100644 (file)
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
 #include <string.h>
 
 #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;
@@ -114,14 +116,14 @@ deck_t *markdown_load(FILE *input) {
                 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 +132,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 +149,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->text[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->text[0] == L'%') {
             hc++;
             line = line->next;
         }
@@ -328,12 +309,12 @@ int markdown_analyse(cstring_t *text, int prev) {
     offset = next_nonblank(text, 0);
 
     // 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->text[eol - 1]); eol--);
 
     // IS_UNORDERED_LIST_#
     if(text->size >= offset + 2 &&
-       (text->text[offset] == '*' || text->text[offset] == '-') &&
-       text->text[offset + 1] == ' ') {
+       (text->text[offset] == L'*' || text->text[offset] == L'-') &&
+       iswspace(text->text[offset + 1])) {
 
         // if different from last lines offset
         if(offset != unordered_list_offset) {
@@ -406,15 +387,15 @@ int markdown_analyse(cstring_t *text, int prev) {
         } else {
 
             // IS_QUOTE
-            if(text->text[offset] == '>') {
+            if(text->text[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->text[offset] == L'-' &&
+               text->text[offset + 1] == L'>' &&
+               iswspace(text->text[offset + 2])) {
                 SET_BIT(bits, IS_CENTER);
 
                 // remove start tag
@@ -422,31 +403,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->text[eol - 1] == L'-' &&
+                   text->text[eol - 2] == L'<' &&
+                   iswspace(text->text[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->text[eol - 1]); eol--);
 
                 }
             }
 
             for(i = offset; i < eol; i++) {
 
-                if(text->text[i] == ' ') {
+                if(iswspace(text->text[i])) {
                     spaces++;
 
                 } else {
                     switch(text->text[i]) {
-                        case '=': equals++;  break;
-                        case '#': hashes++;  break;
-                        case '*': stars++;   break;
-                        case '-': minus++;   break;
-                        case '\\': other++; i++; break;
+                        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 +435,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->text[offset] == L'#' &&
+               iswspace(text->text[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->text[offset] == L'#' &&
+               text->text[offset+1] == L'#' &&
+               iswspace(text->text[offset+2])) {
                 SET_BIT(bits, IS_H2);
                 SET_BIT(bits, IS_H2_ATX);
             }
@@ -501,7 +482,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 +491,12 @@ void markdown_debug(deck_t *deck, int debug) {
             header = deck->header;
             while(header &&
                 header->length > 0 &&
-                header->text->text[0] == '%') {
+                header->text->text[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->text[offset]);
                 header = header->next;
             }
         }
@@ -529,17 +510,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 +531,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->text[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 +557,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 +573,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->text)[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->text)[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->text)[i]))
         i++;
 
     return i;
index 1aa2de6..a7a5c0c 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -21,7 +21,7 @@
 
 #include <stdlib.h>
 #include <assert.h>
-#include <string.h>
+#include <wchar.h>
 #include <stdio.h>
 
 #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 *text) {
     int count = 0;
-    const char *i = text;
+    const wchar_t *i = text;
 
     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++;
index 3e391b1..8d97139 100644 (file)
  */
 
 #include <ctype.h>  // isalnum
-#include <locale.h> // setlocale
-#include <string.h> // strchr
+#include <wchar.h>  // wcschr
+#include <wctype.h> // iswalnum
+#include <string.h> // strcpy
 #include <unistd.h> // usleep
-
 #include "viewer.h"
 
 // color ramp for fading from black to color
@@ -83,9 +83,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();
 
@@ -117,8 +114,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 +151,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 +266,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->text[offset]);
         }
 
         // setup footer
@@ -279,10 +276,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->text[offset]);
         }
+
         // add slide number to right footer
         mvwprintw(stdscr,
                   LINES - 1, COLS - int_length(deck->slides) - int_length(sc) - 6,
@@ -306,7 +304,8 @@ int ncurses_display(deck_t *deck, int notrans, int nofade, int invert, int reloa
         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));
+                      "[%d] ", i);
+            waddwstr(content, url_get_target(i));
         }
 
         // make content visible
@@ -538,8 +537,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->text[offset]);
     }
 
     if(!CHECK_BIT(line->bits, IS_UNORDERED_LIST_1) &&
@@ -592,8 +590,7 @@ void add_line(WINDOW *window, int y, int x, line_t *line, int max_cols, int colo
                     offset = next_word(line->text, offset);
 
                 // print whole lines
-                wprintw(window,
-                        "%s", &line->text->text[offset]);
+                waddwstr(window, &line->text->text[offset]);
 
                 wattroff(window, A_UNDERLINE);
 
@@ -615,10 +612,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 +624,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 +656,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 +669,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 +693,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 +704,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 +720,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 +740,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 +758,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;