summaryrefslogtreecommitdiff
path: root/shell/lash.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-03-13 22:57:56 +0000
committerEric Andersen <andersen@codepoet.org>2001-03-13 22:57:56 +0000
commitb3d6e2df95a21034e41d46a18c71dd1c4e07e987 (patch)
tree2d549a0d8748a9673be658e193a8104149cf2c15 /shell/lash.c
parent798ab301c772cc18ab64f94386da3c7ec10daf42 (diff)
downloadbusybox-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.c180
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;
227static char syntax_err[]="syntax error near unexpected token"; 230static char syntax_err[]="syntax error near unexpected token";
228#endif 231#endif
229 232
233static char *PS1;
234static char *PS2;
235
236
230#ifdef DEBUG_SHELL 237#ifdef DEBUG_SHELL
231static inline void debug_printf(const char *format, ...) 238static 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)
425static int builtin_export(struct child_prog *child) 432static 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) 806static inline void cmdedit_set_initial_prompt(void)
794static 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
811static char* setup_prompt_string(int state) 822static 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
844static int get_command(FILE * source, char *command) 840static 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
908char * 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
913static int expand_arguments(char *command) 943static 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