[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH 2/4] libc: Strings aus breiten Zeichen in readline() benutzen



* libc: Strings aus breiten Zeichen in readline() benutzen intern, da
        das ganze sonst äusserst mühsam wird mit Multibyte-Zeichen wenn
        beispielsweise wortweise Navigation eingabaut werden soll.

Signed-off-by: Antoine Kaufmann <toni@xxxxxxxxxx>
---
 src/modules/lib/readline.c |  154 ++++++++++++++++++++------------------------
 1 files changed, 70 insertions(+), 84 deletions(-)

diff --git a/src/modules/lib/readline.c b/src/modules/lib/readline.c
index dac4305..e740f22 100644
--- a/src/modules/lib/readline.c
+++ b/src/modules/lib/readline.c
@@ -133,69 +133,39 @@ static wint_t keyboard_read_char(void)
 /**
  * Loescht ein Zeichen aus dem Puffer
  */
-static void delchar(char* buffer, int pos, int* size)
+static void delchar(wchar_t* buffer, int pos, int* size)
 {
-    int i;
-    size_t len = strlen(buffer);
-    int clen;
-
-    if (len < pos) {
+    if (pos >= *size) {
         return;
     }
 
-    clen = mblen(buffer + pos, len - pos + 1);
-    for (i = pos; i < BUFFER_SIZE - clen; i++) {
-        buffer[i] = buffer[i + clen];
-        if (buffer[i] == '\0') {
-            break;
-        }
-    }
-
-    buffer[BUFFER_SIZE - clen] = '\0';
-    *size -= clen;
+    wmemmove(buffer + pos, buffer + pos + 1, *size - pos - 1);
+    buffer[--(*size)] = L'\0';
 }
 
 /**
  * Fuegt ein Zeichen in den Buffer ein
  */
-static void inschar(char* buffer, int* pos, int* size, wint_t c)
+static void inschar(wchar_t* buffer, int* pos, int* size, wint_t c)
 {
-    int i;
-    size_t len = strlen(buffer);
-    char mbbuf[MB_CUR_MAX];
-    int clen;
-
-
-    clen = wctomb(mbbuf, c);
-    if ((len < *pos) || (len + clen >= BUFFER_SIZE) || (clen == -1)) {
+    if ((*pos > *size) || (*size >= BUFFER_SIZE)) {
         return;
     }
 
-    for (i = len + clen; i > *pos; i--) {
-        buffer[i] = buffer[i - clen];
-    }
-
-    memcpy(buffer + *pos, mbbuf, clen);
-
-    *pos += clen;
-    *size += clen;
+    wmemmove(buffer + *pos + 1, buffer + *pos, *size - *pos);
+    buffer[(*pos)++] = c;
+    buffer[++(*size)] = L'\0';
 }
 
 /**
  * Veraendert die Pufferposition; positiv => rechts, negativ => links
  */
-static void move_cursor(char* buffer, int* pos, int size, int offset)
+static void move_cursor(wchar_t* buffer, int* pos, int size, int offset)
 {
-    int clen;
-
     if (offset >  0) {
-        // Rechts
-        if ((clen = mblen(buffer + *pos, size - *pos + 1)) > 0) {
-            *pos += clen;
-        }
+        (*pos)++;
     } else {
-        // Links, bis wir ein ganzes Zeichen haben
-        while (--(*pos) && (mblen(buffer + *pos, size - *pos + 1) == -1)) { }
+        (*pos)--;
     }
 }
 
@@ -205,22 +175,9 @@ static void move_cursor(char* buffer, int* pos, int size, int offset)
  * @param start Position von der angefangen werden soll zu zaehlen
  * @param size  Anzahl Zeichen im Puffer
  */
-static int count_visible_chars(char* buffer, int start, int size)
+static int count_visible_chars(wchar_t* buffer, int start, int size)
 {
-    int clen;
-    int count = 0;
-
-    while ((start < size)) {
-        if ((clen = mblen(buffer + start, size - start + 1)) == -1) {
-            // Unvollstaendiges MB-Zeichen wird uebersprungen
-            start++;
-        } else {
-            count++;
-            start += clen;
-        }
-    }
-
-    return count;
+    return size - start;
 }
 
 /**
@@ -254,11 +211,11 @@ static void free_matches_array(char** matches)
  *         Zeile umgebrochen wurde, FALSE wenn entweder nichts gemacht wurde,
  *         oder nur ein passender Match geliefert wurde.
  */
-static bool complete_word(char* buffer, int* pos, int* len)
+static bool complete_word(wchar_t* buffer, int* pos, int* len)
 {
     int word_pos;
     int match_count;
-    int word_len;
+    size_t wword_len;
     char** matches;
     char* replacement;
     int replacement_len;
@@ -272,16 +229,20 @@ static bool complete_word(char* buffer, int* pos, int* len)
     if ((buffer[word_pos] == ' ') && (*pos > word_pos)) {
         word_pos++;
     }
-    word_len = *pos - word_pos;
+    wword_len = *pos - word_pos;
 
     // Wort in einen eigenen Buffer kopieren
+    wchar_t wword[wword_len + 1];
+    wcsncpy(wword, buffer + word_pos, wword_len);
+    wword[wword_len] = 0;
+
+    size_t word_len = wcstombs(NULL, wword, 0);
     char word[word_len + 1];
-    strncpy(word, buffer + word_pos, word_len);
-    word[word_len] = 0;
+    wcstombs(word, wword, word_len + 1);
 
     matches = rl_attempted_completion_function(word, word_pos, *pos);
 
-    // Wir haben nochmal Glueck gehabt, es gibt nicht zu vervollstaendigen ;-)
+    // Wir haben nochmal Glueck gehabt, es gibt nichts zu vervollstaendigen ;-)
     if (matches == NULL) {
         return FALSE;
     }
@@ -325,21 +286,31 @@ static bool complete_word(char* buffer, int* pos, int* len)
         replacement_len = strlen(replacement);
     }
 
+    // Jetzt muessen wir den Text erstmal in einen String aus breiten Zeichen
+    // verwandeln, um in dann direkt in den Puffer kopieren zu koennen.
+    char rpl_copy[replacement_len + 1];
+    memcpy(rpl_copy, replacement, replacement_len);
+    rpl_copy[replacement_len] = '\0';
+
+    size_t wlen = mbstowcs(NULL, rpl_copy, 0);
+    wchar_t wbuf[wlen + 1];
+    mbstowcs(wbuf, rpl_copy, wlen + 1);
+
     // Pruefen ob das ganze nachher noch in den Puffer passt
-    if (*len + replacement_len > BUFFER_SIZE) {
+    if (*len + wlen > BUFFER_SIZE) {
         return matches_list_displayed;
     }
 
     // Text, der dem zu ersetzenden Wort folgt nach hinten schieben
-    memmove(buffer + word_pos + replacement_len, buffer + *pos, (*len - word_len) -
+    wmemmove(buffer + word_pos + wlen, buffer + *pos, (*len - word_len) -
         word_pos + 1);
 
     // Wort ersetzen
-    memcpy(buffer + word_pos, replacement, replacement_len);
+    wmemcpy(buffer + word_pos, wbuf, wlen);
 
     // Position und Laenge des Puffers korrigieren
-    *pos = word_pos + replacement_len;
-    *len = *len + replacement_len - word_len ;
+    *pos = word_pos + wlen;
+    *len = *len + wlen - word_len ;
 
     free_matches_array(matches);
 
@@ -384,7 +355,7 @@ char* readline(const char* prompt)
         return NULL;
     }
 
-    char* buffer = malloc(BUFFER_SIZE);
+    wchar_t buffer[BUFFER_SIZE];
     int old_pos, pos, size;
     bool enter = FALSE;
     int history_pos = -1;
@@ -393,12 +364,10 @@ char* readline(const char* prompt)
     wchar_t cmd_buf[8];
     size_t cmd_pos = 0;
 
-    rl_line_buffer = buffer;
-
     printf("%s", prompt);
     fflush(stdout);
 
-    memset(buffer, 0, BUFFER_SIZE);
+    memset(buffer, 0, BUFFER_SIZE * sizeof(wchar_t));
     pos = size = 0;
     while (!enter)
     {
@@ -427,7 +396,9 @@ again:
         }
 
         if (old_pos != pos) {
-            printf("\033[K\033[s%s\033[u\033[1C", &buffer[old_pos]);
+            printf("\033[K\033[s", buffer[old_pos]);
+            fputws(&buffer[old_pos], stdout);
+            printf("\033[u\033[1C");
             fflush(stdout);
         }
 
@@ -457,7 +428,7 @@ again:
             case END_OF_LINE:
                 printf("\033[%dC",
                     count_visible_chars(buffer, pos, size));
-                pos = strlen(buffer);
+                pos = size;
                 fflush(stdout);
                 break;
 
@@ -478,27 +449,30 @@ again:
                     }
                 }
 
-                memset(buffer, 0, BUFFER_SIZE);
+                memset(buffer, 0, BUFFER_SIZE * sizeof(wchar_t));
                 if (history_pos > -1) {
-                    strncpy(buffer,
+                    mbstowcs(buffer,
                         list_get_element_at(history, history_pos),
-                        BUFFER_SIZE - 1);
+                        BUFFER_SIZE);
                 }
 
                 char* format;
                 asprintf(&format, "\033[%dD", pos);
-                printf("%s\033[K%s", format, buffer);
+                printf("%s\033[K", format);
+                fputws(buffer, stdout);
                 free(format);
                 fflush(stdout);
 
-                pos = size = strlen(buffer);
+                pos = size = wcslen(buffer);
                 break;
 
 
             case DELETE_CHAR:
                 if (pos < size) {
                     delchar(buffer, pos, &size);
-                    printf("\033[K\033[s%s\033[u", &buffer[pos]);
+                    printf("\033[K\033[s");
+                    fputws(&buffer[pos], stdout);
+                    printf("\033[u");
                     fflush(stdout);
                 }
                 break;
@@ -507,7 +481,9 @@ again:
                 if (pos > 0) {
                     move_cursor(buffer, &pos, size, -1);
                     delchar(buffer, pos, &size);
-                    printf("\033[1D\033[K\033[s%s\033[u", &buffer[pos]);
+                    printf("\033[1D\033[K\033[s");
+                    fputws(&buffer[pos], stdout);
+                    printf("\033[u");
                     fflush(stdout);
                 }
                 break;
@@ -527,12 +503,16 @@ again:
                     if (!complete_word(buffer, &pos, &size)) {
                         // Wenn die Match-Liste nicht angezeigt wurde, muss die
                         // Zeile aktualisiert werden
-                        printf("\033[s\033[%dD%s\033[u", old_pos, buffer);
+                        printf("\033[s\033[%dD", old_pos);
+                        fputws(buffer, stdout);
+                        printf("\033[u");
                         if (old_pos != pos) {
                             printf("\033[%dC", pos - old_pos);
                         }
                     } else {
-                        printf("%s%s\033[%dD", prompt, buffer, size - pos);
+                        printf("%s", prompt);
+                        fputws(buffer, stdout);
+                        printf("\033[%dD", size - pos);
                     }
 
                     fflush(stdout);
@@ -544,7 +524,13 @@ again:
         }
     }
 
-    return realloc(buffer, strlen(buffer) + 1);
+    size_t needed_size = wcstombs(NULL, buffer, 0) + 1;
+    char* return_buf = malloc(needed_size);
+    rl_line_buffer = return_buf;
+    wcstombs(return_buf, buffer, needed_size);
+    free(buffer);
+
+    return return_buf;
 }
 
 /**
-- 
1.6.0.6