diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-03-13 22:57:56 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-03-13 22:57:56 +0000 |
commit | b3d6e2df95a21034e41d46a18c71dd1c4e07e987 (patch) | |
tree | 2d549a0d8748a9673be658e193a8104149cf2c15 | |
parent | 798ab301c772cc18ab64f94386da3c7ec10daf42 (diff) | |
download | busybox-w32-b3d6e2df95a21034e41d46a18c71dd1c4e07e987.tar.gz busybox-w32-b3d6e2df95a21034e41d46a18c71dd1c4e07e987.tar.bz2 busybox-w32-b3d6e2df95a21034e41d46a18c71dd1c4e07e987.zip |
Update the lash shell (hopefully the last time...) so things like
echo "foo bar" and echo -n "foo\t\\\\\tbar" work as expected.
Merge prompt printing work from Vladimir.
-Erik
-rw-r--r-- | Config.h | 25 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | cmdedit.c | 173 | ||||
-rw-r--r-- | cmdedit.h | 5 | ||||
-rw-r--r-- | lash.c | 180 | ||||
-rw-r--r-- | sh.c | 180 | ||||
-rw-r--r-- | shell/cmdedit.c | 173 | ||||
-rw-r--r-- | shell/cmdedit.h | 5 | ||||
-rw-r--r-- | shell/lash.c | 180 |
9 files changed, 560 insertions, 362 deletions
@@ -241,7 +241,14 @@ | |||
241 | // | 241 | // |
242 | // Enable command line editing in the shell. | 242 | // Enable command line editing in the shell. |
243 | // Only relevant if BB_SH is enabled. | 243 | // Only relevant if BB_SH is enabled. |
244 | #define BB_FEATURE_SH_COMMAND_EDITING | 244 | #define BB_FEATURE_COMMAND_EDITING |
245 | // | ||
246 | // Enable tab completion in the shell. This is now working quite nicely. | ||
247 | // This feature adds a bit over 4k. Only relevant if BB_SH is enabled. | ||
248 | #define BB_FEATURE_COMMAND_TAB_COMPLETION | ||
249 | // | ||
250 | // Attempts to match usernames in a ~-prefixed path | ||
251 | //#define BB_FEATURE_COMMAND_USERNAME_COMPLETION | ||
245 | // | 252 | // |
246 | //Allow the shell to invoke all the compiled in BusyBox applets as if they | 253 | //Allow the shell to invoke all the compiled in BusyBox applets as if they |
247 | //were shell builtins. Nice for staticly linking an emergency rescue shell, | 254 | //were shell builtins. Nice for staticly linking an emergency rescue shell, |
@@ -258,21 +265,11 @@ | |||
258 | // Only relevant if BB_SH is enabled. | 265 | // Only relevant if BB_SH is enabled. |
259 | #define BB_FEATURE_SH_APPLETS_ALWAYS_WIN | 266 | #define BB_FEATURE_SH_APPLETS_ALWAYS_WIN |
260 | // | 267 | // |
261 | // Enable tab completion in the shell. This is now working quite nicely. | ||
262 | // This feature adds a bit over 4k. Only relevant if BB_SH is enabled. | ||
263 | //#define BB_FEATURE_SH_TAB_COMPLETION | ||
264 | // | ||
265 | // Enable a simpler shell prompt of the form "path #" | ||
266 | // instead of the default "[username@hostname path]#" | ||
267 | // | ||
268 | // Some deeply embedded systems don't have usernames or even hostnames, | 268 | // Some deeply embedded systems don't have usernames or even hostnames, |
269 | // and the default prompt can look rather hideous on them. Uncomment | 269 | // and the default prompt can look rather hideous on them. Uncomment |
270 | // this option for a simpler, path-only prompt (which was the default until | 270 | // this option for a simpler, path-only prompt (which was the default until |
271 | // around BusyBox-0.48): | 271 | // around BusyBox-0.48): |
272 | #define BB_FEATURE_SH_SIMPLE_PROMPT | 272 | #define BB_FEATURE_SIMPLE_PROMPT |
273 | // | ||
274 | // Attempts to match usernames in a ~-prefixed path | ||
275 | //#define BB_FEATURE_SH_USERNAME_COMPLETION | ||
276 | // | 273 | // |
277 | //Turn on extra fbset options | 274 | //Turn on extra fbset options |
278 | //#define BB_FEATURE_FBSET_FANCY | 275 | //#define BB_FEATURE_FBSET_FANCY |
@@ -355,7 +352,7 @@ | |||
355 | #undef BB_MTAB | 352 | #undef BB_MTAB |
356 | #endif | 353 | #endif |
357 | // | 354 | // |
358 | #if defined BB_FEATURE_SH_COMMAND_EDITING && defined BB_SH | 355 | #if defined BB_FEATURE_COMMAND_EDITING && defined BB_SH |
359 | #define BB_CMDEDIT | 356 | #define BB_CMDEDIT |
360 | #endif | 357 | #endif |
361 | // | 358 | // |
@@ -406,7 +403,7 @@ | |||
406 | #define BB_NFSMOUNT | 403 | #define BB_NFSMOUNT |
407 | #endif | 404 | #endif |
408 | // | 405 | // |
409 | #if defined BB_FEATURE_SH_COMMAND_EDITING | 406 | #if defined BB_FEATURE_COMMAND_EDITING |
410 | #ifndef BB_FEATURE_USE_TERMIOS | 407 | #ifndef BB_FEATURE_USE_TERMIOS |
411 | #define BB_FEATURE_USE_TERMIOS | 408 | #define BB_FEATURE_USE_TERMIOS |
412 | #endif | 409 | #endif |
@@ -299,6 +299,7 @@ busybox.links: busybox.mkll Config.h applets.h | |||
299 | - $(SHELL) $^ >$@ | 299 | - $(SHELL) $^ >$@ |
300 | 300 | ||
301 | nfsmount.o cmdedit.o: %.o: %.h | 301 | nfsmount.o cmdedit.o: %.o: %.h |
302 | sh.o: cmdedit.h | ||
302 | $(OBJECTS): %.o: %.c Config.h busybox.h applets.h Makefile | 303 | $(OBJECTS): %.o: %.c Config.h busybox.h applets.h Makefile |
303 | $(CC) -I- $(CFLAGS) -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o | 304 | $(CC) -I- $(CFLAGS) -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o |
304 | 305 | ||
@@ -27,6 +27,7 @@ | |||
27 | Small bugs (simple effect): | 27 | Small bugs (simple effect): |
28 | - not true viewing if terminal size (x*y symbols) less | 28 | - not true viewing if terminal size (x*y symbols) less |
29 | size (prompt + editor`s line + 2 symbols) | 29 | size (prompt + editor`s line + 2 symbols) |
30 | - not true viewing if length prompt less terminal width | ||
30 | */ | 31 | */ |
31 | 32 | ||
32 | 33 | ||
@@ -50,29 +51,36 @@ | |||
50 | 51 | ||
51 | #else | 52 | #else |
52 | 53 | ||
53 | #define BB_FEATURE_SH_COMMAND_EDITING | 54 | #define BB_FEATURE_COMMAND_EDITING |
54 | #define BB_FEATURE_SH_TAB_COMPLETION | 55 | #define BB_FEATURE_COMMAND_TAB_COMPLETION |
55 | #define BB_FEATURE_SH_USERNAME_COMPLETION | 56 | #define BB_FEATURE_COMMAND_USERNAME_COMPLETION |
56 | #define BB_FEATURE_NONPRINTABLE_INVERSE_PUT | 57 | #define BB_FEATURE_NONPRINTABLE_INVERSE_PUT |
57 | #define BB_FEATURE_BASH_STYLE_PROMT | 58 | #undef BB_FEATURE_SIMPLE_PROMPT |
58 | #define BB_FEATURE_CLEAN_UP | 59 | #define BB_FEATURE_CLEAN_UP |
59 | 60 | ||
60 | #define D(x) x | 61 | #define D(x) x |
61 | 62 | ||
63 | #ifndef TRUE | ||
64 | #define TRUE 1 | ||
65 | #endif | ||
66 | #ifndef FALSE | ||
67 | #define FALSE 0 | ||
68 | #endif | ||
69 | |||
62 | #endif /* TEST */ | 70 | #endif /* TEST */ |
63 | 71 | ||
64 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 72 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
65 | #include <dirent.h> | 73 | #include <dirent.h> |
66 | #include <sys/stat.h> | 74 | #include <sys/stat.h> |
67 | #endif | 75 | #endif |
68 | 76 | ||
69 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 77 | #ifdef BB_FEATURE_COMMAND_EDITING |
70 | 78 | ||
71 | #ifndef BB_FEATURE_SH_TAB_COMPLETION | 79 | #ifndef BB_FEATURE_COMMAND_TAB_COMPLETION |
72 | #undef BB_FEATURE_SH_USERNAME_COMPLETION | 80 | #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
73 | #endif | 81 | #endif |
74 | 82 | ||
75 | #if defined(BB_FEATURE_SH_USERNAME_COMPLETION) || defined(BB_FEATURE_BASH_STYLE_PROMT) | 83 | #if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || !defined(BB_FEATURE_SIMPLE_PROMPT) |
76 | #define BB_FEATURE_GETUSERNAME_AND_HOMEDIR | 84 | #define BB_FEATURE_GETUSERNAME_AND_HOMEDIR |
77 | #endif | 85 | #endif |
78 | 86 | ||
@@ -154,26 +162,26 @@ static | |||
154 | volatile int handlers_sets = 0; /* Set next bites: */ | 162 | volatile int handlers_sets = 0; /* Set next bites: */ |
155 | 163 | ||
156 | enum { | 164 | enum { |
157 | SET_ATEXIT = 1, /* when atexit() has been called and | 165 | SET_ATEXIT = 1, /* when atexit() has been called |
158 | get euid,uid,gid to fast compare */ | 166 | and get euid,uid,gid to fast compare */ |
159 | SET_TERM_HANDLERS = 2, /* set many terminates signal handlers */ | 167 | SET_TERM_HANDLERS = 2, /* set many terminates signal handlers */ |
160 | SET_WCHG_HANDLERS = 4, /* winchg signal handler */ | 168 | SET_WCHG_HANDLERS = 4, /* winchg signal handler */ |
161 | SET_RESET_TERM = 8, /* if the terminal needs to be reset upon exit */ | 169 | SET_RESET_TERM = 8, /* if the terminal needs to be reset upon exit */ |
162 | }; | 170 | }; |
163 | 171 | ||
164 | 172 | ||
165 | static int cmdedit_x; /* real x terminal position */ | 173 | static int cmdedit_x; /* real x terminal position */ |
166 | static int cmdedit_y; /* pseudoreal y terminal position */ | 174 | static int cmdedit_y; /* pseudoreal y terminal position */ |
167 | static int cmdedit_prmt_len; /* lenght prompt without colores string */ | 175 | static int cmdedit_prmt_len; /* lenght prompt without colores string */ |
168 | 176 | ||
169 | static int cursor; /* required global for signal handler */ | 177 | static int cursor; /* required global for signal handler */ |
170 | static int len; /* --- "" - - "" - -"- --""-- --""--- */ | 178 | static int len; /* --- "" - - "" - -"- --""-- --""--- */ |
171 | static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ | 179 | static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ |
172 | static | 180 | static |
173 | #ifndef BB_FEATURE_BASH_STYLE_PROMT | 181 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
174 | const | 182 | const |
175 | #endif | 183 | #endif |
176 | char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ | 184 | char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ |
177 | 185 | ||
178 | /* Link into lash to reset context to 0 on ^C and such */ | 186 | /* Link into lash to reset context to 0 on ^C and such */ |
179 | extern unsigned int shell_context; | 187 | extern unsigned int shell_context; |
@@ -185,13 +193,13 @@ static char *home_pwd_buf = ""; | |||
185 | static int my_euid; | 193 | static int my_euid; |
186 | #endif | 194 | #endif |
187 | 195 | ||
188 | #ifdef BB_FEATURE_BASH_STYLE_PROMT | 196 | #ifndef BB_FEATURE_SIMPLE_PROMPT |
189 | static char *hostname_buf = ""; | 197 | static char *hostname_buf = ""; |
190 | static int num_ok_lines = 1; | 198 | static int num_ok_lines = 1; |
191 | #endif | 199 | #endif |
192 | 200 | ||
193 | 201 | ||
194 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 202 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
195 | 203 | ||
196 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | 204 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR |
197 | static int my_euid; | 205 | static int my_euid; |
@@ -200,7 +208,7 @@ static int my_euid; | |||
200 | static int my_uid; | 208 | static int my_uid; |
201 | static int my_gid; | 209 | static int my_gid; |
202 | 210 | ||
203 | #endif /* BB_FEATURE_SH_TAB_COMPLETION */ | 211 | #endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ |
204 | 212 | ||
205 | 213 | ||
206 | static void cmdedit_setwidth(int w, int redraw_flg); | 214 | static void cmdedit_setwidth(int w, int redraw_flg); |
@@ -245,7 +253,6 @@ static void cmdedit_reset_term(void) | |||
245 | if (his_front) { | 253 | if (his_front) { |
246 | struct history *n; | 254 | struct history *n; |
247 | 255 | ||
248 | //while(his_front!=his_end) { | ||
249 | while (his_front != his_end) { | 256 | while (his_front != his_end) { |
250 | n = his_front->n; | 257 | n = his_front->n; |
251 | free(his_front->s); | 258 | free(his_front->s); |
@@ -355,25 +362,27 @@ static void put_prompt(void) | |||
355 | cursor = 0; | 362 | cursor = 0; |
356 | } | 363 | } |
357 | 364 | ||
358 | #ifdef BB_FEATURE_BASH_STYLE_PROMT | 365 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
359 | static void | 366 | static void parse_prompt(const char *prmt_ptr) |
360 | add_to_prompt(char **prmt_mem_ptr, int *alm, int *prmt_len, | ||
361 | const char *addb) | ||
362 | { | 367 | { |
363 | int l = strlen(addb); | 368 | cmdedit_prompt = prmt_ptr; |
364 | 369 | cmdedit_prmt_len = strlen(prmt_ptr); | |
365 | *prmt_len += l; | 370 | put_prompt(); |
371 | } | ||
372 | #else | ||
373 | static void add_to_prompt(char **prmt_mem_ptr, int *alm, | ||
374 | int *prmt_len, const char *addb) | ||
375 | { | ||
376 | *prmt_len += strlen(addb); | ||
366 | if (*alm < (*prmt_len) + 1) { | 377 | if (*alm < (*prmt_len) + 1) { |
367 | *alm = (*prmt_len) + 1; | 378 | *alm = (*prmt_len) + 1; |
368 | *prmt_mem_ptr = xrealloc(*prmt_mem_ptr, *alm); | 379 | *prmt_mem_ptr = xrealloc(*prmt_mem_ptr, *alm); |
369 | } | 380 | } |
370 | strcat(*prmt_mem_ptr, addb); | 381 | strcat(*prmt_mem_ptr, addb); |
371 | } | 382 | } |
372 | #endif | ||
373 | 383 | ||
374 | static void parse_prompt(const char *prmt_ptr) | 384 | static void parse_prompt(const char *prmt_ptr) |
375 | { | 385 | { |
376 | #ifdef BB_FEATURE_BASH_STYLE_PROMT | ||
377 | int alm = strlen(prmt_ptr) + 1; /* supposedly require memory */ | 386 | int alm = strlen(prmt_ptr) + 1; /* supposedly require memory */ |
378 | int prmt_len = 0; | 387 | int prmt_len = 0; |
379 | int sub_len = 0; | 388 | int sub_len = 0; |
@@ -394,9 +403,11 @@ static void parse_prompt(const char *prmt_ptr) | |||
394 | break; | 403 | break; |
395 | prmt_ptr++; | 404 | prmt_ptr++; |
396 | switch (c) { | 405 | switch (c) { |
406 | #ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
397 | case 'u': | 407 | case 'u': |
398 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, user_buf); | 408 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, user_buf); |
399 | continue; | 409 | continue; |
410 | #endif | ||
400 | case 'h': | 411 | case 'h': |
401 | if (hostname_buf[0] == 0) { | 412 | if (hostname_buf[0] == 0) { |
402 | hostname_buf = xcalloc(256, 1); | 413 | hostname_buf = xcalloc(256, 1); |
@@ -415,6 +426,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
415 | case '$': | 426 | case '$': |
416 | c = my_euid == 0 ? '#' : '$'; | 427 | c = my_euid == 0 ? '#' : '$'; |
417 | break; | 428 | break; |
429 | #ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
418 | case 'w': | 430 | case 'w': |
419 | if (pwd_buf[0] == 0) { | 431 | if (pwd_buf[0] == 0) { |
420 | int l; | 432 | int l; |
@@ -429,6 +441,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
429 | } | 441 | } |
430 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, pwd_buf); | 442 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, pwd_buf); |
431 | continue; | 443 | continue; |
444 | #endif | ||
432 | case '!': | 445 | case '!': |
433 | snprintf(buf, sizeof(buf), "%d", num_ok_lines); | 446 | snprintf(buf, sizeof(buf), "%d", num_ok_lines); |
434 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, buf); | 447 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, buf); |
@@ -485,20 +498,21 @@ static void parse_prompt(const char *prmt_ptr) | |||
485 | if (flg_not_length == ']') | 498 | if (flg_not_length == ']') |
486 | sub_len++; | 499 | sub_len++; |
487 | } | 500 | } |
501 | #if 0 | ||
488 | cmdedit_prmt_len = prmt_len - sub_len; | 502 | cmdedit_prmt_len = prmt_len - sub_len; |
489 | cmdedit_prompt = prmt_mem_ptr; | ||
490 | #else | ||
491 | cmdedit_prompt = prmt_ptr; | 503 | cmdedit_prompt = prmt_ptr; |
492 | cmdedit_prmt_len = strlen(prmt_ptr); | 504 | #endif |
493 | #endif | 505 | cmdedit_prompt = prmt_mem_ptr; |
506 | cmdedit_prmt_len = strlen(cmdedit_prompt); | ||
494 | put_prompt(); | 507 | put_prompt(); |
495 | } | 508 | } |
509 | #endif | ||
496 | 510 | ||
497 | 511 | ||
498 | /* draw promt, editor line, and clear tail */ | 512 | /* draw promt, editor line, and clear tail */ |
499 | static void redraw(int y, int back_cursor) | 513 | static void redraw(int y, int back_cursor) |
500 | { | 514 | { |
501 | if (y > 0) /* up to start y */ | 515 | if (y > 0) /* up to start y */ |
502 | printf("\033[%dA", y); | 516 | printf("\033[%dA", y); |
503 | cmdedit_y = 0; /* new quasireal y */ | 517 | cmdedit_y = 0; /* new quasireal y */ |
504 | putchar('\r'); | 518 | putchar('\r'); |
@@ -518,7 +532,7 @@ static void input_delete(void) | |||
518 | 532 | ||
519 | strcpy(command_ps + j, command_ps + j + 1); | 533 | strcpy(command_ps + j, command_ps + j + 1); |
520 | len--; | 534 | len--; |
521 | input_end(); /* rewtite new line */ | 535 | input_end(); /* rewtite new line */ |
522 | cmdedit_set_out_char(0); /* destroy end char */ | 536 | cmdedit_set_out_char(0); /* destroy end char */ |
523 | input_backward(cursor - j); /* back to old pos cursor */ | 537 | input_backward(cursor - j); /* back to old pos cursor */ |
524 | } | 538 | } |
@@ -545,7 +559,7 @@ static void clean_up_and_die(int sig) | |||
545 | { | 559 | { |
546 | goto_new_line(); | 560 | goto_new_line(); |
547 | if (sig != SIGINT) | 561 | if (sig != SIGINT) |
548 | exit(EXIT_SUCCESS); /* cmdedit_reset_term() called in atexit */ | 562 | exit(EXIT_SUCCESS); /* cmdedit_reset_term() called in atexit */ |
549 | cmdedit_reset_term(); | 563 | cmdedit_reset_term(); |
550 | } | 564 | } |
551 | 565 | ||
@@ -556,7 +570,6 @@ static void cmdedit_setwidth(int w, int redraw_flg) | |||
556 | cmdedit_termw = cmdedit_termw % w; | 570 | cmdedit_termw = cmdedit_termw % w; |
557 | } | 571 | } |
558 | if (w > cmdedit_termw) { | 572 | if (w > cmdedit_termw) { |
559 | |||
560 | cmdedit_termw = w; | 573 | cmdedit_termw = w; |
561 | 574 | ||
562 | if (redraw_flg) { | 575 | if (redraw_flg) { |
@@ -590,14 +603,14 @@ extern void cmdedit_init(void) | |||
590 | } | 603 | } |
591 | #endif | 604 | #endif |
592 | 605 | ||
593 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 606 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
594 | 607 | ||
595 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | 608 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR |
596 | my_euid = geteuid(); | 609 | my_euid = geteuid(); |
597 | #endif | 610 | #endif |
598 | my_uid = getuid(); | 611 | my_uid = getuid(); |
599 | my_gid = getgid(); | 612 | my_gid = getgid(); |
600 | #endif /* BB_FEATURE_SH_TAB_COMPLETION */ | 613 | #endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ |
601 | handlers_sets |= SET_ATEXIT; | 614 | handlers_sets |= SET_ATEXIT; |
602 | atexit(cmdedit_reset_term); /* be sure to do this only once */ | 615 | atexit(cmdedit_reset_term); /* be sure to do this only once */ |
603 | } | 616 | } |
@@ -612,7 +625,7 @@ extern void cmdedit_init(void) | |||
612 | 625 | ||
613 | } | 626 | } |
614 | 627 | ||
615 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 628 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
616 | 629 | ||
617 | static int is_execute(const struct stat *st) | 630 | static int is_execute(const struct stat *st) |
618 | { | 631 | { |
@@ -623,7 +636,7 @@ static int is_execute(const struct stat *st) | |||
623 | return FALSE; | 636 | return FALSE; |
624 | } | 637 | } |
625 | 638 | ||
626 | #ifdef BB_FEATURE_SH_USERNAME_COMPLETION | 639 | #ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
627 | 640 | ||
628 | static char **username_tab_completion(char *ud, int *num_matches) | 641 | static char **username_tab_completion(char *ud, int *num_matches) |
629 | { | 642 | { |
@@ -632,19 +645,19 @@ static char **username_tab_completion(char *ud, int *num_matches) | |||
632 | char *temp; | 645 | char *temp; |
633 | 646 | ||
634 | 647 | ||
635 | ud++; /* ~user/... to user/... */ | 648 | ud++; /* ~user/... to user/... */ |
636 | userlen = strlen(ud); | 649 | userlen = strlen(ud); |
637 | 650 | ||
638 | if (num_matches == 0) { /* "~/..." or "~user/..." */ | 651 | if (num_matches == 0) { /* "~/..." or "~user/..." */ |
639 | char *sav_ud = ud - 1; | 652 | char *sav_ud = ud - 1; |
640 | char *home = 0; | 653 | char *home = 0; |
641 | 654 | ||
642 | if (*ud == '/') { /* "~/..." */ | 655 | if (*ud == '/') { /* "~/..." */ |
643 | home = home_pwd_buf; | 656 | home = home_pwd_buf; |
644 | } else { | 657 | } else { |
645 | /* "~user/..." */ | 658 | /* "~user/..." */ |
646 | temp = strchr(ud, '/'); | 659 | temp = strchr(ud, '/'); |
647 | *temp = 0; /* ~user\0 */ | 660 | *temp = 0; /* ~user\0 */ |
648 | entry = getpwnam(ud); | 661 | entry = getpwnam(ud); |
649 | *temp = '/'; /* restore ~user/... */ | 662 | *temp = '/'; /* restore ~user/... */ |
650 | ud = temp; | 663 | ud = temp; |
@@ -660,7 +673,7 @@ static char **username_tab_completion(char *ud, int *num_matches) | |||
660 | strcpy(sav_ud, temp2); | 673 | strcpy(sav_ud, temp2); |
661 | } | 674 | } |
662 | } | 675 | } |
663 | return 0; /* void, result save to argument :-) */ | 676 | return 0; /* void, result save to argument :-) */ |
664 | } else { | 677 | } else { |
665 | /* "~[^/]*" */ | 678 | /* "~[^/]*" */ |
666 | char **matches = (char **) NULL; | 679 | char **matches = (char **) NULL; |
@@ -685,7 +698,7 @@ static char **username_tab_completion(char *ud, int *num_matches) | |||
685 | return (matches); | 698 | return (matches); |
686 | } | 699 | } |
687 | } | 700 | } |
688 | #endif /* BB_FEATURE_SH_USERNAME_COMPLETION */ | 701 | #endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ |
689 | 702 | ||
690 | enum { | 703 | enum { |
691 | FIND_EXE_ONLY = 0, | 704 | FIND_EXE_ONLY = 0, |
@@ -710,11 +723,11 @@ static int path_parse(char ***p, int flags) | |||
710 | npth = 0; | 723 | npth = 0; |
711 | 724 | ||
712 | for (;;) { | 725 | for (;;) { |
713 | npth++; /* count words is + 1 count ':' */ | 726 | npth++; /* count words is + 1 count ':' */ |
714 | tmp = strchr(tmp, ':'); | 727 | tmp = strchr(tmp, ':'); |
715 | if (tmp) { | 728 | if (tmp) { |
716 | if (*++tmp == 0) | 729 | if (*++tmp == 0) |
717 | break; /* :<empty> */ | 730 | break; /* :<empty> */ |
718 | } else | 731 | } else |
719 | break; | 732 | break; |
720 | } | 733 | } |
@@ -723,7 +736,7 @@ static int path_parse(char ***p, int flags) | |||
723 | 736 | ||
724 | tmp = pth; | 737 | tmp = pth; |
725 | (*p)[0] = xstrdup(tmp); | 738 | (*p)[0] = xstrdup(tmp); |
726 | npth = 1; /* count words is + 1 count ':' */ | 739 | npth = 1; /* count words is + 1 count ':' */ |
727 | 740 | ||
728 | for (;;) { | 741 | for (;;) { |
729 | tmp = strchr(tmp, ':'); | 742 | tmp = strchr(tmp, ':'); |
@@ -754,7 +767,7 @@ static char *add_quote_for_spec_chars(char *found) | |||
754 | } | 767 | } |
755 | 768 | ||
756 | static char **exe_n_cwd_tab_completion(char *command, int *num_matches, | 769 | static char **exe_n_cwd_tab_completion(char *command, int *num_matches, |
757 | int type) | 770 | int type) |
758 | { | 771 | { |
759 | 772 | ||
760 | char **matches = 0; | 773 | char **matches = 0; |
@@ -782,7 +795,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, | |||
782 | strcpy(dirbuf, command); | 795 | strcpy(dirbuf, command); |
783 | /* set dir only */ | 796 | /* set dir only */ |
784 | dirbuf[(pfind - command) + 1] = 0; | 797 | dirbuf[(pfind - command) + 1] = 0; |
785 | #ifdef BB_FEATURE_SH_USERNAME_COMPLETION | 798 | #ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
786 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ | 799 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ |
787 | username_tab_completion(dirbuf, 0); | 800 | username_tab_completion(dirbuf, 0); |
788 | #endif | 801 | #endif |
@@ -796,7 +809,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, | |||
796 | for (i = 0; i < npaths; i++) { | 809 | for (i = 0; i < npaths; i++) { |
797 | 810 | ||
798 | dir = opendir(paths[i]); | 811 | dir = opendir(paths[i]); |
799 | if (!dir) /* Don't print an error */ | 812 | if (!dir) /* Don't print an error */ |
800 | continue; | 813 | continue; |
801 | 814 | ||
802 | while ((next = readdir(dir)) != NULL) { | 815 | while ((next = readdir(dir)) != NULL) { |
@@ -987,7 +1000,8 @@ static int find_match(char *matchBuf, int *len_with_quotes) | |||
987 | for (i = 0; int_buf[i]; i++) | 1000 | for (i = 0; int_buf[i]; i++) |
988 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { | 1001 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { |
989 | if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY | 1002 | if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY |
990 | && strncmp(&matchBuf[pos_buf[0]], "cd", 2) == 0) | 1003 | && matchBuf[pos_buf[0]]=='c' |
1004 | && matchBuf[pos_buf[1]]=='d' ) | ||
991 | command_mode = FIND_DIR_ONLY; | 1005 | command_mode = FIND_DIR_ONLY; |
992 | else { | 1006 | else { |
993 | command_mode = FIND_FILE_ONLY; | 1007 | command_mode = FIND_FILE_ONLY; |
@@ -1065,7 +1079,7 @@ static void input_tab(int *lastWasTab) | |||
1065 | /* Free up any memory already allocated */ | 1079 | /* Free up any memory already allocated */ |
1066 | input_tab(0); | 1080 | input_tab(0); |
1067 | 1081 | ||
1068 | #ifdef BB_FEATURE_SH_USERNAME_COMPLETION | 1082 | #ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
1069 | /* If the word starts with `~' and there is no slash in the word, | 1083 | /* If the word starts with `~' and there is no slash in the word, |
1070 | * then try completing this word as a username. */ | 1084 | * then try completing this word as a username. */ |
1071 | 1085 | ||
@@ -1085,7 +1099,7 @@ static void input_tab(int *lastWasTab) | |||
1085 | 1099 | ||
1086 | beep(); | 1100 | beep(); |
1087 | if (!matches) | 1101 | if (!matches) |
1088 | return; /* not found */ | 1102 | return; /* not found */ |
1089 | /* sort */ | 1103 | /* sort */ |
1090 | qsort(matches, num_matches, sizeof(char *), match_compare); | 1104 | qsort(matches, num_matches, sizeof(char *), match_compare); |
1091 | 1105 | ||
@@ -1101,7 +1115,7 @@ static void input_tab(int *lastWasTab) | |||
1101 | free(tmp); | 1115 | free(tmp); |
1102 | return; | 1116 | return; |
1103 | } | 1117 | } |
1104 | } else { /* one match */ | 1118 | } else { /* one match */ |
1105 | tmp = matches[0]; | 1119 | tmp = matches[0]; |
1106 | /* for next completion current found */ | 1120 | /* for next completion current found */ |
1107 | *lastWasTab = FALSE; | 1121 | *lastWasTab = FALSE; |
@@ -1164,7 +1178,7 @@ static void input_tab(int *lastWasTab) | |||
1164 | } | 1178 | } |
1165 | } | 1179 | } |
1166 | } | 1180 | } |
1167 | #endif /* BB_FEATURE_SH_TAB_COMPLETION */ | 1181 | #endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ |
1168 | 1182 | ||
1169 | static void get_previous_history(struct history **hp, struct history *p) | 1183 | static void get_previous_history(struct history **hp, struct history *p) |
1170 | { | 1184 | { |
@@ -1201,6 +1215,7 @@ enum { | |||
1201 | * Furthermore, the "vi" command editing keys are not implemented. | 1215 | * Furthermore, the "vi" command editing keys are not implemented. |
1202 | * | 1216 | * |
1203 | */ | 1217 | */ |
1218 | |||
1204 | extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | 1219 | extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) |
1205 | { | 1220 | { |
1206 | 1221 | ||
@@ -1212,7 +1227,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1212 | struct history *hp = his_end; | 1227 | struct history *hp = his_end; |
1213 | 1228 | ||
1214 | /* prepare before init handlers */ | 1229 | /* prepare before init handlers */ |
1215 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ | 1230 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ |
1216 | len = 0; | 1231 | len = 0; |
1217 | command_ps = command; | 1232 | command_ps = command; |
1218 | 1233 | ||
@@ -1223,9 +1238,11 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1223 | 1238 | ||
1224 | new_settings.c_cc[VMIN] = 1; | 1239 | new_settings.c_cc[VMIN] = 1; |
1225 | new_settings.c_cc[VTIME] = 0; | 1240 | new_settings.c_cc[VTIME] = 0; |
1226 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; /* Turn off CTRL-C, so we can trap it */ | 1241 | /* Turn off CTRL-C, so we can trap it */ |
1242 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; | ||
1227 | new_settings.c_lflag &= ~ICANON; /* unbuffered input */ | 1243 | new_settings.c_lflag &= ~ICANON; /* unbuffered input */ |
1228 | new_settings.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); /* Turn off echoing */ | 1244 | /* Turn off echoing */ |
1245 | new_settings.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); | ||
1229 | } | 1246 | } |
1230 | 1247 | ||
1231 | command[0] = 0; | 1248 | command[0] = 0; |
@@ -1295,7 +1312,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1295 | input_backspace(); | 1312 | input_backspace(); |
1296 | break; | 1313 | break; |
1297 | case '\t': | 1314 | case '\t': |
1298 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 1315 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
1299 | input_tab(&lastWasTab); | 1316 | input_tab(&lastWasTab); |
1300 | #endif | 1317 | #endif |
1301 | break; | 1318 | break; |
@@ -1335,7 +1352,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1335 | return; | 1352 | return; |
1336 | } | 1353 | } |
1337 | switch (c) { | 1354 | switch (c) { |
1338 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 1355 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
1339 | case '\t': /* Alt-Tab */ | 1356 | case '\t': /* Alt-Tab */ |
1340 | 1357 | ||
1341 | input_tab(&lastWasTab); | 1358 | input_tab(&lastWasTab); |
@@ -1402,7 +1419,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1402 | break; | 1419 | break; |
1403 | } | 1420 | } |
1404 | 1421 | ||
1405 | default: /* If it's regular input, do the normal thing */ | 1422 | default: /* If it's regular input, do the normal thing */ |
1406 | #ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT | 1423 | #ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT |
1407 | /* Control-V -- Add non-printable symbol */ | 1424 | /* Control-V -- Add non-printable symbol */ |
1408 | if (c == 22) { | 1425 | if (c == 22) { |
@@ -1493,16 +1510,16 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1493 | history_counter++; | 1510 | history_counter++; |
1494 | } | 1511 | } |
1495 | } | 1512 | } |
1496 | #if defined(BB_FEATURE_BASH_STYLE_PROMT) | 1513 | #if !defined(BB_FEATURE_SIMPLE_PROMPT) |
1497 | num_ok_lines++; | 1514 | num_ok_lines++; |
1498 | #endif | 1515 | #endif |
1499 | } | 1516 | } |
1500 | command[len++] = '\n'; /* set '\n' */ | 1517 | command[len++] = '\n'; /* set '\n' */ |
1501 | command[len] = 0; | 1518 | command[len] = 0; |
1502 | #if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_SH_TAB_COMPLETION) | 1519 | #if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION) |
1503 | input_tab(0); /* strong free */ | 1520 | input_tab(0); /* strong free */ |
1504 | #endif | 1521 | #endif |
1505 | #if defined(BB_FEATURE_BASH_STYLE_PROMT) | 1522 | #if !defined(BB_FEATURE_SIMPLE_PROMPT) |
1506 | free(cmdedit_prompt); | 1523 | free(cmdedit_prompt); |
1507 | #endif | 1524 | #endif |
1508 | return; | 1525 | return; |
@@ -1523,7 +1540,7 @@ extern void cmdedit_terminate(void) | |||
1523 | } | 1540 | } |
1524 | } | 1541 | } |
1525 | 1542 | ||
1526 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ | 1543 | #endif /* BB_FEATURE_COMMAND_EDITING */ |
1527 | 1544 | ||
1528 | 1545 | ||
1529 | #ifdef TEST | 1546 | #ifdef TEST |
@@ -1534,21 +1551,25 @@ int main(int argc, char **argv) | |||
1534 | { | 1551 | { |
1535 | char buff[BUFSIZ]; | 1552 | char buff[BUFSIZ]; |
1536 | char *prompt = | 1553 | char *prompt = |
1537 | #if defined(BB_FEATURE_BASH_STYLE_PROMT) | 1554 | #if !defined(BB_FEATURE_SIMPLE_PROMPT) |
1538 | "\\[\\033[32;1m\\]\\u@\\[\\033[33;1m\\]\\h:\ | 1555 | "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\ |
1539 | \\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ | 1556 | \\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ |
1540 | \\!\\[\\033[36;1m\\]\\$ \\[\\033[0m\\]"; | 1557 | \\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]"; |
1541 | #else | 1558 | #else |
1542 | "% "; | 1559 | "% "; |
1543 | #endif | 1560 | #endif |
1544 | 1561 | ||
1545 | shell_context = 1; | 1562 | shell_context = 1; |
1546 | do { | 1563 | do { |
1564 | int l; | ||
1547 | cmdedit_read_input(prompt, buff); | 1565 | cmdedit_read_input(prompt, buff); |
1566 | l = strlen(buff); | ||
1567 | if(l > 0 && buff[l-1] == '\n') | ||
1568 | buff[l-1] = 0; | ||
1548 | printf("*** cmdedit_read_input() returned line =%s=\n", buff); | 1569 | printf("*** cmdedit_read_input() returned line =%s=\n", buff); |
1549 | } while (shell_context); | 1570 | } while (shell_context); |
1550 | printf("*** cmdedit_read_input() detect ^C\n"); | 1571 | printf("*** cmdedit_read_input() detect ^C\n"); |
1551 | return 0; | 1572 | return 0; |
1552 | } | 1573 | } |
1553 | 1574 | ||
1554 | #endif /* TEST */ | 1575 | #endif /* TEST */ |
@@ -1,13 +1,14 @@ | |||
1 | #ifndef CMDEDIT_H | 1 | #ifndef CMDEDIT_H |
2 | #define CMDEDIT_H | 2 | #define CMDEDIT_H |
3 | 3 | ||
4 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 4 | #ifdef BB_FEATURE_COMMAND_EDITING |
5 | #include <stddef.h> | 5 | #include <stddef.h> |
6 | #include "busybox.h" | ||
6 | 7 | ||
7 | void cmdedit_init(void); | 8 | void cmdedit_init(void); |
8 | void cmdedit_terminate(void); | 9 | void cmdedit_terminate(void); |
9 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ | 10 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ |
10 | 11 | ||
11 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ | 12 | #endif /* BB_FEATURE_COMMAND_EDITING */ |
12 | 13 | ||
13 | #endif /* CMDEDIT_H */ | 14 | #endif /* CMDEDIT_H */ |
@@ -39,11 +39,15 @@ | |||
39 | //#define BB_FEATURE_SH_BACKTICKS | 39 | //#define BB_FEATURE_SH_BACKTICKS |
40 | // | 40 | // |
41 | //If, then, else, etc. support.. This should now behave basically | 41 | //If, then, else, etc. support.. This should now behave basically |
42 | //like any other Bourne shell... | 42 | //like any other Bourne shell -- sortof... |
43 | #define BB_FEATURE_SH_IF_EXPRESSIONS | 43 | #define BB_FEATURE_SH_IF_EXPRESSIONS |
44 | // | 44 | // |
45 | /* This is currently a little broken... */ | 45 | /* This is currently sortof broken, only for the brave... */ |
46 | //#define HANDLE_CONTINUATION_CHARS | 46 | #undef HANDLE_CONTINUATION_CHARS |
47 | // | ||
48 | /* This would be great -- if wordexp wouldn't strip all quoting | ||
49 | * out from the target strings... As is, a parser needs */ | ||
50 | #undef BB_FEATURE_SH_WORDEXP | ||
47 | // | 51 | // |
48 | //For debugging/development on the shell only... | 52 | //For debugging/development on the shell only... |
49 | //#define DEBUG_SHELL | 53 | //#define DEBUG_SHELL |
@@ -61,10 +65,9 @@ | |||
61 | #include <unistd.h> | 65 | #include <unistd.h> |
62 | #include <getopt.h> | 66 | #include <getopt.h> |
63 | 67 | ||
64 | //#undef __GLIBC__ | 68 | #undef BB_FEATURE_SH_WORDEXP |
65 | //#undef __UCLIBC__ | ||
66 | 69 | ||
67 | #if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__) | 70 | #if BB_FEATURE_SH_WORDEXP |
68 | #include <wordexp.h> | 71 | #include <wordexp.h> |
69 | #define expand_t wordexp_t | 72 | #define expand_t wordexp_t |
70 | #undef BB_FEATURE_SH_BACKTICKS | 73 | #undef BB_FEATURE_SH_BACKTICKS |
@@ -227,6 +230,10 @@ static int show_x_trace; | |||
227 | static char syntax_err[]="syntax error near unexpected token"; | 230 | static char syntax_err[]="syntax error near unexpected token"; |
228 | #endif | 231 | #endif |
229 | 232 | ||
233 | static char *PS1; | ||
234 | static char *PS2; | ||
235 | |||
236 | |||
230 | #ifdef DEBUG_SHELL | 237 | #ifdef DEBUG_SHELL |
231 | static inline void debug_printf(const char *format, ...) | 238 | static inline void debug_printf(const char *format, ...) |
232 | { | 239 | { |
@@ -286,7 +293,7 @@ static int builtin_cd(struct child_prog *child) | |||
286 | else | 293 | else |
287 | newdir = child->argv[1]; | 294 | newdir = child->argv[1]; |
288 | if (chdir(newdir)) { | 295 | if (chdir(newdir)) { |
289 | printf("cd: %s: %s\n", newdir, strerror(errno)); | 296 | printf("cd: %s: %m\n", newdir); |
290 | return EXIT_FAILURE; | 297 | return EXIT_FAILURE; |
291 | } | 298 | } |
292 | getcwd(cwd, sizeof(char)*MAX_LINE); | 299 | getcwd(cwd, sizeof(char)*MAX_LINE); |
@@ -425,13 +432,20 @@ static int builtin_pwd(struct child_prog *dummy) | |||
425 | static int builtin_export(struct child_prog *child) | 432 | static int builtin_export(struct child_prog *child) |
426 | { | 433 | { |
427 | int res; | 434 | int res; |
435 | char *v = child->argv[1]; | ||
428 | 436 | ||
429 | if (child->argv[1] == NULL) { | 437 | if (v == NULL) { |
430 | return (builtin_env(child)); | 438 | return (builtin_env(child)); |
431 | } | 439 | } |
432 | res = putenv(child->argv[1]); | 440 | res = putenv(v); |
433 | if (res) | 441 | if (res) |
434 | fprintf(stderr, "export: %s\n", strerror(errno)); | 442 | fprintf(stderr, "export: %m\n"); |
443 | #ifndef BB_FEATURE_SIMPLE_PROMPT | ||
444 | if (strncmp(v, "PS1=", 4)==0) | ||
445 | PS1 = getenv("PS1"); | ||
446 | else if (strncmp(v, "PS2=", 4)==0) | ||
447 | PS2 = getenv("PS2"); | ||
448 | #endif | ||
435 | return (res); | 449 | return (res); |
436 | } | 450 | } |
437 | 451 | ||
@@ -461,7 +475,7 @@ static int builtin_read(struct child_prog *child) | |||
461 | if((s = strdup(string))) | 475 | if((s = strdup(string))) |
462 | res = putenv(s); | 476 | res = putenv(s); |
463 | if (res) | 477 | if (res) |
464 | fprintf(stderr, "read: %s\n", strerror(errno)); | 478 | fprintf(stderr, "read: %m\n"); |
465 | } | 479 | } |
466 | else | 480 | else |
467 | fgets(string, sizeof(string), stdin); | 481 | fgets(string, sizeof(string), stdin); |
@@ -759,8 +773,7 @@ static int setup_redirects(struct child_prog *prog, int squirrel[]) | |||
759 | if (openfd < 0) { | 773 | if (openfd < 0) { |
760 | /* this could get lost if stderr has been redirected, but | 774 | /* this could get lost if stderr has been redirected, but |
761 | bash and ash both lose it as well (though zsh doesn't!) */ | 775 | bash and ash both lose it as well (though zsh doesn't!) */ |
762 | error_msg("error opening %s: %s", redir->filename, | 776 | perror_msg("error opening %s", redir->filename); |
763 | strerror(errno)); | ||
764 | return 1; | 777 | return 1; |
765 | } | 778 | } |
766 | 779 | ||
@@ -790,57 +803,40 @@ static void restore_redirects(int squirrel[]) | |||
790 | } | 803 | } |
791 | } | 804 | } |
792 | 805 | ||
793 | #if defined(BB_FEATURE_SH_SIMPLE_PROMPT) | 806 | static inline void cmdedit_set_initial_prompt(void) |
794 | static char* setup_prompt_string(int state) | ||
795 | { | 807 | { |
796 | char prompt_str[BUFSIZ]; | 808 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
797 | 809 | PS1 = NULL; | |
798 | /* Set up the prompt */ | 810 | PS2 = "> "; |
799 | if (state == 0) { | ||
800 | /* simple prompt */ | ||
801 | sprintf(prompt_str, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); | ||
802 | } else { | ||
803 | strcpy(prompt_str,"> "); | ||
804 | } | ||
805 | |||
806 | return(strdup(prompt_str)); /* Must free this memory */ | ||
807 | } | ||
808 | |||
809 | #else | 811 | #else |
812 | PS1 = getenv("PS1"); | ||
813 | if(PS1==0) { | ||
814 | PS1 = "\\w \\$ "; | ||
815 | } | ||
816 | PS2 = getenv("PS2"); | ||
817 | if(PS2==0) | ||
818 | PS2 = "> "; | ||
819 | #endif | ||
820 | } | ||
810 | 821 | ||
811 | static char* setup_prompt_string(int state) | 822 | static inline void setup_prompt_string(char **prompt_str) |
812 | { | 823 | { |
813 | char user[9],buf[255],*s; | 824 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
814 | char prompt[3]; | ||
815 | char prompt_str[BUFSIZ]; | ||
816 | |||
817 | /* Set up the prompt */ | 825 | /* Set up the prompt */ |
818 | if (state == 0) { | 826 | if (shell_context == 0) { |
819 | /* get User Name and setup prompt */ | 827 | if (PS1) |
820 | strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# "); | 828 | free(PS1); |
821 | my_getpwuid(user, geteuid()); | 829 | PS1=xmalloc(strlen(cwd)+4); |
822 | 830 | sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); | |
823 | /* get HostName */ | 831 | *prompt_str = PS1; |
824 | gethostname(buf, 255); | ||
825 | s = strchr(buf, '.'); | ||
826 | if (s) { | ||
827 | *s = 0; | ||
828 | } | ||
829 | } else { | 832 | } else { |
830 | strcpy(prompt,"> "); | 833 | *prompt_str = PS2; |
831 | } | 834 | } |
832 | 835 | #else | |
833 | if (state == 0) { | 836 | *prompt_str = (shell_context==0)? PS1 : PS2; |
834 | snprintf(prompt_str, BUFSIZ-1, "[%s@%s %s]%s", user, buf, | 837 | #endif |
835 | get_last_path_component(cwd), prompt); | ||
836 | } else { | ||
837 | sprintf(prompt_str, "%s", prompt); | ||
838 | } | ||
839 | return(strdup(prompt_str)); /* Must free this memory */ | ||
840 | } | 838 | } |
841 | 839 | ||
842 | #endif | ||
843 | |||
844 | static int get_command(FILE * source, char *command) | 840 | static int get_command(FILE * source, char *command) |
845 | { | 841 | { |
846 | char *prompt_str; | 842 | char *prompt_str; |
@@ -857,9 +853,9 @@ static int get_command(FILE * source, char *command) | |||
857 | } | 853 | } |
858 | 854 | ||
859 | if (source == stdin) { | 855 | if (source == stdin) { |
860 | prompt_str = setup_prompt_string(shell_context); | 856 | setup_prompt_string(&prompt_str); |
861 | 857 | ||
862 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 858 | #ifdef BB_FEATURE_COMMAND_EDITING |
863 | /* | 859 | /* |
864 | ** enable command line editing only while a command line | 860 | ** enable command line editing only while a command line |
865 | ** is actually being read; otherwise, we'll end up bequeathing | 861 | ** is actually being read; otherwise, we'll end up bequeathing |
@@ -868,11 +864,9 @@ static int get_command(FILE * source, char *command) | |||
868 | */ | 864 | */ |
869 | cmdedit_read_input(prompt_str, command); | 865 | cmdedit_read_input(prompt_str, command); |
870 | cmdedit_terminate(); | 866 | cmdedit_terminate(); |
871 | free(prompt_str); | ||
872 | return 0; | 867 | return 0; |
873 | #else | 868 | #else |
874 | fputs(prompt_str, stdout); | 869 | fputs(prompt_str, stdout); |
875 | free(prompt_str); | ||
876 | #endif | 870 | #endif |
877 | } | 871 | } |
878 | 872 | ||
@@ -910,25 +904,72 @@ static char* itoa(register int i) | |||
910 | } | 904 | } |
911 | #endif | 905 | #endif |
912 | 906 | ||
907 | #if defined BB_FEATURE_SH_ENVIRONMENT && ! defined BB_FEATURE_SH_WORDEXP | ||
908 | char * strsep_space( char *string, int * index) | ||
909 | { | ||
910 | char *token, *begin; | ||
911 | |||
912 | begin = string; | ||
913 | |||
914 | /* Short circuit the trivial case */ | ||
915 | if ( !string || ! string[*index]) | ||
916 | return NULL; | ||
917 | |||
918 | /* Find the end of the token. */ | ||
919 | while( string && string[*index] && !isspace(string[*index]) ) { | ||
920 | (*index)++; | ||
921 | } | ||
922 | |||
923 | /* Find the end of any whitespace trailing behind | ||
924 | * the token and let that be part of the token */ | ||
925 | while( string && string[*index] && isspace(string[*index]) ) { | ||
926 | (*index)++; | ||
927 | } | ||
928 | |||
929 | if (! string && *index==0) { | ||
930 | /* Nothing useful was found */ | ||
931 | return NULL; | ||
932 | } | ||
933 | |||
934 | token = xmalloc(*index); | ||
935 | token[*index] = '\0'; | ||
936 | strncpy(token, string, *index); | ||
937 | |||
938 | return token; | ||
939 | } | ||
940 | #endif | ||
941 | |||
942 | |||
913 | static int expand_arguments(char *command) | 943 | static int expand_arguments(char *command) |
914 | { | 944 | { |
915 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 945 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
916 | expand_t expand_result; | 946 | expand_t expand_result; |
917 | char *src, *dst, *var; | 947 | char *src, *dst, *var; |
948 | int index = 0; | ||
918 | int i=0, length, total_length=0, retval; | 949 | int i=0, length, total_length=0, retval; |
919 | const char *out_of_space = "out of space during expansion"; | 950 | const char *out_of_space = "out of space during expansion"; |
920 | #endif | 951 | #endif |
921 | 952 | ||
922 | /* get rid of the terminating \n */ | 953 | /* get rid of the terminating \n */ |
923 | chomp(command); | 954 | chomp(command); |
955 | |||
956 | /* Fix up escape sequences to be the Real Thing(tm) */ | ||
957 | while( command && command[index]) { | ||
958 | if (command[index] == '\\') { | ||
959 | char *tmp = command+index+1; | ||
960 | command[index+1] = process_escape_sequence( &tmp ); | ||
961 | memmove(command+index, command+index+1, strlen(command+index)); | ||
962 | } | ||
963 | index++; | ||
964 | } | ||
924 | 965 | ||
925 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 966 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
926 | 967 | ||
927 | 968 | ||
928 | #if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__) | 969 | #if BB_FEATURE_SH_WORDEXP |
929 | /* This first part uses wordexp() which is a wonderful C lib | 970 | /* This first part uses wordexp() which is a wonderful C lib |
930 | * function which expands nearly everything. */ | 971 | * function which expands nearly everything. */ |
931 | retval = wordexp (command, &expand_result, 0); | 972 | retval = wordexp (command, &expand_result, WRDE_SHOWERR); |
932 | if (retval == WRDE_NOSPACE) { | 973 | if (retval == WRDE_NOSPACE) { |
933 | /* Mem may have been allocated... */ | 974 | /* Mem may have been allocated... */ |
934 | wordfree (&expand_result); | 975 | wordfree (&expand_result); |
@@ -970,15 +1011,17 @@ static int expand_arguments(char *command) | |||
970 | { | 1011 | { |
971 | 1012 | ||
972 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; | 1013 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; |
973 | char * tmpcmd, *cmd, *cmd_copy; | 1014 | char *tmpcmd, *cmd, *cmd_copy; |
974 | /* We need a clean copy, so strsep can mess up the copy while | 1015 | /* We need a clean copy, so strsep can mess up the copy while |
975 | * we write stuff into the original (in a minute) */ | 1016 | * we write stuff into the original (in a minute) */ |
976 | cmd = cmd_copy = strdup(command); | 1017 | cmd = cmd_copy = strdup(command); |
977 | *command = '\0'; | 1018 | *command = '\0'; |
978 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { | 1019 | for (index = 0, tmpcmd = cmd; |
1020 | (tmpcmd = strsep_space(cmd, &index)) != NULL; cmd += index, index=0) { | ||
979 | if (*tmpcmd == '\0') | 1021 | if (*tmpcmd == '\0') |
980 | break; | 1022 | break; |
981 | retval = glob(tmpcmd, flags, NULL, &expand_result); | 1023 | retval = glob(tmpcmd, flags, NULL, &expand_result); |
1024 | free(tmpcmd); /* Free mem allocated by strsep_space */ | ||
982 | if (retval == GLOB_NOSPACE) { | 1025 | if (retval == GLOB_NOSPACE) { |
983 | /* Mem may have been allocated... */ | 1026 | /* Mem may have been allocated... */ |
984 | globfree (&expand_result); | 1027 | globfree (&expand_result); |
@@ -1711,7 +1754,8 @@ static int busy_loop(FILE * input) | |||
1711 | if (!parse_command(&next_command, &newjob, &inbg) && | 1754 | if (!parse_command(&next_command, &newjob, &inbg) && |
1712 | newjob.num_progs) { | 1755 | newjob.num_progs) { |
1713 | int pipefds[2] = {-1,-1}; | 1756 | int pipefds[2] = {-1,-1}; |
1714 | debug_printf( "job=%p being fed to run_command by busy_loop()'\n", &newjob); | 1757 | debug_printf( "job=%p fed to run_command by busy_loop()'\n", |
1758 | &newjob); | ||
1715 | run_command(&newjob, inbg, pipefds); | 1759 | run_command(&newjob, inbg, pipefds); |
1716 | } | 1760 | } |
1717 | else { | 1761 | else { |
@@ -1879,5 +1923,13 @@ int shell_main(int argc_l, char **argv_l) | |||
1879 | atexit(free_memory); | 1923 | atexit(free_memory); |
1880 | #endif | 1924 | #endif |
1881 | 1925 | ||
1926 | #ifdef BB_FEATURE_COMMAND_EDITING | ||
1927 | cmdedit_set_initial_prompt(); | ||
1928 | #else | ||
1929 | PS1 = NULL; | ||
1930 | PS2 = "> "; | ||
1931 | #endif | ||
1932 | |||
1882 | return (busy_loop(input)); | 1933 | return (busy_loop(input)); |
1883 | } | 1934 | } |
1935 | |||
@@ -39,11 +39,15 @@ | |||
39 | //#define BB_FEATURE_SH_BACKTICKS | 39 | //#define BB_FEATURE_SH_BACKTICKS |
40 | // | 40 | // |
41 | //If, then, else, etc. support.. This should now behave basically | 41 | //If, then, else, etc. support.. This should now behave basically |
42 | //like any other Bourne shell... | 42 | //like any other Bourne shell -- sortof... |
43 | #define BB_FEATURE_SH_IF_EXPRESSIONS | 43 | #define BB_FEATURE_SH_IF_EXPRESSIONS |
44 | // | 44 | // |
45 | /* This is currently a little broken... */ | 45 | /* This is currently sortof broken, only for the brave... */ |
46 | //#define HANDLE_CONTINUATION_CHARS | 46 | #undef HANDLE_CONTINUATION_CHARS |
47 | // | ||
48 | /* This would be great -- if wordexp wouldn't strip all quoting | ||
49 | * out from the target strings... As is, a parser needs */ | ||
50 | #undef BB_FEATURE_SH_WORDEXP | ||
47 | // | 51 | // |
48 | //For debugging/development on the shell only... | 52 | //For debugging/development on the shell only... |
49 | //#define DEBUG_SHELL | 53 | //#define DEBUG_SHELL |
@@ -61,10 +65,9 @@ | |||
61 | #include <unistd.h> | 65 | #include <unistd.h> |
62 | #include <getopt.h> | 66 | #include <getopt.h> |
63 | 67 | ||
64 | //#undef __GLIBC__ | 68 | #undef BB_FEATURE_SH_WORDEXP |
65 | //#undef __UCLIBC__ | ||
66 | 69 | ||
67 | #if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__) | 70 | #if BB_FEATURE_SH_WORDEXP |
68 | #include <wordexp.h> | 71 | #include <wordexp.h> |
69 | #define expand_t wordexp_t | 72 | #define expand_t wordexp_t |
70 | #undef BB_FEATURE_SH_BACKTICKS | 73 | #undef BB_FEATURE_SH_BACKTICKS |
@@ -227,6 +230,10 @@ static int show_x_trace; | |||
227 | static char syntax_err[]="syntax error near unexpected token"; | 230 | static char syntax_err[]="syntax error near unexpected token"; |
228 | #endif | 231 | #endif |
229 | 232 | ||
233 | static char *PS1; | ||
234 | static char *PS2; | ||
235 | |||
236 | |||
230 | #ifdef DEBUG_SHELL | 237 | #ifdef DEBUG_SHELL |
231 | static inline void debug_printf(const char *format, ...) | 238 | static inline void debug_printf(const char *format, ...) |
232 | { | 239 | { |
@@ -286,7 +293,7 @@ static int builtin_cd(struct child_prog *child) | |||
286 | else | 293 | else |
287 | newdir = child->argv[1]; | 294 | newdir = child->argv[1]; |
288 | if (chdir(newdir)) { | 295 | if (chdir(newdir)) { |
289 | printf("cd: %s: %s\n", newdir, strerror(errno)); | 296 | printf("cd: %s: %m\n", newdir); |
290 | return EXIT_FAILURE; | 297 | return EXIT_FAILURE; |
291 | } | 298 | } |
292 | getcwd(cwd, sizeof(char)*MAX_LINE); | 299 | getcwd(cwd, sizeof(char)*MAX_LINE); |
@@ -425,13 +432,20 @@ static int builtin_pwd(struct child_prog *dummy) | |||
425 | static int builtin_export(struct child_prog *child) | 432 | static int builtin_export(struct child_prog *child) |
426 | { | 433 | { |
427 | int res; | 434 | int res; |
435 | char *v = child->argv[1]; | ||
428 | 436 | ||
429 | if (child->argv[1] == NULL) { | 437 | if (v == NULL) { |
430 | return (builtin_env(child)); | 438 | return (builtin_env(child)); |
431 | } | 439 | } |
432 | res = putenv(child->argv[1]); | 440 | res = putenv(v); |
433 | if (res) | 441 | if (res) |
434 | fprintf(stderr, "export: %s\n", strerror(errno)); | 442 | fprintf(stderr, "export: %m\n"); |
443 | #ifndef BB_FEATURE_SIMPLE_PROMPT | ||
444 | if (strncmp(v, "PS1=", 4)==0) | ||
445 | PS1 = getenv("PS1"); | ||
446 | else if (strncmp(v, "PS2=", 4)==0) | ||
447 | PS2 = getenv("PS2"); | ||
448 | #endif | ||
435 | return (res); | 449 | return (res); |
436 | } | 450 | } |
437 | 451 | ||
@@ -461,7 +475,7 @@ static int builtin_read(struct child_prog *child) | |||
461 | if((s = strdup(string))) | 475 | if((s = strdup(string))) |
462 | res = putenv(s); | 476 | res = putenv(s); |
463 | if (res) | 477 | if (res) |
464 | fprintf(stderr, "read: %s\n", strerror(errno)); | 478 | fprintf(stderr, "read: %m\n"); |
465 | } | 479 | } |
466 | else | 480 | else |
467 | fgets(string, sizeof(string), stdin); | 481 | fgets(string, sizeof(string), stdin); |
@@ -759,8 +773,7 @@ static int setup_redirects(struct child_prog *prog, int squirrel[]) | |||
759 | if (openfd < 0) { | 773 | if (openfd < 0) { |
760 | /* this could get lost if stderr has been redirected, but | 774 | /* this could get lost if stderr has been redirected, but |
761 | bash and ash both lose it as well (though zsh doesn't!) */ | 775 | bash and ash both lose it as well (though zsh doesn't!) */ |
762 | error_msg("error opening %s: %s", redir->filename, | 776 | perror_msg("error opening %s", redir->filename); |
763 | strerror(errno)); | ||
764 | return 1; | 777 | return 1; |
765 | } | 778 | } |
766 | 779 | ||
@@ -790,57 +803,40 @@ static void restore_redirects(int squirrel[]) | |||
790 | } | 803 | } |
791 | } | 804 | } |
792 | 805 | ||
793 | #if defined(BB_FEATURE_SH_SIMPLE_PROMPT) | 806 | static inline void cmdedit_set_initial_prompt(void) |
794 | static char* setup_prompt_string(int state) | ||
795 | { | 807 | { |
796 | char prompt_str[BUFSIZ]; | 808 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
797 | 809 | PS1 = NULL; | |
798 | /* Set up the prompt */ | 810 | PS2 = "> "; |
799 | if (state == 0) { | ||
800 | /* simple prompt */ | ||
801 | sprintf(prompt_str, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); | ||
802 | } else { | ||
803 | strcpy(prompt_str,"> "); | ||
804 | } | ||
805 | |||
806 | return(strdup(prompt_str)); /* Must free this memory */ | ||
807 | } | ||
808 | |||
809 | #else | 811 | #else |
812 | PS1 = getenv("PS1"); | ||
813 | if(PS1==0) { | ||
814 | PS1 = "\\w \\$ "; | ||
815 | } | ||
816 | PS2 = getenv("PS2"); | ||
817 | if(PS2==0) | ||
818 | PS2 = "> "; | ||
819 | #endif | ||
820 | } | ||
810 | 821 | ||
811 | static char* setup_prompt_string(int state) | 822 | static inline void setup_prompt_string(char **prompt_str) |
812 | { | 823 | { |
813 | char user[9],buf[255],*s; | 824 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
814 | char prompt[3]; | ||
815 | char prompt_str[BUFSIZ]; | ||
816 | |||
817 | /* Set up the prompt */ | 825 | /* Set up the prompt */ |
818 | if (state == 0) { | 826 | if (shell_context == 0) { |
819 | /* get User Name and setup prompt */ | 827 | if (PS1) |
820 | strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# "); | 828 | free(PS1); |
821 | my_getpwuid(user, geteuid()); | 829 | PS1=xmalloc(strlen(cwd)+4); |
822 | 830 | sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); | |
823 | /* get HostName */ | 831 | *prompt_str = PS1; |
824 | gethostname(buf, 255); | ||
825 | s = strchr(buf, '.'); | ||
826 | if (s) { | ||
827 | *s = 0; | ||
828 | } | ||
829 | } else { | 832 | } else { |
830 | strcpy(prompt,"> "); | 833 | *prompt_str = PS2; |
831 | } | 834 | } |
832 | 835 | #else | |
833 | if (state == 0) { | 836 | *prompt_str = (shell_context==0)? PS1 : PS2; |
834 | snprintf(prompt_str, BUFSIZ-1, "[%s@%s %s]%s", user, buf, | 837 | #endif |
835 | get_last_path_component(cwd), prompt); | ||
836 | } else { | ||
837 | sprintf(prompt_str, "%s", prompt); | ||
838 | } | ||
839 | return(strdup(prompt_str)); /* Must free this memory */ | ||
840 | } | 838 | } |
841 | 839 | ||
842 | #endif | ||
843 | |||
844 | static int get_command(FILE * source, char *command) | 840 | static int get_command(FILE * source, char *command) |
845 | { | 841 | { |
846 | char *prompt_str; | 842 | char *prompt_str; |
@@ -857,9 +853,9 @@ static int get_command(FILE * source, char *command) | |||
857 | } | 853 | } |
858 | 854 | ||
859 | if (source == stdin) { | 855 | if (source == stdin) { |
860 | prompt_str = setup_prompt_string(shell_context); | 856 | setup_prompt_string(&prompt_str); |
861 | 857 | ||
862 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 858 | #ifdef BB_FEATURE_COMMAND_EDITING |
863 | /* | 859 | /* |
864 | ** enable command line editing only while a command line | 860 | ** enable command line editing only while a command line |
865 | ** is actually being read; otherwise, we'll end up bequeathing | 861 | ** is actually being read; otherwise, we'll end up bequeathing |
@@ -868,11 +864,9 @@ static int get_command(FILE * source, char *command) | |||
868 | */ | 864 | */ |
869 | cmdedit_read_input(prompt_str, command); | 865 | cmdedit_read_input(prompt_str, command); |
870 | cmdedit_terminate(); | 866 | cmdedit_terminate(); |
871 | free(prompt_str); | ||
872 | return 0; | 867 | return 0; |
873 | #else | 868 | #else |
874 | fputs(prompt_str, stdout); | 869 | fputs(prompt_str, stdout); |
875 | free(prompt_str); | ||
876 | #endif | 870 | #endif |
877 | } | 871 | } |
878 | 872 | ||
@@ -910,25 +904,72 @@ static char* itoa(register int i) | |||
910 | } | 904 | } |
911 | #endif | 905 | #endif |
912 | 906 | ||
907 | #if defined BB_FEATURE_SH_ENVIRONMENT && ! defined BB_FEATURE_SH_WORDEXP | ||
908 | char * strsep_space( char *string, int * index) | ||
909 | { | ||
910 | char *token, *begin; | ||
911 | |||
912 | begin = string; | ||
913 | |||
914 | /* Short circuit the trivial case */ | ||
915 | if ( !string || ! string[*index]) | ||
916 | return NULL; | ||
917 | |||
918 | /* Find the end of the token. */ | ||
919 | while( string && string[*index] && !isspace(string[*index]) ) { | ||
920 | (*index)++; | ||
921 | } | ||
922 | |||
923 | /* Find the end of any whitespace trailing behind | ||
924 | * the token and let that be part of the token */ | ||
925 | while( string && string[*index] && isspace(string[*index]) ) { | ||
926 | (*index)++; | ||
927 | } | ||
928 | |||
929 | if (! string && *index==0) { | ||
930 | /* Nothing useful was found */ | ||
931 | return NULL; | ||
932 | } | ||
933 | |||
934 | token = xmalloc(*index); | ||
935 | token[*index] = '\0'; | ||
936 | strncpy(token, string, *index); | ||
937 | |||
938 | return token; | ||
939 | } | ||
940 | #endif | ||
941 | |||
942 | |||
913 | static int expand_arguments(char *command) | 943 | static int expand_arguments(char *command) |
914 | { | 944 | { |
915 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 945 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
916 | expand_t expand_result; | 946 | expand_t expand_result; |
917 | char *src, *dst, *var; | 947 | char *src, *dst, *var; |
948 | int index = 0; | ||
918 | int i=0, length, total_length=0, retval; | 949 | int i=0, length, total_length=0, retval; |
919 | const char *out_of_space = "out of space during expansion"; | 950 | const char *out_of_space = "out of space during expansion"; |
920 | #endif | 951 | #endif |
921 | 952 | ||
922 | /* get rid of the terminating \n */ | 953 | /* get rid of the terminating \n */ |
923 | chomp(command); | 954 | chomp(command); |
955 | |||
956 | /* Fix up escape sequences to be the Real Thing(tm) */ | ||
957 | while( command && command[index]) { | ||
958 | if (command[index] == '\\') { | ||
959 | char *tmp = command+index+1; | ||
960 | command[index+1] = process_escape_sequence( &tmp ); | ||
961 | memmove(command+index, command+index+1, strlen(command+index)); | ||
962 | } | ||
963 | index++; | ||
964 | } | ||
924 | 965 | ||
925 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 966 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
926 | 967 | ||
927 | 968 | ||
928 | #if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__) | 969 | #if BB_FEATURE_SH_WORDEXP |
929 | /* This first part uses wordexp() which is a wonderful C lib | 970 | /* This first part uses wordexp() which is a wonderful C lib |
930 | * function which expands nearly everything. */ | 971 | * function which expands nearly everything. */ |
931 | retval = wordexp (command, &expand_result, 0); | 972 | retval = wordexp (command, &expand_result, WRDE_SHOWERR); |
932 | if (retval == WRDE_NOSPACE) { | 973 | if (retval == WRDE_NOSPACE) { |
933 | /* Mem may have been allocated... */ | 974 | /* Mem may have been allocated... */ |
934 | wordfree (&expand_result); | 975 | wordfree (&expand_result); |
@@ -970,15 +1011,17 @@ static int expand_arguments(char *command) | |||
970 | { | 1011 | { |
971 | 1012 | ||
972 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; | 1013 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; |
973 | char * tmpcmd, *cmd, *cmd_copy; | 1014 | char *tmpcmd, *cmd, *cmd_copy; |
974 | /* We need a clean copy, so strsep can mess up the copy while | 1015 | /* We need a clean copy, so strsep can mess up the copy while |
975 | * we write stuff into the original (in a minute) */ | 1016 | * we write stuff into the original (in a minute) */ |
976 | cmd = cmd_copy = strdup(command); | 1017 | cmd = cmd_copy = strdup(command); |
977 | *command = '\0'; | 1018 | *command = '\0'; |
978 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { | 1019 | for (index = 0, tmpcmd = cmd; |
1020 | (tmpcmd = strsep_space(cmd, &index)) != NULL; cmd += index, index=0) { | ||
979 | if (*tmpcmd == '\0') | 1021 | if (*tmpcmd == '\0') |
980 | break; | 1022 | break; |
981 | retval = glob(tmpcmd, flags, NULL, &expand_result); | 1023 | retval = glob(tmpcmd, flags, NULL, &expand_result); |
1024 | free(tmpcmd); /* Free mem allocated by strsep_space */ | ||
982 | if (retval == GLOB_NOSPACE) { | 1025 | if (retval == GLOB_NOSPACE) { |
983 | /* Mem may have been allocated... */ | 1026 | /* Mem may have been allocated... */ |
984 | globfree (&expand_result); | 1027 | globfree (&expand_result); |
@@ -1711,7 +1754,8 @@ static int busy_loop(FILE * input) | |||
1711 | if (!parse_command(&next_command, &newjob, &inbg) && | 1754 | if (!parse_command(&next_command, &newjob, &inbg) && |
1712 | newjob.num_progs) { | 1755 | newjob.num_progs) { |
1713 | int pipefds[2] = {-1,-1}; | 1756 | int pipefds[2] = {-1,-1}; |
1714 | debug_printf( "job=%p being fed to run_command by busy_loop()'\n", &newjob); | 1757 | debug_printf( "job=%p fed to run_command by busy_loop()'\n", |
1758 | &newjob); | ||
1715 | run_command(&newjob, inbg, pipefds); | 1759 | run_command(&newjob, inbg, pipefds); |
1716 | } | 1760 | } |
1717 | else { | 1761 | else { |
@@ -1879,5 +1923,13 @@ int shell_main(int argc_l, char **argv_l) | |||
1879 | atexit(free_memory); | 1923 | atexit(free_memory); |
1880 | #endif | 1924 | #endif |
1881 | 1925 | ||
1926 | #ifdef BB_FEATURE_COMMAND_EDITING | ||
1927 | cmdedit_set_initial_prompt(); | ||
1928 | #else | ||
1929 | PS1 = NULL; | ||
1930 | PS2 = "> "; | ||
1931 | #endif | ||
1932 | |||
1882 | return (busy_loop(input)); | 1933 | return (busy_loop(input)); |
1883 | } | 1934 | } |
1935 | |||
diff --git a/shell/cmdedit.c b/shell/cmdedit.c index 272d22fc0..1b5cbbfab 100644 --- a/shell/cmdedit.c +++ b/shell/cmdedit.c | |||
@@ -27,6 +27,7 @@ | |||
27 | Small bugs (simple effect): | 27 | Small bugs (simple effect): |
28 | - not true viewing if terminal size (x*y symbols) less | 28 | - not true viewing if terminal size (x*y symbols) less |
29 | size (prompt + editor`s line + 2 symbols) | 29 | size (prompt + editor`s line + 2 symbols) |
30 | - not true viewing if length prompt less terminal width | ||
30 | */ | 31 | */ |
31 | 32 | ||
32 | 33 | ||
@@ -50,29 +51,36 @@ | |||
50 | 51 | ||
51 | #else | 52 | #else |
52 | 53 | ||
53 | #define BB_FEATURE_SH_COMMAND_EDITING | 54 | #define BB_FEATURE_COMMAND_EDITING |
54 | #define BB_FEATURE_SH_TAB_COMPLETION | 55 | #define BB_FEATURE_COMMAND_TAB_COMPLETION |
55 | #define BB_FEATURE_SH_USERNAME_COMPLETION | 56 | #define BB_FEATURE_COMMAND_USERNAME_COMPLETION |
56 | #define BB_FEATURE_NONPRINTABLE_INVERSE_PUT | 57 | #define BB_FEATURE_NONPRINTABLE_INVERSE_PUT |
57 | #define BB_FEATURE_BASH_STYLE_PROMT | 58 | #undef BB_FEATURE_SIMPLE_PROMPT |
58 | #define BB_FEATURE_CLEAN_UP | 59 | #define BB_FEATURE_CLEAN_UP |
59 | 60 | ||
60 | #define D(x) x | 61 | #define D(x) x |
61 | 62 | ||
63 | #ifndef TRUE | ||
64 | #define TRUE 1 | ||
65 | #endif | ||
66 | #ifndef FALSE | ||
67 | #define FALSE 0 | ||
68 | #endif | ||
69 | |||
62 | #endif /* TEST */ | 70 | #endif /* TEST */ |
63 | 71 | ||
64 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 72 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
65 | #include <dirent.h> | 73 | #include <dirent.h> |
66 | #include <sys/stat.h> | 74 | #include <sys/stat.h> |
67 | #endif | 75 | #endif |
68 | 76 | ||
69 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 77 | #ifdef BB_FEATURE_COMMAND_EDITING |
70 | 78 | ||
71 | #ifndef BB_FEATURE_SH_TAB_COMPLETION | 79 | #ifndef BB_FEATURE_COMMAND_TAB_COMPLETION |
72 | #undef BB_FEATURE_SH_USERNAME_COMPLETION | 80 | #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
73 | #endif | 81 | #endif |
74 | 82 | ||
75 | #if defined(BB_FEATURE_SH_USERNAME_COMPLETION) || defined(BB_FEATURE_BASH_STYLE_PROMT) | 83 | #if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || !defined(BB_FEATURE_SIMPLE_PROMPT) |
76 | #define BB_FEATURE_GETUSERNAME_AND_HOMEDIR | 84 | #define BB_FEATURE_GETUSERNAME_AND_HOMEDIR |
77 | #endif | 85 | #endif |
78 | 86 | ||
@@ -154,26 +162,26 @@ static | |||
154 | volatile int handlers_sets = 0; /* Set next bites: */ | 162 | volatile int handlers_sets = 0; /* Set next bites: */ |
155 | 163 | ||
156 | enum { | 164 | enum { |
157 | SET_ATEXIT = 1, /* when atexit() has been called and | 165 | SET_ATEXIT = 1, /* when atexit() has been called |
158 | get euid,uid,gid to fast compare */ | 166 | and get euid,uid,gid to fast compare */ |
159 | SET_TERM_HANDLERS = 2, /* set many terminates signal handlers */ | 167 | SET_TERM_HANDLERS = 2, /* set many terminates signal handlers */ |
160 | SET_WCHG_HANDLERS = 4, /* winchg signal handler */ | 168 | SET_WCHG_HANDLERS = 4, /* winchg signal handler */ |
161 | SET_RESET_TERM = 8, /* if the terminal needs to be reset upon exit */ | 169 | SET_RESET_TERM = 8, /* if the terminal needs to be reset upon exit */ |
162 | }; | 170 | }; |
163 | 171 | ||
164 | 172 | ||
165 | static int cmdedit_x; /* real x terminal position */ | 173 | static int cmdedit_x; /* real x terminal position */ |
166 | static int cmdedit_y; /* pseudoreal y terminal position */ | 174 | static int cmdedit_y; /* pseudoreal y terminal position */ |
167 | static int cmdedit_prmt_len; /* lenght prompt without colores string */ | 175 | static int cmdedit_prmt_len; /* lenght prompt without colores string */ |
168 | 176 | ||
169 | static int cursor; /* required global for signal handler */ | 177 | static int cursor; /* required global for signal handler */ |
170 | static int len; /* --- "" - - "" - -"- --""-- --""--- */ | 178 | static int len; /* --- "" - - "" - -"- --""-- --""--- */ |
171 | static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ | 179 | static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ |
172 | static | 180 | static |
173 | #ifndef BB_FEATURE_BASH_STYLE_PROMT | 181 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
174 | const | 182 | const |
175 | #endif | 183 | #endif |
176 | char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ | 184 | char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ |
177 | 185 | ||
178 | /* Link into lash to reset context to 0 on ^C and such */ | 186 | /* Link into lash to reset context to 0 on ^C and such */ |
179 | extern unsigned int shell_context; | 187 | extern unsigned int shell_context; |
@@ -185,13 +193,13 @@ static char *home_pwd_buf = ""; | |||
185 | static int my_euid; | 193 | static int my_euid; |
186 | #endif | 194 | #endif |
187 | 195 | ||
188 | #ifdef BB_FEATURE_BASH_STYLE_PROMT | 196 | #ifndef BB_FEATURE_SIMPLE_PROMPT |
189 | static char *hostname_buf = ""; | 197 | static char *hostname_buf = ""; |
190 | static int num_ok_lines = 1; | 198 | static int num_ok_lines = 1; |
191 | #endif | 199 | #endif |
192 | 200 | ||
193 | 201 | ||
194 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 202 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
195 | 203 | ||
196 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | 204 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR |
197 | static int my_euid; | 205 | static int my_euid; |
@@ -200,7 +208,7 @@ static int my_euid; | |||
200 | static int my_uid; | 208 | static int my_uid; |
201 | static int my_gid; | 209 | static int my_gid; |
202 | 210 | ||
203 | #endif /* BB_FEATURE_SH_TAB_COMPLETION */ | 211 | #endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ |
204 | 212 | ||
205 | 213 | ||
206 | static void cmdedit_setwidth(int w, int redraw_flg); | 214 | static void cmdedit_setwidth(int w, int redraw_flg); |
@@ -245,7 +253,6 @@ static void cmdedit_reset_term(void) | |||
245 | if (his_front) { | 253 | if (his_front) { |
246 | struct history *n; | 254 | struct history *n; |
247 | 255 | ||
248 | //while(his_front!=his_end) { | ||
249 | while (his_front != his_end) { | 256 | while (his_front != his_end) { |
250 | n = his_front->n; | 257 | n = his_front->n; |
251 | free(his_front->s); | 258 | free(his_front->s); |
@@ -355,25 +362,27 @@ static void put_prompt(void) | |||
355 | cursor = 0; | 362 | cursor = 0; |
356 | } | 363 | } |
357 | 364 | ||
358 | #ifdef BB_FEATURE_BASH_STYLE_PROMT | 365 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
359 | static void | 366 | static void parse_prompt(const char *prmt_ptr) |
360 | add_to_prompt(char **prmt_mem_ptr, int *alm, int *prmt_len, | ||
361 | const char *addb) | ||
362 | { | 367 | { |
363 | int l = strlen(addb); | 368 | cmdedit_prompt = prmt_ptr; |
364 | 369 | cmdedit_prmt_len = strlen(prmt_ptr); | |
365 | *prmt_len += l; | 370 | put_prompt(); |
371 | } | ||
372 | #else | ||
373 | static void add_to_prompt(char **prmt_mem_ptr, int *alm, | ||
374 | int *prmt_len, const char *addb) | ||
375 | { | ||
376 | *prmt_len += strlen(addb); | ||
366 | if (*alm < (*prmt_len) + 1) { | 377 | if (*alm < (*prmt_len) + 1) { |
367 | *alm = (*prmt_len) + 1; | 378 | *alm = (*prmt_len) + 1; |
368 | *prmt_mem_ptr = xrealloc(*prmt_mem_ptr, *alm); | 379 | *prmt_mem_ptr = xrealloc(*prmt_mem_ptr, *alm); |
369 | } | 380 | } |
370 | strcat(*prmt_mem_ptr, addb); | 381 | strcat(*prmt_mem_ptr, addb); |
371 | } | 382 | } |
372 | #endif | ||
373 | 383 | ||
374 | static void parse_prompt(const char *prmt_ptr) | 384 | static void parse_prompt(const char *prmt_ptr) |
375 | { | 385 | { |
376 | #ifdef BB_FEATURE_BASH_STYLE_PROMT | ||
377 | int alm = strlen(prmt_ptr) + 1; /* supposedly require memory */ | 386 | int alm = strlen(prmt_ptr) + 1; /* supposedly require memory */ |
378 | int prmt_len = 0; | 387 | int prmt_len = 0; |
379 | int sub_len = 0; | 388 | int sub_len = 0; |
@@ -394,9 +403,11 @@ static void parse_prompt(const char *prmt_ptr) | |||
394 | break; | 403 | break; |
395 | prmt_ptr++; | 404 | prmt_ptr++; |
396 | switch (c) { | 405 | switch (c) { |
406 | #ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
397 | case 'u': | 407 | case 'u': |
398 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, user_buf); | 408 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, user_buf); |
399 | continue; | 409 | continue; |
410 | #endif | ||
400 | case 'h': | 411 | case 'h': |
401 | if (hostname_buf[0] == 0) { | 412 | if (hostname_buf[0] == 0) { |
402 | hostname_buf = xcalloc(256, 1); | 413 | hostname_buf = xcalloc(256, 1); |
@@ -415,6 +426,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
415 | case '$': | 426 | case '$': |
416 | c = my_euid == 0 ? '#' : '$'; | 427 | c = my_euid == 0 ? '#' : '$'; |
417 | break; | 428 | break; |
429 | #ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
418 | case 'w': | 430 | case 'w': |
419 | if (pwd_buf[0] == 0) { | 431 | if (pwd_buf[0] == 0) { |
420 | int l; | 432 | int l; |
@@ -429,6 +441,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
429 | } | 441 | } |
430 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, pwd_buf); | 442 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, pwd_buf); |
431 | continue; | 443 | continue; |
444 | #endif | ||
432 | case '!': | 445 | case '!': |
433 | snprintf(buf, sizeof(buf), "%d", num_ok_lines); | 446 | snprintf(buf, sizeof(buf), "%d", num_ok_lines); |
434 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, buf); | 447 | add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, buf); |
@@ -485,20 +498,21 @@ static void parse_prompt(const char *prmt_ptr) | |||
485 | if (flg_not_length == ']') | 498 | if (flg_not_length == ']') |
486 | sub_len++; | 499 | sub_len++; |
487 | } | 500 | } |
501 | #if 0 | ||
488 | cmdedit_prmt_len = prmt_len - sub_len; | 502 | cmdedit_prmt_len = prmt_len - sub_len; |
489 | cmdedit_prompt = prmt_mem_ptr; | ||
490 | #else | ||
491 | cmdedit_prompt = prmt_ptr; | 503 | cmdedit_prompt = prmt_ptr; |
492 | cmdedit_prmt_len = strlen(prmt_ptr); | 504 | #endif |
493 | #endif | 505 | cmdedit_prompt = prmt_mem_ptr; |
506 | cmdedit_prmt_len = strlen(cmdedit_prompt); | ||
494 | put_prompt(); | 507 | put_prompt(); |
495 | } | 508 | } |
509 | #endif | ||
496 | 510 | ||
497 | 511 | ||
498 | /* draw promt, editor line, and clear tail */ | 512 | /* draw promt, editor line, and clear tail */ |
499 | static void redraw(int y, int back_cursor) | 513 | static void redraw(int y, int back_cursor) |
500 | { | 514 | { |
501 | if (y > 0) /* up to start y */ | 515 | if (y > 0) /* up to start y */ |
502 | printf("\033[%dA", y); | 516 | printf("\033[%dA", y); |
503 | cmdedit_y = 0; /* new quasireal y */ | 517 | cmdedit_y = 0; /* new quasireal y */ |
504 | putchar('\r'); | 518 | putchar('\r'); |
@@ -518,7 +532,7 @@ static void input_delete(void) | |||
518 | 532 | ||
519 | strcpy(command_ps + j, command_ps + j + 1); | 533 | strcpy(command_ps + j, command_ps + j + 1); |
520 | len--; | 534 | len--; |
521 | input_end(); /* rewtite new line */ | 535 | input_end(); /* rewtite new line */ |
522 | cmdedit_set_out_char(0); /* destroy end char */ | 536 | cmdedit_set_out_char(0); /* destroy end char */ |
523 | input_backward(cursor - j); /* back to old pos cursor */ | 537 | input_backward(cursor - j); /* back to old pos cursor */ |
524 | } | 538 | } |
@@ -545,7 +559,7 @@ static void clean_up_and_die(int sig) | |||
545 | { | 559 | { |
546 | goto_new_line(); | 560 | goto_new_line(); |
547 | if (sig != SIGINT) | 561 | if (sig != SIGINT) |
548 | exit(EXIT_SUCCESS); /* cmdedit_reset_term() called in atexit */ | 562 | exit(EXIT_SUCCESS); /* cmdedit_reset_term() called in atexit */ |
549 | cmdedit_reset_term(); | 563 | cmdedit_reset_term(); |
550 | } | 564 | } |
551 | 565 | ||
@@ -556,7 +570,6 @@ static void cmdedit_setwidth(int w, int redraw_flg) | |||
556 | cmdedit_termw = cmdedit_termw % w; | 570 | cmdedit_termw = cmdedit_termw % w; |
557 | } | 571 | } |
558 | if (w > cmdedit_termw) { | 572 | if (w > cmdedit_termw) { |
559 | |||
560 | cmdedit_termw = w; | 573 | cmdedit_termw = w; |
561 | 574 | ||
562 | if (redraw_flg) { | 575 | if (redraw_flg) { |
@@ -590,14 +603,14 @@ extern void cmdedit_init(void) | |||
590 | } | 603 | } |
591 | #endif | 604 | #endif |
592 | 605 | ||
593 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 606 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
594 | 607 | ||
595 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR | 608 | #ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR |
596 | my_euid = geteuid(); | 609 | my_euid = geteuid(); |
597 | #endif | 610 | #endif |
598 | my_uid = getuid(); | 611 | my_uid = getuid(); |
599 | my_gid = getgid(); | 612 | my_gid = getgid(); |
600 | #endif /* BB_FEATURE_SH_TAB_COMPLETION */ | 613 | #endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ |
601 | handlers_sets |= SET_ATEXIT; | 614 | handlers_sets |= SET_ATEXIT; |
602 | atexit(cmdedit_reset_term); /* be sure to do this only once */ | 615 | atexit(cmdedit_reset_term); /* be sure to do this only once */ |
603 | } | 616 | } |
@@ -612,7 +625,7 @@ extern void cmdedit_init(void) | |||
612 | 625 | ||
613 | } | 626 | } |
614 | 627 | ||
615 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 628 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
616 | 629 | ||
617 | static int is_execute(const struct stat *st) | 630 | static int is_execute(const struct stat *st) |
618 | { | 631 | { |
@@ -623,7 +636,7 @@ static int is_execute(const struct stat *st) | |||
623 | return FALSE; | 636 | return FALSE; |
624 | } | 637 | } |
625 | 638 | ||
626 | #ifdef BB_FEATURE_SH_USERNAME_COMPLETION | 639 | #ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
627 | 640 | ||
628 | static char **username_tab_completion(char *ud, int *num_matches) | 641 | static char **username_tab_completion(char *ud, int *num_matches) |
629 | { | 642 | { |
@@ -632,19 +645,19 @@ static char **username_tab_completion(char *ud, int *num_matches) | |||
632 | char *temp; | 645 | char *temp; |
633 | 646 | ||
634 | 647 | ||
635 | ud++; /* ~user/... to user/... */ | 648 | ud++; /* ~user/... to user/... */ |
636 | userlen = strlen(ud); | 649 | userlen = strlen(ud); |
637 | 650 | ||
638 | if (num_matches == 0) { /* "~/..." or "~user/..." */ | 651 | if (num_matches == 0) { /* "~/..." or "~user/..." */ |
639 | char *sav_ud = ud - 1; | 652 | char *sav_ud = ud - 1; |
640 | char *home = 0; | 653 | char *home = 0; |
641 | 654 | ||
642 | if (*ud == '/') { /* "~/..." */ | 655 | if (*ud == '/') { /* "~/..." */ |
643 | home = home_pwd_buf; | 656 | home = home_pwd_buf; |
644 | } else { | 657 | } else { |
645 | /* "~user/..." */ | 658 | /* "~user/..." */ |
646 | temp = strchr(ud, '/'); | 659 | temp = strchr(ud, '/'); |
647 | *temp = 0; /* ~user\0 */ | 660 | *temp = 0; /* ~user\0 */ |
648 | entry = getpwnam(ud); | 661 | entry = getpwnam(ud); |
649 | *temp = '/'; /* restore ~user/... */ | 662 | *temp = '/'; /* restore ~user/... */ |
650 | ud = temp; | 663 | ud = temp; |
@@ -660,7 +673,7 @@ static char **username_tab_completion(char *ud, int *num_matches) | |||
660 | strcpy(sav_ud, temp2); | 673 | strcpy(sav_ud, temp2); |
661 | } | 674 | } |
662 | } | 675 | } |
663 | return 0; /* void, result save to argument :-) */ | 676 | return 0; /* void, result save to argument :-) */ |
664 | } else { | 677 | } else { |
665 | /* "~[^/]*" */ | 678 | /* "~[^/]*" */ |
666 | char **matches = (char **) NULL; | 679 | char **matches = (char **) NULL; |
@@ -685,7 +698,7 @@ static char **username_tab_completion(char *ud, int *num_matches) | |||
685 | return (matches); | 698 | return (matches); |
686 | } | 699 | } |
687 | } | 700 | } |
688 | #endif /* BB_FEATURE_SH_USERNAME_COMPLETION */ | 701 | #endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ |
689 | 702 | ||
690 | enum { | 703 | enum { |
691 | FIND_EXE_ONLY = 0, | 704 | FIND_EXE_ONLY = 0, |
@@ -710,11 +723,11 @@ static int path_parse(char ***p, int flags) | |||
710 | npth = 0; | 723 | npth = 0; |
711 | 724 | ||
712 | for (;;) { | 725 | for (;;) { |
713 | npth++; /* count words is + 1 count ':' */ | 726 | npth++; /* count words is + 1 count ':' */ |
714 | tmp = strchr(tmp, ':'); | 727 | tmp = strchr(tmp, ':'); |
715 | if (tmp) { | 728 | if (tmp) { |
716 | if (*++tmp == 0) | 729 | if (*++tmp == 0) |
717 | break; /* :<empty> */ | 730 | break; /* :<empty> */ |
718 | } else | 731 | } else |
719 | break; | 732 | break; |
720 | } | 733 | } |
@@ -723,7 +736,7 @@ static int path_parse(char ***p, int flags) | |||
723 | 736 | ||
724 | tmp = pth; | 737 | tmp = pth; |
725 | (*p)[0] = xstrdup(tmp); | 738 | (*p)[0] = xstrdup(tmp); |
726 | npth = 1; /* count words is + 1 count ':' */ | 739 | npth = 1; /* count words is + 1 count ':' */ |
727 | 740 | ||
728 | for (;;) { | 741 | for (;;) { |
729 | tmp = strchr(tmp, ':'); | 742 | tmp = strchr(tmp, ':'); |
@@ -754,7 +767,7 @@ static char *add_quote_for_spec_chars(char *found) | |||
754 | } | 767 | } |
755 | 768 | ||
756 | static char **exe_n_cwd_tab_completion(char *command, int *num_matches, | 769 | static char **exe_n_cwd_tab_completion(char *command, int *num_matches, |
757 | int type) | 770 | int type) |
758 | { | 771 | { |
759 | 772 | ||
760 | char **matches = 0; | 773 | char **matches = 0; |
@@ -782,7 +795,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, | |||
782 | strcpy(dirbuf, command); | 795 | strcpy(dirbuf, command); |
783 | /* set dir only */ | 796 | /* set dir only */ |
784 | dirbuf[(pfind - command) + 1] = 0; | 797 | dirbuf[(pfind - command) + 1] = 0; |
785 | #ifdef BB_FEATURE_SH_USERNAME_COMPLETION | 798 | #ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
786 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ | 799 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ |
787 | username_tab_completion(dirbuf, 0); | 800 | username_tab_completion(dirbuf, 0); |
788 | #endif | 801 | #endif |
@@ -796,7 +809,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, | |||
796 | for (i = 0; i < npaths; i++) { | 809 | for (i = 0; i < npaths; i++) { |
797 | 810 | ||
798 | dir = opendir(paths[i]); | 811 | dir = opendir(paths[i]); |
799 | if (!dir) /* Don't print an error */ | 812 | if (!dir) /* Don't print an error */ |
800 | continue; | 813 | continue; |
801 | 814 | ||
802 | while ((next = readdir(dir)) != NULL) { | 815 | while ((next = readdir(dir)) != NULL) { |
@@ -987,7 +1000,8 @@ static int find_match(char *matchBuf, int *len_with_quotes) | |||
987 | for (i = 0; int_buf[i]; i++) | 1000 | for (i = 0; int_buf[i]; i++) |
988 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { | 1001 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { |
989 | if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY | 1002 | if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY |
990 | && strncmp(&matchBuf[pos_buf[0]], "cd", 2) == 0) | 1003 | && matchBuf[pos_buf[0]]=='c' |
1004 | && matchBuf[pos_buf[1]]=='d' ) | ||
991 | command_mode = FIND_DIR_ONLY; | 1005 | command_mode = FIND_DIR_ONLY; |
992 | else { | 1006 | else { |
993 | command_mode = FIND_FILE_ONLY; | 1007 | command_mode = FIND_FILE_ONLY; |
@@ -1065,7 +1079,7 @@ static void input_tab(int *lastWasTab) | |||
1065 | /* Free up any memory already allocated */ | 1079 | /* Free up any memory already allocated */ |
1066 | input_tab(0); | 1080 | input_tab(0); |
1067 | 1081 | ||
1068 | #ifdef BB_FEATURE_SH_USERNAME_COMPLETION | 1082 | #ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION |
1069 | /* If the word starts with `~' and there is no slash in the word, | 1083 | /* If the word starts with `~' and there is no slash in the word, |
1070 | * then try completing this word as a username. */ | 1084 | * then try completing this word as a username. */ |
1071 | 1085 | ||
@@ -1085,7 +1099,7 @@ static void input_tab(int *lastWasTab) | |||
1085 | 1099 | ||
1086 | beep(); | 1100 | beep(); |
1087 | if (!matches) | 1101 | if (!matches) |
1088 | return; /* not found */ | 1102 | return; /* not found */ |
1089 | /* sort */ | 1103 | /* sort */ |
1090 | qsort(matches, num_matches, sizeof(char *), match_compare); | 1104 | qsort(matches, num_matches, sizeof(char *), match_compare); |
1091 | 1105 | ||
@@ -1101,7 +1115,7 @@ static void input_tab(int *lastWasTab) | |||
1101 | free(tmp); | 1115 | free(tmp); |
1102 | return; | 1116 | return; |
1103 | } | 1117 | } |
1104 | } else { /* one match */ | 1118 | } else { /* one match */ |
1105 | tmp = matches[0]; | 1119 | tmp = matches[0]; |
1106 | /* for next completion current found */ | 1120 | /* for next completion current found */ |
1107 | *lastWasTab = FALSE; | 1121 | *lastWasTab = FALSE; |
@@ -1164,7 +1178,7 @@ static void input_tab(int *lastWasTab) | |||
1164 | } | 1178 | } |
1165 | } | 1179 | } |
1166 | } | 1180 | } |
1167 | #endif /* BB_FEATURE_SH_TAB_COMPLETION */ | 1181 | #endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ |
1168 | 1182 | ||
1169 | static void get_previous_history(struct history **hp, struct history *p) | 1183 | static void get_previous_history(struct history **hp, struct history *p) |
1170 | { | 1184 | { |
@@ -1201,6 +1215,7 @@ enum { | |||
1201 | * Furthermore, the "vi" command editing keys are not implemented. | 1215 | * Furthermore, the "vi" command editing keys are not implemented. |
1202 | * | 1216 | * |
1203 | */ | 1217 | */ |
1218 | |||
1204 | extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | 1219 | extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) |
1205 | { | 1220 | { |
1206 | 1221 | ||
@@ -1212,7 +1227,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1212 | struct history *hp = his_end; | 1227 | struct history *hp = his_end; |
1213 | 1228 | ||
1214 | /* prepare before init handlers */ | 1229 | /* prepare before init handlers */ |
1215 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ | 1230 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ |
1216 | len = 0; | 1231 | len = 0; |
1217 | command_ps = command; | 1232 | command_ps = command; |
1218 | 1233 | ||
@@ -1223,9 +1238,11 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1223 | 1238 | ||
1224 | new_settings.c_cc[VMIN] = 1; | 1239 | new_settings.c_cc[VMIN] = 1; |
1225 | new_settings.c_cc[VTIME] = 0; | 1240 | new_settings.c_cc[VTIME] = 0; |
1226 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; /* Turn off CTRL-C, so we can trap it */ | 1241 | /* Turn off CTRL-C, so we can trap it */ |
1242 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; | ||
1227 | new_settings.c_lflag &= ~ICANON; /* unbuffered input */ | 1243 | new_settings.c_lflag &= ~ICANON; /* unbuffered input */ |
1228 | new_settings.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); /* Turn off echoing */ | 1244 | /* Turn off echoing */ |
1245 | new_settings.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); | ||
1229 | } | 1246 | } |
1230 | 1247 | ||
1231 | command[0] = 0; | 1248 | command[0] = 0; |
@@ -1295,7 +1312,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1295 | input_backspace(); | 1312 | input_backspace(); |
1296 | break; | 1313 | break; |
1297 | case '\t': | 1314 | case '\t': |
1298 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 1315 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
1299 | input_tab(&lastWasTab); | 1316 | input_tab(&lastWasTab); |
1300 | #endif | 1317 | #endif |
1301 | break; | 1318 | break; |
@@ -1335,7 +1352,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1335 | return; | 1352 | return; |
1336 | } | 1353 | } |
1337 | switch (c) { | 1354 | switch (c) { |
1338 | #ifdef BB_FEATURE_SH_TAB_COMPLETION | 1355 | #ifdef BB_FEATURE_COMMAND_TAB_COMPLETION |
1339 | case '\t': /* Alt-Tab */ | 1356 | case '\t': /* Alt-Tab */ |
1340 | 1357 | ||
1341 | input_tab(&lastWasTab); | 1358 | input_tab(&lastWasTab); |
@@ -1402,7 +1419,7 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1402 | break; | 1419 | break; |
1403 | } | 1420 | } |
1404 | 1421 | ||
1405 | default: /* If it's regular input, do the normal thing */ | 1422 | default: /* If it's regular input, do the normal thing */ |
1406 | #ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT | 1423 | #ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT |
1407 | /* Control-V -- Add non-printable symbol */ | 1424 | /* Control-V -- Add non-printable symbol */ |
1408 | if (c == 22) { | 1425 | if (c == 22) { |
@@ -1493,16 +1510,16 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1493 | history_counter++; | 1510 | history_counter++; |
1494 | } | 1511 | } |
1495 | } | 1512 | } |
1496 | #if defined(BB_FEATURE_BASH_STYLE_PROMT) | 1513 | #if !defined(BB_FEATURE_SIMPLE_PROMPT) |
1497 | num_ok_lines++; | 1514 | num_ok_lines++; |
1498 | #endif | 1515 | #endif |
1499 | } | 1516 | } |
1500 | command[len++] = '\n'; /* set '\n' */ | 1517 | command[len++] = '\n'; /* set '\n' */ |
1501 | command[len] = 0; | 1518 | command[len] = 0; |
1502 | #if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_SH_TAB_COMPLETION) | 1519 | #if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION) |
1503 | input_tab(0); /* strong free */ | 1520 | input_tab(0); /* strong free */ |
1504 | #endif | 1521 | #endif |
1505 | #if defined(BB_FEATURE_BASH_STYLE_PROMT) | 1522 | #if !defined(BB_FEATURE_SIMPLE_PROMPT) |
1506 | free(cmdedit_prompt); | 1523 | free(cmdedit_prompt); |
1507 | #endif | 1524 | #endif |
1508 | return; | 1525 | return; |
@@ -1523,7 +1540,7 @@ extern void cmdedit_terminate(void) | |||
1523 | } | 1540 | } |
1524 | } | 1541 | } |
1525 | 1542 | ||
1526 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ | 1543 | #endif /* BB_FEATURE_COMMAND_EDITING */ |
1527 | 1544 | ||
1528 | 1545 | ||
1529 | #ifdef TEST | 1546 | #ifdef TEST |
@@ -1534,21 +1551,25 @@ int main(int argc, char **argv) | |||
1534 | { | 1551 | { |
1535 | char buff[BUFSIZ]; | 1552 | char buff[BUFSIZ]; |
1536 | char *prompt = | 1553 | char *prompt = |
1537 | #if defined(BB_FEATURE_BASH_STYLE_PROMT) | 1554 | #if !defined(BB_FEATURE_SIMPLE_PROMPT) |
1538 | "\\[\\033[32;1m\\]\\u@\\[\\033[33;1m\\]\\h:\ | 1555 | "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\ |
1539 | \\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ | 1556 | \\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ |
1540 | \\!\\[\\033[36;1m\\]\\$ \\[\\033[0m\\]"; | 1557 | \\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]"; |
1541 | #else | 1558 | #else |
1542 | "% "; | 1559 | "% "; |
1543 | #endif | 1560 | #endif |
1544 | 1561 | ||
1545 | shell_context = 1; | 1562 | shell_context = 1; |
1546 | do { | 1563 | do { |
1564 | int l; | ||
1547 | cmdedit_read_input(prompt, buff); | 1565 | cmdedit_read_input(prompt, buff); |
1566 | l = strlen(buff); | ||
1567 | if(l > 0 && buff[l-1] == '\n') | ||
1568 | buff[l-1] = 0; | ||
1548 | printf("*** cmdedit_read_input() returned line =%s=\n", buff); | 1569 | printf("*** cmdedit_read_input() returned line =%s=\n", buff); |
1549 | } while (shell_context); | 1570 | } while (shell_context); |
1550 | printf("*** cmdedit_read_input() detect ^C\n"); | 1571 | printf("*** cmdedit_read_input() detect ^C\n"); |
1551 | return 0; | 1572 | return 0; |
1552 | } | 1573 | } |
1553 | 1574 | ||
1554 | #endif /* TEST */ | 1575 | #endif /* TEST */ |
diff --git a/shell/cmdedit.h b/shell/cmdedit.h index b96ffd373..0ab94c6ce 100644 --- a/shell/cmdedit.h +++ b/shell/cmdedit.h | |||
@@ -1,13 +1,14 @@ | |||
1 | #ifndef CMDEDIT_H | 1 | #ifndef CMDEDIT_H |
2 | #define CMDEDIT_H | 2 | #define CMDEDIT_H |
3 | 3 | ||
4 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 4 | #ifdef BB_FEATURE_COMMAND_EDITING |
5 | #include <stddef.h> | 5 | #include <stddef.h> |
6 | #include "busybox.h" | ||
6 | 7 | ||
7 | void cmdedit_init(void); | 8 | void cmdedit_init(void); |
8 | void cmdedit_terminate(void); | 9 | void cmdedit_terminate(void); |
9 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ | 10 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ |
10 | 11 | ||
11 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ | 12 | #endif /* BB_FEATURE_COMMAND_EDITING */ |
12 | 13 | ||
13 | #endif /* CMDEDIT_H */ | 14 | #endif /* CMDEDIT_H */ |
diff --git a/shell/lash.c b/shell/lash.c index 67d6e4f51..49fb6b536 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
@@ -39,11 +39,15 @@ | |||
39 | //#define BB_FEATURE_SH_BACKTICKS | 39 | //#define BB_FEATURE_SH_BACKTICKS |
40 | // | 40 | // |
41 | //If, then, else, etc. support.. This should now behave basically | 41 | //If, then, else, etc. support.. This should now behave basically |
42 | //like any other Bourne shell... | 42 | //like any other Bourne shell -- sortof... |
43 | #define BB_FEATURE_SH_IF_EXPRESSIONS | 43 | #define BB_FEATURE_SH_IF_EXPRESSIONS |
44 | // | 44 | // |
45 | /* This is currently a little broken... */ | 45 | /* This is currently sortof broken, only for the brave... */ |
46 | //#define HANDLE_CONTINUATION_CHARS | 46 | #undef HANDLE_CONTINUATION_CHARS |
47 | // | ||
48 | /* This would be great -- if wordexp wouldn't strip all quoting | ||
49 | * out from the target strings... As is, a parser needs */ | ||
50 | #undef BB_FEATURE_SH_WORDEXP | ||
47 | // | 51 | // |
48 | //For debugging/development on the shell only... | 52 | //For debugging/development on the shell only... |
49 | //#define DEBUG_SHELL | 53 | //#define DEBUG_SHELL |
@@ -61,10 +65,9 @@ | |||
61 | #include <unistd.h> | 65 | #include <unistd.h> |
62 | #include <getopt.h> | 66 | #include <getopt.h> |
63 | 67 | ||
64 | //#undef __GLIBC__ | 68 | #undef BB_FEATURE_SH_WORDEXP |
65 | //#undef __UCLIBC__ | ||
66 | 69 | ||
67 | #if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__) | 70 | #if BB_FEATURE_SH_WORDEXP |
68 | #include <wordexp.h> | 71 | #include <wordexp.h> |
69 | #define expand_t wordexp_t | 72 | #define expand_t wordexp_t |
70 | #undef BB_FEATURE_SH_BACKTICKS | 73 | #undef BB_FEATURE_SH_BACKTICKS |
@@ -227,6 +230,10 @@ static int show_x_trace; | |||
227 | static char syntax_err[]="syntax error near unexpected token"; | 230 | static char syntax_err[]="syntax error near unexpected token"; |
228 | #endif | 231 | #endif |
229 | 232 | ||
233 | static char *PS1; | ||
234 | static char *PS2; | ||
235 | |||
236 | |||
230 | #ifdef DEBUG_SHELL | 237 | #ifdef DEBUG_SHELL |
231 | static inline void debug_printf(const char *format, ...) | 238 | static inline void debug_printf(const char *format, ...) |
232 | { | 239 | { |
@@ -286,7 +293,7 @@ static int builtin_cd(struct child_prog *child) | |||
286 | else | 293 | else |
287 | newdir = child->argv[1]; | 294 | newdir = child->argv[1]; |
288 | if (chdir(newdir)) { | 295 | if (chdir(newdir)) { |
289 | printf("cd: %s: %s\n", newdir, strerror(errno)); | 296 | printf("cd: %s: %m\n", newdir); |
290 | return EXIT_FAILURE; | 297 | return EXIT_FAILURE; |
291 | } | 298 | } |
292 | getcwd(cwd, sizeof(char)*MAX_LINE); | 299 | getcwd(cwd, sizeof(char)*MAX_LINE); |
@@ -425,13 +432,20 @@ static int builtin_pwd(struct child_prog *dummy) | |||
425 | static int builtin_export(struct child_prog *child) | 432 | static int builtin_export(struct child_prog *child) |
426 | { | 433 | { |
427 | int res; | 434 | int res; |
435 | char *v = child->argv[1]; | ||
428 | 436 | ||
429 | if (child->argv[1] == NULL) { | 437 | if (v == NULL) { |
430 | return (builtin_env(child)); | 438 | return (builtin_env(child)); |
431 | } | 439 | } |
432 | res = putenv(child->argv[1]); | 440 | res = putenv(v); |
433 | if (res) | 441 | if (res) |
434 | fprintf(stderr, "export: %s\n", strerror(errno)); | 442 | fprintf(stderr, "export: %m\n"); |
443 | #ifndef BB_FEATURE_SIMPLE_PROMPT | ||
444 | if (strncmp(v, "PS1=", 4)==0) | ||
445 | PS1 = getenv("PS1"); | ||
446 | else if (strncmp(v, "PS2=", 4)==0) | ||
447 | PS2 = getenv("PS2"); | ||
448 | #endif | ||
435 | return (res); | 449 | return (res); |
436 | } | 450 | } |
437 | 451 | ||
@@ -461,7 +475,7 @@ static int builtin_read(struct child_prog *child) | |||
461 | if((s = strdup(string))) | 475 | if((s = strdup(string))) |
462 | res = putenv(s); | 476 | res = putenv(s); |
463 | if (res) | 477 | if (res) |
464 | fprintf(stderr, "read: %s\n", strerror(errno)); | 478 | fprintf(stderr, "read: %m\n"); |
465 | } | 479 | } |
466 | else | 480 | else |
467 | fgets(string, sizeof(string), stdin); | 481 | fgets(string, sizeof(string), stdin); |
@@ -759,8 +773,7 @@ static int setup_redirects(struct child_prog *prog, int squirrel[]) | |||
759 | if (openfd < 0) { | 773 | if (openfd < 0) { |
760 | /* this could get lost if stderr has been redirected, but | 774 | /* this could get lost if stderr has been redirected, but |
761 | bash and ash both lose it as well (though zsh doesn't!) */ | 775 | bash and ash both lose it as well (though zsh doesn't!) */ |
762 | error_msg("error opening %s: %s", redir->filename, | 776 | perror_msg("error opening %s", redir->filename); |
763 | strerror(errno)); | ||
764 | return 1; | 777 | return 1; |
765 | } | 778 | } |
766 | 779 | ||
@@ -790,57 +803,40 @@ static void restore_redirects(int squirrel[]) | |||
790 | } | 803 | } |
791 | } | 804 | } |
792 | 805 | ||
793 | #if defined(BB_FEATURE_SH_SIMPLE_PROMPT) | 806 | static inline void cmdedit_set_initial_prompt(void) |
794 | static char* setup_prompt_string(int state) | ||
795 | { | 807 | { |
796 | char prompt_str[BUFSIZ]; | 808 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
797 | 809 | PS1 = NULL; | |
798 | /* Set up the prompt */ | 810 | PS2 = "> "; |
799 | if (state == 0) { | ||
800 | /* simple prompt */ | ||
801 | sprintf(prompt_str, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); | ||
802 | } else { | ||
803 | strcpy(prompt_str,"> "); | ||
804 | } | ||
805 | |||
806 | return(strdup(prompt_str)); /* Must free this memory */ | ||
807 | } | ||
808 | |||
809 | #else | 811 | #else |
812 | PS1 = getenv("PS1"); | ||
813 | if(PS1==0) { | ||
814 | PS1 = "\\w \\$ "; | ||
815 | } | ||
816 | PS2 = getenv("PS2"); | ||
817 | if(PS2==0) | ||
818 | PS2 = "> "; | ||
819 | #endif | ||
820 | } | ||
810 | 821 | ||
811 | static char* setup_prompt_string(int state) | 822 | static inline void setup_prompt_string(char **prompt_str) |
812 | { | 823 | { |
813 | char user[9],buf[255],*s; | 824 | #ifdef BB_FEATURE_SIMPLE_PROMPT |
814 | char prompt[3]; | ||
815 | char prompt_str[BUFSIZ]; | ||
816 | |||
817 | /* Set up the prompt */ | 825 | /* Set up the prompt */ |
818 | if (state == 0) { | 826 | if (shell_context == 0) { |
819 | /* get User Name and setup prompt */ | 827 | if (PS1) |
820 | strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# "); | 828 | free(PS1); |
821 | my_getpwuid(user, geteuid()); | 829 | PS1=xmalloc(strlen(cwd)+4); |
822 | 830 | sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); | |
823 | /* get HostName */ | 831 | *prompt_str = PS1; |
824 | gethostname(buf, 255); | ||
825 | s = strchr(buf, '.'); | ||
826 | if (s) { | ||
827 | *s = 0; | ||
828 | } | ||
829 | } else { | 832 | } else { |
830 | strcpy(prompt,"> "); | 833 | *prompt_str = PS2; |
831 | } | 834 | } |
832 | 835 | #else | |
833 | if (state == 0) { | 836 | *prompt_str = (shell_context==0)? PS1 : PS2; |
834 | snprintf(prompt_str, BUFSIZ-1, "[%s@%s %s]%s", user, buf, | 837 | #endif |
835 | get_last_path_component(cwd), prompt); | ||
836 | } else { | ||
837 | sprintf(prompt_str, "%s", prompt); | ||
838 | } | ||
839 | return(strdup(prompt_str)); /* Must free this memory */ | ||
840 | } | 838 | } |
841 | 839 | ||
842 | #endif | ||
843 | |||
844 | static int get_command(FILE * source, char *command) | 840 | static int get_command(FILE * source, char *command) |
845 | { | 841 | { |
846 | char *prompt_str; | 842 | char *prompt_str; |
@@ -857,9 +853,9 @@ static int get_command(FILE * source, char *command) | |||
857 | } | 853 | } |
858 | 854 | ||
859 | if (source == stdin) { | 855 | if (source == stdin) { |
860 | prompt_str = setup_prompt_string(shell_context); | 856 | setup_prompt_string(&prompt_str); |
861 | 857 | ||
862 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 858 | #ifdef BB_FEATURE_COMMAND_EDITING |
863 | /* | 859 | /* |
864 | ** enable command line editing only while a command line | 860 | ** enable command line editing only while a command line |
865 | ** is actually being read; otherwise, we'll end up bequeathing | 861 | ** is actually being read; otherwise, we'll end up bequeathing |
@@ -868,11 +864,9 @@ static int get_command(FILE * source, char *command) | |||
868 | */ | 864 | */ |
869 | cmdedit_read_input(prompt_str, command); | 865 | cmdedit_read_input(prompt_str, command); |
870 | cmdedit_terminate(); | 866 | cmdedit_terminate(); |
871 | free(prompt_str); | ||
872 | return 0; | 867 | return 0; |
873 | #else | 868 | #else |
874 | fputs(prompt_str, stdout); | 869 | fputs(prompt_str, stdout); |
875 | free(prompt_str); | ||
876 | #endif | 870 | #endif |
877 | } | 871 | } |
878 | 872 | ||
@@ -910,25 +904,72 @@ static char* itoa(register int i) | |||
910 | } | 904 | } |
911 | #endif | 905 | #endif |
912 | 906 | ||
907 | #if defined BB_FEATURE_SH_ENVIRONMENT && ! defined BB_FEATURE_SH_WORDEXP | ||
908 | char * strsep_space( char *string, int * index) | ||
909 | { | ||
910 | char *token, *begin; | ||
911 | |||
912 | begin = string; | ||
913 | |||
914 | /* Short circuit the trivial case */ | ||
915 | if ( !string || ! string[*index]) | ||
916 | return NULL; | ||
917 | |||
918 | /* Find the end of the token. */ | ||
919 | while( string && string[*index] && !isspace(string[*index]) ) { | ||
920 | (*index)++; | ||
921 | } | ||
922 | |||
923 | /* Find the end of any whitespace trailing behind | ||
924 | * the token and let that be part of the token */ | ||
925 | while( string && string[*index] && isspace(string[*index]) ) { | ||
926 | (*index)++; | ||
927 | } | ||
928 | |||
929 | if (! string && *index==0) { | ||
930 | /* Nothing useful was found */ | ||
931 | return NULL; | ||
932 | } | ||
933 | |||
934 | token = xmalloc(*index); | ||
935 | token[*index] = '\0'; | ||
936 | strncpy(token, string, *index); | ||
937 | |||
938 | return token; | ||
939 | } | ||
940 | #endif | ||
941 | |||
942 | |||
913 | static int expand_arguments(char *command) | 943 | static int expand_arguments(char *command) |
914 | { | 944 | { |
915 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 945 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
916 | expand_t expand_result; | 946 | expand_t expand_result; |
917 | char *src, *dst, *var; | 947 | char *src, *dst, *var; |
948 | int index = 0; | ||
918 | int i=0, length, total_length=0, retval; | 949 | int i=0, length, total_length=0, retval; |
919 | const char *out_of_space = "out of space during expansion"; | 950 | const char *out_of_space = "out of space during expansion"; |
920 | #endif | 951 | #endif |
921 | 952 | ||
922 | /* get rid of the terminating \n */ | 953 | /* get rid of the terminating \n */ |
923 | chomp(command); | 954 | chomp(command); |
955 | |||
956 | /* Fix up escape sequences to be the Real Thing(tm) */ | ||
957 | while( command && command[index]) { | ||
958 | if (command[index] == '\\') { | ||
959 | char *tmp = command+index+1; | ||
960 | command[index+1] = process_escape_sequence( &tmp ); | ||
961 | memmove(command+index, command+index+1, strlen(command+index)); | ||
962 | } | ||
963 | index++; | ||
964 | } | ||
924 | 965 | ||
925 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 966 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
926 | 967 | ||
927 | 968 | ||
928 | #if ( (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) ) || defined (__UCLIBC__) | 969 | #if BB_FEATURE_SH_WORDEXP |
929 | /* This first part uses wordexp() which is a wonderful C lib | 970 | /* This first part uses wordexp() which is a wonderful C lib |
930 | * function which expands nearly everything. */ | 971 | * function which expands nearly everything. */ |
931 | retval = wordexp (command, &expand_result, 0); | 972 | retval = wordexp (command, &expand_result, WRDE_SHOWERR); |
932 | if (retval == WRDE_NOSPACE) { | 973 | if (retval == WRDE_NOSPACE) { |
933 | /* Mem may have been allocated... */ | 974 | /* Mem may have been allocated... */ |
934 | wordfree (&expand_result); | 975 | wordfree (&expand_result); |
@@ -970,15 +1011,17 @@ static int expand_arguments(char *command) | |||
970 | { | 1011 | { |
971 | 1012 | ||
972 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; | 1013 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; |
973 | char * tmpcmd, *cmd, *cmd_copy; | 1014 | char *tmpcmd, *cmd, *cmd_copy; |
974 | /* We need a clean copy, so strsep can mess up the copy while | 1015 | /* We need a clean copy, so strsep can mess up the copy while |
975 | * we write stuff into the original (in a minute) */ | 1016 | * we write stuff into the original (in a minute) */ |
976 | cmd = cmd_copy = strdup(command); | 1017 | cmd = cmd_copy = strdup(command); |
977 | *command = '\0'; | 1018 | *command = '\0'; |
978 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { | 1019 | for (index = 0, tmpcmd = cmd; |
1020 | (tmpcmd = strsep_space(cmd, &index)) != NULL; cmd += index, index=0) { | ||
979 | if (*tmpcmd == '\0') | 1021 | if (*tmpcmd == '\0') |
980 | break; | 1022 | break; |
981 | retval = glob(tmpcmd, flags, NULL, &expand_result); | 1023 | retval = glob(tmpcmd, flags, NULL, &expand_result); |
1024 | free(tmpcmd); /* Free mem allocated by strsep_space */ | ||
982 | if (retval == GLOB_NOSPACE) { | 1025 | if (retval == GLOB_NOSPACE) { |
983 | /* Mem may have been allocated... */ | 1026 | /* Mem may have been allocated... */ |
984 | globfree (&expand_result); | 1027 | globfree (&expand_result); |
@@ -1711,7 +1754,8 @@ static int busy_loop(FILE * input) | |||
1711 | if (!parse_command(&next_command, &newjob, &inbg) && | 1754 | if (!parse_command(&next_command, &newjob, &inbg) && |
1712 | newjob.num_progs) { | 1755 | newjob.num_progs) { |
1713 | int pipefds[2] = {-1,-1}; | 1756 | int pipefds[2] = {-1,-1}; |
1714 | debug_printf( "job=%p being fed to run_command by busy_loop()'\n", &newjob); | 1757 | debug_printf( "job=%p fed to run_command by busy_loop()'\n", |
1758 | &newjob); | ||
1715 | run_command(&newjob, inbg, pipefds); | 1759 | run_command(&newjob, inbg, pipefds); |
1716 | } | 1760 | } |
1717 | else { | 1761 | else { |
@@ -1879,5 +1923,13 @@ int shell_main(int argc_l, char **argv_l) | |||
1879 | atexit(free_memory); | 1923 | atexit(free_memory); |
1880 | #endif | 1924 | #endif |
1881 | 1925 | ||
1926 | #ifdef BB_FEATURE_COMMAND_EDITING | ||
1927 | cmdedit_set_initial_prompt(); | ||
1928 | #else | ||
1929 | PS1 = NULL; | ||
1930 | PS2 = "> "; | ||
1931 | #endif | ||
1932 | |||
1882 | return (busy_loop(input)); | 1933 | return (busy_loop(input)); |
1883 | } | 1934 | } |
1935 | |||