[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH] libc: Verarbeitung der Tastenbefehle in readline vereinheitlicht
* libc: Verarbeitung der Tastenbefehle in readline vereinheitlicht damit
einfacher Neue eingebaut werden koennen.
Signed-off-by: Antoine Kaufmann <toni@xxxxxxxxxx>
---
src/modules/lib/readline.c | 313 ++++++++++++++++++++++++++++----------------
1 files changed, 199 insertions(+), 114 deletions(-)
diff --git a/src/modules/lib/readline.c b/src/modules/lib/readline.c
index 879b475..b2df3fc 100644
--- a/src/modules/lib/readline.c
+++ b/src/modules/lib/readline.c
@@ -37,6 +37,69 @@
#define BUFFER_SIZE 255
+
+/** Typ mit allen Befehlen, die eingegeben werden koennen, fuer readline. */
+typedef enum {
+ UNKNOWN_COMMAND = 0,
+
+ // Cursor Bewegen
+ /// Cursor um ein Zeichen nach vorne bewegen
+ FORWARD_CHAR,
+ /// Cursor um ein Zeichen nach hinten bewegen
+ BACKWARD_CHAR,
+ /// Cursor an den Anfang der Zeile bewegen
+ BEGINNING_OF_LINE,
+ /// Cursor an das Ende der Zeile bewegen
+ END_OF_LINE,
+
+ // Text editieren
+ /// Zeile abschliessen
+ ACCEPT_LINE,
+ /// Zeichen unter dem Cursor loeschen
+ DELETE_CHAR,
+ /// Zeichen hinter dem Cursor loeschen
+ BACKWARD_DELETE_CHAR,
+ /// Vervollstaendigen
+ COMPLETE,
+
+ // History
+ /// Eine Zeile zurueck in der History
+ PREVIOUS_HISTORY,
+ /// Eine Zeile vorwaerts in der History
+ NEXT_HISTORY,
+} rl_command_t;
+
+/** Eingebaute Tastensequenzen fuer die Befehle */
+static struct {
+ wint_t* seq;
+ rl_command_t cmd;
+} builtin_commands [] = {
+ /// Pfeil rechts
+ { L"\033[C", FORWARD_CHAR },
+ /// Pfeil links
+ { L"\033[D", BACKWARD_CHAR },
+ /// Pos1
+ { L"\033[H", BEGINNING_OF_LINE },
+ /// Ende
+ { L"\033[F", END_OF_LINE },
+
+ /// Enter
+ { L"\n", ACCEPT_LINE },
+ /// Del
+ { L"\033[3~", DELETE_CHAR },
+ /// Ruecktaste
+ { L"\b", BACKWARD_DELETE_CHAR },
+ /// Tab
+ { L"\t", COMPLETE },
+
+ /// Pfeil hoch
+ { L"\033[A", PREVIOUS_HISTORY },
+ /// Pfeil runter
+ { L"\033[B", NEXT_HISTORY },
+
+ { NULL, UNKNOWN_COMMAND },
+};
+
static list_t* history = NULL;
/**
@@ -284,6 +347,44 @@ static bool complete_word(char* buffer, int* pos, int* len)
}
/**
+ * Anfang des uebergebenen Puffers mit moeglichen Befehlstasten vergleichen.
+ * Wird eine Uebereinstimmung gefunden, wird der gefundene Befehl in *cmd
+ * abgelegt.
+ *
+ * @return Wird eine vollstaendige Befehlssequenz gefunden, wird die Anzahl
+ * Bytes zurueckgegeben, die die Sequenz in Anspruch genommen hat. Falls
+ * eine unvollstaendige Sequenz am Anfang des Puffers liegt, die aber
+ * mit weiteren Zeichen noch zu einem gueltigen Befehl wird, wird 0
+ * zurueckgegeben. Passt die Sequenz hingegen zu keinem Befehl, wird -1
+ * zurueckgegeben.
+ */
+static int find_command(const wchar_t* buf, size_t len, rl_command_t* cmd)
+{
+ int found_part = 0;
+ size_t seq_len;
+ size_t min_len;
+ size_t i;
+
+ for (i = 0; builtin_commands[i].seq; i++) {
+ seq_len = wcslen(builtin_commands[i].seq);
+ min_len = (len < seq_len ? len : seq_len);
+
+ if (!wcsncmp(buf, builtin_commands[i].seq, min_len)) {
+ // Passt genau
+ if (seq_len <= len) {
+ *cmd = builtin_commands[i].cmd;
+ return seq_len;
+ } else {
+ // Es fehlt noch ein bisschen was, koennte aber noch werden
+ found_part++;
+ }
+ }
+ }
+
+ return (found_part > 0 ? 0 : -1);
+}
+
+/**
* Prompt anzeigen und Zeile von der Tastatur einlesen
*/
char* readline(const char* prompt)
@@ -293,10 +394,14 @@ char* readline(const char* prompt)
}
char* buffer = malloc(BUFFER_SIZE);
- int pos, size;
+ int old_pos, pos, size;
bool enter = FALSE;
int history_pos = -1;
+ rl_command_t command;
+ wchar_t cmd_buf[8];
+ size_t cmd_pos = 0;
+
rl_line_buffer = buffer;
printf("%s", prompt);
@@ -306,127 +411,113 @@ char* readline(const char* prompt)
pos = size = 0;
while (!enter)
{
- wint_t c = keyboard_read_char();
+ int result;
- switch (c) {
- case WEOF:
- case '\0':
- c = keyboard_read_char();
- enter = TRUE;
+ command = UNKNOWN_COMMAND;
+ old_pos = pos;
- printf("\r\n");
- fflush(stdout);
+ if ((cmd_buf[cmd_pos++] = keyboard_read_char()) == WEOF) {
+ // Mehr gibts nicht, auch das WEOF wird nicht mehr gebraucht
+ if (!--cmd_pos) {
break;
+ }
+ enter = TRUE;
+ }
+again:
+ result = find_command(cmd_buf, cmd_pos, &command);
+ if (result > 0) {
+ cmd_pos -= result;
+ wmemmove(cmd_buf, cmd_buf + result, cmd_pos);
+ } else if (result < 0) {
+ inschar(buffer, &pos, &size, cmd_buf[0]);
+ wmemmove(cmd_buf, cmd_buf + 1, cmd_pos);
+
+ // Neu eingefuegtes Zeichen und allenfalls Folgende auf den
+ // Bildschirm bringen
+ printf("\033[K\033[s%s\033[u\033[1C", &buffer[old_pos]);
+ fflush(stdout);
+
+ // Erstes Zeichen weg(raus aus dem Befehlspuffer und rein in den
+ // Datenpuffer) und erneut versuchen
+ cmd_pos--;
+ if (cmd_pos) {
+ goto again;
+ }
+ }
- // Escapesequenzen fuer Kontrolltasten verarbeiten
- case '\033':
- {
- char buf[4];
- int i;
- memset(buf, 0, sizeof(buf));
-
- if ((buf [0] = keyboard_read_char())!= '[') {
- goto seq_nomatch;
+ switch (command) {
+ case BACKWARD_CHAR:
+ if (pos > 0) {
+ printf("\033[1D");
+ fflush(stdout);
+ move_cursor(buffer, &pos, size, -1);
}
+ break;
- buf[1] = keyboard_read_char();
- switch (buf[1]) {
- // Links
- case 'D':
- if (pos > 0) {
- printf("\033[1D");
- fflush(stdout);
- move_cursor(buffer, &pos, size, -1);
- }
- break;
-
- // Rechts
- case 'C':
- if (pos < size) {
- printf("\033[1C");
- fflush(stdout);
- move_cursor(buffer, &pos, size, 1);
- }
- break;
-
- // Hoch/Runter
- case 'A':
- case 'B':
- if (buf[1] == 'A') {
- if (history_pos < (int) list_size(history) - 1) {
- history_pos++;
- } else {
- break;
- }
- } else {
- if (history_pos > -1) {
- history_pos--;
- } else {
- break;
- }
- }
+ case FORWARD_CHAR:
+ if (pos < size) {
+ printf("\033[1C");
+ fflush(stdout);
+ move_cursor(buffer, &pos, size, 1);
+ }
+ break;
- memset(buffer, 0, BUFFER_SIZE);
- if (history_pos > -1) {
- strncpy(buffer,
- list_get_element_at(history, history_pos),
- BUFFER_SIZE - 1);
- }
+ case BEGINNING_OF_LINE:
+ printf("\033[%dD", count_visible_chars(buffer, 0, pos));
+ pos = 0;
+ fflush(stdout);
+ break;
- char* format;
- asprintf(&format, "\033[%dD", pos);
- printf("%s\033[K%s", format, buffer);
- free(format);
- fflush(stdout);
+ case END_OF_LINE:
+ printf("\033[%dC",
+ count_visible_chars(buffer, pos, size));
+ pos = strlen(buffer);
+ fflush(stdout);
+ break;
- pos = size = strlen(buffer);
+ case PREVIOUS_HISTORY:
+ case NEXT_HISTORY:
+ if (command == PREVIOUS_HISTORY) {
+ if (history_pos < (int) list_size(history) - 1) {
+ history_pos++;
+ } else {
break;
-
- // Entfernen
- case '3':
- // Der Entfernen-Taste muss noch eine Tilde folgen
- if ((buf[2] = keyboard_read_char()) != '~') {
- goto seq_nomatch;
- }
-
- if (pos < size) {
- delchar(buffer, pos, &size);
- printf("\033[K\033[s%s\033[u", &buffer[pos]);
- fflush(stdout);
- }
+ }
+ } else {
+ if (history_pos > -1) {
+ history_pos--;
+ } else {
break;
+ }
+ }
+ memset(buffer, 0, BUFFER_SIZE);
+ if (history_pos > -1) {
+ strncpy(buffer,
+ list_get_element_at(history, history_pos),
+ BUFFER_SIZE - 1);
+ }
+ char* format;
+ asprintf(&format, "\033[%dD", pos);
+ printf("%s\033[K%s", format, buffer);
+ free(format);
+ fflush(stdout);
- // Pos1
- case 'H':
- printf("\033[%dD", count_visible_chars(buffer, 0, pos));
- pos = 0;
- fflush(stdout);
- break;
-
- // Ende
- case 'F':
- printf("\033[%dC",
- count_visible_chars(buffer, pos, size));
- pos = strlen(buffer);
- fflush(stdout);
- break;
+ pos = size = strlen(buffer);
+ break;
- default:
- goto seq_nomatch;
- }
- break;
-seq_nomatch:
- for (i = 0; (c = buf[i]); i++) {
- ungetc(buf[i], stdin);
+ case DELETE_CHAR:
+ if (pos < size) {
+ delchar(buffer, pos, &size);
+ printf("\033[K\033[s%s\033[u", &buffer[pos]);
+ fflush(stdout);
}
break;
- }
- case '\b':
+ case BACKWARD_DELETE_CHAR:
if (pos > 0) {
move_cursor(buffer, &pos, size, -1);
delchar(buffer, pos, &size);
@@ -435,15 +526,15 @@ seq_nomatch:
}
break;
- case '\n':
- enter = TRUE;
-
+
+ case ACCEPT_LINE:
+ enter = TRUE;
+
printf("\r\n");
fflush(stdout);
break;
-
- case '\t':
+ case COMPLETE:
if (rl_attempted_completion_function != NULL) {
int old_pos = pos;
@@ -462,13 +553,7 @@ seq_nomatch:
}
break;
- default:
- if (pos < BUFFER_SIZE - 1) {
- int old_pos = pos;
- inschar(buffer, &pos, &size, c);
- printf("\033[K\033[s%s\033[u\033[1C", &buffer[old_pos]);
- fflush(stdout);
- }
+ case UNKNOWN_COMMAND:
break;
}
}
--
1.6.0.6