aboutsummaryrefslogtreecommitdiff
path: root/shell/cmdedit.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-22 07:21:38 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-22 07:21:38 +0000
commit8e1c71529c2bf38a04d4a117e625e59044a0785a (patch)
tree2f115293c25e7ee9307f268ec198e2cf486ff070 /shell/cmdedit.c
parent00cdbd8fc20a4e2e2208f90a2691a3806c931b06 (diff)
downloadbusybox-w32-8e1c71529c2bf38a04d4a117e625e59044a0785a.tar.gz
busybox-w32-8e1c71529c2bf38a04d4a117e625e59044a0785a.tar.bz2
busybox-w32-8e1c71529c2bf38a04d4a117e625e59044a0785a.zip
Convert cmdedit into more generic line input facility
(make history and completion optional at runtime). Use it for fdisk, as an example. Some unrelated fixes in fdisk are also here.
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