aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-21 19:18:19 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-21 19:18:19 +0000
commit82b39e83ab13660f0b76a52519e1ac44e30fff7c (patch)
tree196849676460770eb35aaf240cbe68cb5238de45
parent7b1f23610f4e9ba08b1f12e25fb1301b321bf584 (diff)
downloadbusybox-w32-82b39e83ab13660f0b76a52519e1ac44e30fff7c.tar.gz
busybox-w32-82b39e83ab13660f0b76a52519e1ac44e30fff7c.tar.bz2
busybox-w32-82b39e83ab13660f0b76a52519e1ac44e30fff7c.zip
sanitize cmdedit a bit (group functions by task etc)
-rw-r--r--shell/cmdedit.c759
-rw-r--r--shell/cmdedit.h4
2 files changed, 368 insertions, 395 deletions
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index 32001324f..617f3a29a 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -28,19 +28,11 @@
28 - not true viewing if length prompt less terminal width 28 - not true viewing if length prompt less terminal width
29 */ 29 */
30 30
31#include "busybox.h"
32#include <sys/ioctl.h> 31#include <sys/ioctl.h>
33 32#include "busybox.h"
34#include "cmdedit.h" 33#include "cmdedit.h"
35 34
36 35
37#if ENABLE_LOCALE_SUPPORT
38#define Isprint(c) isprint(c)
39#else
40#define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
41#endif
42
43
44/* FIXME: obsolete CONFIG item? */ 36/* FIXME: obsolete CONFIG item? */
45#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 37#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
46 38
@@ -56,38 +48,34 @@
56#endif /* TEST */ 48#endif /* TEST */
57 49
58 50
51/* Entire file (except TESTing part) sits inside this #if */
59#if ENABLE_FEATURE_COMMAND_EDITING 52#if ENABLE_FEATURE_COMMAND_EDITING
60 53
54
55#if ENABLE_LOCALE_SUPPORT
56#define Isprint(c) isprint(c)
57#else
58#define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233'))
59#endif
60
61#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ 61#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
62(ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT) 62(ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT)
63 63
64/* Maximum length of the linked list for the command line history */ 64/* Maximum length of command line history */
65#if !ENABLE_FEATURE_COMMAND_HISTORY 65#if !ENABLE_FEATURE_COMMAND_HISTORY
66#define MAX_HISTORY 15 66#define MAX_HISTORY 15
67#else 67#else
68#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0) 68#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0)
69#endif 69#endif
70 70
71#if MAX_HISTORY > 0
72static char *history[MAX_HISTORY+1]; /* history + current */
73/* saved history lines */
74static int n_history;
75/* current pointer to history line */
76static int cur_history;
77#endif
78 71
79#define setTermSettings(fd,argp) tcsetattr(fd, TCSANOW, argp) 72/* Current termios and the previous termios before starting sh */
80#define getTermSettings(fd,argp) tcgetattr(fd, argp);
81
82/* Current termio and the previous termio before starting sh */
83static struct termios initial_settings, new_settings; 73static struct termios initial_settings, new_settings;
84 74
85
86static 75static
87volatile int cmdedit_termw = 80; /* actual terminal width */ 76volatile unsigned cmdedit_termw = 80; /* actual terminal width */
88static 77static
89volatile int handlers_sets = 0; /* Set next bites: */ 78volatile int handlers_sets = 0; /* Set next bits: */
90
91enum { 79enum {
92 SET_ATEXIT = 1, /* when atexit() has been called 80 SET_ATEXIT = 1, /* when atexit() has been called
93 and get euid,uid,gid to fast compare */ 81 and get euid,uid,gid to fast compare */
@@ -98,84 +86,46 @@ enum {
98 86
99static int cmdedit_x; /* real x terminal position */ 87static int cmdedit_x; /* real x terminal position */
100static int cmdedit_y; /* pseudoreal y terminal position */ 88static int cmdedit_y; /* pseudoreal y terminal position */
101static int cmdedit_prmt_len; /* lenght prompt without colores string */ 89static int cmdedit_prmt_len; /* length of prompt without colores string */
102
103static int cursor; /* required globals for signal handler */
104static int len; /* --- "" - - "" -- -"- --""-- --""--- */
105static char *command_ps; /* --- "" - - "" -- -"- --""-- --""--- */
106static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; /* -- */
107 90
108#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR 91static int cursor;
109static char *user_buf = ""; 92static int len;
110static char *home_pwd_buf = ""; 93static char *command_ps;
111static int my_euid; 94static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt;
112#endif
113 95
114#if ENABLE_FEATURE_SH_FANCY_PROMPT 96#if ENABLE_FEATURE_SH_FANCY_PROMPT
115static char *hostname_buf; 97static char *hostname_buf;
116static int num_ok_lines = 1; 98static int num_ok_lines = 1;
117#endif 99#endif
118 100
101#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
102static char *user_buf = "";
103static char *home_pwd_buf = "";
104#endif
119 105
120#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION 106#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR || ENABLE_FEATURE_COMMAND_TAB_COMPLETION
121
122#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
123static int my_euid; 107static int my_euid;
124#endif 108#endif
125 109
110#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
126static int my_uid; 111static int my_uid;
127static int my_gid; 112static int my_gid;
113#endif
128 114
129#endif /* FEATURE_COMMAND_TAB_COMPLETION */ 115/* Put 'command_ps[cursor]', cursor++.
130 116 * Advance cursor on screen. If we reached right margin, scroll text up
131static void cmdedit_setwidth(int w, int redraw_flg); 117 * and remove terminal margin effect by printing 'next_char' */
132
133static void win_changed(int nsig)
134{
135 static sighandler_t previous_SIGWINCH_handler; /* for reset */
136
137 /* emulate || signal call */
138 if (nsig == -SIGWINCH || nsig == SIGWINCH) {
139 int width = 0;
140 get_terminal_width_height(0, &width, NULL);
141 cmdedit_setwidth(width, nsig == SIGWINCH);
142 }
143 /* Unix not all standard in recall signal */
144
145 if (nsig == -SIGWINCH) /* save previous handler */
146 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
147 else if (nsig == SIGWINCH) /* signaled called handler */
148 signal(SIGWINCH, win_changed); /* set for next call */
149 else /* nsig == 0 */
150 /* set previous handler */
151 signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */
152}
153
154static void cmdedit_reset_term(void)
155{
156 if (handlers_sets & SET_RESET_TERM) {
157/* sparc and other have broken termios support: use old termio handling. */
158 setTermSettings(STDIN_FILENO, (void *) &initial_settings);
159 handlers_sets &= ~SET_RESET_TERM;
160 }
161 if (handlers_sets & SET_WCHG_HANDLERS) {
162 /* reset SIGWINCH handler to previous (default) */
163 win_changed(0);
164 handlers_sets &= ~SET_WCHG_HANDLERS;
165 }
166 fflush(stdout);
167}
168
169
170/* special for recount position for scroll and remove terminal margin effect */
171static void cmdedit_set_out_char(int next_char) 118static void cmdedit_set_out_char(int next_char)
172{ 119{
173 int c = (unsigned char)command_ps[cursor]; 120 int c = (unsigned char)command_ps[cursor];
174 121
175 if (c == 0) 122 if (c == '\0') {
176 c = ' '; /* destroy end char? */ 123 /* erase character after end of input string */
124 c = ' ';
125 }
177#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 126#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
178 if (!Isprint(c)) { /* Inverse put non-printable characters */ 127 /* Display non-printable characters in reverse */
128 if (!Isprint(c)) {
179 if (c >= 128) 129 if (c >= 128)
180 c -= 128; 130 c -= 128;
181 if (c < ' ') 131 if (c < ' ')
@@ -193,21 +143,19 @@ static void cmdedit_set_out_char(int next_char)
193 /* terminal is scrolled down */ 143 /* terminal is scrolled down */
194 cmdedit_y++; 144 cmdedit_y++;
195 cmdedit_x = 0; 145 cmdedit_x = 0;
196
197 if (!next_char)
198 next_char = ' ';
199 /* destroy "(auto)margin" */ 146 /* destroy "(auto)margin" */
200 putchar(next_char); 147 putchar(next_char);
201 putchar('\b'); 148 putchar('\b');
202 } 149 }
150// Huh? What if command_ps[cursor] == '\0' (we are at the end already?)
203 cursor++; 151 cursor++;
204} 152}
205 153
206/* Move to end line. Bonus: rewrite line from cursor */ 154/* Move to end of line (by printing all chars till the end) */
207static void input_end(void) 155static void input_end(void)
208{ 156{
209 while (cursor < len) 157 while (cursor < len)
210 cmdedit_set_out_char(0); 158 cmdedit_set_out_char(' ');
211} 159}
212 160
213/* Go to the next line */ 161/* Go to the next line */
@@ -238,26 +186,32 @@ static void input_backward(int num)
238 num = cursor; 186 num = cursor;
239 cursor -= num; /* new cursor (in command, not terminal) */ 187 cursor -= num; /* new cursor (in command, not terminal) */
240 188
241 if (cmdedit_x >= num) { /* no to up line */ 189 if (cmdedit_x >= num) {
242 cmdedit_x -= num; 190 cmdedit_x -= num;
243 if (num < 4) 191 if (num <= 4)
244 while (num-- > 0) 192 while (num > 0) {
245 putchar('\b'); 193 putchar('\b');
194 num--;
195 }
246 else 196 else
247 printf("\033[%dD", num); 197 printf("\033[%dD", num);
248 } else { 198 } else {
199 /* Need to go one or more lines up */
249 int count_y; 200 int count_y;
250 201
251 if (cmdedit_x) { 202 //if (cmdedit_x) {
252 putchar('\r'); /* back to first terminal pos. */ 203 // /* back to first column */
253 num -= cmdedit_x; /* set previous backward */ 204 // putchar('\r');
254 } 205 // num -= cmdedit_x;
206 //}
207 num -= cmdedit_x;//
255 count_y = 1 + num / cmdedit_termw; 208 count_y = 1 + num / cmdedit_termw;
256 printf("\033[%dA", count_y); 209 //printf("\033[%dA", count_y);
257 cmdedit_y -= count_y; 210 cmdedit_y -= count_y;
258 /* require forward after uping */
259 cmdedit_x = cmdedit_termw * count_y - num; 211 cmdedit_x = cmdedit_termw * count_y - num;
260 printf("\033[%dC", cmdedit_x); /* set term cursor */ 212 //printf("\033[%dC", cmdedit_x);
213 /* go to 1st col; go up; go to correct column */
214 printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x);//
261 } 215 }
262} 216}
263 217
@@ -269,136 +223,6 @@ static void put_prompt(void)
269 cmdedit_y = 0; /* new quasireal y */ 223 cmdedit_y = 0; /* new quasireal y */
270} 224}
271 225
272#if !ENABLE_FEATURE_SH_FANCY_PROMPT
273static void parse_prompt(const char *prmt_ptr)
274{
275 cmdedit_prompt = prmt_ptr;
276 cmdedit_prmt_len = strlen(prmt_ptr);
277 put_prompt();
278}
279#else
280static void parse_prompt(const char *prmt_ptr)
281{
282 int prmt_len = 0;
283 size_t cur_prmt_len = 0;
284 char flg_not_length = '[';
285 char *prmt_mem_ptr = xzalloc(1);
286 char *pwd_buf = xgetcwd(0);
287 char buf2[PATH_MAX + 1];
288 char buf[2];
289 char c;
290 char *pbuf;
291
292 if (!pwd_buf) {
293 pwd_buf = (char *)bb_msg_unknown;
294 }
295
296 while (*prmt_ptr) {
297 pbuf = buf;
298 pbuf[1] = 0;
299 c = *prmt_ptr++;
300 if (c == '\\') {
301 const char *cp = prmt_ptr;
302 int l;
303
304 c = bb_process_escape_sequence(&prmt_ptr);
305 if (prmt_ptr == cp) {
306 if (*cp == 0)
307 break;
308 c = *prmt_ptr++;
309 switch (c) {
310#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
311 case 'u':
312 pbuf = user_buf;
313 break;
314#endif
315 case 'h':
316 pbuf = hostname_buf;
317 if (pbuf == 0) {
318 pbuf = xzalloc(256);
319 if (gethostname(pbuf, 255) < 0) {
320 strcpy(pbuf, "?");
321 } else {
322 char *s = strchr(pbuf, '.');
323 if (s)
324 *s = 0;
325 }
326 hostname_buf = pbuf;
327 }
328 break;
329 case '$':
330 c = (my_euid == 0 ? '#' : '$');
331 break;
332#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
333 case 'w':
334 pbuf = pwd_buf;
335 l = strlen(home_pwd_buf);
336 if (home_pwd_buf[0] != 0
337 && strncmp(home_pwd_buf, pbuf, l) == 0
338 && (pbuf[l]=='/' || pbuf[l]=='\0')
339 && strlen(pwd_buf+l)<PATH_MAX
340 ) {
341 pbuf = buf2;
342 *pbuf = '~';
343 strcpy(pbuf+1, pwd_buf+l);
344 }
345 break;
346#endif
347 case 'W':
348 pbuf = pwd_buf;
349 cp = strrchr(pbuf,'/');
350 if (cp != NULL && cp != pbuf)
351 pbuf += (cp-pbuf) + 1;
352 break;
353 case '!':
354 snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
355 break;
356 case 'e': case 'E': /* \e \E = \033 */
357 c = '\033';
358 break;
359 case 'x': case 'X':
360 for (l = 0; l < 3;) {
361 int h;
362 buf2[l++] = *prmt_ptr;
363 buf2[l] = 0;
364 h = strtol(buf2, &pbuf, 16);
365 if (h > UCHAR_MAX || (pbuf - buf2) < l) {
366 l--;
367 break;
368 }
369 prmt_ptr++;
370 }
371 buf2[l] = 0;
372 c = (char)strtol(buf2, 0, 16);
373 if (c == 0)
374 c = '?';
375 pbuf = buf;
376 break;
377 case '[': case ']':
378 if (c == flg_not_length) {
379 flg_not_length = flg_not_length == '[' ? ']' : '[';
380 continue;
381 }
382 break;
383 }
384 }
385 }
386 if (pbuf == buf)
387 *pbuf = c;
388 cur_prmt_len = strlen(pbuf);
389 prmt_len += cur_prmt_len;
390 if (flg_not_length != ']')
391 cmdedit_prmt_len += cur_prmt_len;
392 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
393 }
394 if (pwd_buf!=(char *)bb_msg_unknown)
395 free(pwd_buf);
396 cmdedit_prompt = prmt_mem_ptr;
397 put_prompt();
398}
399#endif
400
401
402/* draw prompt, editor line, and clear tail */ 226/* draw prompt, editor line, and clear tail */
403static void redraw(int y, int back_cursor) 227static void redraw(int y, int back_cursor)
404{ 228{
@@ -407,7 +231,7 @@ static void redraw(int y, int back_cursor)
407 putchar('\r'); 231 putchar('\r');
408 put_prompt(); 232 put_prompt();
409 input_end(); /* rewrite */ 233 input_end(); /* rewrite */
410 printf("\033[J"); /* destroy tail after cursor */ 234 printf("\033[J"); /* erase after cursor */
411 input_backward(back_cursor); 235 input_backward(back_cursor);
412} 236}
413 237
@@ -444,14 +268,16 @@ static void input_delete(int save)
444 strcpy(command_ps + j, command_ps + j + 1); 268 strcpy(command_ps + j, command_ps + j + 1);
445 len--; 269 len--;
446 input_end(); /* rewrite new line */ 270 input_end(); /* rewrite new line */
447 cmdedit_set_out_char(0); /* destroy end char */ 271 cmdedit_set_out_char(' '); /* erase char */
448 input_backward(cursor - j); /* back to old pos cursor */ 272 input_backward(cursor - j); /* back to old pos cursor */
449} 273}
450 274
451#if ENABLE_FEATURE_COMMAND_EDITING_VI 275#if ENABLE_FEATURE_COMMAND_EDITING_VI
452static void put(void) 276static void put(void)
453{ 277{
454 int ocursor, j = delp - delbuf; 278 int ocursor;
279 int j = delp - delbuf;
280
455 if (j == 0) 281 if (j == 0)
456 return; 282 return;
457 ocursor = cursor; 283 ocursor = cursor;
@@ -481,60 +307,6 @@ static void input_forward(void)
481 cmdedit_set_out_char(command_ps[cursor + 1]); 307 cmdedit_set_out_char(command_ps[cursor + 1]);
482} 308}
483 309
484static void cmdedit_setwidth(int w, int redraw_flg)
485{
486 cmdedit_termw = cmdedit_prmt_len + 2;
487 if (w <= cmdedit_termw) {
488 cmdedit_termw = cmdedit_termw % w;
489 }
490 if (w > cmdedit_termw) {
491 cmdedit_termw = w;
492
493 if (redraw_flg) {
494 /* new y for current cursor */
495 int new_y = (cursor + cmdedit_prmt_len) / w;
496
497 /* redraw */
498 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
499 fflush(stdout);
500 }
501 }
502}
503
504static void cmdedit_init(void)
505{
506 cmdedit_prmt_len = 0;
507 if (!(handlers_sets & SET_WCHG_HANDLERS)) {
508 /* emulate usage handler to set handler and call yours work */
509 win_changed(-SIGWINCH);
510 handlers_sets |= SET_WCHG_HANDLERS;
511 }
512
513 if (!(handlers_sets & SET_ATEXIT)) {
514#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
515 struct passwd *entry;
516
517 my_euid = geteuid();
518 entry = getpwuid(my_euid);
519 if (entry) {
520 user_buf = xstrdup(entry->pw_name);
521 home_pwd_buf = xstrdup(entry->pw_dir);
522 }
523#endif
524
525#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
526
527#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
528 my_euid = geteuid();
529#endif
530 my_uid = getuid();
531 my_gid = getgid();
532#endif /* FEATURE_COMMAND_TAB_COMPLETION */
533 handlers_sets |= SET_ATEXIT;
534 atexit(cmdedit_reset_term); /* be sure to do this only once */
535 }
536}
537
538#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION 310#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
539 311
540static char **matches; 312static char **matches;
@@ -550,20 +322,6 @@ static void add_match(char *matched)
550 num_matches++; 322 num_matches++;
551} 323}
552 324
553/*
554static int is_execute(const struct stat *st)
555{
556 if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
557 || (my_uid == st->st_uid && (st->st_mode & S_IXUSR))
558 || (my_gid == st->st_gid && (st->st_mode & S_IXGRP))
559 || (st->st_mode & S_IXOTH)
560 ) {
561 return TRUE;
562 }
563 return FALSE;
564}
565*/
566
567#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 325#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
568 326
569static void username_tab_completion(char *ud, char *with_shash_flg) 327static void username_tab_completion(char *ud, char *with_shash_flg)
@@ -624,15 +382,16 @@ enum {
624 382
625#if ENABLE_ASH 383#if ENABLE_ASH
626const char *cmdedit_path_lookup; 384const char *cmdedit_path_lookup;
627#else
628#define cmdedit_path_lookup getenv("PATH")
629#endif 385#endif
630
631static int path_parse(char ***p, int flags) 386static int path_parse(char ***p, int flags)
632{ 387{
633 int npth; 388 int npth;
634 const char *tmp; 389 const char *tmp;
390#if ENABLE_ASH
635 const char *pth = cmdedit_path_lookup; 391 const char *pth = cmdedit_path_lookup;
392#else
393 const char *pth = getenv("PATH")
394#endif
636 395
637 /* if not setenv PATH variable, to search cur dir "." */ 396 /* if not setenv PATH variable, to search cur dir "." */
638 if (flags != FIND_EXE_ONLY) 397 if (flags != FIND_EXE_ONLY)
@@ -649,7 +408,7 @@ static int path_parse(char ***p, int flags)
649 tmp = strchr(tmp, ':'); 408 tmp = strchr(tmp, ':');
650 if (!tmp) 409 if (!tmp)
651 break; 410 break;
652 if (*++tmp == 0) 411 if (*++tmp == '\0')
653 break; /* :<empty> */ 412 break; /* :<empty> */
654 } 413 }
655 414
@@ -672,20 +431,6 @@ static int path_parse(char ***p, int flags)
672 return npth; 431 return npth;
673} 432}
674 433
675static char *add_quote_for_spec_chars(char *found)
676{
677 int l = 0;
678 char *s = xmalloc((strlen(found) + 1) * 2);
679
680 while (*found) {
681 if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
682 s[l++] = '\\';
683 s[l++] = *found++;
684 }
685 s[l] = 0;
686 return s;
687}
688
689static void exe_n_cwd_tab_completion(char *command, int type) 434static void exe_n_cwd_tab_completion(char *command, int type)
690{ 435{
691 DIR *dir; 436 DIR *dir;
@@ -699,6 +444,7 @@ static void exe_n_cwd_tab_completion(char *command, int type)
699 char *found; 444 char *found;
700 char *pfind = strrchr(command, '/'); 445 char *pfind = strrchr(command, '/');
701 446
447 npaths = 1;
702 path1[0] = "."; 448 path1[0] = ".";
703 449
704 if (pfind == NULL) { 450 if (pfind == NULL) {
@@ -706,20 +452,15 @@ static void exe_n_cwd_tab_completion(char *command, int type)
706 npaths = path_parse(&paths, type); 452 npaths = path_parse(&paths, type);
707 pfind = command; 453 pfind = command;
708 } else { 454 } else {
709 /* with dir */ 455 /* dirbuf = ".../.../.../" */
710 /* save for change */ 456 safe_strncpy(dirbuf, command, (pfind - command) + 2);
711 strcpy(dirbuf, command);
712 /* set dir only */
713 dirbuf[(pfind - command) + 1] = 0;
714#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 457#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
715 if (dirbuf[0] == '~') /* ~/... or ~user/... */ 458 if (dirbuf[0] == '~') /* ~/... or ~user/... */
716 username_tab_completion(dirbuf, dirbuf); 459 username_tab_completion(dirbuf, dirbuf);
717#endif 460#endif
718 /* "strip" dirname in command */
719 pfind++;
720
721 paths[0] = dirbuf; 461 paths[0] = dirbuf;
722 npaths = 1; /* only 1 dir */ 462 /* point to 'l' in "..../last_component" */
463 pfind++;
723 } 464 }
724 465
725 for (i = 0; i < npaths; i++) { 466 for (i = 0; i < npaths; i++) {
@@ -994,6 +735,20 @@ static int match_compare(const void *a, const void *b)
994 return strcmp(*(char**)a, *(char**)b); 735 return strcmp(*(char**)a, *(char**)b);
995} 736}
996 737
738static char *add_quote_for_spec_chars(char *found)
739{
740 int l = 0;
741 char *s = xmalloc((strlen(found) + 1) * 2);
742
743 while (*found) {
744 if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found))
745 s[l++] = '\\';
746 s[l++] = *found++;
747 }
748 s[l] = 0;
749 return s;
750}
751
997static void input_tab(int *lastWasTab) 752static void input_tab(int *lastWasTab)
998{ 753{
999 /* Do TAB completion */ 754 /* Do TAB completion */
@@ -1121,7 +876,15 @@ static void input_tab(int *lastWasTab)
1121} 876}
1122#endif /* FEATURE_COMMAND_TAB_COMPLETION */ 877#endif /* FEATURE_COMMAND_TAB_COMPLETION */
1123 878
879
1124#if MAX_HISTORY > 0 880#if MAX_HISTORY > 0
881
882static char *history[MAX_HISTORY+1]; /* history + current */
883/* saved history lines */
884static int n_history;
885/* current pointer to history line */
886static int cur_history;
887
1125static void get_previous_history(void) 888static void get_previous_history(void)
1126{ 889{
1127 if (command_ps[0] != 0 || history[cur_history] == 0) { 890 if (command_ps[0] != 0 || history[cur_history] == 0) {
@@ -1193,14 +956,9 @@ void save_history (const char *tofile)
1193 fclose(fp); 956 fclose(fp);
1194 } 957 }
1195} 958}
1196#endif 959#endif /* FEATURE_COMMAND_SAVEHISTORY */
1197
1198#endif
1199 960
1200enum { 961#endif /* MAX_HISTORY > 0 */
1201 ESC = 27,
1202 DEL = 127,
1203};
1204 962
1205 963
1206/* 964/*
@@ -1217,14 +975,13 @@ enum {
1217 * CTL-t -- Transpose two characters 975 * CTL-t -- Transpose two characters
1218 * 976 *
1219 * Minimalist vi-style command line editing available if configured. 977 * Minimalist vi-style command line editing available if configured.
1220 * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us> 978 * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us>
1221 *
1222 */ 979 */
1223 980
1224#if ENABLE_FEATURE_COMMAND_EDITING_VI 981#if ENABLE_FEATURE_COMMAND_EDITING_VI
1225static int vi_mode; 982static int vi_mode;
1226 983
1227void setvimode ( int viflag ) 984void setvimode(int viflag)
1228{ 985{
1229 vi_mode = viflag; 986 vi_mode = viflag;
1230} 987}
@@ -1320,6 +1077,225 @@ vi_back_motion(char *command)
1320 input_backward(1); 1077 input_backward(1);
1321 } 1078 }
1322} 1079}
1080#else
1081enum { vi_mode = 0 };
1082#endif
1083
1084
1085/*
1086 * cmdedit_read_input and its helpers
1087 */
1088
1089#define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp)
1090#define getTermSettings(fd, argp) tcgetattr(fd, argp);
1091
1092static sighandler_t previous_SIGWINCH_handler;
1093
1094static void cmdedit_reset_term(void)
1095{
1096 if (handlers_sets & SET_RESET_TERM) {
1097 setTermSettings(STDIN_FILENO, (void *) &initial_settings);
1098 handlers_sets &= ~SET_RESET_TERM;
1099 }
1100 if (handlers_sets & SET_WCHG_HANDLERS) {
1101 /* restore SIGWINCH handler */
1102 signal(SIGWINCH, previous_SIGWINCH_handler);
1103 handlers_sets &= ~SET_WCHG_HANDLERS;
1104 }
1105 fflush(stdout);
1106}
1107
1108static void cmdedit_setwidth(int w, int redraw_flg)
1109{
1110 cmdedit_termw = cmdedit_prmt_len + 2;
1111 if (w <= cmdedit_termw) {
1112 cmdedit_termw = cmdedit_termw % w;
1113 }
1114 if (w > cmdedit_termw) {
1115 cmdedit_termw = w;
1116
1117 if (redraw_flg) {
1118 /* new y for current cursor */
1119 int new_y = (cursor + cmdedit_prmt_len) / w;
1120
1121 /* redraw */
1122 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
1123 fflush(stdout);
1124 }
1125 }
1126}
1127
1128static void win_changed(int nsig)
1129{
1130 int width;
1131 get_terminal_width_height(0, &width, NULL);
1132 cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
1133 if (nsig == SIGWINCH)
1134 signal(SIGWINCH, win_changed); /* rearm ourself */
1135}
1136
1137static void cmdedit_init(void)
1138{
1139 cmdedit_prmt_len = 0;
1140 if (!(handlers_sets & SET_WCHG_HANDLERS)) {
1141 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
1142 win_changed(0); /* do initial resizing */
1143 handlers_sets |= SET_WCHG_HANDLERS;
1144 }
1145
1146 if (!(handlers_sets & SET_ATEXIT)) {
1147#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1148 struct passwd *entry;
1149
1150 my_euid = geteuid();
1151 entry = getpwuid(my_euid);
1152 if (entry) {
1153 user_buf = xstrdup(entry->pw_name);
1154 home_pwd_buf = xstrdup(entry->pw_dir);
1155 }
1156#endif
1157
1158#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1159
1160#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1161 my_euid = geteuid();
1162#endif
1163 my_uid = getuid();
1164 my_gid = getgid();
1165#endif /* FEATURE_COMMAND_TAB_COMPLETION */
1166 handlers_sets |= SET_ATEXIT;
1167// Crap. We should be able to do it without atexit.
1168 atexit(cmdedit_reset_term); /* be sure to do this only once */
1169 }
1170}
1171
1172#if !ENABLE_FEATURE_SH_FANCY_PROMPT
1173static void parse_prompt(const char *prmt_ptr)
1174{
1175 cmdedit_prompt = prmt_ptr;
1176 cmdedit_prmt_len = strlen(prmt_ptr);
1177 put_prompt();
1178}
1179#else
1180static void parse_prompt(const char *prmt_ptr)
1181{
1182 int prmt_len = 0;
1183 size_t cur_prmt_len = 0;
1184 char flg_not_length = '[';
1185 char *prmt_mem_ptr = xzalloc(1);
1186 char *pwd_buf = xgetcwd(0);
1187 char buf2[PATH_MAX + 1];
1188 char buf[2];
1189 char c;
1190 char *pbuf;
1191
1192 if (!pwd_buf) {
1193 pwd_buf = (char *)bb_msg_unknown;
1194 }
1195
1196 while (*prmt_ptr) {
1197 pbuf = buf;
1198 pbuf[1] = 0;
1199 c = *prmt_ptr++;
1200 if (c == '\\') {
1201 const char *cp = prmt_ptr;
1202 int l;
1203
1204 c = bb_process_escape_sequence(&prmt_ptr);
1205 if (prmt_ptr == cp) {
1206 if (*cp == 0)
1207 break;
1208 c = *prmt_ptr++;
1209 switch (c) {
1210#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1211 case 'u':
1212 pbuf = user_buf;
1213 break;
1214#endif
1215 case 'h':
1216 pbuf = hostname_buf;
1217 if (!pbuf) {
1218 pbuf = xzalloc(256);
1219 if (gethostname(pbuf, 255) < 0) {
1220 strcpy(pbuf, "?");
1221 } else {
1222 char *s = strchr(pbuf, '.');
1223 if (s)
1224 *s = '\0';
1225 }
1226 hostname_buf = pbuf;
1227 }
1228 break;
1229 case '$':
1230 c = (my_euid == 0 ? '#' : '$');
1231 break;
1232#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1233 case 'w':
1234 pbuf = pwd_buf;
1235 l = strlen(home_pwd_buf);
1236 if (home_pwd_buf[0] != 0
1237 && strncmp(home_pwd_buf, pbuf, l) == 0
1238 && (pbuf[l]=='/' || pbuf[l]=='\0')
1239 && strlen(pwd_buf+l)<PATH_MAX
1240 ) {
1241 pbuf = buf2;
1242 *pbuf = '~';
1243 strcpy(pbuf+1, pwd_buf+l);
1244 }
1245 break;
1246#endif
1247 case 'W':
1248 pbuf = pwd_buf;
1249 cp = strrchr(pbuf,'/');
1250 if (cp != NULL && cp != pbuf)
1251 pbuf += (cp-pbuf) + 1;
1252 break;
1253 case '!':
1254 snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines);
1255 break;
1256 case 'e': case 'E': /* \e \E = \033 */
1257 c = '\033';
1258 break;
1259 case 'x': case 'X':
1260 for (l = 0; l < 3;) {
1261 int h;
1262 buf2[l++] = *prmt_ptr;
1263 buf2[l] = 0;
1264 h = strtol(buf2, &pbuf, 16);
1265 if (h > UCHAR_MAX || (pbuf - buf2) < l) {
1266 l--;
1267 break;
1268 }
1269 prmt_ptr++;
1270 }
1271 buf2[l] = 0;
1272 c = (char)strtol(buf2, NULL, 16);
1273 if (c == 0)
1274 c = '?';
1275 pbuf = buf;
1276 break;
1277 case '[': case ']':
1278 if (c == flg_not_length) {
1279 flg_not_length = flg_not_length == '[' ? ']' : '[';
1280 continue;
1281 }
1282 break;
1283 }
1284 }
1285 }
1286 if (pbuf == buf)
1287 *pbuf = c;
1288 cur_prmt_len = strlen(pbuf);
1289 prmt_len += cur_prmt_len;
1290 if (flg_not_length != ']')
1291 cmdedit_prmt_len += cur_prmt_len;
1292 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
1293 }
1294 if (pwd_buf!=(char *)bb_msg_unknown)
1295 free(pwd_buf);
1296 cmdedit_prompt = prmt_mem_ptr;
1297 put_prompt();
1298}
1323#endif 1299#endif
1324 1300
1325/* 1301/*
@@ -1337,18 +1313,19 @@ vi_back_motion(char *command)
1337#define vi_case(caselabel) USE_FEATURE_COMMAND_EDITING(caselabel) 1313#define vi_case(caselabel) USE_FEATURE_COMMAND_EDITING(caselabel)
1338 1314
1339/* convert uppercase ascii to equivalent control char, for readability */ 1315/* convert uppercase ascii to equivalent control char, for readability */
1340#define CNTRL(uc_char) ((uc_char) - 0x40) 1316#undef CTRL
1317#define CTRL(a) ((a) & ~0x40)
1341 1318
1342 1319
1343int cmdedit_read_input(char *prompt, char command[BUFSIZ]) 1320int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1344{ 1321{
1345 int break_out = 0;
1346 int lastWasTab = FALSE; 1322 int lastWasTab = FALSE;
1347 unsigned char c;
1348 unsigned int ic; 1323 unsigned int ic;
1324 unsigned char c;
1325 smallint break_out = 0;
1349#if ENABLE_FEATURE_COMMAND_EDITING_VI 1326#if ENABLE_FEATURE_COMMAND_EDITING_VI
1350 unsigned int prevc; 1327 smallint vi_cmdmode = 0;
1351 int vi_cmdmode = 0; 1328 smalluint prevc;
1352#endif 1329#endif
1353 /* prepare before init handlers */ 1330 /* prepare before init handlers */
1354 cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ 1331 cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */
@@ -1401,20 +1378,20 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1401 goto_new_line(); 1378 goto_new_line();
1402 break_out = 1; 1379 break_out = 1;
1403 break; 1380 break;
1404 case CNTRL('A'): 1381 case CTRL('A'):
1405 vi_case( case '0'|vbit: ) 1382 vi_case( case '0'|vbit: )
1406 /* Control-a -- Beginning of line */ 1383 /* Control-a -- Beginning of line */
1407 input_backward(cursor); 1384 input_backward(cursor);
1408 break; 1385 break;
1409 case CNTRL('B'): 1386 case CTRL('B'):
1410 vi_case( case 'h'|vbit: ) 1387 vi_case( case 'h'|vbit: )
1411 vi_case( case '\b'|vbit: ) 1388 vi_case( case '\b'|vbit: )
1412 vi_case( case DEL|vbit: ) 1389 vi_case( case '\x7f'|vbit: ) /* DEL */
1413 /* Control-b -- Move back one character */ 1390 /* Control-b -- Move back one character */
1414 input_backward(1); 1391 input_backward(1);
1415 break; 1392 break;
1416 case CNTRL('C'): 1393 case CTRL('C'):
1417 vi_case( case CNTRL('C')|vbit: ) 1394 vi_case( case CTRL('C')|vbit: )
1418 /* Control-c -- stop gathering input */ 1395 /* Control-c -- stop gathering input */
1419 goto_new_line(); 1396 goto_new_line();
1420#if !ENABLE_ASH 1397#if !ENABLE_ASH
@@ -1427,39 +1404,41 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1427 break_out = -1; /* to control traps */ 1404 break_out = -1; /* to control traps */
1428#endif 1405#endif
1429 break; 1406 break;
1430 case CNTRL('D'): 1407 case CTRL('D'):
1431 /* Control-d -- Delete one character, or exit 1408 /* Control-d -- Delete one character, or exit
1432 * if the len=0 and no chars to delete */ 1409 * if the len=0 and no chars to delete */
1433 if (len == 0) { 1410 if (len == 0) {
1434 errno = 0; 1411 errno = 0;
1435 prepare_to_die: 1412 prepare_to_die:
1413// So, our API depends on whether we have ash compiled in or not? Crap...
1436#if !ENABLE_ASH 1414#if !ENABLE_ASH
1437 printf("exit"); 1415 printf("exit");
1438 goto_new_line(); 1416 goto_new_line();
1439 /* cmdedit_reset_term() called in atexit */ 1417 /* cmdedit_reset_term() called in atexit */
1418// FIXME. this is definitely not good
1440 exit(EXIT_SUCCESS); 1419 exit(EXIT_SUCCESS);
1441#else 1420#else
1442 /* to control stopped jobs */ 1421 /* to control stopped jobs */
1443 len = break_out = -1; 1422 break_out = len = -1;
1444 break; 1423 break;
1445#endif 1424#endif
1446 } else { 1425 } else {
1447 input_delete(0); 1426 input_delete(0);
1448 } 1427 }
1449 break; 1428 break;
1450 case CNTRL('E'): 1429 case CTRL('E'):
1451 vi_case( case '$'|vbit: ) 1430 vi_case( case '$'|vbit: )
1452 /* Control-e -- End of line */ 1431 /* Control-e -- End of line */
1453 input_end(); 1432 input_end();
1454 break; 1433 break;
1455 case CNTRL('F'): 1434 case CTRL('F'):
1456 vi_case( case 'l'|vbit: ) 1435 vi_case( case 'l'|vbit: )
1457 vi_case( case ' '|vbit: ) 1436 vi_case( case ' '|vbit: )
1458 /* Control-f -- Move forward one character */ 1437 /* Control-f -- Move forward one character */
1459 input_forward(); 1438 input_forward();
1460 break; 1439 break;
1461 case '\b': 1440 case '\b':
1462 case DEL: 1441 case '\x7f': /* DEL */
1463 /* Control-h and DEL */ 1442 /* Control-h and DEL */
1464 input_backspace(); 1443 input_backspace();
1465 break; 1444 break;
@@ -1468,28 +1447,28 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1468 input_tab(&lastWasTab); 1447 input_tab(&lastWasTab);
1469#endif 1448#endif
1470 break; 1449 break;
1471 case CNTRL('K'): 1450 case CTRL('K'):
1472 /* Control-k -- clear to end of line */ 1451 /* Control-k -- clear to end of line */
1473 command[cursor] = 0; 1452 command[cursor] = 0;
1474 len = cursor; 1453 len = cursor;
1475 printf("\033[J"); 1454 printf("\033[J");
1476 break; 1455 break;
1477 case CNTRL('L'): 1456 case CTRL('L'):
1478 vi_case( case CNTRL('L')|vbit: ) 1457 vi_case( case CTRL('L')|vbit: )
1479 /* Control-l -- clear screen */ 1458 /* Control-l -- clear screen */
1480 printf("\033[H"); 1459 printf("\033[H");
1481 redraw(0, len - cursor); 1460 redraw(0, len - cursor);
1482 break; 1461 break;
1483#if MAX_HISTORY > 0 1462#if MAX_HISTORY > 0
1484 case CNTRL('N'): 1463 case CTRL('N'):
1485 vi_case( case CNTRL('N')|vbit: ) 1464 vi_case( case CTRL('N')|vbit: )
1486 vi_case( case 'j'|vbit: ) 1465 vi_case( case 'j'|vbit: )
1487 /* Control-n -- Get next command in history */ 1466 /* Control-n -- Get next command in history */
1488 if (get_next_history()) 1467 if (get_next_history())
1489 goto rewrite_line; 1468 goto rewrite_line;
1490 break; 1469 break;
1491 case CNTRL('P'): 1470 case CTRL('P'):
1492 vi_case( case CNTRL('P')|vbit: ) 1471 vi_case( case CTRL('P')|vbit: )
1493 vi_case( case 'k'|vbit: ) 1472 vi_case( case 'k'|vbit: )
1494 /* Control-p -- Get previous command from history */ 1473 /* Control-p -- Get previous command from history */
1495 if (cur_history > 0) { 1474 if (cur_history > 0) {
@@ -1500,16 +1479,16 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1500 } 1479 }
1501 break; 1480 break;
1502#endif 1481#endif
1503 case CNTRL('U'): 1482 case CTRL('U'):
1504 vi_case( case CNTRL('U')|vbit: ) 1483 vi_case( case CTRL('U')|vbit: )
1505 /* Control-U -- Clear line before cursor */ 1484 /* Control-U -- Clear line before cursor */
1506 if (cursor) { 1485 if (cursor) {
1507 strcpy(command, command + cursor); 1486 strcpy(command, command + cursor);
1508 redraw(cmdedit_y, len -= cursor); 1487 redraw(cmdedit_y, len -= cursor);
1509 } 1488 }
1510 break; 1489 break;
1511 case CNTRL('W'): 1490 case CTRL('W'):
1512 vi_case( case CNTRL('W')|vbit: ) 1491 vi_case( case CTRL('W')|vbit: )
1513 /* Control-W -- Remove the last word */ 1492 /* Control-W -- Remove the last word */
1514 while (cursor > 0 && isspace(command[cursor-1])) 1493 while (cursor > 0 && isspace(command[cursor-1]))
1515 input_backspace(); 1494 input_backspace();
@@ -1645,7 +1624,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1645 break; 1624 break;
1646#endif /* FEATURE_COMMAND_EDITING_VI */ 1625#endif /* FEATURE_COMMAND_EDITING_VI */
1647 1626
1648 case ESC: 1627 case '\x1b': /* ESC */
1649 1628
1650#if ENABLE_FEATURE_COMMAND_EDITING_VI 1629#if ENABLE_FEATURE_COMMAND_EDITING_VI
1651 if (vi_mode) { 1630 if (vi_mode) {
@@ -1676,7 +1655,6 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1676 switch (c) { 1655 switch (c) {
1677#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION 1656#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1678 case '\t': /* Alt-Tab */ 1657 case '\t': /* Alt-Tab */
1679
1680 input_tab(&lastWasTab); 1658 input_tab(&lastWasTab);
1681 break; 1659 break;
1682#endif 1660#endif
@@ -1686,24 +1664,19 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1686 if (cur_history > 0) { 1664 if (cur_history > 0) {
1687 get_previous_history(); 1665 get_previous_history();
1688 goto rewrite_line; 1666 goto rewrite_line;
1689 } else {
1690 beep();
1691 } 1667 }
1668 beep();
1692 break; 1669 break;
1693 case 'B': 1670 case 'B':
1694 /* Down Arrow -- Get next command in history */ 1671 /* Down Arrow -- Get next command in history */
1695 if (!get_next_history()) 1672 if (!get_next_history())
1696 break; 1673 break;
1697 /* Rewrite the line with the selected history item */ 1674 /* Rewrite the line with the selected history item */
1698rewrite_line: 1675 rewrite_line:
1699 /* change command */ 1676 /* change command */
1700 len = strlen(strcpy(command, history[cur_history])); 1677 len = strlen(strcpy(command, history[cur_history]));
1701 /* redraw and go to eol (bol, in vi */ 1678 /* redraw and go to eol (bol, in vi */
1702#if ENABLE_FEATURE_COMMAND_EDITING_VI 1679 redraw(cmdedit_y, vi_mode ? 9999 : 0);
1703 redraw(cmdedit_y, vi_mode ? 9999:0);
1704#else
1705 redraw(cmdedit_y, 0);
1706#endif
1707 break; 1680 break;
1708#endif 1681#endif
1709 case 'C': 1682 case 'C':
@@ -1737,7 +1710,7 @@ rewrite_line:
1737 default: /* If it's regular input, do the normal thing */ 1710 default: /* If it's regular input, do the normal thing */
1738#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 1711#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
1739 /* Control-V -- Add non-printable symbol */ 1712 /* Control-V -- Add non-printable symbol */
1740 if (c == CNTRL('V')) { 1713 if (c == CTRL('V')) {
1741 if (safe_read(0, &c, 1) < 1) 1714 if (safe_read(0, &c, 1) < 1)
1742 goto prepare_to_die; 1715 goto prepare_to_die;
1743 if (c == 0) { 1716 if (c == 0) {
@@ -1763,7 +1736,7 @@ rewrite_line:
1763 if (cursor == (len - 1)) { /* Append if at the end of the line */ 1736 if (cursor == (len - 1)) { /* Append if at the end of the line */
1764 *(command + cursor) = c; 1737 *(command + cursor) = c;
1765 *(command + cursor + 1) = 0; 1738 *(command + cursor + 1) = 0;
1766 cmdedit_set_out_char(0); 1739 cmdedit_set_out_char(' ');
1767 } else { /* Insert otherwise */ 1740 } else { /* Insert otherwise */
1768 int sc = cursor; 1741 int sc = cursor;
1769 1742
@@ -1796,7 +1769,7 @@ rewrite_line:
1796 1769
1797 free(history[MAX_HISTORY]); 1770 free(history[MAX_HISTORY]);
1798 history[MAX_HISTORY] = 0; 1771 history[MAX_HISTORY] = 0;
1799 /* After max history, remove the oldest command */ 1772 /* After max history, remove the oldest command */
1800 if (i >= MAX_HISTORY) { 1773 if (i >= MAX_HISTORY) {
1801 free(history[0]); 1774 free(history[0]);
1802 for (i = 0; i < MAX_HISTORY-1; i++) 1775 for (i = 0; i < MAX_HISTORY-1; i++)
@@ -1805,24 +1778,22 @@ rewrite_line:
1805 history[i++] = xstrdup(command); 1778 history[i++] = xstrdup(command);
1806 cur_history = i; 1779 cur_history = i;
1807 n_history = i; 1780 n_history = i;
1808#if ENABLE_FEATURE_SH_FANCY_PROMPT 1781 USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;)
1809 num_ok_lines++;
1810#endif
1811 }
1812#else /* MAX_HISTORY == 0 */
1813#if ENABLE_FEATURE_SH_FANCY_PROMPT
1814 if (len > 0) { /* no put empty line */
1815 num_ok_lines++;
1816 } 1782 }
1817#endif 1783#else /* MAX_HISTORY == 0 */
1818#endif /* MAX_HISTORY > 0 */ 1784 /* dont put empty line */
1785 USE_FEATURE_SH_FANCY_PROMPT(if (len > 0) num_ok_lines++;)
1786#endif /* MAX_HISTORY */
1787
1819 if (break_out > 0) { 1788 if (break_out > 0) {
1820 command[len++] = '\n'; /* set '\n' */ 1789 command[len++] = '\n';
1821 command[len] = 0; 1790 command[len] = '\0';
1822 } 1791 }
1792
1823#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION 1793#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1824 input_tab(0); /* strong free */ 1794 input_tab(0);
1825#endif 1795#endif
1796
1826#if ENABLE_FEATURE_SH_FANCY_PROMPT 1797#if ENABLE_FEATURE_SH_FANCY_PROMPT
1827 free(cmdedit_prompt); 1798 free(cmdedit_prompt);
1828#endif 1799#endif
@@ -1833,13 +1804,15 @@ rewrite_line:
1833#endif /* FEATURE_COMMAND_EDITING */ 1804#endif /* FEATURE_COMMAND_EDITING */
1834 1805
1835 1806
1836#ifdef TEST 1807/*
1808 * Testing
1809 */
1837 1810
1838const char *applet_name = "debug stuff usage"; 1811#ifdef TEST
1839 1812
1840#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
1841#include <locale.h> 1813#include <locale.h>
1842#endif 1814
1815const char *applet_name = "debug stuff usage";
1843 1816
1844int main(int argc, char **argv) 1817int main(int argc, char **argv)
1845{ 1818{
diff --git a/shell/cmdedit.h b/shell/cmdedit.h
index f5863921a..4a32cf63e 100644
--- a/shell/cmdedit.h
+++ b/shell/cmdedit.h
@@ -4,11 +4,11 @@
4 4
5int cmdedit_read_input(char* promptStr, char* command); 5int cmdedit_read_input(char* promptStr, char* command);
6 6
7#ifdef CONFIG_ASH 7#if ENABLE_ASH
8extern const char *cmdedit_path_lookup; 8extern const char *cmdedit_path_lookup;
9#endif 9#endif
10 10
11#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 11#if ENABLE_FEATURE_COMMAND_SAVEHISTORY
12void load_history(const char *fromfile); 12void load_history(const char *fromfile);
13void save_history(const char *tofile); 13void save_history(const char *tofile);
14#endif 14#endif