aboutsummaryrefslogtreecommitdiff
path: root/shell/cmdedit.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/cmdedit.c')
-rw-r--r--shell/cmdedit.c316
1 files changed, 157 insertions, 159 deletions
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index a1432af15..554a4ebec 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -30,7 +30,6 @@
30 30
31#include <sys/ioctl.h> 31#include <sys/ioctl.h>
32#include "busybox.h" 32#include "busybox.h"
33#include "cmdedit.h"
34 33
35 34
36/* FIXME: obsolete CONFIG item? */ 35/* FIXME: obsolete CONFIG item? */
@@ -51,7 +50,6 @@
51/* Entire file (except TESTing part) sits inside this #if */ 50/* Entire file (except TESTing part) sits inside this #if */
52#if ENABLE_FEATURE_COMMAND_EDITING 51#if ENABLE_FEATURE_COMMAND_EDITING
53 52
54
55#if ENABLE_LOCALE_SUPPORT 53#if ENABLE_LOCALE_SUPPORT
56#define Isprint(c) isprint(c) 54#define Isprint(c) isprint(c)
57#else 55#else
@@ -61,29 +59,21 @@
61#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ 59#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
62(ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT) 60(ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT)
63 61
64/* Maximum length of command line history */
65#if !ENABLE_FEATURE_COMMAND_HISTORY
66#define MAX_HISTORY 15
67#else
68#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0)
69#endif
70 62
63static line_input_t *state;
71 64
72/* Current termios and the previous termios before starting sh */
73static struct termios initial_settings, new_settings; 65static struct termios initial_settings, new_settings;
74 66
75static 67static volatile unsigned cmdedit_termw = 80; /* actual terminal width */
76volatile unsigned cmdedit_termw = 80; /* actual terminal width */
77
78 68
79static int cmdedit_x; /* real x terminal position */ 69static int cmdedit_x; /* real x terminal position */
80static int cmdedit_y; /* pseudoreal y terminal position */ 70static int cmdedit_y; /* pseudoreal y terminal position */
81static int cmdedit_prmt_len; /* length of prompt (without colors etc) */ 71static int cmdedit_prmt_len; /* length of prompt (without colors etc) */
82 72
83static int cursor; 73static unsigned cursor;
84static int len; 74static unsigned command_len;
85static char *command_ps; 75static char *command_ps;
86static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; 76static const char *cmdedit_prompt;
87 77
88#if ENABLE_FEATURE_SH_FANCY_PROMPT 78#if ENABLE_FEATURE_SH_FANCY_PROMPT
89static char *hostname_buf; 79static char *hostname_buf;
@@ -142,7 +132,7 @@ static void cmdedit_set_out_char(int next_char)
142/* Move to end of line (by printing all chars till the end) */ 132/* Move to end of line (by printing all chars till the end) */
143static void input_end(void) 133static void input_end(void)
144{ 134{
145 while (cursor < len) 135 while (cursor < command_len)
146 cmdedit_set_out_char(' '); 136 cmdedit_set_out_char(' ');
147} 137}
148 138
@@ -200,7 +190,7 @@ static void input_backward(unsigned num)
200static void put_prompt(void) 190static void put_prompt(void)
201{ 191{
202 out1str(cmdedit_prompt); 192 out1str(cmdedit_prompt);
203 cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ 193 cmdedit_x = cmdedit_prmt_len;
204 cursor = 0; 194 cursor = 0;
205// Huh? what if cmdedit_prmt_len >= width? 195// Huh? what if cmdedit_prmt_len >= width?
206 cmdedit_y = 0; /* new quasireal y */ 196 cmdedit_y = 0; /* new quasireal y */
@@ -231,7 +221,7 @@ static void input_delete(int save)
231{ 221{
232 int j = cursor; 222 int j = cursor;
233 223
234 if (j == len) 224 if (j == command_len)
235 return; 225 return;
236 226
237#if ENABLE_FEATURE_COMMAND_EDITING_VI 227#if ENABLE_FEATURE_COMMAND_EDITING_VI
@@ -249,7 +239,7 @@ static void input_delete(int save)
249#endif 239#endif
250 240
251 strcpy(command_ps + j, command_ps + j + 1); 241 strcpy(command_ps + j, command_ps + j + 1);
252 len--; 242 command_len--;
253 input_end(); /* rewrite new line */ 243 input_end(); /* rewrite new line */
254 cmdedit_set_out_char(' '); /* erase char */ 244 cmdedit_set_out_char(' '); /* erase char */
255 input_backward(cursor - j); /* back to old pos cursor */ 245 input_backward(cursor - j); /* back to old pos cursor */
@@ -285,7 +275,7 @@ static void input_backspace(void)
285/* Move forward one character */ 275/* Move forward one character */
286static void input_forward(void) 276static void input_forward(void)
287{ 277{
288 if (cursor < len) 278 if (cursor < command_len)
289 cmdedit_set_out_char(command_ps[cursor + 1]); 279 cmdedit_set_out_char(command_ps[cursor + 1]);
290} 280}
291 281
@@ -372,54 +362,50 @@ enum {
372 FIND_FILE_ONLY = 2, 362 FIND_FILE_ONLY = 2,
373}; 363};
374 364
375#if ENABLE_ASH
376const char *cmdedit_path_lookup;
377#endif
378static int path_parse(char ***p, int flags) 365static int path_parse(char ***p, int flags)
379{ 366{
380 int npth; 367 int npth;
381 const char *tmp; 368 const char *tmp;
382#if ENABLE_ASH 369 const char *pth;
383 const char *pth = cmdedit_path_lookup; 370 char **res;
384#else
385 const char *pth = getenv("PATH")
386#endif
387 371
388 /* if not setenv PATH variable, to search cur dir "." */ 372 /* if not setenv PATH variable, to search cur dir "." */
389 if (flags != FIND_EXE_ONLY) 373 if (flags != FIND_EXE_ONLY)
390 return 1; 374 return 1;
375
376 if (state->flags & WITH_PATH_LOOKUP)
377 pth = state->path_lookup;
378 else
379 pth = getenv("PATH");
391 /* PATH=<empty> or PATH=:<empty> */ 380 /* PATH=<empty> or PATH=:<empty> */
392 if (!pth || !pth[0] || LONE_CHAR(pth, ':')) 381 if (!pth || !pth[0] || LONE_CHAR(pth, ':'))
393 return 1; 382 return 1;
394 383
395 tmp = pth; 384 tmp = pth;
396 npth = 0; 385 npth = 1; /* path component count */
397
398 while (1) { 386 while (1) {
399 npth++; /* count words is + 1 count ':' */
400 tmp = strchr(tmp, ':'); 387 tmp = strchr(tmp, ':');
401 if (!tmp) 388 if (!tmp)
402 break; 389 break;
403 if (*++tmp == '\0') 390 if (*++tmp == '\0')
404 break; /* :<empty> */ 391 break; /* :<empty> */
392 npth++;
405 } 393 }
406 394
407 *p = xmalloc(npth * sizeof(char *)); 395 res = xmalloc(npth * sizeof(char*));
408 396 res[0] = xstrdup(pth);
409 tmp = pth; 397 tmp = pth;
410 (*p)[0] = xstrdup(tmp); 398 npth = 1;
411 npth = 1; /* count words is + 1 count ':' */
412
413 while (1) { 399 while (1) {
414 tmp = strchr(tmp, ':'); 400 tmp = strchr(tmp, ':');
415 if (!tmp) 401 if (!tmp)
416 break; 402 break;
417 (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ 403 *tmp++ = '\0'; /* ':' -> '\0' */
418 if (*++tmp == 0) 404 if (*tmp == '\0')
419 break; /* :<empty> */ 405 break; /* :<empty> */
420 (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ 406 res[npth++] = tmp;
421 } 407 }
422 408 *p = res;
423 return npth; 409 return npth;
424} 410}
425 411
@@ -742,6 +728,9 @@ static int match_compare(const void *a, const void *b)
742/* Do TAB completion */ 728/* Do TAB completion */
743static void input_tab(int *lastWasTab) 729static void input_tab(int *lastWasTab)
744{ 730{
731 if (!(state->flags & TAB_COMPLETION))
732 return;
733
745 if (!*lastWasTab) { 734 if (!*lastWasTab) {
746 char *tmp, *tmp1; 735 char *tmp, *tmp1;
747 int len_found; 736 int len_found;
@@ -764,13 +753,13 @@ static void input_tab(int *lastWasTab)
764#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 753#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
765 /* If the word starts with `~' and there is no slash in the word, 754 /* If the word starts with `~' and there is no slash in the word,
766 * then try completing this word as a username. */ 755 * then try completing this word as a username. */
767 756 if (state->flags & USERNAME_COMPLETION)
768 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) 757 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0)
769 username_tab_completion(matchBuf, NULL); 758 username_tab_completion(matchBuf, NULL);
770 if (!matches)
771#endif 759#endif
772 /* Try to match any executable in our path and everything 760 /* Try to match any executable in our path and everything
773 * in the current working directory */ 761 * in the current working directory */
762 if (!matches)
774 exe_n_cwd_tab_completion(matchBuf, find_type); 763 exe_n_cwd_tab_completion(matchBuf, find_type);
775 /* Sort, then remove any duplicates found */ 764 /* Sort, then remove any duplicates found */
776 if (matches) { 765 if (matches) {
@@ -855,51 +844,48 @@ static void input_tab(int *lastWasTab)
855 } 844 }
856} 845}
857 846
847#else
848#define input_tab(a) ((void)0)
858#endif /* FEATURE_COMMAND_TAB_COMPLETION */ 849#endif /* FEATURE_COMMAND_TAB_COMPLETION */
859 850
860 851
861#if MAX_HISTORY > 0 852#if MAX_HISTORY > 0
862 853
863static char *history[MAX_HISTORY+1]; /* history + current */ 854/* state->flags is already checked to be nonzero */
864/* saved history lines */
865static int n_history;
866/* current pointer to history line */
867static int cur_history;
868
869static void get_previous_history(void) 855static void get_previous_history(void)
870{ 856{
871 if (command_ps[0] != '\0' || history[cur_history] == NULL) { 857 if (command_ps[0] != '\0' || state->history[state->cur_history] == NULL) {
872 free(history[cur_history]); 858 free(state->history[state->cur_history]);
873 history[cur_history] = xstrdup(command_ps); 859 state->history[state->cur_history] = xstrdup(command_ps);
874 } 860 }
875 cur_history--; 861 state->cur_history--;
876} 862}
877 863
878static int get_next_history(void) 864static int get_next_history(void)
879{ 865{
880 int ch = cur_history; 866 if (state->flags & DO_HISTORY) {
881 867 int ch = state->cur_history;
882 if (ch < n_history) { 868 if (ch < state->cnt_history) {
883 get_previous_history(); /* save the current history line */ 869 get_previous_history(); /* save the current history line */
884 cur_history = ch + 1; 870 state->cur_history = ch + 1;
885 return cur_history; 871 return state->cur_history;
886 } else { 872 }
887 beep();
888 return 0;
889 } 873 }
874 beep();
875 return 0;
890} 876}
891 877
892#if ENABLE_FEATURE_COMMAND_SAVEHISTORY 878#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
879/* state->flags is already checked to be nonzero */
893void load_history(const char *fromfile) 880void load_history(const char *fromfile)
894{ 881{
895 FILE *fp; 882 FILE *fp;
896 int hi; 883 int hi;
897 884
898 /* cleanup old */ 885 /* cleanup old */
899 886 for (hi = state->cnt_history; hi > 0;) {
900 for (hi = n_history; hi > 0;) {
901 hi--; 887 hi--;
902 free(history[hi]); 888 free(state->history[hi]);
903 } 889 }
904 890
905 fp = fopen(fromfile, "r"); 891 fp = fopen(fromfile, "r");
@@ -917,29 +903,62 @@ void load_history(const char *fromfile)
917 free(hl); 903 free(hl);
918 continue; 904 continue;
919 } 905 }
920 history[hi++] = hl; 906 state->history[hi++] = hl;
921 } 907 }
922 fclose(fp); 908 fclose(fp);
923 } 909 }
924 cur_history = n_history = hi; 910 state->cur_history = state->cnt_history = hi;
925} 911}
926 912
913/* state->flags is already checked to be nonzero */
927void save_history(const char *tofile) 914void save_history(const char *tofile)
928{ 915{
929 FILE *fp = fopen(tofile, "w"); 916 FILE *fp;
930 917
918 fp = fopen(tofile, "w");
931 if (fp) { 919 if (fp) {
932 int i; 920 int i;
933 921
934 for (i = 0; i < n_history; i++) { 922 for (i = 0; i < state->cnt_history; i++) {
935 fprintf(fp, "%s\n", history[i]); 923 fprintf(fp, "%s\n", state->history[i]);
936 } 924 }
937 fclose(fp); 925 fclose(fp);
938 } 926 }
939} 927}
928#else
929#define load_history(a) ((void)0)
930#define save_history(a) ((void)0)
940#endif /* FEATURE_COMMAND_SAVEHISTORY */ 931#endif /* FEATURE_COMMAND_SAVEHISTORY */
941 932
942#endif /* MAX_HISTORY > 0 */ 933static void remember_in_history(const char *str)
934{
935 int i;
936
937 if (!(state->flags & DO_HISTORY))
938 return;
939
940 i = state->cnt_history;
941 free(state->history[MAX_HISTORY]);
942 state->history[MAX_HISTORY] = NULL;
943 /* After max history, remove the oldest command */
944 if (i >= MAX_HISTORY) {
945 free(state->history[0]);
946 for (i = 0; i < MAX_HISTORY-1; i++)
947 state->history[i] = state->history[i+1];
948 }
949// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..."
950// (i.e. do not save dups?)
951 state->history[i++] = xstrdup(str);
952 state->cur_history = i;
953 state->cnt_history = i;
954 if (state->flags & SAVE_HISTORY)
955 save_history(state->hist_file);
956 USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;)
957}
958
959#else /* MAX_HISTORY == 0 */
960#define remember_in_history(a) ((void)0)
961#endif /* MAX_HISTORY */
943 962
944 963
945/* 964/*
@@ -960,13 +979,6 @@ void save_history(const char *tofile)
960 */ 979 */
961 980
962#if ENABLE_FEATURE_COMMAND_EDITING_VI 981#if ENABLE_FEATURE_COMMAND_EDITING_VI
963static int vi_mode;
964
965void setvimode(int viflag)
966{
967 vi_mode = viflag;
968}
969
970static void 982static void
971vi_Word_motion(char *command, int eat) 983vi_Word_motion(char *command, int eat)
972{ 984{
@@ -1058,13 +1070,11 @@ vi_back_motion(char *command)
1058 input_backward(1); 1070 input_backward(1);
1059 } 1071 }
1060} 1072}
1061#else
1062enum { vi_mode = 0 };
1063#endif 1073#endif
1064 1074
1065 1075
1066/* 1076/*
1067 * cmdedit_read_input and its helpers 1077 * read_line_input and its helpers
1068 */ 1078 */
1069 1079
1070#if !ENABLE_FEATURE_SH_FANCY_PROMPT 1080#if !ENABLE_FEATURE_SH_FANCY_PROMPT
@@ -1190,7 +1200,7 @@ static void parse_prompt(const char *prmt_ptr)
1190 cmdedit_prmt_len += cur_prmt_len; 1200 cmdedit_prmt_len += cur_prmt_len;
1191 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); 1201 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
1192 } 1202 }
1193 if (pwd_buf!=(char *)bb_msg_unknown) 1203 if (pwd_buf != (char *)bb_msg_unknown)
1194 free(pwd_buf); 1204 free(pwd_buf);
1195 cmdedit_prompt = prmt_mem_ptr; 1205 cmdedit_prompt = prmt_mem_ptr;
1196 put_prompt(); 1206 put_prompt();
@@ -1217,7 +1227,7 @@ static void cmdedit_setwidth(unsigned w, int redraw_flg)
1217 /* new y for current cursor */ 1227 /* new y for current cursor */
1218 int new_y = (cursor + cmdedit_prmt_len) / w; 1228 int new_y = (cursor + cmdedit_prmt_len) / w;
1219 /* redraw */ 1229 /* redraw */
1220 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); 1230 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
1221 fflush(stdout); 1231 fflush(stdout);
1222 } 1232 }
1223} 1233}
@@ -1275,9 +1285,10 @@ static void cmdedit_init(void)
1275#undef CTRL 1285#undef CTRL
1276#define CTRL(a) ((a) & ~0x40) 1286#define CTRL(a) ((a) & ~0x40)
1277 1287
1278 1288int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *st)
1279int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1280{ 1289{
1290 static const int null_flags;
1291
1281 int lastWasTab = FALSE; 1292 int lastWasTab = FALSE;
1282 unsigned int ic; 1293 unsigned int ic;
1283 unsigned char c; 1294 unsigned char c;
@@ -1286,18 +1297,28 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1286 smallint vi_cmdmode = 0; 1297 smallint vi_cmdmode = 0;
1287 smalluint prevc; 1298 smalluint prevc;
1288#endif 1299#endif
1300
1301// FIXME: audit & improve this
1302 if (maxsize > BUFSIZ)
1303 maxsize = BUFSIZ;
1304
1305 /* With null flags, no other fields are ever used */
1306 state = st ? st : (line_input_t*) &null_flags;
1307 if (state->flags & SAVE_HISTORY)
1308 load_history(state->hist_file);
1309
1289 /* prepare before init handlers */ 1310 /* prepare before init handlers */
1290 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ 1311 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
1291 len = 0; 1312 command_len = 0;
1292 command_ps = command; 1313 command_ps = command;
1293 command[0] = '\0'; 1314 command[0] = '\0';
1294 1315
1295 getTermSettings(0, (void *) &initial_settings); 1316 getTermSettings(0, (void *) &initial_settings);
1296 memcpy(&new_settings, &initial_settings, sizeof(struct termios)); 1317 memcpy(&new_settings, &initial_settings, sizeof(new_settings));
1297 new_settings.c_lflag &= ~ICANON; /* unbuffered input */ 1318 new_settings.c_lflag &= ~ICANON; /* unbuffered input */
1298 /* Turn off echoing and CTRL-C, so we can trap it */ 1319 /* Turn off echoing and CTRL-C, so we can trap it */
1299 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); 1320 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);
1300 /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ 1321 /* Hmm, in linux c_cc[] is not parsed if ICANON is off */
1301 new_settings.c_cc[VMIN] = 1; 1322 new_settings.c_cc[VMIN] = 1;
1302 new_settings.c_cc[VTIME] = 0; 1323 new_settings.c_cc[VTIME] = 0;
1303 /* Turn off CTRL-C, so we can trap it */ 1324 /* Turn off CTRL-C, so we can trap it */
@@ -1354,34 +1375,18 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1354 vi_case(CTRL('C')|vbit:) 1375 vi_case(CTRL('C')|vbit:)
1355 /* Control-c -- stop gathering input */ 1376 /* Control-c -- stop gathering input */
1356 goto_new_line(); 1377 goto_new_line();
1357#if !ENABLE_ASH 1378 command_len = 0;
1358 command[0] = '\0'; 1379 break_out = -1; /* "do not append '\n'" */
1359 len = 0;
1360 lastWasTab = FALSE;
1361 put_prompt();
1362#else
1363 len = 0;
1364 break_out = -1; /* to control traps */
1365#endif
1366 break; 1380 break;
1367 case CTRL('D'): 1381 case CTRL('D'):
1368 /* Control-d -- Delete one character, or exit 1382 /* Control-d -- Delete one character, or exit
1369 * if the len=0 and no chars to delete */ 1383 * if the len=0 and no chars to delete */
1370 if (len == 0) { 1384 if (command_len == 0) {
1371 errno = 0; 1385 errno = 0;
1372 prepare_to_die: 1386 prepare_to_die:
1373// So, our API depends on whether we have ash compiled in or not? Crap...
1374#if !ENABLE_ASH
1375 printf("exit");
1376 goto_new_line();
1377 /* cmdedit_reset_term() called in atexit */
1378// FIXME. this is definitely not good
1379 exit(EXIT_SUCCESS);
1380#else
1381 /* to control stopped jobs */ 1387 /* to control stopped jobs */
1382 break_out = len = -1; 1388 break_out = command_len = -1;
1383 break; 1389 break;
1384#endif
1385 } 1390 }
1386 input_delete(0); 1391 input_delete(0);
1387 break; 1392 break;
@@ -1407,23 +1412,21 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1407 break; 1412 break;
1408 1413
1409 case '\t': 1414 case '\t':
1410#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1411 input_tab(&lastWasTab); 1415 input_tab(&lastWasTab);
1412#endif
1413 break; 1416 break;
1414 1417
1415#if ENABLE_FEATURE_EDITING_FANCY_KEYS 1418#if ENABLE_FEATURE_EDITING_FANCY_KEYS
1416 case CTRL('K'): 1419 case CTRL('K'):
1417 /* Control-k -- clear to end of line */ 1420 /* Control-k -- clear to end of line */
1418 command[cursor] = 0; 1421 command[cursor] = 0;
1419 len = cursor; 1422 command_len = cursor;
1420 printf("\033[J"); 1423 printf("\033[J");
1421 break; 1424 break;
1422 case CTRL('L'): 1425 case CTRL('L'):
1423 vi_case(CTRL('L')|vbit:) 1426 vi_case(CTRL('L')|vbit:)
1424 /* Control-l -- clear screen */ 1427 /* Control-l -- clear screen */
1425 printf("\033[H"); 1428 printf("\033[H");
1426 redraw(0, len - cursor); 1429 redraw(0, command_len - cursor);
1427 break; 1430 break;
1428#endif 1431#endif
1429 1432
@@ -1439,12 +1442,11 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1439 vi_case(CTRL('P')|vbit:) 1442 vi_case(CTRL('P')|vbit:)
1440 vi_case('k'|vbit:) 1443 vi_case('k'|vbit:)
1441 /* Control-p -- Get previous command from history */ 1444 /* Control-p -- Get previous command from history */
1442 if (cur_history > 0) { 1445 if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
1443 get_previous_history(); 1446 get_previous_history();
1444 goto rewrite_line; 1447 goto rewrite_line;
1445 } else {
1446 beep();
1447 } 1448 }
1449 beep();
1448 break; 1450 break;
1449#endif 1451#endif
1450 1452
@@ -1454,7 +1456,8 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1454 /* Control-U -- Clear line before cursor */ 1456 /* Control-U -- Clear line before cursor */
1455 if (cursor) { 1457 if (cursor) {
1456 strcpy(command, command + cursor); 1458 strcpy(command, command + cursor);
1457 redraw(cmdedit_y, len -= cursor); 1459 command_len -= cursor;
1460 redraw(cmdedit_y, command_len);
1458 } 1461 }
1459 break; 1462 break;
1460#endif 1463#endif
@@ -1571,7 +1574,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1571 break; 1574 break;
1572 case '$': /* "d$", "c$" */ 1575 case '$': /* "d$", "c$" */
1573 clear_to_eol: 1576 clear_to_eol:
1574 while (cursor < len) 1577 while (cursor < command_len)
1575 input_delete(1); 1578 input_delete(1);
1576 break; 1579 break;
1577 } 1580 }
@@ -1599,7 +1602,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1599 case '\x1b': /* ESC */ 1602 case '\x1b': /* ESC */
1600 1603
1601#if ENABLE_FEATURE_COMMAND_EDITING_VI 1604#if ENABLE_FEATURE_COMMAND_EDITING_VI
1602 if (vi_mode) { 1605 if (state->flags & VI_MODE) {
1603 /* ESC: insert mode --> command mode */ 1606 /* ESC: insert mode --> command mode */
1604 vi_cmdmode = 1; 1607 vi_cmdmode = 1;
1605 input_backward(1); 1608 input_backward(1);
@@ -1634,7 +1637,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1634#if MAX_HISTORY > 0 1637#if MAX_HISTORY > 0
1635 case 'A': 1638 case 'A':
1636 /* Up Arrow -- Get previous command from history */ 1639 /* Up Arrow -- Get previous command from history */
1637 if (cur_history > 0) { 1640 if ((state->flags & DO_HISTORY) && state->cur_history > 0) {
1638 get_previous_history(); 1641 get_previous_history();
1639 goto rewrite_line; 1642 goto rewrite_line;
1640 } 1643 }
@@ -1647,9 +1650,9 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1647 rewrite_line: 1650 rewrite_line:
1648 /* Rewrite the line with the selected history item */ 1651 /* Rewrite the line with the selected history item */
1649 /* change command */ 1652 /* change command */
1650 len = strlen(strcpy(command, history[cur_history])); 1653 command_len = strlen(strcpy(command, state->history[state->cur_history]));
1651 /* redraw and go to eol (bol, in vi */ 1654 /* redraw and go to eol (bol, in vi */
1652 redraw(cmdedit_y, vi_mode ? 9999 : 0); 1655 redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0);
1653 break; 1656 break;
1654#endif 1657#endif
1655 case 'C': 1658 case 'C':
@@ -1700,18 +1703,18 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1700 if (!Isprint(c)) /* Skip non-printable characters */ 1703 if (!Isprint(c)) /* Skip non-printable characters */
1701 break; 1704 break;
1702 1705
1703 if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ 1706 if (command_len >= (maxsize - 2)) /* Need to leave space for enter */
1704 break; 1707 break;
1705 1708
1706 len++; 1709 command_len++;
1707 if (cursor == (len - 1)) { /* Append if at the end of the line */ 1710 if (cursor == (command_len - 1)) { /* Append if at the end of the line */
1708 command[cursor] = c; 1711 command[cursor] = c;
1709 command[cursor+1] = '\0'; 1712 command[cursor+1] = '\0';
1710 cmdedit_set_out_char(' '); 1713 cmdedit_set_out_char(' ');
1711 } else { /* Insert otherwise */ 1714 } else { /* Insert otherwise */
1712 int sc = cursor; 1715 int sc = cursor;
1713 1716
1714 memmove(command + sc + 1, command + sc, len - sc); 1717 memmove(command + sc + 1, command + sc, command_len - sc);
1715 command[sc] = c; 1718 command[sc] = c;
1716 sc++; 1719 sc++;
1717 /* rewrite from cursor */ 1720 /* rewrite from cursor */
@@ -1728,35 +1731,12 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1728 lastWasTab = FALSE; 1731 lastWasTab = FALSE;
1729 } 1732 }
1730 1733
1731#if MAX_HISTORY > 0 1734 if (command_len > 0)
1732 /* Handle command history log */ 1735 remember_in_history(command);
1733 /* cleanup may be saved current command line */
1734 if (len > 0) {
1735 int i = n_history;
1736
1737 free(history[MAX_HISTORY]);
1738 history[MAX_HISTORY] = NULL;
1739 /* After max history, remove the oldest command */
1740 if (i >= MAX_HISTORY) {
1741 free(history[0]);
1742 for (i = 0; i < MAX_HISTORY-1; i++)
1743 history[i] = history[i+1];
1744 }
1745// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..."
1746// (i.e. do not save dups?)
1747 history[i++] = xstrdup(command);
1748 cur_history = i;
1749 n_history = i;
1750 USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;)
1751 }
1752#else /* MAX_HISTORY == 0 */
1753 /* dont put empty line */
1754 USE_FEATURE_SH_FANCY_PROMPT(if (len > 0) num_ok_lines++;)
1755#endif /* MAX_HISTORY */
1756 1736
1757 if (break_out > 0) { 1737 if (break_out > 0) {
1758 command[len++] = '\n'; 1738 command[command_len++] = '\n';
1759 command[len] = '\0'; 1739 command[command_len] = '\0';
1760 } 1740 }
1761 1741
1762#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION 1742#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION
@@ -1764,11 +1744,29 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1764#endif 1744#endif
1765 1745
1766#if ENABLE_FEATURE_SH_FANCY_PROMPT 1746#if ENABLE_FEATURE_SH_FANCY_PROMPT
1767 free(cmdedit_prompt); 1747 free((char*)cmdedit_prompt);
1768#endif 1748#endif
1769 /* restore initial_settings and SIGWINCH handler */ 1749 /* restore initial_settings and SIGWINCH handler */
1770 cmdedit_reset_term(); 1750 cmdedit_reset_term();
1771 return len; 1751 return command_len;
1752}
1753
1754line_input_t *new_line_input_t(int flags)
1755{
1756 line_input_t *n = xzalloc(sizeof(*n));
1757 n->flags = flags;
1758 return n;
1759}
1760
1761#else
1762
1763#undef read_line_input
1764int read_line_input(const char* prompt, char* command, int maxsize)
1765{
1766 fputs(prompt, stdout);
1767 fflush(stdout);
1768 fgets(command, maxsize, stdin);
1769 return strlen(command);
1772} 1770}
1773 1771
1774#endif /* FEATURE_COMMAND_EDITING */ 1772#endif /* FEATURE_COMMAND_EDITING */
@@ -1801,13 +1799,13 @@ int main(int argc, char **argv)
1801#endif 1799#endif
1802 while (1) { 1800 while (1) {
1803 int l; 1801 int l;
1804 l = cmdedit_read_input(prompt, buff); 1802 l = read_line_input(prompt, buff);
1805 if (l <= 0 || buff[l-1] != '\n') 1803 if (l <= 0 || buff[l-1] != '\n')
1806 break; 1804 break;
1807 buff[l-1] = 0; 1805 buff[l-1] = 0;
1808 printf("*** cmdedit_read_input() returned line =%s=\n", buff); 1806 printf("*** read_line_input() returned line =%s=\n", buff);
1809 } 1807 }
1810 printf("*** cmdedit_read_input() detect ^D\n"); 1808 printf("*** read_line_input() detect ^D\n");
1811 return 0; 1809 return 0;
1812} 1810}
1813 1811