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 /shell/lash.c | |
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
Diffstat (limited to 'shell/lash.c')
-rw-r--r-- | shell/lash.c | 180 |
1 files changed, 116 insertions, 64 deletions
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 | |||