From b51dad6408462dbf75405e8484997ec455c33e9c Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Fri, 23 Jul 2010 09:46:49 +0200 Subject: [PATCH 01/44] Minor fixes from changeset a5f54865d41c3f181a06 from Heimdal project http://github.com/heimdal/heimdal --- src/complete.c | 7 +++---- src/editline.c | 7 ++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/complete.c b/src/complete.c index 420b0f0..c1eb394 100644 --- a/src/complete.c +++ b/src/complete.c @@ -186,10 +186,9 @@ char *default_rl_complete(char *pathname, int *unique) j = strlen(av[0]) - len + 2; if ((p = NEW(char, j + 1)) != NULL) { COPYFROMTO(p, av[0] + len, j); - if ((new = NEW(char, strlen(dir) + strlen(av[0]) + 2)) != NULL) { - (void)strcpy(new, dir); - (void)strcat(new, "/"); - (void)strcat(new, av[0]); + len = strlen(dir) + strlen(av[0]) + 2; + if ((new = NEW(char, len)) != NULL) { + snprintf(new, len, "%s/%s", dir, av[0]); rl_add_slash(new, p); DISPOSE(new); } diff --git a/src/editline.c b/src/editline.c index 7258405..3bf612a 100644 --- a/src/editline.c +++ b/src/editline.c @@ -182,7 +182,7 @@ static void tty_string(char *p) static int tty_get(void) { - char c; + char c; int r; tty_flush(); @@ -194,9 +194,10 @@ static int tty_get(void) return *Input++; do { - r= read(0, &c, (SIZE_T)1); + r = read(0, &c, 1); } while (r == -1 && errno == EINTR); - return r == 1 ? c : EOF; + + return r == 1 ? c : EOF; } #define tty_back() (backspace ? tty_puts(backspace) : tty_put('\b')) From 64219dc1f032aad23167d7758540379e08feac33 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Fri, 23 Jul 2010 09:54:08 +0200 Subject: [PATCH 02/44] \? -> ? by Johan Danielsson of Heimdal project http://github.com/heimdal/heimdal --- man/editline.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/editline.3 b/man/editline.3 index 58ecdaf..fe5b8d3 100644 --- a/man/editline.3 +++ b/man/editline.3 @@ -102,7 +102,7 @@ ESC\ ^H Delete previous word (backspace key) [n] ESC\ DEL Delete previous word (delete key) [n] ESC\ SP Set the mark (space key); see ^X^X and ^Y above ESC\ \. Get the last (or [n]'th) word from previous line -ESC\ \? Show possible completions; see below +ESC\ ? Show possible completions; see below ESC\ < Move to start of history ESC\ > Move to end of history ESC\ b Move backward a word [n] From 511a1a65a4e87323a0c142bc8a50ff7790dcef95 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Fri, 23 Jul 2010 11:01:51 +0200 Subject: [PATCH 03/44] Nuke NEW, DISPOSE, RENEW, and COPYFROMTO macros, by Johan Danielsson This is a manual merge of 98c988dd10888cfb72c4 from http://github.com/heimdal/heimdal --- src/complete.c | 56 +++++++++++++----------- src/editline.c | 114 ++++++++++++++++++++++++++++++------------------- src/editline.h | 5 --- 3 files changed, 102 insertions(+), 73 deletions(-) diff --git a/src/complete.c b/src/complete.c index c1eb394..fe70ecf 100644 --- a/src/complete.c +++ b/src/complete.c @@ -27,12 +27,14 @@ /* Return an allocated copy of a string. */ char *strdup(const char *p) { - char *new; + char *new = malloc(sizeof(char) * strlen(p)); - if ((new = NEW(char, strlen(p) + 1)) != NULL) - (void)strcpy(new, p); + if (new) { + strcpy(new, p); + return new; + } - return new; + return NULL; } #endif @@ -77,25 +79,26 @@ static int FindMatches(char *dir, char *file, char ***avp) choices++; if ((total += strlen(p)) > MAX_TOTAL_MATCHES) { /* This is a bit too much. */ - while (ac > 0) DISPOSE(av[--ac]); + while (ac > 0) free(av[--ac]); continue; } if ((ac % MEM_INC) == 0) { - if ((new = NEW(char*, ac + MEM_INC)) == NULL) { + new = malloc(sizeof(char *) * (ac + MEM_INC)); + if (!new) { total = 0; break; } if (ac) { - COPYFROMTO(new, av, ac * sizeof (char **)); - DISPOSE(av); + memcpy(new, av, ac * sizeof(char **)); + free(av); } *avp = av = new; } if ((av[ac] = strdup(p)) == NULL) { if (ac == 0) - DISPOSE(av); + free(av); total = 0; break; } @@ -134,7 +137,7 @@ static int SplitPath(char *path, char **dirpart, char **filepart) if ((dpart = strdup(DOT)) == NULL) return -1; if ((fpart = strdup(path)) == NULL) { - DISPOSE(dpart); + free(dpart); return -1; } } @@ -143,7 +146,7 @@ static int SplitPath(char *path, char **dirpart, char **filepart) return -1; dpart[fpart - path + 1] = '\0'; if ((fpart = strdup(++fpart)) == NULL) { - DISPOSE(dpart); + free(dpart); return -1; } } @@ -172,8 +175,8 @@ char *default_rl_complete(char *pathname, int *unique) return NULL; if ((ac = FindMatches(dir, file, &av)) == 0) { - DISPOSE(dir); - DISPOSE(file); + free(dir); + free(file); return NULL; } @@ -184,13 +187,15 @@ char *default_rl_complete(char *pathname, int *unique) /* Exactly one match -- finish it off. */ *unique = 1; j = strlen(av[0]) - len + 2; - if ((p = NEW(char, j + 1)) != NULL) { - COPYFROMTO(p, av[0] + len, j); + p = malloc(sizeof(char) * (j + 1)); + if (p) { + memcpy(p, av[0] + len, j); len = strlen(dir) + strlen(av[0]) + 2; - if ((new = NEW(char, len)) != NULL) { + new = malloc(sizeof(char) * len); + if (new) { snprintf(new, len, "%s/%s", dir, av[0]); rl_add_slash(new, p); - DISPOSE(new); + free(new); } } } @@ -205,8 +210,9 @@ char *default_rl_complete(char *pathname, int *unique) breakout: if (i > len) { j = i - len + 1; - if ((p = NEW(char, j)) != NULL) { - COPYFROMTO(p, av[0] + len, j); + p = malloc(sizeof(char) * j); + if (p) { + memcpy(p, av[0] + len, j); p[j - 1] = '\0'; } } @@ -214,11 +220,11 @@ char *default_rl_complete(char *pathname, int *unique) } /* Clean up and return. */ - DISPOSE(dir); - DISPOSE(file); + free(dir); + free(file); for (i = 0; i < ac; i++) - DISPOSE(av[i]); - DISPOSE(av); + free(av[i]); + free(av); return p; } @@ -234,8 +240,8 @@ int default_rl_list_possib(char *pathname, char ***avp) return 0; ac = FindMatches(dir, file, avp); - DISPOSE(dir); - DISPOSE(file); + free(dir); + free(file); return ac; } diff --git a/src/editline.c b/src/editline.c index 3bf612a..5bef448 100644 --- a/src/editline.c +++ b/src/editline.c @@ -70,7 +70,7 @@ typedef struct { typedef struct { int Size; int Pos; - const char *Lines[HIST_SIZE]; + char *Lines[HIST_SIZE]; } el_hist_t; /* @@ -85,7 +85,7 @@ int rl_quit; int rl_susp; #endif -static const char NIL[] = ""; +static char NIL[] = ""; static const char *Input = NIL; static const char *Prompt; static char *Yanked; @@ -145,7 +145,7 @@ static void tty_put(const char c) Screen[ScreenCount] = c; if (++ScreenCount >= ScreenSize - 1) { ScreenSize += SCREEN_INC; - RENEW(Screen, char, ScreenSize); + Screen = realloc(Screen, sizeof(char) * ScreenSize); } } @@ -454,11 +454,12 @@ static el_status_t insert_string(const char *p) len = strlen((char *)p); if (rl_end + len >= Length) { - if ((new = NEW(char, Length + len + MEM_INC)) == NULL) + new = malloc(sizeof(char) * (Length + len + MEM_INC)); + if (!new) return CSstay; if (Length) { - COPYFROMTO(new, rl_line_buffer, Length); - DISPOSE(rl_line_buffer); + memcpy(new, rl_line_buffer, Length); + free(rl_line_buffer); } rl_line_buffer = new; Length += len + MEM_INC; @@ -466,7 +467,7 @@ static el_status_t insert_string(const char *p) for (q = &rl_line_buffer[rl_point], i = rl_end - rl_point; --i >= 0; ) q[len + i] = q[i]; - COPYFROMTO(&rl_line_buffer[rl_point], p, len); + memcpy(&rl_line_buffer[rl_point], p, len); rl_end += len; rl_line_buffer[rl_end] = '\0'; tty_string(&rl_line_buffer[rl_point]); @@ -549,7 +550,7 @@ static el_status_t h_last(void) */ static int substrcmp(const char *text, const char *pat, size_t len) { - char c; + char c; if ((c = *pat) == '\0') return *text == '\0'; @@ -570,7 +571,7 @@ static const char *search_hist(const char *search, const char *(*move)(void)) /* Save or get remembered search pattern. */ if (search && *search) { if (old_search) - DISPOSE(old_search); + free(old_search); old_search = (char *)strdup((char *)search); } else { @@ -594,6 +595,7 @@ static const char *search_hist(const char *search, const char *(*move)(void)) if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) return H.Lines[H.Pos]; H.Pos = pos; + return NULL; } @@ -647,15 +649,16 @@ static el_status_t fd_char(void) static void save_yank(int begin, int i) { if (Yanked) { - DISPOSE(Yanked); + free(Yanked); Yanked = NULL; } if (i < 1) return; - if ((Yanked = NEW(char, (SIZE_T)i + 1)) != NULL) { - COPYFROMTO(Yanked, &rl_line_buffer[begin], i); + Yanked = malloc(sizeof(char) * (i + 1)); + if (Yanked) { + memcpy(Yanked, &rl_line_buffer[begin], i); Yanked[i] = '\0'; } } @@ -768,14 +771,17 @@ static el_status_t insert_char(int c) return insert_string(buff); } - if ((p = NEW(char, Repeat + 1)) == NULL) + p = malloc(sizeof(char) * (Repeat + 1)); + if (!p) return CSstay; + for (i = Repeat, q = p; --i >= 0; ) *q++ = c; *q = '\0'; Repeat = 0; s = insert_string(p); - DISPOSE(p); + free(p); + return s; } @@ -950,7 +956,7 @@ static char *editinput(void) return NULL; } -static void hist_add(const char *p) +static void hist_add(char *p) { int i; @@ -959,7 +965,7 @@ static void hist_add(const char *p) if (H.Size < HIST_SIZE) H.Lines[H.Size++] = p; else { - DISPOSE(H.Lines[0]); + free(H.Lines[0]); for (i = 0; i < HIST_SIZE - 1; i++) H.Lines[i] = H.Lines[i + 1]; H.Lines[i] = p; @@ -974,14 +980,19 @@ static char *read_redirected(void) char *line; char *end; - p = line = NEW(char, size); + p = line = malloc(sizeof(char) * size); + if (!p) + return NULL; + end = p + size; while (1) { if (p == end) { int oldpos = end - line; size += MEM_INC; - p = RENEW(line, char, size); + p = line = realloc(line, sizeof(char) * size); + if (!p) + return NULL; end = p + size; p += oldpos; /* Continue where we left off... */ @@ -996,6 +1007,7 @@ static char *read_redirected(void) p++; } *p = '\0'; + return line; } @@ -1035,9 +1047,10 @@ char *readline(const char *prompt) return read_redirected(); } - if (rl_line_buffer == NULL) { + if (!rl_line_buffer) { Length = MEM_INC; - if ((rl_line_buffer = NEW(char, Length)) == NULL) + rl_line_buffer = malloc(sizeof(char) * Length); + if (!rl_line_buffer) return NULL; } @@ -1045,7 +1058,10 @@ char *readline(const char *prompt) rl_ttyset(0); hist_add(NIL); ScreenSize = SCREEN_INC; - Screen = NEW(char, ScreenSize); + Screen = malloc(sizeof(char) * ScreenSize); + if (!Screen) + return NULL; + Prompt = prompt ? prompt : NIL; tty_puts(Prompt); if ((line = editinput()) != NULL) { @@ -1054,14 +1070,14 @@ char *readline(const char *prompt) tty_flush(); } rl_ttyset(1); - DISPOSE(Screen); - DISPOSE(H.Lines[--H.Size]); + free(Screen); + free(H.Lines[--H.Size]); if (line != NULL && *line != '\0' #ifdef CONFIG_UNIQUE_HISTORY - && !(H.Pos && strcmp((char *) line, (char *) H.Lines[H.Pos - 1]) == 0) + && !(H.Pos && strcmp(line, H.Lines[H.Pos - 1]) == 0) #endif - && !(H.Size && strcmp((char *) line, (char *) H.Lines[H.Size - 1]) == 0) + && !(H.Size && strcmp(line, H.Lines[H.Size - 1]) == 0) ) { hist_add(line); } @@ -1071,7 +1087,8 @@ char *readline(const char *prompt) Signal = 0; kill(getpid(), s); } - return (char *)line; + + return line; } void add_history(char *p __attribute__ ((unused))) @@ -1113,17 +1130,22 @@ static char *find_word(void) } } } + len = rl_point - (p - rl_line_buffer) + 1; - if ((new = NEW(char, len)) == NULL) + new = malloc(sizeof(char) * len); + if (!new) return NULL; + q = new; while (p < &rl_line_buffer[rl_point]) { if (*p == '\\') { - if (++p == &rl_line_buffer[rl_point]) break; + if (++p == &rl_line_buffer[rl_point]) + break; } *q++ = *p++; } *q = '\0'; + return new; } @@ -1140,12 +1162,13 @@ static el_status_t c_possible(void) word = find_word(); ac = rl_list_possib((char *)word, (char ***)&av); if (word) - DISPOSE(word); + free(word); if (ac) { columns(ac, av); while (--ac >= 0) - DISPOSE(av[ac]); - DISPOSE(av); + free(av[ac]); + free(av); + return CSmove; } return ring_bell(); @@ -1166,11 +1189,13 @@ static el_status_t c_complete(void) word = find_word(); p = (char *)rl_complete((char *)word, &unique); if (word) - DISPOSE(word); + free(word); if (p) { len = strlen((char *)p); word = p; - new = q = NEW(char, 2 * len + 1); + new = q = malloc(sizeof(char) * (2 * len + 1)); + if (!new) + return CSstay; while (*p) { if ((*p < ' ' || strchr(SEPS, (char) *p) != NULL) && (!unique || p[1] != 0)) { @@ -1179,7 +1204,7 @@ static el_status_t c_complete(void) *q++ = *p++; } *q = '\0'; - DISPOSE(word); + free(word); if (len > 0) { s = insert_string(new); #ifdef CONFIG_ANNOYING_NOISE @@ -1187,8 +1212,9 @@ static el_status_t c_complete(void) ring_bell(); #endif } - DISPOSE(new); - if (len > 0) return s; + free(new); + if (len > 0) + return s; } return c_possible(); } @@ -1352,7 +1378,8 @@ static int argify(char *line, char ***avp) int i; i = MEM_INC; - if ((*avp = p = NEW(char *, i))== NULL) + *avp = p = malloc(sizeof(char *) * i); + if (!p) return 0; for (c = line; isspace(*c); c++) @@ -1365,14 +1392,14 @@ static int argify(char *line, char ***avp) *c++ = '\0'; if (*c && *c != '\n') { if (ac + 1 == i) { - new = NEW(char *, i + MEM_INC); - if (new == NULL) { + new = malloc(sizeof(char *) * (i + MEM_INC)); + if (!new) { p[ac] = NULL; return ac; } - COPYFROMTO(new, p, i * sizeof (char **)); + memcpy(new, p, i * sizeof(char **)); i += MEM_INC; - DISPOSE(p); + free(p); *avp = p = new; } p[ac++] = c; @@ -1406,8 +1433,9 @@ static el_status_t last_argument(void) s = ac ? insert_string(av[ac - 1]) : CSstay; if (ac) - DISPOSE(av); - DISPOSE(p); + free(av); + free(p); + return s; } diff --git a/src/editline.h b/src/editline.h index fe68cc2..8539927 100644 --- a/src/editline.h +++ b/src/editline.h @@ -62,11 +62,6 @@ typedef unsigned char CHAR; #define MEM_INC 64 #define SCREEN_INC 256 -#define DISPOSE(p) free((char *)(p)) -#define NEW(T, c) ((T *)malloc((unsigned int)(sizeof (T) * (c)))) -#define RENEW(p, T, c) (p = (T *)realloc((char *)(p), (unsigned int)(sizeof (T) * (c)))) -#define COPYFROMTO(new, p, len) (void)memcpy((char *)(new), (char *)(p), (int)(len)) - /* ** Variables and routines internal to this package. */ From 98b846c8b1efd8e0eef114415463c0b9701dac72 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 00:50:40 +0200 Subject: [PATCH 04/44] Revert function pointers for rl_complete() and rl_list_possib() introduced in 0.2.2. Instead merge afd8b4de9dca8ec6afc3 from http://github.com/heimdal/heimdal.git project. This lets rl_complete() and rl_list_possib() become wrapper functions calling a set of function pointers, set using rl_set_complete_func() and rl_set_list_possib_funct(). Each wrapper has a fallback to do filename completion, which in turn can be disabled by leaving out --enable-default-complete from the configure line. This change, admittedly quite intrusive for a library, is a better implementation in many ways. For one it is much more readable, but it also enables further adoption of other editline forks as well as a simpler implementation of GNU Readline function pointers rl_completion_entry_function and rl_attempted_completion_function at a later stage. My apologies to everyone for whom this change breaks backwards compatibility. For help on converting your code, please see examples/cli.c. --- examples/cli.c | 4 ++-- include/editline.h | 12 +++++++--- src/complete.c | 60 ++++++++++++++++++++++++++++++++++++++++------ src/editline.c | 25 +------------------ src/editline.h | 10 ++++---- 5 files changed, 69 insertions(+), 42 deletions(-) diff --git a/examples/cli.c b/examples/cli.c index c9e0345..58cdbf5 100644 --- a/examples/cli.c +++ b/examples/cli.c @@ -84,8 +84,8 @@ int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused))) char *prompt = "cli> "; /* Setup callbacks */ - rl_complete = &my_rl_complete; - rl_list_possib = &my_rl_list_possib; + rl_set_complete_func(&my_rl_complete); + rl_set_list_possib_func(&my_rl_list_possib); while ((line = readline(prompt)) != NULL) { (void)printf("\t\t\t|%s|\n", line); diff --git a/include/editline.h b/include/editline.h index 06e7259..802700f 100644 --- a/include/editline.h +++ b/include/editline.h @@ -21,12 +21,18 @@ #ifndef __EDITLINE_H__ #define __EDITLINE_H__ +/* Editline specific types, despite rl_ prefix. From Heimdal project. */ +typedef char* (*rl_complete_func_t)(char*, int*); +typedef int (*rl_list_possib_func_t)(char*, char***); + /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? (Default:1) */ extern int rl_meta_chars; -/* Assign these to get command completion, see cli.c for example usage. */ -extern char *(*rl_complete) (char *token, int *match); -extern int (*rl_list_possib)(char *token, char ***av); +/* Use these functions to set custom command/file completion, see cli.c for example usage. */ +rl_complete_func_t rl_set_complete_func(rl_complete_func_t func); +rl_list_possib_func_t rl_set_list_possib_func(rl_list_possib_func_t func); + +/* Editline specific functions. */ /* For compatibility with FSF readline. */ extern int rl_point; diff --git a/src/complete.c b/src/complete.c index fe70ecf..8900fa1 100644 --- a/src/complete.c +++ b/src/complete.c @@ -156,9 +156,19 @@ static int SplitPath(char *path, char **dirpart, char **filepart) return 0; } +static rl_complete_func_t el_complete_func = NULL; + +/* For compatibility with the Heimdal project. */ +rl_complete_func_t rl_set_complete_func(rl_complete_func_t func) +{ + rl_complete_func_t old = el_complete_func; + el_complete_func = func; + return old; +} + /* Attempt to complete the pathname, returning an allocated copy. - * Fill in *unique if we completed it, or set it to 0 if ambiguous. */ -char *default_rl_complete(char *pathname, int *unique) + * Fill in *match if we completed it, or set it to 0 if ambiguous. */ +char *el_filename_complete(char *pathname, int *match) { char **av; char *dir; @@ -185,7 +195,7 @@ char *default_rl_complete(char *pathname, int *unique) len = strlen(file); if (ac == 1) { /* Exactly one match -- finish it off. */ - *unique = 1; + *match = 1; j = strlen(av[0]) - len + 2; p = malloc(sizeof(char) * (j + 1)); if (p) { @@ -200,7 +210,7 @@ char *default_rl_complete(char *pathname, int *unique) } } else { - *unique = 0; + *match = 0; if (len) { /* Find largest matching substring. */ for (i = len, end = strlen(av[0]); i < end; i++) @@ -229,8 +239,30 @@ char *default_rl_complete(char *pathname, int *unique) return p; } -/* Return all possible completions. */ -int default_rl_list_possib(char *pathname, char ***avp) +char *rl_complete(char *token, int *match) +{ + if (el_complete_func) + return el_complete_func(token, match); + +#ifdef CONFIG_DEFAULT_COMPLETE + return el_filename_complete(token, match); +#else + return NULL; +#endif +} + +static rl_list_possib_func_t el_list_possib_func = NULL; + +/* For compatibility with the Heimdal project. */ +rl_list_possib_func_t rl_set_list_possib_func(rl_list_possib_func_t func) +{ + rl_list_possib_func_t old = el_list_possib_func; + el_list_possib_func = func; + return old; +} + +/* Default possible completions. */ +int el_filename_list_possib(char *pathname, char ***av) { char *dir; char *file; @@ -239,13 +271,27 @@ int default_rl_list_possib(char *pathname, char ***avp) if (SplitPath(pathname, &dir, &file) < 0) return 0; - ac = FindMatches(dir, file, avp); + ac = FindMatches(dir, file, av); free(dir); free(file); return ac; } +/* Return all possible completions. */ +int rl_list_possib(char *token, char ***av) +{ + if (el_list_possib_func) + return el_list_possib_func(token, av); + +#ifdef CONFIG_DEFAULT_COMPLETE + return el_filename_list_possib(token, av); +#else + return 0; +#endif +} + + /** * Local Variables: * version-control: t diff --git a/src/editline.c b/src/editline.c index 5bef448..1cf62e6 100644 --- a/src/editline.c +++ b/src/editline.c @@ -115,8 +115,6 @@ const char *rl_readline_name;/* Set by calling program, for conditional pa /* User definable callbacks. */ char **(*rl_attempted_completion_function)(const char *token, int start, int end); -char *(*rl_comlete)(char *token, int *match); -int (*rl_list_possib)(char *token, char ***av); /* Declarations. */ static char *editinput(void); @@ -1018,20 +1016,6 @@ void rl_reset_terminal(char *p __attribute__((__unused__))) void rl_initialize(void) { -#ifdef CONFIG_DEFAULT_COMPLETE - int done = 0; - - if (!done) - { - if (!rl_complete) - rl_complete = &default_rl_complete; - - if (!rl_list_possib) - rl_list_possib = &default_rl_list_possib; - - done = 1; - } -#endif } char *readline(const char *prompt) @@ -1155,10 +1139,6 @@ static el_status_t c_possible(void) char *word; int ac; - if (!rl_list_possib) { - return ring_bell(); - } - word = find_word(); ac = rl_list_possib((char *)word, (char ***)&av); if (word) @@ -1171,6 +1151,7 @@ static el_status_t c_possible(void) return CSmove; } + return ring_bell(); } @@ -1182,10 +1163,6 @@ static el_status_t c_complete(void) int unique; el_status_t s = 0; - if (!rl_complete) { - return ring_bell(); - } - word = find_word(); p = (char *)rl_complete((char *)word, &unique); if (word) diff --git a/src/editline.h b/src/editline.h index 8539927..ef165e2 100644 --- a/src/editline.h +++ b/src/editline.h @@ -73,12 +73,10 @@ extern int rl_quit; #ifdef CONFIG_SIGSTOP extern int rl_susp; #endif -#ifdef CONFIG_DEFAULT_COMPLETE -extern char *default_rl_complete(char *pathname, int *unique); -extern int default_rl_list_possib(char *pathname, char ***avp); -#endif -extern void rl_ttyset(int Reset); -extern void rl_add_slash(char *path, char *p); +void rl_ttyset(int Reset); +void rl_add_slash(char *path, char *p); +char *rl_complete(char *token, int *match); +int rl_list_possib(char *token, char ***av); #ifndef HAVE_STDLIB_H extern char *getenv(const char *name); From ceb19957330ed7478df475b3b03f5950b2b8bf31 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 02:02:14 +0200 Subject: [PATCH 05/44] Add fallback backspace in case tgetstr("le") fails. --- src/editline.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/editline.c b/src/editline.c index 1cf62e6..ab2fa71 100644 --- a/src/editline.c +++ b/src/editline.c @@ -238,10 +238,12 @@ static void tty_info(void) if ((term = getenv("TERM")) == NULL) term = "dumb"; if (-1 != tgetent(buff, term)) { - if ((backspace = tgetstr("le", &bp)) != NULL) - backspace = strdup(backspace); - tty_cols = tgetnum("co"); - tty_rows = tgetnum("li"); + if ((backspace = tgetstr("le", &bp)) != NULL) + backspace = strdup(backspace); + else + backspace = "\b"; + tty_cols = tgetnum("co"); + tty_rows = tgetnum("li"); } /* Make sure to check width & rows and fallback to TIOCGWINSZ if available. */ #endif From a84801107374edfd275bafd201e5a3986a2b3382 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 02:02:56 +0200 Subject: [PATCH 06/44] Move strdup() fallback implementation to platform code. --- src/complete.c | 15 --------------- src/sysunix.c | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/complete.c b/src/complete.c index 8900fa1..44ed547 100644 --- a/src/complete.c +++ b/src/complete.c @@ -23,21 +23,6 @@ #define MAX_TOTAL_MATCHES (256 << sizeof(char *)) -#ifndef HAVE_STRDUP -/* Return an allocated copy of a string. */ -char *strdup(const char *p) -{ - char *new = malloc(sizeof(char) * strlen(p)); - - if (new) { - strcpy(new, p); - return new; - } - - return NULL; -} -#endif - /* Wrap strcmp() for qsort() */ static int compare(const void *p1, const void *p2) { diff --git a/src/sysunix.c b/src/sysunix.c index 74bd1ac..4827f33 100644 --- a/src/sysunix.c +++ b/src/sysunix.c @@ -142,6 +142,21 @@ void rl_ttyset(int Reset) #error Unsupported platform, missing tcgetattr(), termio.h and sgtty.h #endif /* Neither HAVE_SGTTY_H, HAVE_TERMIO_H or HAVE_TCGETATTR */ +#ifndef HAVE_STRDUP +/* Return an allocated copy of a string. */ +char *strdup(const char *p) +{ + char *new = malloc(sizeof(char) * strlen(p)); + + if (new) { + strcpy(new, p); + return new; + } + + return NULL; +} +#endif + void rl_add_slash(char *path, char *p) { struct stat Sb; From d4aa5ac29398cdb821d99a74f1700a5cfae4401b Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 02:15:18 +0200 Subject: [PATCH 07/44] Minor cleanup --- examples/testit.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/examples/testit.c b/examples/testit.c index 8f3a747..80295c2 100644 --- a/examples/testit.c +++ b/examples/testit.c @@ -33,39 +33,44 @@ #include "editline.h" #ifndef HAVE_PERROR +extern int errno; void perror(char *s) { - extern int errno; - - (void)fprintf(stderr, "%s: error %d\n", s, errno); + fprintf(stderr, "%s: error %d\n", s, errno); } #endif /* !HAVE_PERROR */ int main(int argc, char *argv[] __attribute__ ((unused))) { - char *prompt; - char *p; - int doit; + int doit; + char *prompt, *p; doit = argc == 1; if ((prompt = getenv("TESTPROMPT")) == NULL) - prompt = "testit> "; + prompt = "testit> "; while ((p = readline(prompt)) != NULL) { - (void)printf("\t\t\t|%s|\n", p); + printf("\t\t\t|%s|\n", p); if (doit) { if (strncmp(p, "cd ", 3) == 0) { - if (chdir(&p[3]) < 0) { + if (chdir(&p[3]) < 0) perror(&p[3]); - } - } - else if (system(p) != 0) { + } else if (system(p) != 0) { perror(p); - } - } + } + } add_history(p); free(p); } return 0; } + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "ellemtel" + * c-basic-offset: 4 + * End: + */ From 522e534448cc3ada7695caa9fbac1e8b82d60f92 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 02:21:28 +0200 Subject: [PATCH 08/44] Remove unnecessary casts. --- src/editline.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/editline.c b/src/editline.c index ab2fa71..881f12d 100644 --- a/src/editline.c +++ b/src/editline.c @@ -210,9 +210,9 @@ static void tty_info(void) { static int init; #ifdef CONFIG_USE_TERMCAP - char *term; + char *term; char buff[2048]; - char *bp; + char *bp; #endif #ifdef TIOCGWINSZ struct winsize W; @@ -1142,7 +1142,7 @@ static el_status_t c_possible(void) int ac; word = find_word(); - ac = rl_list_possib((char *)word, (char ***)&av); + ac = rl_list_possib(word, &av); if (word) free(word); if (ac) { From 5a8ad742d956b8f30f196d8967d183bcbd57152c Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 02:39:45 +0200 Subject: [PATCH 09/44] Adding -Wcast-qual revealed some more interesting casts. --- configure | 2 +- configure.ac | 2 +- src/complete.c | 6 +++--- src/editline.c | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/configure b/configure index 6910daf..7448e97 100755 --- a/configure +++ b/configure @@ -11274,7 +11274,7 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$saved_cflags" -AM_CFLAGS="-std=gnu99 $inline_cflags -W -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow" +AM_CFLAGS="-std=gnu99 $inline_cflags -W -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow -Wcast-qual" ### The following magic for determining the location of termcap library is from GNU Texinfo diff --git a/configure.ac b/configure.ac index 5bd3472..4b155cc 100644 --- a/configure.ac +++ b/configure.ac @@ -111,7 +111,7 @@ AC_COMPILE_IFELSE(AC_LANG_PROGRAM([]), nopointersign_cflags="-Wno-pointer-sign", nopointersign_cflags="") CFLAGS="$saved_cflags" -AM_CFLAGS="-std=gnu99 $inline_cflags -W -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow" +AM_CFLAGS="-std=gnu99 $inline_cflags -W -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow -Wcast-qual" AC_SUBST(AM_CFLAGS) ### The following magic for determining the location of termcap library is from GNU Texinfo diff --git a/src/complete.c b/src/complete.c index 44ed547..64e97f5 100644 --- a/src/complete.c +++ b/src/complete.c @@ -23,11 +23,11 @@ #define MAX_TOTAL_MATCHES (256 << sizeof(char *)) -/* Wrap strcmp() for qsort() */ +/* Wrap strcmp() for qsort() -- weird construct to pass -Wcast-qual */ static int compare(const void *p1, const void *p2) { - char **v1 = (char **)p1; - char **v2 = (char **)p2; + char *const *v1 = (char *const *)p1; + char *const *v2 = (char *const *)p2; return strcmp(*v1, *v2); } diff --git a/src/editline.c b/src/editline.c index 881f12d..67a1bbf 100644 --- a/src/editline.c +++ b/src/editline.c @@ -452,7 +452,7 @@ static el_status_t insert_string(const char *p) char *new; char *q; - len = strlen((char *)p); + len = strlen(p); if (rl_end + len >= Length) { new = malloc(sizeof(char) * (Length + len + MEM_INC)); if (!new) @@ -566,13 +566,13 @@ static const char *search_hist(const char *search, const char *(*move)(void)) int len; int pos; int (*match)(const char *s1, const char *s2, size_t n); - char *pat; + const char *pat; /* Save or get remembered search pattern. */ if (search && *search) { if (old_search) free(old_search); - old_search = (char *)strdup((char *)search); + old_search = strdup(search); } else { if (old_search == NULL || *old_search == '\0') @@ -583,16 +583,16 @@ static const char *search_hist(const char *search, const char *(*move)(void)) /* Set up pattern-finder. */ if (*search == '^') { match = strncmp; - pat = (char *)(search + 1); + pat = search + 1; } else { match = substrcmp; - pat = (char *)search; + pat = search; } len = strlen(pat); for (pos = H.Pos; (*move)() != NULL; ) - if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) + if (match(H.Lines[H.Pos], pat, len) == 0) return H.Lines[H.Pos]; H.Pos = pos; From c7b78df006a6c8588bf343fcda2f78738dbb4eda Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 02:46:04 +0200 Subject: [PATCH 10/44] Fix lingering bug, post incrementing pointers is almost never a good idea. --- src/complete.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/complete.c b/src/complete.c index 64e97f5..3ff11d1 100644 --- a/src/complete.c +++ b/src/complete.c @@ -125,12 +125,11 @@ static int SplitPath(char *path, char **dirpart, char **filepart) free(dpart); return -1; } - } - else { + } else { if ((dpart = strdup(path)) == NULL) return -1; dpart[fpart - path + 1] = '\0'; - if ((fpart = strdup(++fpart)) == NULL) { + if ((fpart = strdup(fpart + 1)) == NULL) { free(dpart); return -1; } From 02ea37e4de71ac58fe6d77238513c0f8948e4458 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 02:52:51 +0200 Subject: [PATCH 11/44] Clarify code when CONFIG_ANSI_ARROWS is selected. --- src/editline.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/editline.c b/src/editline.c index 67a1bbf..9cf6488 100644 --- a/src/editline.c +++ b/src/editline.c @@ -815,25 +815,28 @@ static el_status_t meta(void) if ((c = tty_get()) == EOF) return CSeof; + #ifdef CONFIG_ANSI_ARROWS /* Also include VT-100 arrows. */ if (c == '[' || c == 'O') { c = tty_get(); -// printf ("E[%c\n", c); switch (c) { - default: return ring_bell(); - case EOF: return CSeof; - case '2': tty_get(); return CSstay; /* Insert */ - case '3': tty_get(); return del_char(); /* Delete */ - case '5': tty_get(); return CSstay; /* PgUp */ - case '6': tty_get(); return CSstay; /* PgDn */ - case 'A': return h_prev(); /* Up */ - case 'B': return h_next(); /* Down */ - case 'C': return fd_char(); /* Left */ - case 'D': return bk_char(); /* Right */ - case 'F': return end_line(); /* End */ - case 'H': return beg_line(); /* Home */ + case EOF: return CSeof; + case '2': tty_get(); return CSstay; /* Insert */ + case '3': tty_get(); return del_char(); /* Delete */ + case '5': tty_get(); return CSstay; /* PgUp */ + case '6': tty_get(); return CSstay; /* PgDn */ + case 'A': return h_prev(); /* Up */ + case 'B': return h_next(); /* Down */ + case 'C': return fd_char(); /* Left */ + case 'D': return bk_char(); /* Right */ + case 'F': return end_line(); /* End */ + case 'H': return beg_line(); /* Home */ + default: /* Fall through */ + break; } + + return ring_bell(); } #endif /* CONFIG_ANSI_ARROWS */ From 8e13c7b5aeb55dcacbcd2b93c564135623627fc9 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 03:05:23 +0200 Subject: [PATCH 12/44] Fix memory leak --- src/editline.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/editline.c b/src/editline.c index 9cf6488..2e1fc5c 100644 --- a/src/editline.c +++ b/src/editline.c @@ -1392,12 +1392,13 @@ static int argify(char *line, char ***avp) } *c = '\0'; p[ac] = NULL; + return ac; } static el_status_t last_argument(void) { - char **av; + char **av = NULL; char *p; el_status_t s; int ac; @@ -1414,7 +1415,7 @@ static el_status_t last_argument(void) else s = ac ? insert_string(av[ac - 1]) : CSstay; - if (ac) + if (av) free(av); free(p); From a7eea67253341f5a545b36e5529a1085b5eaf8ac Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 03:09:00 +0200 Subject: [PATCH 13/44] Cast size_t to int, confuses some compilers otherwise. --- src/editline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editline.c b/src/editline.c index 2e1fc5c..140ad8e 100644 --- a/src/editline.c +++ b/src/editline.c @@ -437,7 +437,7 @@ static void ceol(void) static void clear_line(void) { - rl_point = -strlen(Prompt); + rl_point = -(int)strlen(Prompt); tty_put('\r'); ceol(); rl_point = 0; From 83e4837f39c313fe13970cae1f59801915c08633 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 03:12:45 +0200 Subject: [PATCH 14/44] Remove unused CHAR type and replace SIZE_T with size_t, we check for that. --- src/complete.c | 18 +++++++++--------- src/editline.c | 12 ++++++------ src/editline.h | 6 ------ 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/complete.c b/src/complete.c index 3ff11d1..80fe8e7 100644 --- a/src/complete.c +++ b/src/complete.c @@ -41,10 +41,10 @@ static int FindMatches(char *dir, char *file, char ***avp) char *p; DIR *dp; DIRENTRY *ep; - SIZE_T ac; - SIZE_T len; - SIZE_T choices; - SIZE_T total; + size_t ac; + size_t len; + size_t choices; + size_t total; if ((dp = opendir(dir)) == NULL) return 0; @@ -159,11 +159,11 @@ char *el_filename_complete(char *pathname, int *match) char *file; char *new; char *p; - SIZE_T ac; - SIZE_T end; - SIZE_T i; - SIZE_T j; - SIZE_T len; + size_t ac; + size_t end; + size_t i; + size_t j; + size_t len; if (SplitPath(pathname, &dir, &file) < 0) return NULL; diff --git a/src/editline.c b/src/editline.c index 140ad8e..e2e3bdf 100644 --- a/src/editline.c +++ b/src/editline.c @@ -99,9 +99,9 @@ static int Pushed; static int Signal; static el_keymap_t Map[]; static el_keymap_t MetaMap[]; -static SIZE_T Length; -static SIZE_T ScreenCount; -static SIZE_T ScreenSize; +static size_t Length; +static size_t ScreenCount; +static size_t ScreenSize; static char *backspace; static int tty_cols; static int tty_rows; @@ -447,7 +447,7 @@ static void clear_line(void) static el_status_t insert_string(const char *p) { - SIZE_T len; + size_t len; int i; char *new; char *q; @@ -1105,7 +1105,7 @@ static char *find_word(void) { char *p, *q; char *new; - SIZE_T len; + size_t len; p = &rl_line_buffer[rl_point]; while (p > rl_line_buffer) { @@ -1164,7 +1164,7 @@ static el_status_t c_complete(void) { char *p, *q; char *word, *new; - SIZE_T len; + size_t len; int unique; el_status_t s = 0; diff --git a/src/editline.h b/src/editline.h index ef165e2..61ecef6 100644 --- a/src/editline.h +++ b/src/editline.h @@ -53,12 +53,6 @@ # include #endif -#ifndef SIZE_T -#define SIZE_T unsigned int -#endif - -typedef unsigned char CHAR; - #define MEM_INC 64 #define SCREEN_INC 256 From be921400bb28fed7418733b0d83d3323ee04b2a1 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 03:38:25 +0200 Subject: [PATCH 15/44] Merge el_no_echo patch from Festival speech-tools editline fork --- include/editline.h | 1 + src/editline.c | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/editline.h b/include/editline.h index 802700f..5b8f922 100644 --- a/include/editline.h +++ b/include/editline.h @@ -40,6 +40,7 @@ extern int rl_mark; extern int rl_end; extern char *rl_line_buffer; extern const char *rl_readline_name; +extern int el_no_echo; /* e.g under emacs, don't echo except prompt */ extern void rl_reset_terminal(char *p); extern void rl_initialize(void); diff --git a/src/editline.c b/src/editline.c index e2e3bdf..71a99a3 100644 --- a/src/editline.c +++ b/src/editline.c @@ -106,6 +106,7 @@ static char *backspace; static int tty_cols; static int tty_rows; +int el_no_echo = 0; /* e.g., under Emacs */ int rl_point; int rl_mark; int rl_end; @@ -133,7 +134,8 @@ static void tty_flush(void) ssize_t res; if (ScreenCount) { - res = write (1, Screen, ScreenCount); + if (!el_no_echo) + res = write (1, Screen, ScreenCount); ScreenCount = 0; } } @@ -1052,8 +1054,17 @@ char *readline(const char *prompt) return NULL; Prompt = prompt ? prompt : NIL; - tty_puts(Prompt); - if ((line = editinput()) != NULL) { + if (el_no_echo) { + int old = el_no_echo; + el_no_echo = 0; + tty_puts(Prompt); + tty_flush(); + el_no_echo = old; + } else { + tty_puts(Prompt); + } + line = editinput(); + if (line) { line = strdup(line); tty_puts(NEWLINE); tty_flush(); From f16cbece5a2c3e313088ed1175281511baaa8be4 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 24 Jul 2010 03:46:58 +0200 Subject: [PATCH 16/44] Rename Signal --> el_intr_pending. From Festival speech-tools. --- src/editline.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/editline.c b/src/editline.c index 71a99a3..2820fd5 100644 --- a/src/editline.c +++ b/src/editline.c @@ -96,7 +96,7 @@ static int Repeat; static int OldPoint; static int PushBack; static int Pushed; -static int Signal; +static int el_intr_pending; static el_keymap_t Map[]; static el_keymap_t MetaMap[]; static size_t Length; @@ -621,8 +621,8 @@ static el_status_t h_search(void) Prompt = old_prompt; Searching = 0; tty_puts(Prompt); - if (p == NULL && Signal > 0) { - Signal = 0; + if (p == NULL && el_intr_pending > 0) { + el_intr_pending = 0; clear_line(); return redisplay(); } @@ -902,16 +902,16 @@ static el_status_t tty_special(int c) if (c == rl_eof && rl_point == 0 && rl_end == 0) return CSeof; if (c == rl_intr) { - Signal = SIGINT; + el_intr_pending = SIGINT; return CSsignal; } if (c == rl_quit) { - Signal = SIGQUIT; + el_intr_pending = SIGQUIT; return CSeof; } #ifdef CONFIG_SIGSTOP if (c == rl_susp) { - Signal = SIGTSTP; + el_intr_pending = SIGTSTP; return CSsignal; } #endif @@ -927,7 +927,7 @@ static char *editinput(void) OldPoint = rl_point = rl_mark = rl_end = 0; rl_line_buffer[0] = '\0'; - Signal = -1; + el_intr_pending = -1; while ((c = tty_get()) != EOF) switch (tty_special(c)) { case CSdone: @@ -1028,7 +1028,6 @@ void rl_initialize(void) char *readline(const char *prompt) { char *line; - int s; /* Unless called by the user already. */ rl_initialize(); @@ -1082,9 +1081,9 @@ char *readline(const char *prompt) hist_add(line); } - if (Signal > 0) { - s = Signal; - Signal = 0; + if (el_intr_pending > 0) { + int s = el_intr_pending; + el_intr_pending = 0; kill(getpid(), s); } From dbad0d087161e9788ad4ac0c7e36df1217ab8ce1 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 25 Jul 2010 21:43:41 +0200 Subject: [PATCH 17/44] Minor. --- examples/cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cli.c b/examples/cli.c index 58cdbf5..c1aa002 100644 --- a/examples/cli.c +++ b/examples/cli.c @@ -88,7 +88,7 @@ int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused))) rl_set_list_possib_func(&my_rl_list_possib); while ((line = readline(prompt)) != NULL) { - (void)printf("\t\t\t|%s|\n", line); + printf("\t\t\t|%s|\n", line); free(line); } From 67e9aa3f2b27f704adae0235f834c27d9eadb0e0 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 25 Jul 2010 22:01:04 +0200 Subject: [PATCH 18/44] Revert broken Debian patch for 8-bit char input, fix tty_show() instead. This changeset fixes an old Debian patch that attempted to fix the display of 8-bit characters in the function emacs(). It accidentally crippled the function of M-d and M-DEL. The latter was however also broken by being mapped to wipe(), more on that below. The real fix is to set rl_meta_chars to 0 by default and in the tty_show() function, which tried to be smart and output control and meta characters (in the wrong order as well). Simply disabling the special code for output of control characters fixes 8-bit input. We also nuke the old and broken wipe() function that was mapped to M-DEL, instead we map that key binding to bk_kill_word(), which works. --- include/editline.h | 2 +- src/editline.c | 56 +++++++++++++++++++--------------------------- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/include/editline.h b/include/editline.h index 5b8f922..9684410 100644 --- a/include/editline.h +++ b/include/editline.h @@ -25,7 +25,7 @@ typedef char* (*rl_complete_func_t)(char*, int*); typedef int (*rl_list_possib_func_t)(char*, char***); -/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? (Default:1) */ +/* Display 8-bit chars "as-is" or as `M-x'? Toggle with M-m. (Default:0 - "as-is") */ extern int rl_meta_chars; /* Use these functions to set custom command/file completion, see cli.c for example usage. */ diff --git a/src/editline.c b/src/editline.c index 2820fd5..d533428 100644 --- a/src/editline.c +++ b/src/editline.c @@ -110,7 +110,7 @@ int el_no_echo = 0; /* e.g., under Emacs */ int rl_point; int rl_mark; int rl_end; -int rl_meta_chars = 1; /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */ +int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */ char *rl_line_buffer; const char *rl_readline_name;/* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ @@ -161,17 +161,20 @@ static void tty_show(char c) tty_put('^'); tty_put('?'); } - else if (ISCTL(c)) { - tty_put('^'); - tty_put(UNCTL(c)); - } else if (rl_meta_chars && ISMETA(c)) { tty_put('M'); tty_put('-'); tty_put(UNMETA(c)); } - else +#if 0 + else if (ISCTL(c)) { + tty_put('^'); + tty_put(UNCTL(c)); + } +#endif + else { tty_put(c); + } } static void tty_string(char *p) @@ -861,26 +864,30 @@ static el_status_t meta(void) static el_status_t emacs(int c) { - el_status_t s; - el_keymap_t *kp; + el_status_t s; + el_keymap_t *kp; + + /* Save point before interpreting input character 'c'. */ + OldPoint = rl_point; -#if 0 /* Debian patch removes this to be able to handle 8-bit input */ /* This test makes it impossible to enter eight-bit characters when * meta-char mode is enabled. */ - OldPoint = rl_point; if (rl_meta_chars && ISMETA(c)) { Pushed = 1; PushBack = UNMETA(c); return meta(); } -#endif /* Debian patch removal. */ - for (kp = Map; kp->Function; kp++) + + for (kp = Map; kp->Function; kp++) { if (kp->Key == c) break; - s = kp->Function ? (*kp->Function)() : insert_char((int)c); - if (!Pushed) + } + s = kp->Function ? (*kp->Function)() : insert_char(c); + if (!Pushed) { /* No pushback means no repeat count; hacky, but true. */ Repeat = NO_ARG; + } + return s; } @@ -1241,23 +1248,6 @@ static el_status_t quote(void) return (c = tty_get()) == EOF ? CSeof : insert_char((int)c); } -static el_status_t wipe(void) -{ - int i; - - if (rl_mark > rl_end) - return ring_bell(); - - if (rl_point > rl_mark) { - i = rl_point; - rl_point = rl_mark; - rl_mark = i; - reposition(); - } - - return delete_string(rl_mark - rl_point); -} - static el_status_t mk_set(void) { rl_mark = rl_point; @@ -1467,8 +1457,8 @@ static el_keymap_t Map[] = { }; static el_keymap_t MetaMap[]= { - { CTL('H'), wipe }, - { DEL, wipe }, + { CTL('H'), bk_kill_word }, + { DEL, bk_kill_word }, { ' ', mk_set }, { '.', last_argument }, { '<', h_first }, From 0d9ce0ce064d3aacf551fea8da7231f4c1056a99 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 25 Jul 2010 22:14:14 +0200 Subject: [PATCH 19/44] Refactor of variable names, for improved readline compat. --- src/editline.c | 153 +++++++++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 69 deletions(-) diff --git a/src/editline.c b/src/editline.c index d533428..1ad47f5 100644 --- a/src/editline.c +++ b/src/editline.c @@ -85,17 +85,16 @@ int rl_quit; int rl_susp; #endif -static char NIL[] = ""; -static const char *Input = NIL; -static const char *Prompt; +static char NILSTR[] = ""; +static const char *el_input = NILSTR; static char *Yanked; static char *Screen; static char NEWLINE[]= CRLF; static el_hist_t H; static int Repeat; -static int OldPoint; -static int PushBack; -static int Pushed; +static int old_point; +static int el_push_back; +static int el_pushed; static int el_intr_pending; static el_keymap_t Map[]; static el_keymap_t MetaMap[]; @@ -112,6 +111,7 @@ int rl_mark; int rl_end; int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */ char *rl_line_buffer; +const char *rl_prompt; const char *rl_readline_name;/* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ /* User definable callbacks. */ @@ -189,12 +189,12 @@ static int tty_get(void) int r; tty_flush(); - if (Pushed) { - Pushed = 0; - return PushBack; + if (el_pushed) { + el_pushed = 0; + return el_push_back; } - if (*Input) - return *Input++; + if (*el_input) + return *el_input++; do { r = read(0, &c, 1); @@ -306,7 +306,7 @@ static void reposition(void) char *p; tty_put('\r'); - tty_puts(Prompt); + tty_puts(rl_prompt); for (i = rl_point, p = rl_line_buffer; --i >= 0; p++) tty_show(*p); } @@ -349,8 +349,8 @@ static el_status_t do_macro(int c) name[2] = '_'; name[3] = '\0'; - if ((Input = (char *)getenv((char *)name)) == NULL) { - Input = NIL; + if ((el_input = (char *)getenv((char *)name)) == NULL) { + el_input = NILSTR; return ring_bell(); } return CSstay; @@ -387,10 +387,10 @@ static el_status_t do_case(el_case_t type) char *p; do_forward(CSstay); - if (OldPoint != rl_point) { - if ((count = rl_point - OldPoint) < 0) + if (old_point != rl_point) { + if ((count = rl_point - old_point) < 0) count = -count; - rl_point = OldPoint; + rl_point = old_point; if ((end = rl_point + count) > rl_end) end = rl_end; for (i = rl_point, p = &rl_line_buffer[i]; i < end; i++, p++) { @@ -442,7 +442,7 @@ static void ceol(void) static void clear_line(void) { - rl_point = -(int)strlen(Prompt); + rl_point = -(int)strlen(rl_prompt); tty_put('\r'); ceol(); rl_point = 0; @@ -483,8 +483,8 @@ static el_status_t insert_string(const char *p) static el_status_t redisplay(void) { - tty_puts(NEWLINE); - tty_puts(Prompt); + tty_puts(NEWLINE); /* XXX: Use "\r\e[K" to get really neat effect on ANSI capable terminals. */ + tty_puts(rl_prompt); tty_string(rl_line_buffer); return CSmove; } @@ -616,14 +616,14 @@ static el_status_t h_search(void) Searching = 1; clear_line(); - old_prompt = Prompt; - Prompt = "Search: "; - tty_puts(Prompt); + old_prompt = rl_prompt; + rl_prompt = "Search: "; + tty_puts(rl_prompt); move = Repeat == NO_ARG ? prev_hist : next_hist; p = editinput(); - Prompt = old_prompt; + rl_prompt = old_prompt; Searching = 0; - tty_puts(Prompt); + tty_puts(rl_prompt); if (p == NULL && el_intr_pending > 0) { el_intr_pending = 0; clear_line(); @@ -848,8 +848,8 @@ static el_status_t meta(void) if (isdigit(c)) { for (Repeat = c - '0'; (c = tty_get()) != EOF && isdigit(c); ) Repeat = Repeat * 10 + c - '0'; - Pushed = 1; - PushBack = c; + el_pushed = 1; + el_push_back = c; return CSstay; } @@ -868,13 +868,13 @@ static el_status_t emacs(int c) el_keymap_t *kp; /* Save point before interpreting input character 'c'. */ - OldPoint = rl_point; + old_point = rl_point; /* This test makes it impossible to enter eight-bit characters when * meta-char mode is enabled. */ if (rl_meta_chars && ISMETA(c)) { - Pushed = 1; - PushBack = UNMETA(c); + el_pushed = 1; + el_push_back = UNMETA(c); return meta(); } @@ -883,7 +883,7 @@ static el_status_t emacs(int c) break; } s = kp->Function ? (*kp->Function)() : insert_char(c); - if (!Pushed) { + if (!el_pushed) { /* No pushback means no repeat count; hacky, but true. */ Repeat = NO_ARG; } @@ -931,40 +931,50 @@ static char *editinput(void) int c; Repeat = NO_ARG; - OldPoint = rl_point = rl_mark = rl_end = 0; + old_point = rl_point = rl_mark = rl_end = 0; rl_line_buffer[0] = '\0'; el_intr_pending = -1; - while ((c = tty_get()) != EOF) + while ((c = tty_get()) != EOF) { switch (tty_special(c)) { - case CSdone: - return rl_line_buffer; - case CSeof: - return NULL; - case CSsignal: - return (char *)""; - case CSmove: - reposition(); - break; - case CSdispatch: - switch (emacs(c)) { - case CSdone: - return rl_line_buffer; - case CSeof: - return NULL; - case CSsignal: - return (char *)""; - case CSmove: - reposition(); - break; - case CSdispatch: - case CSstay: - break; - } - break; - case CSstay: - break; + case CSdone: + return rl_line_buffer; + + case CSeof: + return NULL; + + case CSsignal: + return (char *)""; + + case CSmove: + reposition(); + break; + + case CSdispatch: + switch (emacs(c)) { + case CSdone: + return rl_line_buffer; + + case CSeof: + return NULL; + + case CSsignal: + return (char *)""; + + case CSmove: + reposition(); + break; + + case CSdispatch: + case CSstay: + break; + } + break; + + case CSstay: + break; } + } return NULL; } @@ -1030,6 +1040,8 @@ void rl_reset_terminal(char *p __attribute__((__unused__))) void rl_initialize(void) { + if (!rl_prompt) + rl_prompt = "? "; } char *readline(const char *prompt) @@ -1053,28 +1065,30 @@ char *readline(const char *prompt) tty_info(); rl_ttyset(0); - hist_add(NIL); + hist_add(NILSTR); ScreenSize = SCREEN_INC; Screen = malloc(sizeof(char) * ScreenSize); if (!Screen) return NULL; - Prompt = prompt ? prompt : NIL; + rl_prompt = prompt ? prompt : NILSTR; if (el_no_echo) { int old = el_no_echo; el_no_echo = 0; - tty_puts(Prompt); + tty_puts(rl_prompt); tty_flush(); el_no_echo = old; } else { - tty_puts(Prompt); + tty_puts(rl_prompt); } + line = editinput(); if (line) { line = strdup(line); tty_puts(NEWLINE); tty_flush(); } + rl_ttyset(1); free(Screen); free(H.Lines[--H.Size]); @@ -1315,9 +1329,9 @@ static el_status_t fd_kill_word(void) int i; do_forward(CSstay); - if (OldPoint != rl_point) { - i = rl_point - OldPoint; - rl_point = OldPoint; + if (old_point != rl_point) { + i = rl_point - old_point; + rl_point = old_point; return delete_string(i); } return CSstay; @@ -1346,8 +1360,9 @@ static el_status_t bk_word(void) static el_status_t bk_kill_word(void) { bk_word(); - if (OldPoint != rl_point) - return delete_string(OldPoint - rl_point); + if (old_point != rl_point) + return delete_string(old_point - rl_point); + return CSstay; } From 20c55a58da6981796e298866c4ee341893969ef8 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 25 Jul 2010 22:17:10 +0200 Subject: [PATCH 20/44] Add el_bind_key_in_metamap() from Festival speech-tools. Support for Meta key binding imported from Festival speech-tools, author Alan W Black . Code released under the original license. --- include/editline.h | 7 ++++++ src/editline.c | 53 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/include/editline.h b/include/editline.h index 9684410..8691a11 100644 --- a/include/editline.h +++ b/include/editline.h @@ -21,9 +21,15 @@ #ifndef __EDITLINE_H__ #define __EDITLINE_H__ +/* Command status codes. */ +typedef enum { + CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal +} el_status_t; + /* Editline specific types, despite rl_ prefix. From Heimdal project. */ typedef char* (*rl_complete_func_t)(char*, int*); typedef int (*rl_list_possib_func_t)(char*, char***); +typedef el_status_t (*el_keymap_func_t)(void); /* Display 8-bit chars "as-is" or as `M-x'? Toggle with M-m. (Default:0 - "as-is") */ extern int rl_meta_chars; @@ -33,6 +39,7 @@ rl_complete_func_t rl_set_complete_func(rl_complete_func_t func); rl_list_possib_func_t rl_set_list_possib_func(rl_list_possib_func_t func); /* Editline specific functions. */ +void el_bind_key_in_metamap(char c, el_keymap_func_t func); /* For compatibility with FSF readline. */ extern int rl_point; diff --git a/src/editline.c b/src/editline.c index 1ad47f5..6407f3e 100644 --- a/src/editline.c +++ b/src/editline.c @@ -1,6 +1,7 @@ /* Main editing routines for editline library. * * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved. + * Copyright (c) 1998 Alan W. Black , for Edinburgh Speech Tools. * * This software is not subject to any license of the American Telephone * and Telegraph Company or of the Regents of the University of California. @@ -42,13 +43,6 @@ #endif #define SEPS "\"#$&'()*:;<=>?[\\]^`{|}~\n\t " -/* -** Command status codes. -*/ -typedef enum { - CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal -} el_status_t; - /* ** The type of case-changing to perform. */ @@ -1238,6 +1232,14 @@ static el_status_t accept_line(void) return CSdone; } +#ifdef SYSTEM_IS_WIN32 +static el_status_t end_of_input(void) +{ + rl_line_buffer[rl_end] = '\0'; + return CSeof; +} +#endif + static el_status_t transpose(void) { char c; @@ -1437,7 +1439,7 @@ static el_status_t last_argument(void) return s; } -static el_keymap_t Map[] = { +static el_keymap_t Map[33] = { { CTL('@'), mk_set }, { CTL('A'), beg_line }, { CTL('B'), bk_char }, @@ -1463,7 +1465,11 @@ static el_keymap_t Map[] = { { CTL('W'), bk_kill_word }, { CTL('X'), exchange }, { CTL('Y'), yank }, - { CTL('Z'), end_line }, +#ifdef SYSTEM_IS_WIN32 + { CTL('Z'), end_of_input }, +#else + { CTL('Z'), ring_bell }, +#endif { CTL('['), meta }, { CTL(']'), move_to_char }, { CTL('^'), ring_bell }, @@ -1471,7 +1477,7 @@ static el_keymap_t Map[] = { { 0, NULL } }; -static el_keymap_t MetaMap[]= { +static el_keymap_t MetaMap[64]= { { CTL('H'), bk_kill_word }, { DEL, bk_kill_word }, { ' ', mk_set }, @@ -1490,6 +1496,33 @@ static el_keymap_t MetaMap[]= { { 0, NULL } }; +void el_bind_key_in_metamap(char c, el_keymap_func_t func) +{ + /* Add given function to key map for META keys */ + int i; + + for (i = 0; MetaMap[i].Key != 0; i++) + { + if (MetaMap[i].Key == c) + { + MetaMap[i].Function = func; + return; + } + } + + /* A new key so have to add it to end */ + if (i == 63) + { + fprintf(stderr,"editline: MetaMap table full, requires increase\n"); + return; + } + + MetaMap[i].Function = func; + MetaMap[i].Key = c; + MetaMap[i + 1].Function = 0; /* Zero the last location */ + MetaMap[i + 1].Key = 0; /* Zero the last location */ +} + /** * Local Variables: * version-control: t From 167059d159d613e710ed40c69951a6574ef1dc95 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 25 Jul 2010 22:22:56 +0200 Subject: [PATCH 21/44] Obfuscate email address --- src/editline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editline.c b/src/editline.c index 6407f3e..c828826 100644 --- a/src/editline.c +++ b/src/editline.c @@ -1,7 +1,7 @@ /* Main editing routines for editline library. * * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved. - * Copyright (c) 1998 Alan W. Black , for Edinburgh Speech Tools. + * Copyright (c) 1998 Alan W. Black , for Edinburgh Speech Tools. * * This software is not subject to any license of the American Telephone * and Telegraph Company or of the Regents of the University of California. From 02acd55b2e233e3ecf9df9ea294d03ecb02b4313 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 26 Jul 2010 01:44:18 +0200 Subject: [PATCH 22/44] Support for capitalizing words (M-c) from Festival speech-tools by Alan W Black --- src/editline.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/editline.c b/src/editline.c index c828826..002b111 100644 --- a/src/editline.c +++ b/src/editline.c @@ -47,7 +47,7 @@ ** The type of case-changing to perform. */ typedef enum { - TOupper, TOlower + TOupper, TOlower, TOcapitalize } el_case_t; /* @@ -350,6 +350,7 @@ static el_status_t do_macro(int c) return CSstay; } +/* Skip forward to start of next word. If @move is set we also move the cursor. */ static el_status_t do_forward(el_status_t move) { int i; @@ -358,11 +359,14 @@ static el_status_t do_forward(el_status_t move) i = 0; do { p = &rl_line_buffer[rl_point]; - for ( ; rl_point < rl_end && (*p == ' ' || !isalnum(*p)); rl_point++, p++) + + /* Skip to end of word, if inside a word. */ + for (; rl_point < rl_end && isalnum(p[0]); rl_point++, p++) if (move == CSmove) right(CSstay); - for (; rl_point < rl_end && isalnum(*p); rl_point++, p++) + /* Skip to next word, or skip leading white space if outside a word. */ + for ( ; rl_point < rl_end && (p[0] == ' ' || !isalnum(p[0])); rl_point++, p++) if (move == CSmove) right(CSstay); @@ -384,20 +388,22 @@ static el_status_t do_case(el_case_t type) if (old_point != rl_point) { if ((count = rl_point - old_point) < 0) count = -count; + rl_point = old_point; if ((end = rl_point + count) > rl_end) end = rl_end; - for (i = rl_point, p = &rl_line_buffer[i]; i < end; i++, p++) { - if (type == TOupper) { + + for (i = rl_point, p = &rl_line_buffer[i]; rl_point < end; p++) { + if ((type == TOupper) || (type == TOcapitalize && rl_point == i)) { if (islower(*p)) *p = toupper(*p); - } - else if (isupper(*p)) { + } else if (isupper(*p)) { *p = tolower(*p); } right(CSmove); } } + return CSstay; } @@ -411,6 +417,11 @@ static el_status_t case_up_word(void) return do_case(TOupper); } +static el_status_t case_cap_word(void) +{ + return do_case(TOcapitalize); +} + static void ceol(void) { int extras; @@ -518,7 +529,7 @@ static el_status_t do_hist(const char *(*move)(void)) i = 0; do { - if ((p = (*move)()) == NULL) + if ((p = move()) == NULL) return ring_bell(); } while (++i < Repeat); return do_insert_hist(p); @@ -590,7 +601,7 @@ static const char *search_hist(const char *search, const char *(*move)(void)) } len = strlen(pat); - for (pos = H.Pos; (*move)() != NULL; ) + for (pos = H.Pos; move() != NULL; ) if (match(H.Lines[H.Pos], pat, len) == 0) return H.Lines[H.Pos]; H.Pos = pos; @@ -851,7 +862,7 @@ static el_status_t meta(void) return do_macro(c); for (kp = MetaMap; kp->Function; kp++) if (kp->Key == c) - return (*kp->Function)(); + return kp->Function(); return ring_bell(); } @@ -876,7 +887,7 @@ static el_status_t emacs(int c) if (kp->Key == c) break; } - s = kp->Function ? (*kp->Function)() : insert_char(c); + s = kp->Function ? kp->Function() : insert_char(c); if (!el_pushed) { /* No pushback means no repeat count; hacky, but true. */ Repeat = NO_ARG; @@ -1486,6 +1497,7 @@ static el_keymap_t MetaMap[64]= { { '>', h_last }, { '?', c_possible }, { 'b', bk_word }, + { 'c', case_cap_word }, { 'd', fd_kill_word }, { 'f', fd_word }, { 'l', case_down_word }, From bde0c0c9d642cd91d3dcebaaeec301bd0babece5 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 26 Jul 2010 02:03:31 +0200 Subject: [PATCH 23/44] Cuddle else statments, that's the way of the samurai - also minor cleanup. --- src/complete.c | 3 +-- src/editline.c | 36 ++++++++++++++++-------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/complete.c b/src/complete.c index 80fe8e7..7913082 100644 --- a/src/complete.c +++ b/src/complete.c @@ -192,8 +192,7 @@ char *el_filename_complete(char *pathname, int *match) free(new); } } - } - else { + } else { *match = 0; if (len) { /* Find largest matching substring. */ diff --git a/src/editline.c b/src/editline.c index 002b111..8c73b17 100644 --- a/src/editline.c +++ b/src/editline.c @@ -154,8 +154,7 @@ static void tty_show(char c) if (c == DEL) { tty_put('^'); tty_put('?'); - } - else if (rl_meta_chars && ISMETA(c)) { + } else if (rl_meta_chars && ISMETA(c)) { tty_put('M'); tty_put('-'); tty_put(UNMETA(c)); @@ -309,9 +308,9 @@ static void left(el_status_t Change) { tty_back(); if (rl_point) { - if (ISCTL(rl_line_buffer[rl_point - 1])) + if (ISCTL(rl_line_buffer[rl_point - 1])) { tty_back(); - else if (rl_meta_chars && ISMETA(rl_line_buffer[rl_point - 1])) { + } else if (rl_meta_chars && ISMETA(rl_line_buffer[rl_point - 1])) { tty_back(); tty_back(); } @@ -433,8 +432,7 @@ static void ceol(void) if (ISCTL(*p)) { tty_put(' '); extras++; - } - else if (rl_meta_chars && ISMETA(*p)) { + } else if (rl_meta_chars && ISMETA(*p)) { tty_put(' '); tty_put(' '); extras += 2; @@ -583,8 +581,7 @@ static const char *search_hist(const char *search, const char *(*move)(void)) if (old_search) free(old_search); old_search = strdup(search); - } - else { + } else { if (old_search == NULL || *old_search == '\0') return NULL; search = old_search; @@ -594,17 +591,18 @@ static const char *search_hist(const char *search, const char *(*move)(void)) if (*search == '^') { match = strncmp; pat = search + 1; - } - else { + } else { match = substrcmp; pat = search; } len = strlen(pat); - for (pos = H.Pos; move() != NULL; ) + pos = H.Pos; /* Save H.Pos */ + while (move()) { if (match(H.Lines[H.Pos], pat, len) == 0) return H.Lines[H.Pos]; - H.Pos = pos; + } + H.Pos = pos; /* Restore H.Pos */ return NULL; } @@ -690,8 +688,7 @@ static el_status_t delete_string(int count) if (ISCTL(*p)) { i = 2; tty_put(' '); - } - else if (rl_meta_chars && ISMETA(*p)) { + } else if (rl_meta_chars && ISMETA(*p)) { i = 3; tty_put(' '); tty_put(' '); @@ -752,8 +749,7 @@ static el_status_t kill_line(void) rl_point = Repeat; reposition(); delete_string(i - rl_point); - } - else if (Repeat > rl_point) { + } else if (Repeat > rl_point) { right(CSmove); delete_string(Repeat - rl_point - 1); } @@ -989,9 +985,9 @@ static void hist_add(char *p) if ((p = (char *)strdup((char *)p)) == NULL) return; - if (H.Size < HIST_SIZE) + if (H.Size < HIST_SIZE) { H.Lines[H.Size++] = p; - else { + } else { free(H.Lines[0]); for (i = 0; i < HIST_SIZE - 1; i++) H.Lines[i] = H.Lines[i + 1]; @@ -1414,9 +1410,9 @@ static int argify(char *line, char ***avp) } p[ac++] = c; } - } - else + } else { c++; + } } *c = '\0'; p[ac] = NULL; From f617f842932a2a832cad80179887c27d8516775c Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 26 Jul 2010 02:09:15 +0200 Subject: [PATCH 24/44] Fix display of quoted (contro) characters w/o breaking 8-bit display --- src/editline.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/editline.c b/src/editline.c index 8c73b17..15cac78 100644 --- a/src/editline.c +++ b/src/editline.c @@ -158,14 +158,10 @@ static void tty_show(char c) tty_put('M'); tty_put('-'); tty_put(UNMETA(c)); - } -#if 0 - else if (ISCTL(c)) { + } else if (ISCTL(c) && !ISMETA(c)) { tty_put('^'); tty_put(UNCTL(c)); - } -#endif - else { + } else { tty_put(c); } } From 2a9b087bbc16aab6fc55b53cf97d17da499b0e2a Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Fri, 30 Jul 2010 01:56:25 +0200 Subject: [PATCH 25/44] Update with more wish-list items, UTF-8 support is not high prio, but would be neat. --- TODO | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 4aaa106..155de1e 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,11 @@ TODO -* Port "fileman" example from BSD editline +* Port "fileman" example from BSD libedit, http://www.thrysoee.dk/editline/ * Add support for rl_bind_key(), currently one needs to "hack" the Map[] * Add support for inhibiting completion: rl_inhibit_completion * Make "char *rl_prompt" globally visible. * Add support for rl_set_prompt(). +* Add support for --enable-utf8 to configure +* Use strcmp(nl_langinfo(CODESET), "UTF-8") to look for utf8 capable terminal. +* Implement simple UTF-8 parser according to http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 From f1edf7ae524ee05ee9c6e7584b44ad541af8e3c6 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Fri, 30 Jul 2010 02:03:46 +0200 Subject: [PATCH 26/44] Replace previous commit for quoted chars with a much improved one. 1. Simplify code in reposition() 2. Add tty_push() for commonly used operation, reduce code duplication. 3. Fix left() so that it treats 8-bit chars as one when not in meta-mode. 4. Replace isalnum() with homegrown implementation that understands 8-bit and control chars. 5. Fix ceol() before introducing ANSI "kill-to-end-of-line" escape code. This actually seems to work, previously I erronesouly used an UTF-8 terminal for testing. Which of course broke the test on an ISO-8859-1 [only] terminal. --- src/editline.c | 91 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/src/editline.c b/src/editline.c index 15cac78..43bd7bc 100644 --- a/src/editline.c +++ b/src/editline.c @@ -119,6 +119,22 @@ extern int tgetent(char *, const char *); extern int tgetnum(const char *); #endif + +/* +** Misc. local helper functions. +*/ +static int is_alpha_num(unsigned char c) +{ + if (isalnum(c)) + return 1; + if (ISMETA(c)) + return 1; + if (ISCTL(c)) + return 1; + + return 0; +} + /* ** TTY input/output functions. */ @@ -129,7 +145,7 @@ static void tty_flush(void) if (ScreenCount) { if (!el_no_echo) - res = write (1, Screen, ScreenCount); + res = write(1, Screen, ScreenCount); ScreenCount = 0; } } @@ -149,18 +165,18 @@ static void tty_puts(const char *p) tty_put(*p++); } -static void tty_show(char c) +static void tty_show(unsigned char c) { if (c == DEL) { tty_put('^'); tty_put('?'); + } else if (ISCTL(c)) { + tty_put('^'); + tty_put(UNCTL(c)); } else if (rl_meta_chars && ISMETA(c)) { tty_put('M'); tty_put('-'); tty_put(UNMETA(c)); - } else if (ISCTL(c) && !ISMETA(c)) { - tty_put('^'); - tty_put(UNCTL(c)); } else { tty_put(c); } @@ -172,6 +188,12 @@ static void tty_string(char *p) tty_show(*p++); } +static void tty_push(int c) +{ + el_pushed = 1; + el_push_back = c; +} + static int tty_get(void) { char c; @@ -291,23 +313,24 @@ static void columns(int ac, char **av) static void reposition(void) { - int i; - char *p; + int i; tty_put('\r'); tty_puts(rl_prompt); - for (i = rl_point, p = rl_line_buffer; --i >= 0; p++) - tty_show(*p); + for (i = 0; i < rl_point; i++) + tty_show(rl_line_buffer[i]); } static void left(el_status_t Change) { - tty_back(); if (rl_point) { - if (ISCTL(rl_line_buffer[rl_point - 1])) { - tty_back(); - } else if (rl_meta_chars && ISMETA(rl_line_buffer[rl_point - 1])) { - tty_back(); + tty_back(); + if (ISMETA(rl_line_buffer[rl_point - 1])) { + if (rl_meta_chars) { + tty_back(); + tty_back(); + } + } else if (ISCTL(rl_line_buffer[rl_point - 1])) { tty_back(); } } @@ -318,6 +341,7 @@ static void left(el_status_t Change) static void right(el_status_t Change) { tty_show(rl_line_buffer[rl_point]); + if (Change == CSmove) rl_point++; } @@ -356,12 +380,12 @@ static el_status_t do_forward(el_status_t move) p = &rl_line_buffer[rl_point]; /* Skip to end of word, if inside a word. */ - for (; rl_point < rl_end && isalnum(p[0]); rl_point++, p++) + for (; rl_point < rl_end && is_alpha_num(p[0]); rl_point++, p++) if (move == CSmove) right(CSstay); /* Skip to next word, or skip leading white space if outside a word. */ - for ( ; rl_point < rl_end && (p[0] == ' ' || !isalnum(p[0])); rl_point++, p++) + for ( ; rl_point < rl_end && (p[0] == ' ' || !is_alpha_num(p[0])); rl_point++, p++) if (move == CSmove) right(CSstay); @@ -425,13 +449,15 @@ static void ceol(void) for (extras = 0, i = rl_point, p = &rl_line_buffer[i]; i <= rl_end; i++, p++) { tty_put(' '); - if (ISCTL(*p)) { + if (ISMETA(*p)) { + if (rl_meta_chars) { + tty_put(' '); + tty_put(' '); + extras += 2; + } + } if (ISCTL(*p)) { tty_put(' '); extras++; - } else if (rl_meta_chars && ISMETA(*p)) { - tty_put(' '); - tty_put(' '); - extras += 2; } } @@ -485,6 +511,7 @@ static el_status_t redisplay(void) tty_puts(NEWLINE); /* XXX: Use "\r\e[K" to get really neat effect on ANSI capable terminals. */ tty_puts(rl_prompt); tty_string(rl_line_buffer); + return CSmove; } @@ -509,10 +536,12 @@ static el_status_t do_insert_hist(const char *p) { if (p == NULL) return ring_bell(); + rl_point = 0; reposition(); ceol(); rl_end = 0; + return insert_string(p); } @@ -821,8 +850,7 @@ static el_status_t meta(void) #ifdef CONFIG_ANSI_ARROWS /* Also include VT-100 arrows. */ if (c == '[' || c == 'O') { - c = tty_get(); - switch (c) { + switch (tty_get()) { case EOF: return CSeof; case '2': tty_get(); return CSstay; /* Insert */ case '3': tty_get(); return del_char(); /* Delete */ @@ -845,16 +873,16 @@ static el_status_t meta(void) if (isdigit(c)) { for (Repeat = c - '0'; (c = tty_get()) != EOF && isdigit(c); ) Repeat = Repeat * 10 + c - '0'; - el_pushed = 1; - el_push_back = c; + tty_push(c); return CSstay; } if (isupper(c)) return do_macro(c); - for (kp = MetaMap; kp->Function; kp++) + for (kp = MetaMap; kp->Function; kp++) { if (kp->Key == c) return kp->Function(); + } return ring_bell(); } @@ -867,11 +895,8 @@ static el_status_t emacs(int c) /* Save point before interpreting input character 'c'. */ old_point = rl_point; - /* This test makes it impossible to enter eight-bit characters when - * meta-char mode is enabled. */ if (rl_meta_chars && ISMETA(c)) { - el_pushed = 1; - el_push_back = UNMETA(c); + tty_push(UNMETA(c)); return meta(); } @@ -890,7 +915,7 @@ static el_status_t emacs(int c) static el_status_t tty_special(int c) { - if (rl_meta_chars && ISMETA(c)) + if (rl_meta_chars && ISMETA(c)) return CSdispatch; if (c == rl_erase || c == DEL) @@ -1349,10 +1374,10 @@ static el_status_t bk_word(void) i = 0; do { - for (p = &rl_line_buffer[rl_point]; p > rl_line_buffer && !isalnum(p[-1]); p--) + for (p = &rl_line_buffer[rl_point]; p > rl_line_buffer && !is_alpha_num(p[-1]); p--) left(CSmove); - for (; p > rl_line_buffer && p[-1] != ' ' && isalnum(p[-1]); p--) + for (; p > rl_line_buffer && !isblank(p[-1]) && is_alpha_num(p[-1]); p--) left(CSmove); if (rl_point == 0) From 3fedfd444404020913a6dc6ec02b117c749fa70d Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sat, 31 Jul 2010 02:27:24 +0200 Subject: [PATCH 27/44] Update man page slightly. --- man/editline.3 | 104 +++++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/man/editline.3 b/man/editline.3 index fe5b8d3..9b71686 100644 --- a/man/editline.3 +++ b/man/editline.3 @@ -3,54 +3,43 @@ editline \- command-line editing library with history .SH SYNOPSIS .nf -.B "char *" -.B "readline(prompt)" -.B " char *prompt;" - -.B "void" -.B "add_history(line)" -.B " char *line;" +.B "char *readline(char *prompt);" .fi .SH DESCRIPTION .I Editline -is a library that provides an line-editing interface with text recall. -It is intended to be compatible with the +is a library that provides an line-editing interface with history. +It is intended to be functionally equivalent with the .I readline library provided by the Free Software Foundation, but much smaller. The bulk of this manual page describes the user interface. .PP The -.I readline -routine returns a line of text with the trailing newline removed. -The data is returned in a buffer allocated with +.I readline() +function displays the given +.I prompt +on stdout, waits for user input on stdin and then +returns a line of text with the trailing newline removed. The data is returned in a +buffer allocated with .IR malloc (3), so the space should be released with .IR free (3) when the calling program is done with it. -Before accepting input from the user, the specified -.I prompt -is displayed on the terminal. .PP Each line returned is copied to the internal history list, unless it happens -to be equal to the previous line. +to be equal to the previous line. This is configurable if you are building editline +from source. .SS "User Interface" -A program that uses this library provides a simple emacs-like editing -interface to its users. -A line may be edited before it is sent to the calling program by typing either -control characters or escape sequences. -A control character, shown as a caret followed by a letter, is typed by -holding down the ``control'' key while the letter is typed. -For example, ``^A'' is a control-A. -An escape sequence is entered by typing the ``escape'' key followed by one or -more characters. -The escape key is abbreviated as ``ESC''. -Note that unlike control keys, case matters in escape sequences; ``ESC\ F'' -is not the same as ``ESC\ f''. +A program that uses this library provides a simple emacs-like editing interface to +its users. A line may be edited before it is sent to the calling program by typing +either control characters or escape sequences. A control character, shown as a caret +followed by a letter, is typed by holding down the ``control'' key while the letter +is typed. For example, ``^A'' is a control-A. An escape sequence is entered by +typing the ``escape'' key followed by one or more characters. The escape key is +abbreviated as ``ESC''. Note that unlike control keys, case matters in escape +sequences; ``ESC\ F'' is not the same as ``ESC\ f''. .PP -An editing command may be typed anywhere on the line, not just at the -beginning. -In addition, a return may also be typed anywhere on the line, not just at -the end. +An editing command may be typed anywhere on the line, not just at the beginning. In +addition, a return may also be typed anywhere on the line, not just at the end. .PP Most editing commands may be given a repeat count, .IR n , @@ -81,8 +70,8 @@ The following control characters are accepted: ^M Done with line (alternate return key) ^N Get next line from history [n] ^P Get previous line from history [n] -^R Search backward (forward if [n]) through history for text; -\& must start line if text begins with an uparrow +^R Search backward (forward if [n]) through history for +\& text; must start line if text begins with an uparrow ^T Transpose characters ^V Insert next character, even if it is an edit command ^W Wipe to the mark @@ -109,7 +98,8 @@ ESC\ b Move backward a word [n] ESC\ d Delete word under cursor [n] ESC\ f Move forward a word [n] ESC\ l Make word lowercase [n] -ESC\ m Toggle if 8bit chars display normally or with ``M\-'' prefix +ESC\ m Toggle if 8bit chars display normally or with an +\& ``M\-'' prefix ESC\ u Make word uppercase [n] ESC\ y Yank back last killed text ESC\ v Show library version @@ -164,11 +154,41 @@ for you: .RE The tab key is shown by ``[TAB]'' and the automatically-entered text is shown in italics. -.SH "BUGS AND LIMITATIONS" -Doesn't know how to handle multiple lines. -.SH AUTHORS -Simmule R. Turner -and Rich $alz . -Original manual page by DaviD W. Sanderson . -.\" $PchId: editline.3,v 1.3 1996/02/22 21:18:51 philip Exp $ +.SH "USAGE" +To include +.I readline() +in your program, simply call it as you do any other function. Just make sure to link +your program with libeditline. + +.SS "Example" +The following brief example lets you enter a line and edit it, then displays it. + +.nf +.B "#include " +.B "" +.B "extern char *readline(char *prompt);" +.B "" +.B "int main (void)" +.B "{" +.B " char *p;" +.B "" +.B " while ((p = readline(``CLI> '')) != NULL) {" +.B " printf(\"%s\n\", p);" +.B " free(p);" +.B " }" +.B "" +.B " return 0;" +.B "}" +.fi + +.SH "BUGS AND LIMITATIONS" +Doesn't know how to handle multiple lines or unicode characters well. See the TODO +file in the distribution if you want to help out. + +.SH AUTHORS +The original editline library was created by Simmule R. Turner and Rich $alz. It is +now maintained in several forks: Heimdal, Festival speech tools, Mozilla, Google +Gadgets for Linux, and many other places. The original manual page was made by DaviD +W. Sanderson. This version was made by Joachim Nilsson . + From b48de203e7486c64249971486012bde9295298c4 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 2 Aug 2010 16:02:59 +0200 Subject: [PATCH 28/44] Always build complete.c now that we have changed completion handling. After the revert of function pointers for rl_complete() and rl_list_possib(), introduced in v0.2.2, we need to build complete.c for all configurations. The user should use the rl_set_*_func() calls merged from the Heimdal project's readline fork. --- src/Makefile.am | 6 +----- src/Makefile.in | 12 +++--------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 4493edb..47cb2fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,3 @@ AUTOMAKE_OPTIONS = foreign lib_LTLIBRARIES = libeditline.la -libeditline_la_SOURCES = editline.c editline.h sysunix.c unix.h -if CONFIG_DEFAULT_COMPLETE -# Built-in completion handler. -libeditline_la_SOURCES += complete.c -endif +libeditline_la_SOURCES = editline.c editline.h complete.c sysunix.c unix.h diff --git a/src/Makefile.in b/src/Makefile.in index ee5f05a..2036e8d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -34,8 +34,6 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -# Built-in completion handler. -@CONFIG_DEFAULT_COMPLETE_TRUE@am__append_1 = complete.c subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -73,10 +71,7 @@ am__base_list = \ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libeditline_la_LIBADD = -am__libeditline_la_SOURCES_DIST = editline.c editline.h sysunix.c \ - unix.h complete.c -@CONFIG_DEFAULT_COMPLETE_TRUE@am__objects_1 = complete.lo -am_libeditline_la_OBJECTS = editline.lo sysunix.lo $(am__objects_1) +am_libeditline_la_OBJECTS = editline.lo complete.lo sysunix.lo libeditline_la_OBJECTS = $(am_libeditline_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) @@ -108,7 +103,7 @@ AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libeditline_la_SOURCES) -DIST_SOURCES = $(am__libeditline_la_SOURCES_DIST) +DIST_SOURCES = $(libeditline_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -228,8 +223,7 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign lib_LTLIBRARIES = libeditline.la -libeditline_la_SOURCES = editline.c editline.h sysunix.c unix.h \ - $(am__append_1) +libeditline_la_SOURCES = editline.c editline.h complete.c sysunix.c unix.h all: all-am .SUFFIXES: From 80ca9e18110458314263624f658c275b60575fb1 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 3 Aug 2010 00:14:48 +0200 Subject: [PATCH 29/44] Restore previously discarded (and incomplete) OS9 backend files. --- Make.os9 | 19 +++++++++++++++++++ src/os9.h | 10 ++++++++++ src/sysos9.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 Make.os9 create mode 100644 src/os9.h create mode 100644 src/sysos9.c diff --git a/Make.os9 b/Make.os9 new file mode 100644 index 0000000..c632847 --- /dev/null +++ b/Make.os9 @@ -0,0 +1,19 @@ +## $Revision: 1.2 $ +## +## OS-9 makefile for editline library. +## + +.SUFFIXES: + +RFILES = editline.r complete.r sysos9.r + +%.r: %.c + cc68 -r -Dstrchr=index -Dstrrchr=rindex -DNEED_STRDUP -DSYS_OS9 $*.c + +testit: testit.r editline.lib + cc68 -f=testit testit.r -l=editline.lib + +$(RFILES): $(RFILES:%.r=%.c) + +editline.lib: $(RFILES) + cat $(RFILES) >$@ diff --git a/src/os9.h b/src/os9.h new file mode 100644 index 0000000..7bb7cf3 --- /dev/null +++ b/src/os9.h @@ -0,0 +1,10 @@ +/* $Revision: 1.1 $ +** +** Editline system header file for OS-9 (on 68k). +*/ + +#define CRLF "\r\l" +#define FORWARD extern + +#include +typedef struct direct DIRENTRY; diff --git a/src/sysos9.c b/src/sysos9.c new file mode 100644 index 0000000..fd23aa4 --- /dev/null +++ b/src/sysos9.c @@ -0,0 +1,46 @@ +/* $Revision: 1.1 $ +** +** OS-9 system-dependant routines for editline library. +*/ +#include "editline.h" +#include +#include + + +void +rl_ttyset(Reset) + int Reset; +{ + static struct sgbuf old; + struct sgbuf new; + + + if (Reset == 0) { + _gs_opt(0, &old); + _gs_opt(0, &new); + new.sg_backsp = 0; new.sg_delete = 0; new.sg_echo = 0; + new.sg_alf = 0; new.sg_nulls = 0; new.sg_pause = 0; + new.sg_page = 0; new.sg_bspch = 0; new.sg_dlnch = 0; + new.sg_eorch = 0; new.sg_eofch = 0; new.sg_rlnch = 0; + new.sg_dulnch = 0; new.sg_psch = 0; new.sg_kbich = 0; + new.sg_kbach = 0; new.sg_bsech = 0; new.sg_bellch = 0; + new.sg_xon = 0; new.sg_xoff = 0; new.sg_tabcr = 0; + new.sg_tabsiz = 0; + _ss_opt(0, &new); + rl_erase = old.sg_bspch; + rl_kill = old.sg_dlnch; + rl_eof = old.sg_eofch; + rl_intr = old.sg_kbich; + rl_quit = -1; + } + else + _ss_opt(0, &old); +} + +void +rl_add_slash(path, p) + char *path; + char *p; +{ + (void)strcat(p, access(path, S_IREAD | S_IFDIR) ? " " : "/"); +} From 76ec5adba69549b00976065b02b0481cdba098e8 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 3 Aug 2010 00:26:06 +0200 Subject: [PATCH 30/44] ANSI-fication and minor cleanup of old OS-9 files. --- src/os9.h | 25 ++++++++++++++++++++----- src/sysos9.c | 49 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/os9.h b/src/os9.h index 7bb7cf3..826e0e2 100644 --- a/src/os9.h +++ b/src/os9.h @@ -1,10 +1,25 @@ -/* $Revision: 1.1 $ -** -** Editline system header file for OS-9 (on 68k). -*/ +/* Editline system header file for OS-9 (on 68k). + * + * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ #define CRLF "\r\l" -#define FORWARD extern #include typedef struct direct DIRENTRY; diff --git a/src/sysos9.c b/src/sysos9.c index fd23aa4..b69ed07 100644 --- a/src/sysos9.c +++ b/src/sysos9.c @@ -1,20 +1,32 @@ -/* $Revision: 1.1 $ -** -** OS-9 system-dependant routines for editline library. -*/ +/* OS-9 (on 68k) system-dependant routines for editline library. + * + * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ #include "editline.h" #include #include - -void -rl_ttyset(Reset) - int Reset; +void rl_ttyset(int Reset) { static struct sgbuf old; struct sgbuf new; - if (Reset == 0) { _gs_opt(0, &old); _gs_opt(0, &new); @@ -33,14 +45,21 @@ rl_ttyset(Reset) rl_intr = old.sg_kbich; rl_quit = -1; } - else + else { _ss_opt(0, &old); + } } -void -rl_add_slash(path, p) - char *path; - char *p; +void rl_add_slash(char *path, char *p) { - (void)strcat(p, access(path, S_IREAD | S_IFDIR) ? " " : "/"); + strcat(p, access(path, S_IREAD | S_IFDIR) ? " " : "/"); } + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "ellemtel" + * c-basic-offset: 4 + * End: + */ From 55aaddbc5453f5410c9bd0fe1094e5f7eaf7759e Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 3 Aug 2010 21:01:01 +0200 Subject: [PATCH 31/44] Restore add_history(), for compat and simplify code. --- include/editline.h | 2 +- src/editline.c | 41 +++++++++++++++++++---------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/include/editline.h b/include/editline.h index 8691a11..b0d7969 100644 --- a/include/editline.h +++ b/include/editline.h @@ -52,6 +52,6 @@ extern void rl_reset_terminal(char *p); extern void rl_initialize(void); extern char *readline(const char *prompt); -extern void add_history(char *line); /* OBSOLETE: Made part of readline(). -- kjb */ +extern void add_history(const char *line); #endif /* __EDITLINE_H__ */ diff --git a/src/editline.c b/src/editline.c index 43bd7bc..41054b4 100644 --- a/src/editline.c +++ b/src/editline.c @@ -1000,19 +1000,27 @@ static char *editinput(void) return NULL; } -static void hist_add(char *p) +static void hist_add(const char *p) { int i; + char *s; - if ((p = (char *)strdup((char *)p)) == NULL) +#ifdef CONFIG_UNIQUE_HISTORY + if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0) + return; +#endif + if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0) + return; + + if ((s = strdup(p)) == NULL) return; if (H.Size < HIST_SIZE) { - H.Lines[H.Size++] = p; + H.Lines[H.Size++] = s; } else { free(H.Lines[0]); for (i = 0; i < HIST_SIZE - 1; i++) H.Lines[i] = H.Lines[i + 1]; - H.Lines[i] = p; + H.Lines[i] = s; } H.Pos = H.Size - 1; } @@ -1068,7 +1076,7 @@ void rl_initialize(void) char *readline(const char *prompt) { - char *line; + char *line; /* Unless called by the user already. */ rl_initialize(); @@ -1115,14 +1123,9 @@ char *readline(const char *prompt) free(Screen); free(H.Lines[--H.Size]); - if (line != NULL && *line != '\0' -#ifdef CONFIG_UNIQUE_HISTORY - && !(H.Pos && strcmp(line, H.Lines[H.Pos - 1]) == 0) -#endif - && !(H.Size && strcmp(line, H.Lines[H.Size - 1]) == 0) - ) { + /* Always add history, if it's a sane line. */ + if (line != NULL && *line != '\0') hist_add(line); - } if (el_intr_pending > 0) { int s = el_intr_pending; @@ -1133,20 +1136,14 @@ char *readline(const char *prompt) return line; } -void add_history(char *p __attribute__ ((unused))) +/* Even though readline() itself adds history automatically, the user can also add + * lines. This is for compat with GNU Readline. */ +void add_history(const char *p) { -#ifdef obsolete /* Made part of readline(). -- kjb */ if (p == NULL || *p == '\0') return; -#ifdef CONFIG_UNIQUE_HISTORY - if (H.Pos && strcmp(p, (char *) H.Lines[H.Pos - 1]) == 0) - return; -#endif - if (H.Size && strcmp(p, (char *) H.Lines[H.Size - 1]) == 0) - return; - hist_add((char *)p); -#endif + hist_add(p); } From 04a0cbd902b9db96208808e7622b21dcdb6f7d56 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 4 Aug 2010 02:12:19 +0200 Subject: [PATCH 32/44] Allocate history scrollback buffer at runtime instead of at configure. Also make sure "unique history" is enabled by default in configure. --- config.h.in | 5 +---- configure | 42 ++++++++++++++---------------------------- configure.ac | 19 +++++-------------- include/editline.h | 6 ++++-- src/editline.c | 25 ++++++++++++++++++------- 5 files changed, 42 insertions(+), 55 deletions(-) diff --git a/config.h.in b/config.h.in index 5e4085b..834ba6f 100644 --- a/config.h.in +++ b/config.h.in @@ -18,7 +18,7 @@ /* Define to enable SIGSTOP (Ctrl-Z) key. */ #undef CONFIG_SIGSTOP -/* Don't save command if same as last one. */ +/* Define to skip duplicate lines in the scrollback history. */ #undef CONFIG_UNIQUE_HISTORY /* Define to use the termcap library for terminal size. */ @@ -115,9 +115,6 @@ /* Enable static keyword, hides internal methods. */ #undef HIDE -/* Number of lines in history. */ -#undef HIST_SIZE - /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK diff --git a/configure b/configure index 7448e97..5563ad8 100755 --- a/configure +++ b/configure @@ -869,13 +869,12 @@ with_pic enable_fast_install with_gnu_ld enable_libtool_lock +enable_unique_history enable_default_complete enable_arrow_keys enable_sigstop enable_terminal_bell enable_termcap -enable_history -enable_unique_history ' ac_precious_vars='build_alias host_alias @@ -1514,13 +1513,14 @@ Optional Features: --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) + --disable-unique-history + Disable uniqify of scrollback. Default: duplicate + entries are ignored. Use this to save dupes. --enable-default-complete Enable default completion handler. --enable-arrow-keys Enable ANSI arrow keys. --enable-sigstop Enable SIGSTOP key. --enable-terminal-bell Enable terminal bell on completion. --enable-termcap Use the termcap library for terminal size. - --enable-history=LINES Enable scrollback history, default off. - --enable-unique-history Uniqify scrollback history, i.e., don't save dupes. Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -11130,6 +11130,16 @@ fi done +# Check whether --enable-unique-history was given. +if test "${enable_unique_history+set}" = set; then : + enableval=$enable_unique_history; +else + +$as_echo "#define CONFIG_UNIQUE_HISTORY 1" >>confdefs.h + +fi + + # Check whether --enable-default-complete was given. if test "${enable_default_complete+set}" = set; then : enableval=$enable_default_complete; complete=true; @@ -11178,30 +11188,6 @@ $as_echo "#define CONFIG_USE_TERMCAP /**/" >>confdefs.h fi -# Default history size 1, i.e. disabled. -let HIST_SIZE=1 -# Check whether --enable-history was given. -if test "${enable_history+set}" = set; then : - enableval=$enable_history; let HIST_SIZE=$enableval -fi - -if test $HIST_SIZE -lt 1; then - let HIST_SIZE=1 -fi - -cat >>confdefs.h <<_ACEOF -#define HIST_SIZE $HIST_SIZE -_ACEOF - - -# Check whether --enable-unique-history was given. -if test "${enable_unique_history+set}" = set; then : - enableval=$enable_unique_history; -$as_echo "#define CONFIG_UNIQUE_HISTORY /**/" >>confdefs.h - -fi - - # Restore gnu89 inline semantics on gcc 4.3 and newer saved_cflags="$CFLAGS" CFLAGS="$CFLAGS -fgnu89-inline" diff --git a/configure.ac b/configure.ac index 4b155cc..6905385 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,11 @@ AC_PROG_GCC_TRADITIONAL AC_FUNC_STAT AC_CHECK_FUNCS([strchr strdup strrchr tcgetattr perror]) +AC_ARG_ENABLE(unique-history, + [AS_HELP_STRING([--disable-unique-history], + [Disable uniqify of scrollback. Default: duplicate entries are ignored. Use this to save dupes.])], + , AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.])) + AC_ARG_ENABLE(default-complete, [ --enable-default-complete Enable default completion handler.], complete=true; AC_DEFINE(CONFIG_DEFAULT_COMPLETE,, [Define to enable the default completion handler.])) @@ -73,20 +78,6 @@ AC_ARG_ENABLE(termcap, [ --enable-termcap Use the termcap library for terminal size.], AC_DEFINE([CONFIG_USE_TERMCAP],, [Define to use the termcap library for terminal size.])) -# Default history size 1, i.e. disabled. -let HIST_SIZE=1 -AC_ARG_ENABLE(history, - [ --enable-history=LINES Enable scrollback history, default off.], - let HIST_SIZE=$enableval) -if test $HIST_SIZE -lt 1; then - let HIST_SIZE=1 -fi -AC_DEFINE_UNQUOTED(HIST_SIZE, $HIST_SIZE, [Number of lines in history.]) - -AC_ARG_ENABLE(unique-history, - [ --enable-unique-history Uniqify scrollback history, i.e., don't save dupes.], - AC_DEFINE([CONFIG_UNIQUE_HISTORY],, [Don't save command if same as last one.])) - # Restore gnu89 inline semantics on gcc 4.3 and newer saved_cflags="$CFLAGS" CFLAGS="$CFLAGS -fgnu89-inline" diff --git a/include/editline.h b/include/editline.h index b0d7969..a27d7b5 100644 --- a/include/editline.h +++ b/include/editline.h @@ -47,9 +47,11 @@ extern int rl_mark; extern int rl_end; extern char *rl_line_buffer; extern const char *rl_readline_name; -extern int el_no_echo; /* e.g under emacs, don't echo except prompt */ -extern void rl_reset_terminal(char *p); +extern int el_no_echo; /* e.g under emacs, don't echo except prompt */ +extern int el_hist_size; /* size of history scrollback buffer, default: 15 */ + extern void rl_initialize(void); +extern void rl_reset_terminal(char *p); extern char *readline(const char *prompt); extern void add_history(const char *line); diff --git a/src/editline.c b/src/editline.c index 41054b4..9304c00 100644 --- a/src/editline.c +++ b/src/editline.c @@ -38,9 +38,6 @@ #define META(x) ((x) | 0x80) #define ISMETA(x) ((x) & 0x80) #define UNMETA(x) ((x) & 0x7F) -#ifndef HIST_SIZE /* Default to one line history, i.e. disabled. */ -#define HIST_SIZE 1 -#endif #define SEPS "\"#$&'()*:;<=>?[\\]^`{|}~\n\t " /* @@ -64,7 +61,7 @@ typedef struct { typedef struct { int Size; int Pos; - char *Lines[HIST_SIZE]; + char **Lines; } el_hist_t; /* @@ -79,12 +76,18 @@ int rl_quit; int rl_susp; #endif +int el_hist_size = 15; +static el_hist_t H = { + .Size = 0, + .Pos = 0, + .Lines = NULL, +}; + static char NILSTR[] = ""; static const char *el_input = NILSTR; static char *Yanked; static char *Screen; static char NEWLINE[]= CRLF; -static el_hist_t H; static int Repeat; static int old_point; static int el_push_back; @@ -1000,6 +1003,12 @@ static char *editinput(void) return NULL; } +static void hist_alloc(void) +{ + if (!H.Lines) + H.Lines = calloc(el_hist_size, sizeof(char *)); +} + static void hist_add(const char *p) { int i; @@ -1014,11 +1023,11 @@ static void hist_add(const char *p) if ((s = strdup(p)) == NULL) return; - if (H.Size < HIST_SIZE) { + if (H.Size < el_hist_size) { H.Lines[H.Size++] = s; } else { free(H.Lines[0]); - for (i = 0; i < HIST_SIZE - 1; i++) + for (i = 0; i < el_hist_size - 1; i++) H.Lines[i] = H.Lines[i + 1]; H.Lines[i] = s; } @@ -1072,6 +1081,8 @@ void rl_initialize(void) { if (!rl_prompt) rl_prompt = "? "; + + hist_alloc(); } char *readline(const char *prompt) From aea0d604783486e9b5b423e919ab66fd532ae55a Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 4 Aug 2010 02:18:44 +0200 Subject: [PATCH 33/44] Remove copyright, not big enough contribution - also, was not even in patch from Mr. Black. --- src/editline.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/editline.c b/src/editline.c index 9304c00..266b267 100644 --- a/src/editline.c +++ b/src/editline.c @@ -1,7 +1,6 @@ /* Main editing routines for editline library. * * Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved. - * Copyright (c) 1998 Alan W. Black , for Edinburgh Speech Tools. * * This software is not subject to any license of the American Telephone * and Telegraph Company or of the Regents of the University of California. From d04bdaf38f799e64ca0c1ba85fff604060ee48a9 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 4 Aug 2010 02:23:05 +0200 Subject: [PATCH 34/44] Add support for read_history(char *filename) and write_history(char *filename) --- examples/cli.c | 5 +++++ include/editline.h | 3 +++ src/editline.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/examples/cli.c b/examples/cli.c index c1aa002..3b4673d 100644 --- a/examples/cli.c +++ b/examples/cli.c @@ -22,6 +22,8 @@ #include "editline.h" #include +#define HISTORY "/tmp/.cli-history" + static char *list[] = { "foo ", "bar ", "bsd ", "cli ", "ls ", "cd ", "malloc ", "tee ", NULL }; @@ -86,11 +88,14 @@ int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused))) /* Setup callbacks */ rl_set_complete_func(&my_rl_complete); rl_set_list_possib_func(&my_rl_list_possib); + read_history(HISTORY); while ((line = readline(prompt)) != NULL) { printf("\t\t\t|%s|\n", line); free(line); } + write_history(HISTORY); + return 0; } diff --git a/include/editline.h b/include/editline.h index a27d7b5..f85bd99 100644 --- a/include/editline.h +++ b/include/editline.h @@ -56,4 +56,7 @@ extern void rl_reset_terminal(char *p); extern char *readline(const char *prompt); extern void add_history(const char *line); +extern int read_history(const char *filename); +extern int write_history(const char *filename); + #endif /* __EDITLINE_H__ */ diff --git a/src/editline.c b/src/editline.c index 266b267..f95a2b6 100644 --- a/src/editline.c +++ b/src/editline.c @@ -1155,6 +1155,50 @@ void add_history(const char *p) hist_add(p); } + + +int read_history(const char *filename) +{ + FILE *fp; + char buf[SCREEN_INC]; + + hist_alloc(); + fp = fopen(filename, "r"); + if (fp) { + H.Size = 0; + while (H.Size < el_hist_size) { + if (!fgets(buf, SCREEN_INC, fp)) + break; + buf[strlen(buf) - 1] = 0; /* Remove '\n' */ + add_history(buf); + } + fclose(fp); + + return 0; + } + + return errno; +} + +int write_history(const char *filename) +{ + FILE *fp; + + hist_alloc(); + fp = fopen(filename, "w"); + if (fp) { + int i = 0; + + while (i < H.Size) { + fprintf(fp, "%s\n", H.Lines[i++]); + } + fclose(fp); + + return 0; + } + + return errno; +} /* From ff404e2088490be1ec05a5c614a9b17f1d11d0de Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 4 Aug 2010 02:39:57 +0200 Subject: [PATCH 35/44] Move to use AS_HELP_STRING() and make default-complete enabled by default. --- configure | 69 +++++++++++++++++++++++----------------------------- configure.ac | 21 ++++++++-------- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/configure b/configure index 5563ad8..eb502b3 100755 --- a/configure +++ b/configure @@ -748,8 +748,6 @@ am__EXEEXT_TRUE LTLIBOBJS TERMLIBS AM_CFLAGS -CONFIG_DEFAULT_COMPLETE_FALSE -CONFIG_DEFAULT_COMPLETE_TRUE LIBOBJS CPP OTOOL64 @@ -1516,11 +1514,12 @@ Optional Features: --disable-unique-history Disable uniqify of scrollback. Default: duplicate entries are ignored. Use this to save dupes. - --enable-default-complete Enable default completion handler. - --enable-arrow-keys Enable ANSI arrow keys. - --enable-sigstop Enable SIGSTOP key. - --enable-terminal-bell Enable terminal bell on completion. - --enable-termcap Use the termcap library for terminal size. + --disable-default-complete + Disable default (filename) completion handler. + --disable-arrow-keys Disable ANSI arrow keys. + --enable-sigstop Enable SIGSTOP key. + --enable-terminal-bell Enable terminal bell on completion. + --enable-termcap Use termcap library to query terminal size. Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -4562,13 +4561,13 @@ if test "${lt_cv_nm_interface+set}" = set; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:4565: $ac_compile\"" >&5) + (eval echo "\"\$as_me:4564: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:4568: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:4567: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:4571: output\"" >&5) + (eval echo "\"\$as_me:4570: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -5774,7 +5773,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5777 "configure"' > conftest.$ac_ext + echo '#line 5776 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7304,11 +7303,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7307: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7306: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7311: \$? = $ac_status" >&5 + echo "$as_me:7310: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7643,11 +7642,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7646: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7645: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7650: \$? = $ac_status" >&5 + echo "$as_me:7649: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7748,11 +7747,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7751: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7750: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7755: \$? = $ac_status" >&5 + echo "$as_me:7754: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7803,11 +7802,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7806: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7805: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7810: \$? = $ac_status" >&5 + echo "$as_me:7809: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -10187,7 +10186,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10190 "configure" +#line 10189 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10283,7 +10282,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10286 "configure" +#line 10285 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11142,24 +11141,20 @@ fi # Check whether --enable-default-complete was given. if test "${enable_default_complete+set}" = set; then : - enableval=$enable_default_complete; complete=true; -$as_echo "#define CONFIG_DEFAULT_COMPLETE /**/" >>confdefs.h - -fi - - if test x$complete = xtrue; then - CONFIG_DEFAULT_COMPLETE_TRUE= - CONFIG_DEFAULT_COMPLETE_FALSE='#' + enableval=$enable_default_complete; else - CONFIG_DEFAULT_COMPLETE_TRUE='#' - CONFIG_DEFAULT_COMPLETE_FALSE= + +$as_echo "#define CONFIG_DEFAULT_COMPLETE 1" >>confdefs.h + fi # Check whether --enable-arrow-keys was given. if test "${enable_arrow_keys+set}" = set; then : enableval=$enable_arrow_keys; -$as_echo "#define CONFIG_ANSI_ARROWS /**/" >>confdefs.h +else + +$as_echo "#define CONFIG_ANSI_ARROWS 1" >>confdefs.h fi @@ -11167,7 +11162,7 @@ fi # Check whether --enable-sigstop was given. if test "${enable_sigstop+set}" = set; then : enableval=$enable_sigstop; -$as_echo "#define CONFIG_SIGSTOP /**/" >>confdefs.h +$as_echo "#define CONFIG_SIGSTOP 1" >>confdefs.h fi @@ -11175,7 +11170,7 @@ fi # Check whether --enable-terminal-bell was given. if test "${enable_terminal_bell+set}" = set; then : enableval=$enable_terminal_bell; -$as_echo "#define CONFIG_ANNOYING_NOISE /**/" >>confdefs.h +$as_echo "#define CONFIG_ANNOYING_NOISE 1" >>confdefs.h fi @@ -11183,7 +11178,7 @@ fi # Check whether --enable-termcap was given. if test "${enable_termcap+set}" = set; then : enableval=$enable_termcap; -$as_echo "#define CONFIG_USE_TERMCAP /**/" >>confdefs.h +$as_echo "#define CONFIG_USE_TERMCAP 1" >>confdefs.h fi @@ -11520,10 +11515,6 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${CONFIG_DEFAULT_COMPLETE_TRUE}" && test -z "${CONFIG_DEFAULT_COMPLETE_FALSE}"; then - as_fn_error "conditional \"CONFIG_DEFAULT_COMPLETE\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi : ${CONFIG_STATUS=./config.status} ac_write_fail=0 diff --git a/configure.ac b/configure.ac index 6905385..60c1fdc 100644 --- a/configure.ac +++ b/configure.ac @@ -58,25 +58,24 @@ AC_ARG_ENABLE(unique-history, , AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.])) AC_ARG_ENABLE(default-complete, - [ --enable-default-complete Enable default completion handler.], - complete=true; AC_DEFINE(CONFIG_DEFAULT_COMPLETE,, [Define to enable the default completion handler.])) -AM_CONDITIONAL([CONFIG_DEFAULT_COMPLETE], [test x$complete = xtrue]) + [AS_HELP_STRING([--disable-default-complete], [Disable default (filename) completion handler.])], + , AC_DEFINE(CONFIG_DEFAULT_COMPLETE, 1, [Define to enable the default completion handler.])) AC_ARG_ENABLE(arrow-keys, - [ --enable-arrow-keys Enable ANSI arrow keys.], - AC_DEFINE([CONFIG_ANSI_ARROWS],, [Define to include ANSI arrow keys support.])) + [AS_HELP_STRING([--disable-arrow-keys], [Disable ANSI arrow keys.])], + , AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.])) AC_ARG_ENABLE(sigstop, - [ --enable-sigstop Enable SIGSTOP key.], - AC_DEFINE([CONFIG_SIGSTOP],, [Define to enable SIGSTOP (Ctrl-Z) key.])) + [AS_HELP_STRING([--enable-sigstop], [Enable SIGSTOP key.])], + AC_DEFINE([CONFIG_SIGSTOP], 1, [Define to enable SIGSTOP (Ctrl-Z) key.])) AC_ARG_ENABLE(terminal-bell, - [ --enable-terminal-bell Enable terminal bell on completion.], - AC_DEFINE([CONFIG_ANNOYING_NOISE],, [Define to enable terminal bell on completion.])) + [AS_HELP_STRING([--enable-terminal-bell], [Enable terminal bell on completion.])], + AC_DEFINE([CONFIG_ANNOYING_NOISE], 1, [Define to enable terminal bell on completion.])) AC_ARG_ENABLE(termcap, - [ --enable-termcap Use the termcap library for terminal size.], - AC_DEFINE([CONFIG_USE_TERMCAP],, [Define to use the termcap library for terminal size.])) + [AS_HELP_STRING([--enable-termcap], [Use termcap library to query terminal size.])], + AC_DEFINE([CONFIG_USE_TERMCAP], 1, [Define to use the termcap library for terminal size.])) # Restore gnu89 inline semantics on gcc 4.3 and newer saved_cflags="$CFLAGS" From bdf5384c5bbaeb00ba33f32639b42d5691c671c6 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 4 Aug 2010 02:44:20 +0200 Subject: [PATCH 36/44] Build examples (tests) as static, for easy debugging. --- examples/Makefile.am | 2 +- examples/Makefile.in | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index f64a1d3..2b5d47a 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -3,4 +3,4 @@ AUTOMAKE_OPTIONS = foreign noinst_PROGRAMS = testit cli LDADD = $(top_builddir)/src/libeditline.la $(TERMLIBS) AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include - +AM_LDFLAGS = -static diff --git a/examples/Makefile.in b/examples/Makefile.in index 94be494..efdb2a9 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -210,6 +210,7 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign LDADD = $(top_builddir)/src/libeditline.la $(TERMLIBS) +AM_LDFLAGS = -static all: all-am .SUFFIXES: From 6a8ecd7e2e690f6c6f054092e443f59d5e67e9a4 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 4 Aug 2010 03:08:38 +0200 Subject: [PATCH 37/44] Remove unused constant 'HIDE' --- config.h.in | 3 --- configure | 3 --- configure.ac | 1 - 3 files changed, 7 deletions(-) diff --git a/config.h.in b/config.h.in index 834ba6f..9f67c31 100644 --- a/config.h.in +++ b/config.h.in @@ -112,9 +112,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* Enable static keyword, hides internal methods. */ -#undef HIDE - /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK diff --git a/configure b/configure index eb502b3..7ed4a1d 100755 --- a/configure +++ b/configure @@ -10907,9 +10907,6 @@ fi $as_echo "#define SYS_UNIX 1" >>confdefs.h - -$as_echo "#define HIDE 1" >>confdefs.h - ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = x""yes; then : diff --git a/configure.ac b/configure.ac index 60c1fdc..af6feec 100644 --- a/configure.ac +++ b/configure.ac @@ -43,7 +43,6 @@ AC_HEADER_TIOCGWINSZ # Overrides and types, should be a check. AC_DEFINE([SYS_UNIX], [1], [Default to UNIX backend, should be detected.]) -AC_DEFINE([HIDE], [1], [Enable static keyword, hides internal methods.]) AC_TYPE_SIZE_T # Checks for library functions. From 0a75b182b1ce78d29495d55034f88b5cae7ca3b2 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 5 Aug 2010 01:08:30 +0200 Subject: [PATCH 38/44] Improve GNU readline compat, patch by Steve Tell in 1997 and 1998 This changeset adds support for: * rl_prep_terminal(), * rl_deprep_terminal(), both of which are only wrappers to rl_ttyset(). * rl_getc() and: * (*rl_getc_function), defaults to rl_getc() * (*rl_event_hook) * (*rl_prep_term_function), defaults to rl_prep_terminal() * (*rl_deprep_term_function), defaults to rl_deprep_terminal() For further details, see http://www.cs.unc.edu/~tell/dist/magic-readline.README Differences from Steve's commit include: signal safety in rl_getc(), restart read() on EINTR, and make sure to support "int meta_flag" to rl_prep_terminal() which is the GNU syntax. To that end I reused the inverse of rl_meta_chars. --- include/editline.h | 16 ++++++++++++---- src/editline.c | 45 +++++++++++++++++++++++++++++++++++---------- src/sysunix.c | 20 +++++++++++++++----- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/include/editline.h b/include/editline.h index f85bd99..4cd9d04 100644 --- a/include/editline.h +++ b/include/editline.h @@ -30,14 +30,14 @@ typedef enum { typedef char* (*rl_complete_func_t)(char*, int*); typedef int (*rl_list_possib_func_t)(char*, char***); typedef el_status_t (*el_keymap_func_t)(void); +typedef int (*rl_hook_func_t) (void); +typedef int (*rl_getc_func_t)(void); +typedef void (*rl_voidfunc_t)(void); +typedef void (*rl_vintfunc_t)(int); /* Display 8-bit chars "as-is" or as `M-x'? Toggle with M-m. (Default:0 - "as-is") */ extern int rl_meta_chars; -/* Use these functions to set custom command/file completion, see cli.c for example usage. */ -rl_complete_func_t rl_set_complete_func(rl_complete_func_t func); -rl_list_possib_func_t rl_set_list_possib_func(rl_list_possib_func_t func); - /* Editline specific functions. */ void el_bind_key_in_metamap(char c, el_keymap_func_t func); @@ -59,4 +59,12 @@ extern void add_history(const char *line); extern int read_history(const char *filename); extern int write_history(const char *filename); +rl_complete_func_t rl_set_complete_func(rl_complete_func_t func); +rl_list_possib_func_t rl_set_list_possib_func(rl_list_possib_func_t func); + +void rl_prep_terminal(int meta_flag); +void rl_deprep_terminal(void); + +int rl_getc(void); + #endif /* __EDITLINE_H__ */ diff --git a/src/editline.c b/src/editline.c index f95a2b6..17dc553 100644 --- a/src/editline.c +++ b/src/editline.c @@ -63,6 +63,11 @@ typedef struct { char **Lines; } el_hist_t; +rl_getc_func_t rl_getc_function = rl_getc; +rl_hook_func_t rl_event_hook; +rl_vintfunc_t rl_prep_term_function = rl_prep_terminal; +rl_voidfunc_t rl_deprep_term_function = rl_deprep_terminal; + /* ** Globals. */ @@ -109,6 +114,7 @@ int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0 char *rl_line_buffer; const char *rl_prompt; const char *rl_readline_name;/* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ +FILE *rl_instream; /* User definable callbacks. */ char **(*rl_attempted_completion_function)(const char *token, int start, int end); @@ -196,11 +202,20 @@ static void tty_push(int c) el_push_back = c; } +int rl_getc(void) +{ + int r; + char c; + + do { + r = read(0, &c, 1); + } while (r == -1 && errno == EINTR); + + return r == 1 ? c : EOF; +} + static int tty_get(void) { - char c; - int r; - tty_flush(); if (el_pushed) { el_pushed = 0; @@ -208,12 +223,8 @@ static int tty_get(void) } if (*el_input) return *el_input++; - do - { - r = read(0, &c, 1); - } while (r == -1 && errno == EINTR); - return r == 1 ? c : EOF; + return rl_getc_function(); } #define tty_back() (backspace ? tty_puts(backspace) : tty_put('\b')) @@ -280,6 +291,20 @@ static void tty_info(void) } +/* +** Glue routines to rl_ttyset() +*/ +void rl_prep_terminal(int meta_flag) +{ + rl_meta_chars = !meta_flag; + rl_ttyset(0); +} + +void rl_deprep_terminal(void) +{ + rl_ttyset(1); +} + /* ** Print an array of words in columns. */ @@ -1104,7 +1129,7 @@ char *readline(const char *prompt) } tty_info(); - rl_ttyset(0); + rl_prep_term_function(!rl_meta_chars); hist_add(NILSTR); ScreenSize = SCREEN_INC; Screen = malloc(sizeof(char) * ScreenSize); @@ -1129,7 +1154,7 @@ char *readline(const char *prompt) tty_flush(); } - rl_ttyset(1); + rl_deprep_term_function(); free(Screen); free(H.Lines[--H.Size]); diff --git a/src/sysunix.c b/src/sysunix.c index 4827f33..7d38eb7 100644 --- a/src/sysunix.c +++ b/src/sysunix.c @@ -43,7 +43,11 @@ void rl_ttyset(int Reset) new = old; new.c_lflag &= ~(ECHO | ICANON | ISIG); - new.c_iflag &= ~(ISTRIP | INPCK); + new.c_iflag &= ~INPCK; + if (rl_meta_chars) + new.c_iflag |= ISTRIP; + else + new.c_iflag &= ~ISTRIP; new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; if (-1 == tcsetattr(0, TCSADRAIN, &new)) @@ -76,7 +80,12 @@ void rl_ttyset(int Reset) new = old; new.c_lflag &= ~(ECHO | ICANON | ISIG); - new.c_iflag &= ~(ISTRIP | INPCK); + new.c_iflag &= ~INPCK; + if (rl_meta_chars) + new.c_iflag |= ISTRIP; + else + new.c_iflag &= ~ISTRIP; + new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; if (-1 == ioctl(0, TCSETAW, &new)) @@ -121,9 +130,10 @@ void rl_ttyset(int Reset) new_sgttyb = old_sgttyb; new_sgttyb.sg_flags &= ~ECHO; new_sgttyb.sg_flags |= RAW; -#ifdef PASS8 - new_sgttyb.sg_flags |= PASS8; -#endif + if (rl_meta_chars) + new_sgttyb.sg_flags &= ~PASS8; + else + new_sgttyb.sg_flags |= PASS8; if (-1 == ioctl(0, TIOCSETP, &new_sgttyb)) perror("Failed TIOCSETP"); new_tchars = old_tchars; From 5de90af58fe405d5c3f97917ebf7fc6ed4380326 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 5 Aug 2010 01:56:09 +0200 Subject: [PATCH 39/44] Fix new GNU Readline compat function pointers. --- include/editline.h | 18 +++++++++--------- src/complete.c | 12 ++++++------ src/editline.c | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/editline.h b/include/editline.h index 4cd9d04..de602be 100644 --- a/include/editline.h +++ b/include/editline.h @@ -27,13 +27,13 @@ typedef enum { } el_status_t; /* Editline specific types, despite rl_ prefix. From Heimdal project. */ -typedef char* (*rl_complete_func_t)(char*, int*); -typedef int (*rl_list_possib_func_t)(char*, char***); -typedef el_status_t (*el_keymap_func_t)(void); -typedef int (*rl_hook_func_t) (void); -typedef int (*rl_getc_func_t)(void); -typedef void (*rl_voidfunc_t)(void); -typedef void (*rl_vintfunc_t)(int); +typedef char* rl_complete_func_t(char*, int*); +typedef int rl_list_possib_func_t(char*, char***); +typedef el_status_t el_keymap_func_t(void); +typedef int rl_hook_func_t(void); +typedef int rl_getc_func_t(void); +typedef void rl_voidfunc_t(void); +typedef void rl_vintfunc_t(int); /* Display 8-bit chars "as-is" or as `M-x'? Toggle with M-m. (Default:0 - "as-is") */ extern int rl_meta_chars; @@ -59,8 +59,8 @@ extern void add_history(const char *line); extern int read_history(const char *filename); extern int write_history(const char *filename); -rl_complete_func_t rl_set_complete_func(rl_complete_func_t func); -rl_list_possib_func_t rl_set_list_possib_func(rl_list_possib_func_t func); +rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func); +rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *func); void rl_prep_terminal(int meta_flag); void rl_deprep_terminal(void); diff --git a/src/complete.c b/src/complete.c index 7913082..96230e9 100644 --- a/src/complete.c +++ b/src/complete.c @@ -140,12 +140,12 @@ static int SplitPath(char *path, char **dirpart, char **filepart) return 0; } -static rl_complete_func_t el_complete_func = NULL; +static rl_complete_func_t *el_complete_func = NULL; /* For compatibility with the Heimdal project. */ -rl_complete_func_t rl_set_complete_func(rl_complete_func_t func) +rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func) { - rl_complete_func_t old = el_complete_func; + rl_complete_func_t *old = el_complete_func; el_complete_func = func; return old; } @@ -234,12 +234,12 @@ char *rl_complete(char *token, int *match) #endif } -static rl_list_possib_func_t el_list_possib_func = NULL; +static rl_list_possib_func_t *el_list_possib_func = NULL; /* For compatibility with the Heimdal project. */ -rl_list_possib_func_t rl_set_list_possib_func(rl_list_possib_func_t func) +rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *func) { - rl_list_possib_func_t old = el_list_possib_func; + rl_list_possib_func_t *old = el_list_possib_func; el_list_possib_func = func; return old; } diff --git a/src/editline.c b/src/editline.c index 17dc553..3bec483 100644 --- a/src/editline.c +++ b/src/editline.c @@ -63,10 +63,10 @@ typedef struct { char **Lines; } el_hist_t; -rl_getc_func_t rl_getc_function = rl_getc; -rl_hook_func_t rl_event_hook; -rl_vintfunc_t rl_prep_term_function = rl_prep_terminal; -rl_voidfunc_t rl_deprep_term_function = rl_deprep_terminal; +rl_getc_func_t *rl_getc_function = rl_getc; +rl_hook_func_t *rl_event_hook; +rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal; +rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal; /* ** Globals. From 27fcc878a13e4151cb4797d3cb994b40784e8530 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 5 Aug 2010 02:00:35 +0200 Subject: [PATCH 40/44] Make sure rl_instream defaults to NULL and add rl_outstream. --- include/editline.h | 2 ++ src/editline.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/editline.h b/include/editline.h index de602be..18c7539 100644 --- a/include/editline.h +++ b/include/editline.h @@ -47,6 +47,8 @@ extern int rl_mark; extern int rl_end; extern char *rl_line_buffer; extern const char *rl_readline_name; +extern FILE *rl_instream; /* The stdio stream from which input is read. Defaults to stdin if NULL - Not supported yet! */ +extern FILE *rl_outstream; /* The stdio stream to which output is flushed. Defaults to stdout if NULL - Not supported yet! */ extern int el_no_echo; /* e.g under emacs, don't echo except prompt */ extern int el_hist_size; /* size of history scrollback buffer, default: 15 */ diff --git a/src/editline.c b/src/editline.c index 3bec483..d2e97a7 100644 --- a/src/editline.c +++ b/src/editline.c @@ -113,8 +113,9 @@ int rl_end; int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */ char *rl_line_buffer; const char *rl_prompt; -const char *rl_readline_name;/* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ -FILE *rl_instream; +const char *rl_readline_name; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ +FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL - Not supported yet! */ +FILE *rl_outstream = NULL; /* The stdio stream to which output is flushed. Defaults to stdout if NULL - Not supported yet! */ /* User definable callbacks. */ char **(*rl_attempted_completion_function)(const char *token, int start, int end); From 5e9177fd18a710a51d36084ecf528e98ac633300 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 5 Aug 2010 12:48:51 +0200 Subject: [PATCH 41/44] Add support for el_bind_key() and example usage binding '?' in examples/cli.c This changeset refactors el_bind_key_in_metamap() into two functions, adding el_bind_key(), to provide the ability for the user to bind keys in both the regular and the meta-key maps. Several useful, but previously internal, functions have been made global to facilitate the example code mentioned above. These are likely useful to the user of this library as well: el_print_columns() - Display words in columns across a tty_cols wide screen. el_ring_bell() - Can be used as default key binding function. el_find_word() - Returns a copy of the word at rl_point. --- TODO | 2 +- examples/cli.c | 23 ++++++++++++ include/editline.h | 10 ++++- src/editline.c | 91 +++++++++++++++++++++++++--------------------- src/editline.h | 3 ++ 5 files changed, 86 insertions(+), 43 deletions(-) diff --git a/TODO b/TODO index 155de1e..208388c 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ TODO * Port "fileman" example from BSD libedit, http://www.thrysoee.dk/editline/ -* Add support for rl_bind_key(), currently one needs to "hack" the Map[] +* Add support for rl_bind_key(), currently only en editline specific el_bind_key() exists. * Add support for inhibiting completion: rl_inhibit_completion * Make "char *rl_prompt" globally visible. * Add support for rl_set_prompt(). diff --git a/examples/cli.c b/examples/cli.c index 3b4673d..105fb79 100644 --- a/examples/cli.c +++ b/examples/cli.c @@ -80,6 +80,28 @@ static int my_rl_list_possib(char *token, char ***av) return total; } +el_status_t list_possible(void) +{ + char **av; + char *word; + int ac; + + word = el_find_word(); + ac = rl_list_possib(word, &av); + if (word) + free(word); + if (ac) { + el_print_columns(ac, av); + while (--ac >= 0) + free(av[ac]); + free(av); + + return CSmove; + } + + return el_ring_bell(); +} + int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused))) { char *line; @@ -88,6 +110,7 @@ int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused))) /* Setup callbacks */ rl_set_complete_func(&my_rl_complete); rl_set_list_possib_func(&my_rl_list_possib); + el_bind_key('?', list_possible); read_history(HISTORY); while ((line = readline(prompt)) != NULL) { diff --git a/include/editline.h b/include/editline.h index 18c7539..7804204 100644 --- a/include/editline.h +++ b/include/editline.h @@ -39,7 +39,15 @@ typedef void rl_vintfunc_t(int); extern int rl_meta_chars; /* Editline specific functions. */ -void el_bind_key_in_metamap(char c, el_keymap_func_t func); +extern char * el_find_word(void); +extern void el_print_columns(int ac, char **av); +extern el_status_t el_ring_bell(void); + +extern void el_bind_key(int key, el_keymap_func_t function); +extern void el_bind_key_in_metamap(int key, el_keymap_func_t function); + +extern char *rl_complete(char *token, int *match); +extern int rl_list_possib(char *token, char ***av); /* For compatibility with FSF readline. */ extern int rl_point; diff --git a/src/editline.c b/src/editline.c index d2e97a7..a37fef6 100644 --- a/src/editline.c +++ b/src/editline.c @@ -309,7 +309,7 @@ void rl_deprep_terminal(void) /* ** Print an array of words in columns. */ -static void columns(int ac, char **av) +void el_print_columns(int ac, char **av) { char *p; int i; @@ -374,7 +374,7 @@ static void right(el_status_t Change) rl_point++; } -static el_status_t ring_bell(void) +el_status_t el_ring_bell(void) { tty_put('\07'); tty_flush(); @@ -392,7 +392,7 @@ static el_status_t do_macro(int c) if ((el_input = (char *)getenv((char *)name)) == NULL) { el_input = NILSTR; - return ring_bell(); + return el_ring_bell(); } return CSstay; } @@ -563,7 +563,7 @@ static const char *prev_hist(void) static el_status_t do_insert_hist(const char *p) { if (p == NULL) - return ring_bell(); + return el_ring_bell(); rl_point = 0; reposition(); @@ -581,7 +581,7 @@ static el_status_t do_hist(const char *(*move)(void)) i = 0; do { if ((p = move()) == NULL) - return ring_bell(); + return el_ring_bell(); } while (++i < Repeat); return do_insert_hist(p); } @@ -668,7 +668,7 @@ static el_status_t h_search(void) const char *p; if (Searching) - return ring_bell(); + return el_ring_bell(); Searching = 1; clear_line(); @@ -688,7 +688,7 @@ static el_status_t h_search(void) p = search_hist(p, move); clear_line(); if (p == NULL) { - ring_bell(); + el_ring_bell(); return redisplay(); } return do_insert_hist(p); @@ -730,7 +730,7 @@ static el_status_t delete_string(int count) char *p; if (count <= 0 || rl_end == rl_point) - return ring_bell(); + return el_ring_bell(); if (count == 1 && rl_point == rl_end - 1) { /* Optimize common case of delete at end of line. */ @@ -894,7 +894,7 @@ static el_status_t meta(void) break; } - return ring_bell(); + return el_ring_bell(); } #endif /* CONFIG_ANSI_ARROWS */ @@ -912,7 +912,7 @@ static el_status_t meta(void) return kp->Function(); } - return ring_bell(); + return el_ring_bell(); } static el_status_t emacs(int c) @@ -1231,7 +1231,7 @@ int write_history(const char *filename) ** Move back to the beginning of the current word and return an ** allocated copy of it. */ -static char *find_word(void) +char *el_find_word(void) { char *p, *q; char *new; @@ -1274,12 +1274,12 @@ static el_status_t c_possible(void) char *word; int ac; - word = find_word(); + word = el_find_word(); ac = rl_list_possib(word, &av); if (word) free(word); if (ac) { - columns(ac, av); + el_print_columns(ac, av); while (--ac >= 0) free(av[ac]); free(av); @@ -1287,7 +1287,7 @@ static el_status_t c_possible(void) return CSmove; } - return ring_bell(); + return el_ring_bell(); } static el_status_t c_complete(void) @@ -1298,7 +1298,7 @@ static el_status_t c_complete(void) int unique; el_status_t s = 0; - word = find_word(); + word = el_find_word(); p = (char *)rl_complete((char *)word, &unique); if (word) free(word); @@ -1321,7 +1321,7 @@ static el_status_t c_complete(void) s = insert_string(new); #ifdef CONFIG_ANNOYING_NOISE if (!unique) - ring_bell(); + el_ring_bell(); #endif } free(new); @@ -1380,7 +1380,7 @@ static el_status_t exchange(void) int c; if ((c = tty_get()) != CTL('X')) - return c == EOF ? CSeof : ring_bell(); + return c == EOF ? CSeof : el_ring_bell(); if ((c = rl_mark) <= rl_end) { rl_mark = rl_point; @@ -1400,7 +1400,7 @@ static el_status_t yank(void) static el_status_t copy_region(void) { if (rl_mark > rl_end) - return ring_bell(); + return el_ring_bell(); if (rl_point > rl_mark) save_yank(rl_mark, rl_point - rl_mark); @@ -1526,14 +1526,14 @@ static el_status_t last_argument(void) int ac; if (H.Size == 1 || (p = (char *)H.Lines[H.Size - 2]) == NULL) - return ring_bell(); + return el_ring_bell(); if ((p = strdup(p)) == NULL) return CSstay; ac = argify(p, &av); if (Repeat != NO_ARG) - s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); + s = Repeat < ac ? insert_string(av[Repeat]) : el_ring_bell(); else s = ac ? insert_string(av[ac - 1]) : CSstay; @@ -1544,14 +1544,14 @@ static el_status_t last_argument(void) return s; } -static el_keymap_t Map[33] = { +static el_keymap_t Map[64] = { { CTL('@'), mk_set }, { CTL('A'), beg_line }, { CTL('B'), bk_char }, { CTL('D'), del_char }, { CTL('E'), end_line }, { CTL('F'), fd_char }, - { CTL('G'), ring_bell }, + { CTL('G'), el_ring_bell }, { CTL('H'), bk_del_char }, { CTL('I'), c_complete }, { CTL('J'), accept_line }, @@ -1559,13 +1559,13 @@ static el_keymap_t Map[33] = { { CTL('L'), redisplay }, { CTL('M'), accept_line }, { CTL('N'), h_next }, - { CTL('O'), ring_bell }, + { CTL('O'), el_ring_bell }, { CTL('P'), h_prev }, - { CTL('Q'), ring_bell }, + { CTL('Q'), el_ring_bell }, { CTL('R'), h_search }, - { CTL('S'), ring_bell }, + { CTL('S'), el_ring_bell }, { CTL('T'), transpose }, - { CTL('U'), ring_bell }, + { CTL('U'), el_ring_bell }, { CTL('V'), quote }, { CTL('W'), bk_kill_word }, { CTL('X'), exchange }, @@ -1573,12 +1573,12 @@ static el_keymap_t Map[33] = { #ifdef SYSTEM_IS_WIN32 { CTL('Z'), end_of_input }, #else - { CTL('Z'), ring_bell }, + { CTL('Z'), el_ring_bell }, #endif { CTL('['), meta }, { CTL(']'), move_to_char }, - { CTL('^'), ring_bell }, - { CTL('_'), ring_bell }, + { CTL('^'), el_ring_bell }, + { CTL('_'), el_ring_bell }, { 0, NULL } }; @@ -1602,31 +1602,40 @@ static el_keymap_t MetaMap[64]= { { 0, NULL } }; -void el_bind_key_in_metamap(char c, el_keymap_func_t func) +static void el_bind_key_in_map(int key, el_keymap_func_t function, el_keymap_t map[], size_t mapsz) { - /* Add given function to key map for META keys */ - int i; + size_t i; - for (i = 0; MetaMap[i].Key != 0; i++) + for (i = 0; Map[i].Function != NULL; i++) { - if (MetaMap[i].Key == c) + if (map[i].Key == key) { - MetaMap[i].Function = func; + map[i].Function = function; return; } } /* A new key so have to add it to end */ - if (i == 63) + if (i == mapsz) { - fprintf(stderr,"editline: MetaMap table full, requires increase\n"); + fprintf(stderr,"editline: failed binding key 0x%x, keymap full.\n", key); return; } - MetaMap[i].Function = func; - MetaMap[i].Key = c; - MetaMap[i + 1].Function = 0; /* Zero the last location */ - MetaMap[i + 1].Key = 0; /* Zero the last location */ + map[i].Key = key; + map[i].Function = function; + + map[i + 1].Function = NULL; /* Terminate list */ +} + +void el_bind_key(int key, el_keymap_func_t function) +{ + el_bind_key_in_map(key, function, Map, ARRAY_ELEMENTS(Map)); +} + +void el_bind_key_in_metamap(int key, el_keymap_func_t function) +{ + el_bind_key_in_map(key, function, MetaMap, ARRAY_ELEMENTS(MetaMap)); } /** diff --git a/src/editline.h b/src/editline.h index 61ecef6..0e3df78 100644 --- a/src/editline.h +++ b/src/editline.h @@ -56,6 +56,9 @@ #define MEM_INC 64 #define SCREEN_INC 256 +/* http://stackoverflow.com/questions/1598773/is-there-a-standard-function-in-c-that-would-return-the-length-of-an-array/1598827#1598827 */ +#define ARRAY_ELEMENTS(arr) ((sizeof(arr)/sizeof(0[arr])) / ((size_t)(!(sizeof(arr) % sizeof(0[arr]))))) + /* ** Variables and routines internal to this package. */ From de6ff117bb832bcaa1cad4ce815fc438c04d73e9 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 5 Aug 2010 13:20:35 +0200 Subject: [PATCH 42/44] Implement compat. support for rl_instream and rl_outstream --- src/editline.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/editline.c b/src/editline.c index a37fef6..42e13db 100644 --- a/src/editline.c +++ b/src/editline.c @@ -97,6 +97,8 @@ static int old_point; static int el_push_back; static int el_pushed; static int el_intr_pending; +static int el_infd = 0; /* STDIN */ +static int el_outfd = 1; /* STDOUT */ static el_keymap_t Map[]; static el_keymap_t MetaMap[]; static size_t Length; @@ -113,9 +115,9 @@ int rl_end; int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */ char *rl_line_buffer; const char *rl_prompt; -const char *rl_readline_name; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ -FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL - Not supported yet! */ -FILE *rl_outstream = NULL; /* The stdio stream to which output is flushed. Defaults to stdout if NULL - Not supported yet! */ +const char *rl_readline_name; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ +FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL */ +FILE *rl_outstream = NULL; /* The stdio stream to which output is flushed. Defaults to stdout if NULL */ /* User definable callbacks. */ char **(*rl_attempted_completion_function)(const char *token, int start, int end); @@ -154,7 +156,7 @@ static void tty_flush(void) if (ScreenCount) { if (!el_no_echo) - res = write(1, Screen, ScreenCount); + res = write(el_outfd, Screen, ScreenCount); ScreenCount = 0; } } @@ -209,7 +211,7 @@ int rl_getc(void) char c; do { - r = read(0, &c, 1); + r = read(el_infd, &c, 1); } while (r == -1 && errno == EINTR); return r == 1 ? c : EOF; @@ -1083,7 +1085,7 @@ static char *read_redirected(void) p += oldpos; /* Continue where we left off... */ } - if (read(0, p, 1) <= 0) { + if (read(el_infd, p, 1) <= 0) { /* Ignore "incomplete" lines at EOF, just like we do for a tty. */ free(line); return NULL; @@ -1108,6 +1110,14 @@ void rl_initialize(void) rl_prompt = "? "; hist_alloc(); + + /* Setup I/O descriptors */ + if (!rl_instream) el_infd = 0; + else el_infd = fileno(rl_instream); + if (el_infd < 0) el_infd = 0; + if (!rl_outstream) el_outfd = 1; + else el_outfd = fileno(rl_outstream); + if (el_outfd < 0) el_outfd = 1; } char *readline(const char *prompt) From 1c89c9886c68d2e5e98bbbe5e4385c90c18593d4 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 5 Aug 2010 15:14:06 +0200 Subject: [PATCH 43/44] Refactor tty_info() to make rl_reset_terminal() useful. --- include/editline.h | 2 +- src/editline.c | 106 ++++++++++++++++++++++++--------------------- src/editline.h | 4 +- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/include/editline.h b/include/editline.h index 7804204..ee28d75 100644 --- a/include/editline.h +++ b/include/editline.h @@ -61,7 +61,7 @@ extern int el_no_echo; /* e.g under emacs, don't echo except prompt */ extern int el_hist_size; /* size of history scrollback buffer, default: 15 */ extern void rl_initialize(void); -extern void rl_reset_terminal(char *p); +extern void rl_reset_terminal(const char *terminal_name); extern char *readline(const char *prompt); extern void add_history(const char *line); diff --git a/src/editline.c b/src/editline.c index 42e13db..8dc3bb5 100644 --- a/src/editline.c +++ b/src/editline.c @@ -29,6 +29,8 @@ */ #define SCREEN_COLS 80 #define SCREEN_ROWS 24 +#define EL_STDIN 0 +#define EL_STDOUT 1 #define NO_ARG (-1) #define DEL 127 #define CTL(x) ((x) & 0x1F) @@ -92,21 +94,22 @@ static const char *el_input = NILSTR; static char *Yanked; static char *Screen; static char NEWLINE[]= CRLF; +static const char *el_term = "dumb"; static int Repeat; static int old_point; static int el_push_back; static int el_pushed; static int el_intr_pending; -static int el_infd = 0; /* STDIN */ -static int el_outfd = 1; /* STDOUT */ +static int el_infd = EL_STDIN; +static int el_outfd = EL_STDOUT; static el_keymap_t Map[]; static el_keymap_t MetaMap[]; static size_t Length; static size_t ScreenCount; static size_t ScreenSize; -static char *backspace; -static int tty_cols; -static int tty_rows; +static char *backspace = "\b"; +static int tty_cols = SCREEN_COLS; +static int tty_rows = SCREEN_ROWS; int el_no_echo = 0; /* e.g., under Emacs */ int rl_point; @@ -230,7 +233,7 @@ static int tty_get(void) return rl_getc_function(); } -#define tty_back() (backspace ? tty_puts(backspace) : tty_put('\b')) +#define tty_back() tty_puts(backspace) static void tty_backn(int n) { @@ -240,21 +243,13 @@ static void tty_backn(int n) static void tty_info(void) { - static int init; -#ifdef CONFIG_USE_TERMCAP - char *term; - char buff[2048]; - char *bp; -#endif -#ifdef TIOCGWINSZ - struct winsize W; -#endif + static int init; if (init) { #ifdef TIOCGWINSZ - /* Perhaps we got resized. */ - if (ioctl(0, TIOCGWINSZ, &W) >= 0 - && W.ws_col > 0 && W.ws_row > 0) { + struct winsize W; + + if (ioctl(el_outfd, TIOCGWINSZ, &W) >= 0 && W.ws_col > 0 && W.ws_row > 0) { tty_cols = (int)W.ws_col; tty_rows = (int)W.ws_row; } @@ -265,32 +260,7 @@ static void tty_info(void) /* Initialize to faulty values to trigger fallback if nothing else works. */ tty_cols = tty_rows = -1; -#ifdef CONFIG_USE_TERMCAP - bp = buff; - if ((term = getenv("TERM")) == NULL) - term = "dumb"; - if (-1 != tgetent(buff, term)) { - if ((backspace = tgetstr("le", &bp)) != NULL) - backspace = strdup(backspace); - else - backspace = "\b"; - tty_cols = tgetnum("co"); - tty_rows = tgetnum("li"); - } - /* Make sure to check width & rows and fallback to TIOCGWINSZ if available. */ -#endif - - if (tty_cols <= 0 || tty_rows <= 0) { -#ifdef TIOCGWINSZ - if (-1 != ioctl(0, TIOCGWINSZ, &W)) { - tty_cols = (int)W.ws_col; - tty_rows = (int)W.ws_row; - return; - } -#endif - tty_cols = SCREEN_COLS; - tty_rows = SCREEN_ROWS; - } + rl_reset_terminal(NULL); } @@ -1100,8 +1070,46 @@ static char *read_redirected(void) } /* For compatibility with FSF readline. */ -void rl_reset_terminal(char *p __attribute__((__unused__))) +void rl_reset_terminal(const char *terminal_name) { +#ifdef CONFIG_USE_TERMCAP + char buff[2048]; + char *bp; +#endif +#ifdef TIOCGWINSZ + struct winsize W; +#endif + + if (terminal_name) { + el_term = terminal_name; + return; + } + + if ((el_term = getenv("TERM")) == NULL) + el_term = "dumb"; + +#ifdef CONFIG_USE_TERMCAP + bp = buff; + if (-1 != tgetent(buff, el_term)) { + if ((backspace = tgetstr("le", &bp)) != NULL) + backspace = strdup(backspace); + tty_cols = tgetnum("co"); + tty_rows = tgetnum("li"); + } + /* Make sure to check width & rows and fallback to TIOCGWINSZ if available. */ +#endif + + if (tty_cols <= 0 || tty_rows <= 0) { +#ifdef TIOCGWINSZ + if (-1 != ioctl(el_outfd, TIOCGWINSZ, &W)) { + tty_cols = (int)W.ws_col; + tty_rows = (int)W.ws_row; + return; + } +#endif + tty_cols = SCREEN_COLS; + tty_rows = SCREEN_ROWS; + } } void rl_initialize(void) @@ -1112,12 +1120,12 @@ void rl_initialize(void) hist_alloc(); /* Setup I/O descriptors */ - if (!rl_instream) el_infd = 0; + if (!rl_instream) el_infd = EL_STDIN; else el_infd = fileno(rl_instream); - if (el_infd < 0) el_infd = 0; - if (!rl_outstream) el_outfd = 1; + if (el_infd < 0) el_infd = EL_STDIN; + if (!rl_outstream) el_outfd = EL_STDOUT; else el_outfd = fileno(rl_outstream); - if (el_outfd < 0) el_outfd = 1; + if (el_outfd < 0) el_outfd = EL_STDOUT; } char *readline(const char *prompt) diff --git a/src/editline.h b/src/editline.h index 0e3df78..e316a41 100644 --- a/src/editline.h +++ b/src/editline.h @@ -53,8 +53,8 @@ # include #endif -#define MEM_INC 64 -#define SCREEN_INC 256 +#define MEM_INC 64 +#define SCREEN_INC 256 /* http://stackoverflow.com/questions/1598773/is-there-a-standard-function-in-c-that-would-return-the-length-of-an-array/1598827#1598827 */ #define ARRAY_ELEMENTS(arr) ((sizeof(arr)/sizeof(0[arr])) / ((size_t)(!(sizeof(arr) % sizeof(0[arr]))))) From 916fac7cad23ba9b5e2cd8a53c9ee1fac33a4ca7 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Fri, 6 Aug 2010 23:56:51 +0200 Subject: [PATCH 44/44] Line scroll branch todo. --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 208388c..2fb6ed1 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,7 @@ TODO * Port "fileman" example from BSD libedit, http://www.thrysoee.dk/editline/ +* Instead of supporting multiline input, try the Emacs approach, line scrolling. * Add support for rl_bind_key(), currently only en editline specific el_bind_key() exists. * Add support for inhibiting completion: rl_inhibit_completion * Make "char *rl_prompt" globally visible.