X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fcmdedit.c;h=c4cb9d9c45291adebd51b06c4bfd9a7a9a1dc144;hb=e4baaa2d2795c14775b26213d143e9f9f65e4d54;hp=0ab1958038742d1e9312c41cc26da972def40164;hpb=81fe123040b53490b239b3d2abc8cc93d6d462ae;p=oweals%2Fbusybox.git diff --git a/shell/cmdedit.c b/shell/cmdedit.c index 0ab195803..c4cb9d9c4 100644 --- a/shell/cmdedit.c +++ b/shell/cmdedit.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Termios command line History and Editting. + * Termios command line History and Editing. * * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. * Written by: Vladimir Oleynik @@ -43,17 +43,23 @@ #include "busybox.h" +#include "../shell/cmdedit.h" + + #ifdef CONFIG_LOCALE_SUPPORT #define Isprint(c) isprint((c)) #else #define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') ) #endif -#ifndef TEST - -#define D(x) +#ifdef TEST -#else +/* pretect redefined for test */ +#undef CONFIG_FEATURE_COMMAND_EDITING +#undef CONFIG_FEATURE_COMMAND_TAB_COMPLETION +#undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION +#undef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT +#undef CONFIG_FEATURE_CLEAN_UP #define CONFIG_FEATURE_COMMAND_EDITING #define CONFIG_FEATURE_COMMAND_TAB_COMPLETION @@ -61,8 +67,6 @@ #define CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT #define CONFIG_FEATURE_CLEAN_UP -#define D(x) x - #endif /* TEST */ #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION @@ -72,20 +76,12 @@ #ifdef CONFIG_FEATURE_COMMAND_EDITING -#ifndef CONFIG_FEATURE_COMMAND_TAB_COMPLETION -#undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION -#endif - #if defined(CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(CONFIG_FEATURE_SH_FANCY_PROMPT) #define CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR #endif #ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR -# ifndef TEST -# include "pwd_.h" -# else -# include -# endif /* TEST */ +#include "pwd_.h" #endif /* advanced FEATURES */ @@ -167,15 +163,13 @@ static void cmdedit_setwidth(int w, int redraw_flg); static void win_changed(int nsig) { - struct winsize win = { 0, 0, 0, 0 }; static sighandler_t previous_SIGWINCH_handler; /* for reset */ /* emulate || signal call */ if (nsig == -SIGWINCH || nsig == SIGWINCH) { - ioctl(0, TIOCGWINSZ, &win); - if (win.ws_col > 0) { - cmdedit_setwidth(win.ws_col, nsig == SIGWINCH); - } + int width = 0; + get_terminal_width_height(0, &width, NULL); + cmdedit_setwidth(width, nsig == SIGWINCH); } /* Unix not all standart in recall signal */ @@ -192,7 +186,7 @@ static void cmdedit_reset_term(void) { if ((handlers_sets & SET_RESET_TERM) != 0) { /* sparc and other have broken termios support: use old termio handling. */ - setTermSettings(fileno(stdin), (void *) &initial_settings); + setTermSettings(STDIN_FILENO, (void *) &initial_settings); handlers_sets &= ~SET_RESET_TERM; } if ((handlers_sets & SET_WCHG_HANDLERS) != 0) { @@ -265,7 +259,7 @@ static inline void beep(void) putchar('\007'); } -/* Move back one charactor */ +/* Move back one character */ /* special for slow terminal */ static void input_backward(int num) { @@ -316,7 +310,7 @@ static void parse_prompt(const char *prmt_ptr) static void parse_prompt(const char *prmt_ptr) { int prmt_len = 0; - int sub_len = 0; + size_t cur_prmt_len = 0; char flg_not_length = '['; char *prmt_mem_ptr = xcalloc(1, 1); char *pwd_buf = xgetcwd(0); @@ -421,21 +415,21 @@ static void parse_prompt(const char *prmt_ptr) } if(pbuf == buf) *pbuf = c; - prmt_len += strlen(pbuf); + cur_prmt_len = strlen(pbuf); + prmt_len += cur_prmt_len; + if (flg_not_length != ']') + cmdedit_prmt_len += cur_prmt_len; prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); - if (flg_not_length == ']') - sub_len++; } if(pwd_buf!=(char *)bb_msg_unknown) free(pwd_buf); cmdedit_prompt = prmt_mem_ptr; - cmdedit_prmt_len = prmt_len - sub_len; put_prompt(); } #endif -/* draw promt, editor line, and clear tail */ +/* draw prompt, editor line, and clear tail */ static void redraw(int y, int back_cursor) { if (y > 0) /* up to start y */ @@ -447,39 +441,72 @@ static void redraw(int y, int back_cursor) input_backward(back_cursor); } -/* Delete the char in front of the cursor */ -static void input_delete(void) +#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI +static char delbuf[BUFSIZ]; /* a place to store deleted characters */ +static char *delp = delbuf; +static int newdelflag; /* whether delbuf should be reused yet */ +#endif + +/* Delete the char in front of the cursor, optionally saving it + * for later putback */ +static void input_delete(int save) { int j = cursor; if (j == len) return; +#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI + if (save) { + if (newdelflag) { + delp = delbuf; + newdelflag = 0; + } + if (delp - delbuf < BUFSIZ) + *delp++ = command_ps[j]; + } +#endif + strcpy(command_ps + j, command_ps + j + 1); len--; - input_end(); /* rewtite new line */ + input_end(); /* rewrite new line */ cmdedit_set_out_char(0); /* destroy end char */ input_backward(cursor - j); /* back to old pos cursor */ } +#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI +static void put(void) +{ + int ocursor, j = delp - delbuf; + if (j == 0) + return; + ocursor = cursor; + /* open hole and then fill it */ + memmove(command_ps + cursor + j, command_ps + cursor, len - cursor + 1); + strncpy(command_ps + cursor, delbuf, j); + len += j; + input_end(); /* rewrite new line */ + input_backward(cursor-ocursor-j+1); /* at end of new text */ +} +#endif + /* Delete the char in back of the cursor */ static void input_backspace(void) { if (cursor > 0) { input_backward(1); - input_delete(); + input_delete(0); } } -/* Move forward one charactor */ +/* Move forward one character */ static void input_forward(void) { if (cursor < len) cmdedit_set_out_char(command_ps[cursor + 1]); } - static void cmdedit_setwidth(int w, int redraw_flg) { cmdedit_termw = cmdedit_prmt_len + 2; @@ -614,14 +641,20 @@ enum { FIND_FILE_ONLY = 2, }; +#ifdef CONFIG_ASH +const char *cmdedit_path_lookup; +#else +#define cmdedit_path_lookup getenv("PATH") +#endif + static int path_parse(char ***p, int flags) { int npth; - char *tmp; - char *pth; + const char *tmp; + const char *pth; /* if not setenv PATH variable, to search cur dir "." */ - if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 || + if (flags != FIND_EXE_ONLY || (pth = cmdedit_path_lookup) == 0 || /* PATH= or PATH=: */ *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) { return 1; @@ -782,8 +815,8 @@ static int match_compare(const void *a, const void *b) #define QUOT (UCHAR_MAX+1) #define collapse_pos(is, in) { \ - memcpy(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \ - memcpy(pos_buf+(is), pos_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); } + memmove(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \ + memmove(pos_buf+(is), pos_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); } static int find_match(char *matchBuf, int *len_with_quotes) { @@ -1189,8 +1222,7 @@ extern void save_history ( const char *tofile ) int i; for ( i = 0; i < n_history; i++ ) { - fputs ( history [i], fp ); - fputc ( '\n', fp ); + fprintf(fp, "%s\n", history [i]); } fclose ( fp ); } @@ -1208,7 +1240,7 @@ enum { /* * This function is used to grab a character buffer * from the input file descriptor and allows you to - * a string with full command editing (sortof like + * a string with full command editing (sort of like * a mini readline). * * The following standard commands are not implemented: @@ -1218,18 +1250,147 @@ enum { * ESC-h -- Delete forward one word * CTL-t -- Transpose two characters * - * Furthermore, the "vi" command editing keys are not implemented. + * Minimalist vi-style command line editing available if configured. + * vi mode implemented 2005 by Paul Fox * */ +#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI +static int vi_mode; + +void setvimode ( int viflag ) +{ + vi_mode = viflag; +} + +static void +vi_Word_motion(char *command, int eat) +{ + while (cursor < len && !isspace(command[cursor])) + input_forward(); + if (eat) while (cursor < len && isspace(command[cursor])) + input_forward(); +} + +static void +vi_word_motion(char *command, int eat) +{ + if (isalnum(command[cursor]) || command[cursor] == '_') { + while (cursor < len && + (isalnum(command[cursor+1]) || + command[cursor+1] == '_')) + input_forward(); + } else if (ispunct(command[cursor])) { + while (cursor < len && + (ispunct(command[cursor+1]))) + input_forward(); + } + + if (cursor < len) + input_forward(); + + if (eat && cursor < len && isspace(command[cursor])) + while (cursor < len && isspace(command[cursor])) + input_forward(); +} + +static void +vi_End_motion(char *command) +{ + input_forward(); + while (cursor < len && isspace(command[cursor])) + input_forward(); + while (cursor < len-1 && !isspace(command[cursor+1])) + input_forward(); +} + +static void +vi_end_motion(char *command) +{ + if (cursor >= len-1) + return; + input_forward(); + while (cursor < len-1 && isspace(command[cursor])) + input_forward(); + if (cursor >= len-1) + return; + if (isalnum(command[cursor]) || command[cursor] == '_') { + while (cursor < len-1 && + (isalnum(command[cursor+1]) || + command[cursor+1] == '_')) + input_forward(); + } else if (ispunct(command[cursor])) { + while (cursor < len-1 && + (ispunct(command[cursor+1]))) + input_forward(); + } +} + +static void +vi_Back_motion(char *command) +{ + while (cursor > 0 && isspace(command[cursor-1])) + input_backward(1); + while (cursor > 0 && !isspace(command[cursor-1])) + input_backward(1); +} + +static void +vi_back_motion(char *command) +{ + if (cursor <= 0) + return; + input_backward(1); + while (cursor > 0 && isspace(command[cursor])) + input_backward(1); + if (cursor <= 0) + return; + if (isalnum(command[cursor]) || command[cursor] == '_') { + while (cursor > 0 && + (isalnum(command[cursor-1]) || + command[cursor-1] == '_')) + input_backward(1); + } else if (ispunct(command[cursor])) { + while (cursor > 0 && + (ispunct(command[cursor-1]))) + input_backward(1); + } +} +#endif + +/* + * the normal emacs mode and vi's insert mode are the same. + * commands entered when in vi command mode ("escape mode") get + * an extra bit added to distinguish them. this lets them share + * much of the code in the big switch and while loop. i + * experimented with an ugly macro to make the case labels for + * these cases go away entirely when vi mode isn't configured, in + * hopes of letting the jump tables get smaller: + * #define vcase(caselabel) caselabel + * and then + * case CNTRL('A'): + * case vcase(VICMD('0'):) + * but it didn't seem to make any difference in code size, + * and the macro-ized code was too ugly. + */ + +#define VI_cmdbit 0x100 +#define VICMD(somecmd) ((somecmd)|VI_cmdbit) + +/* convert uppercase ascii to equivalent control char, for readability */ +#define CNTRL(uc_char) ((uc_char) - 0x40) + int cmdedit_read_input(char *prompt, char command[BUFSIZ]) { int break_out = 0; int lastWasTab = FALSE; - unsigned char c = 0; - + unsigned char c; +#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI + unsigned int ic, prevc; + int vi_cmdmode = 0; +#endif /* prepare before init handlers */ cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ len = 0; @@ -1240,7 +1401,6 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) new_settings.c_lflag &= ~ICANON; /* unbuffered input */ /* Turn off echoing and CTRL-C, so we can trap it */ new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); -#ifndef linux /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; @@ -1249,7 +1409,6 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) # define _POSIX_VDISABLE '\0' # endif new_settings.c_cc[VINTR] = _POSIX_VDISABLE; -#endif command[0] = 0; setTermSettings(0, (void *) &new_settings); @@ -1268,37 +1427,55 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) /* if we can't read input then exit */ goto prepare_to_die; - switch (c) { +#ifdef CONFIG_FEATURE_COMMAND_EDITING_VI + newdelflag = 1; + ic = c; + if (vi_cmdmode) + ic |= VI_cmdbit; + switch (ic) +#else + switch (c) +#endif + { case '\n': case '\r': + case VICMD('\n'): + case VICMD('\r'): /* Enter */ goto_new_line(); break_out = 1; break; - case 1: + case CNTRL('A'): + case VICMD('0'): /* Control-a -- Beginning of line */ input_backward(cursor); break; - case 2: + case CNTRL('B'): + case VICMD('h'): + case VICMD('\b'): + case VICMD(DEL): /* Control-b -- Move back one character */ input_backward(1); break; - case 3: + case CNTRL('C'): + case VICMD(CNTRL('C')): /* Control-c -- stop gathering input */ goto_new_line(); +#ifndef CONFIG_ASH command[0] = 0; len = 0; -#if !defined(CONFIG_ASH) lastWasTab = FALSE; put_prompt(); #else - break_out = 2; + len = 0; + break_out = -1; /* to control traps */ #endif break; - case 4: + case CNTRL('D'): /* Control-d -- Delete one character, or exit * if the len=0 and no chars to delete */ if (len == 0) { + errno = 0; prepare_to_die: #if !defined(CONFIG_ASH) printf("exit"); @@ -1306,18 +1483,22 @@ prepare_to_die: /* cmdedit_reset_term() called in atexit */ exit(EXIT_SUCCESS); #else - break_out = -1; /* for control stoped jobs */ + /* to control stopped jobs */ + len = break_out = -1; break; #endif } else { - input_delete(); + input_delete(0); } break; - case 5: + case CNTRL('E'): + case VICMD('$'): /* Control-e -- End of line */ input_end(); break; - case 6: + case CNTRL('F'): + case VICMD('l'): + case VICMD(' '): /* Control-f -- Move forward one character */ input_forward(); break; @@ -1331,24 +1512,29 @@ prepare_to_die: input_tab(&lastWasTab); #endif break; - case 11: + case CNTRL('K'): /* Control-k -- clear to end of line */ *(command + cursor) = 0; len = cursor; printf("\033[J"); break; - case 12: - /* Control-l -- clear screen */ + case CNTRL('L'): + case VICMD(CNTRL('L')): + /* Control-l -- clear screen */ printf("\033[H"); redraw(0, len-cursor); break; #if MAX_HISTORY >= 1 - case 14: + case CNTRL('N'): + case VICMD(CNTRL('N')): + case VICMD('j'): /* Control-n -- Get next command in history */ if (get_next_history()) goto rewrite_line; break; - case 16: + case CNTRL('P'): + case VICMD(CNTRL('P')): + case VICMD('k'): /* Control-p -- Get previous command from history */ if (cur_history > 0) { get_previous_history(); @@ -1358,22 +1544,178 @@ prepare_to_die: } break; #endif - case 21: + case CNTRL('U'): + case VICMD(CNTRL('U')): /* Control-U -- Clear line before cursor */ if (cursor) { strcpy(command, command + cursor); redraw(cmdedit_y, len -= cursor); } break; + case CNTRL('W'): + case VICMD(CNTRL('W')): + /* Control-W -- Remove the last word */ + while (cursor > 0 && isspace(command[cursor-1])) + input_backspace(); + while (cursor > 0 &&!isspace(command[cursor-1])) + input_backspace(); + break; +#if CONFIG_FEATURE_COMMAND_EDITING_VI + case VICMD('i'): + vi_cmdmode = 0; + break; + case VICMD('I'): + input_backward(cursor); + vi_cmdmode = 0; + break; + case VICMD('a'): + input_forward(); + vi_cmdmode = 0; + break; + case VICMD('A'): + input_end(); + vi_cmdmode = 0; + break; + case VICMD('x'): + input_delete(1); + break; + case VICMD('X'): + if (cursor > 0) { + input_backward(1); + input_delete(1); + } + break; + case VICMD('W'): + vi_Word_motion(command, 1); + break; + case VICMD('w'): + vi_word_motion(command, 1); + break; + case VICMD('E'): + vi_End_motion(command); + break; + case VICMD('e'): + vi_end_motion(command); + break; + case VICMD('B'): + vi_Back_motion(command); + break; + case VICMD('b'): + vi_back_motion(command); + break; + case VICMD('C'): + vi_cmdmode = 0; + /* fall through */ + case VICMD('D'): + goto clear_to_eol; + + case VICMD('c'): + vi_cmdmode = 0; + /* fall through */ + case VICMD('d'): + { + int nc, sc; + sc = cursor; + prevc = ic; + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; + if (c == (prevc & 0xff)) { + /* "cc", "dd" */ + input_backward(cursor); + goto clear_to_eol; + break; + } + switch(c) { + case 'w': + case 'W': + case 'e': + case 'E': + switch (c) { + case 'w': /* "dw", "cw" */ + vi_word_motion(command, vi_cmdmode); + break; + case 'W': /* 'dW', 'cW' */ + vi_Word_motion(command, vi_cmdmode); + break; + case 'e': /* 'de', 'ce' */ + vi_end_motion(command); + input_forward(); + break; + case 'E': /* 'dE', 'cE' */ + vi_End_motion(command); + input_forward(); + break; + } + nc = cursor; + input_backward(cursor - sc); + while (nc-- > cursor) + input_delete(1); + break; + case 'b': /* "db", "cb" */ + case 'B': /* implemented as B */ + if (c == 'b') + vi_back_motion(command); + else + vi_Back_motion(command); + while (sc-- > cursor) + input_delete(1); + break; + case ' ': /* "d ", "c " */ + input_delete(1); + break; + case '$': /* "d$", "c$" */ + clear_to_eol: + while (cursor < len) + input_delete(1); + break; + } + } + break; + case VICMD('p'): + input_forward(); + /* fallthrough */ + case VICMD('P'): + put(); + break; + case VICMD('r'): + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; + if (c == 0) + beep(); + else { + *(command + cursor) = c; + putchar(c); + putchar('\b'); + } + break; +#endif /* CONFIG_FEATURE_COMMAND_EDITING_VI */ case ESC:{ +#if CONFIG_FEATURE_COMMAND_EDITING_VI + if (vi_mode) { + /* ESC: insert mode --> command mode */ + vi_cmdmode = 1; + input_backward(1); + break; + } +#endif /* escape sequence follows */ if (safe_read(0, &c, 1) < 1) goto prepare_to_die; /* different vt100 emulations */ if (c == '[' || c == 'O') { + case VICMD('['): + case VICMD('O'): if (safe_read(0, &c, 1) < 1) goto prepare_to_die; } + if (c >= '1' && c <= '9') { + unsigned char dummy; + + if (safe_read(0, &dummy, 1) < 1) + goto prepare_to_die; + if(dummy != '~') + c = 0; + } switch (c) { #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION case '\t': /* Alt-Tab */ @@ -1394,13 +1736,17 @@ prepare_to_die: case 'B': /* Down Arrow -- Get next command in history */ if (!get_next_history()) - break; + break; /* Rewrite the line with the selected history item */ rewrite_line: /* change command */ len = strlen(strcpy(command, history[cur_history])); - /* redraw and go to end line */ + /* redraw and go to eol (bol, in vi */ +#if CONFIG_FEATURE_COMMAND_EDITING_VI + redraw(cmdedit_y, vi_mode ? 9999:0); +#else redraw(cmdedit_y, 0); +#endif break; #endif case 'C': @@ -1413,35 +1759,29 @@ rewrite_line: break; case '3': /* Delete */ - input_delete(); + input_delete(0); break; case '1': case 'H': - /* Home (Ctrl-A) */ + /* */ input_backward(cursor); break; case '4': case 'F': - /* End (Ctrl-E) */ + /* */ input_end(); break; default: - if (!(c >= '1' && c <= '9')) - c = 0; + c = 0; beep(); } - if (c >= '1' && c <= '9') - do - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - while (c != '~'); break; } default: /* If it's regular input, do the normal thing */ #ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT /* Control-V -- Add non-printable symbol */ - if (c == 22) { + if (c == CNTRL('V')) { if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == 0) { @@ -1450,8 +1790,14 @@ rewrite_line: } } else #endif - if (!Isprint(c)) /* Skip non-printable characters */ - break; + { +#if CONFIG_FEATURE_COMMAND_EDITING_VI + if (vi_cmdmode) /* don't self-insert */ + break; +#endif + if (!Isprint(c)) /* Skip non-printable characters */ + break; + } if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ break; @@ -1489,10 +1835,11 @@ rewrite_line: #if MAX_HISTORY >= 1 /* Handle command history log */ /* cleanup may be saved current command line */ - free(history[MAX_HISTORY]); - history[MAX_HISTORY] = 0; - if (len) { /* no put empty line */ + if (len> 0) { /* no put empty line */ int i = n_history; + + free(history[MAX_HISTORY]); + history[MAX_HISTORY] = 0; /* After max history, remove the oldest command */ if (i >= MAX_HISTORY) { free(history[0]); @@ -1508,12 +1855,12 @@ rewrite_line: } #else /* MAX_HISTORY < 1 */ #if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) - if (len) { /* no put empty line */ + if (len > 0) { /* no put empty line */ num_ok_lines++; } #endif #endif /* MAX_HISTORY >= 1 */ - if(break_out == 1) { + if (break_out > 0) { command[len++] = '\n'; /* set '\n' */ command[len] = 0; } @@ -1524,11 +1871,7 @@ rewrite_line: free(cmdedit_prompt); #endif cmdedit_reset_term(); -#if !defined(CONFIG_ASH) return len; -#else - return break_out < 0 ? break_out : len; -#endif } @@ -1539,7 +1882,6 @@ rewrite_line: #ifdef TEST const char *bb_applet_name = "debug stuff usage"; -const char *memory_exhausted = "Memory exhausted"; #ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT #include @@ -1562,15 +1904,15 @@ int main(int argc, char **argv) #endif while(1) { int l; - cmdedit_read_input(prompt, buff); - l = strlen(buff); - if(l==0) - break; - if(l > 0 && buff[l-1] == '\n') + l = cmdedit_read_input(prompt, buff); + if(l > 0 && buff[l-1] == '\n') { buff[l-1] = 0; - printf("*** cmdedit_read_input() returned line =%s=\n", buff); + printf("*** cmdedit_read_input() returned line =%s=\n", buff); + } else { + break; + } } - printf("*** cmdedit_read_input() detect ^C\n"); + printf("*** cmdedit_read_input() detect ^D\n"); return 0; }