[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [tyndur-devel] [PATCH 2/4] libc: Strings aus breiten Zeichen in readline() benutzen
Am Sonntag, 17. Mai 2009 18:19 schrieb Antoine Kaufmann:
> * 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)) {
Off by one. BUFFER_SIZE ist mit Nullbyte.
> 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)--;
> }
> }
Diese Funktion hat so eigentlich keine Daseinsberechtigung mehr. ;-)
>
> @@ -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;
> }
Da bleibt ebenfalls beeindruckend viel Funktion übrig.
>
> /**
> @@ -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';
Wozu müssen wir den String erstmal kopieren? mbstowcs nimmt doch einen const
char*, macht uns also nichts kaputt?
> +
> + size_t wlen = mbstowcs(NULL, rpl_copy, 0);
> + wchar_t wbuf[wlen + 1];
> + mbstowcs(wbuf, rpl_copy, wlen + 1);
Yay, word_len, wword_len und wlen. Das ist total intuitiv.
> +
> // 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));
Haben wir kein wmemset?
> 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);
Wieso ist hier plötzlich mehr Platz als vorher?
> }
>
> 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);
Der lag doch auf dem Stack?
> +
> + return return_buf;
> }
>
> /**