[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