diff options
| author | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-03-09 19:21:37 +0000 |
|---|---|---|
| committer | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-03-09 19:21:37 +0000 |
| commit | 39368919ec7c010ad88de4e91c750e26d6e326bb (patch) | |
| tree | 0f7dbc3b592232f49a6696e46dded7b721289391 | |
| parent | 01fa725c87f4117a848e062c22c353ba167df40d (diff) | |
| download | busybox-w32-39368919ec7c010ad88de4e91c750e26d6e326bb.tar.gz busybox-w32-39368919ec7c010ad88de4e91c750e26d6e326bb.tar.bz2 busybox-w32-39368919ec7c010ad88de4e91c750e26d6e326bb.zip | |
Ok, sh.c should be working now. Many thanks to Larry Doolittle
for his timely help -- nearly all of the work in this patch is
his.
-Erik
git-svn-id: svn://busybox.net/trunk/busybox@2022 69ca8d6d-28ef-0310-b511-8ec308f3f277
| -rw-r--r-- | lash.c | 168 | ||||
| -rw-r--r-- | sh.c | 168 | ||||
| -rw-r--r-- | shell/lash.c | 168 |
3 files changed, 249 insertions, 255 deletions
| @@ -916,6 +916,7 @@ static int expand_arguments(char *command) | |||
| 916 | expand_t expand_result; | 916 | expand_t expand_result; |
| 917 | char *src, *dst, *var; | 917 | char *src, *dst, *var; |
| 918 | int i=0, length, total_length=0, retval; | 918 | int i=0, length, total_length=0, retval; |
| 919 | const char *out_of_space = "out of space during expansion"; | ||
| 919 | #endif | 920 | #endif |
| 920 | 921 | ||
| 921 | /* get rid of the terminating \n */ | 922 | /* get rid of the terminating \n */ |
| @@ -931,7 +932,7 @@ static int expand_arguments(char *command) | |||
| 931 | if (retval == WRDE_NOSPACE) { | 932 | if (retval == WRDE_NOSPACE) { |
| 932 | /* Mem may have been allocated... */ | 933 | /* Mem may have been allocated... */ |
| 933 | wordfree (&expand_result); | 934 | wordfree (&expand_result); |
| 934 | error_msg("out of space during expansion"); | 935 | error_msg(out_of_space); |
| 935 | return FALSE; | 936 | return FALSE; |
| 936 | } | 937 | } |
| 937 | if (retval < 0) { | 938 | if (retval < 0) { |
| @@ -946,7 +947,7 @@ static int expand_arguments(char *command) | |||
| 946 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { | 947 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { |
| 947 | length=strlen(expand_result.we_wordv[i])+1; | 948 | length=strlen(expand_result.we_wordv[i])+1; |
| 948 | if (BUFSIZ-total_length-length <= 0) { | 949 | if (BUFSIZ-total_length-length <= 0) { |
| 949 | error_msg("out of space during expansion"); | 950 | error_msg(out_of_space); |
| 950 | return FALSE; | 951 | return FALSE; |
| 951 | } | 952 | } |
| 952 | strcat(command+total_length, expand_result.we_wordv[i++]); | 953 | strcat(command+total_length, expand_result.we_wordv[i++]); |
| @@ -956,139 +957,136 @@ static int expand_arguments(char *command) | |||
| 956 | wordfree (&expand_result); | 957 | wordfree (&expand_result); |
| 957 | #else | 958 | #else |
| 958 | 959 | ||
| 959 | /* Ok. They don't have glibc and they don't have uClibc. Chances are | 960 | /* Ok. They don't have a recent glibc and they don't have uClibc. Chances |
| 960 | * about 100% they don't have wordexp(), so instead, the best we can do is | 961 | * are about 100% they don't have wordexp(). So instead the best we can do |
| 961 | * use glob, which is better then nothing, but certainly not perfect */ | 962 | * is use glob and then fixup environment variables and such ourselves. |
| 963 | * This is better then nothing, but certainly not perfect */ | ||
| 962 | 964 | ||
| 963 | /* It turns out that glob is very stupid. We have to feed it | 965 | /* It turns out that glob is very stupid. We have to feed it one word at a |
| 964 | * one word at a time since it can't cope with a full string. | 966 | * time since it can't cope with a full string. Here we convert command |
| 965 | * Here we convert command (char*) into cmd (char**, one word | 967 | * (char*) into cmd (char**, one word per string) */ |
| 966 | * per string) */ | ||
| 967 | { | 968 | { |
| 968 | 969 | ||
| 969 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; | 970 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; |
| 970 | char * tmpcmd; | 971 | char * tmpcmd; |
| 971 | /* We need a clean copy, so strsep can mess up the copy while | 972 | /* We need a clean copy, so strsep can mess up the copy while |
| 972 | * we write stuff into the original in a minute */ | 973 | * we write stuff into the original (in a minute) */ |
| 973 | char * cmd = strdup(command); | 974 | char * cmd = strdup(command); |
| 975 | *command = '\0'; | ||
| 974 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { | 976 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { |
| 975 | if (*tmpcmd == '\0') | 977 | if (*tmpcmd == '\0') |
| 976 | break; | 978 | break; |
| 977 | retval = glob(tmpcmd, flags, NULL, &expand_result); | 979 | retval = glob(tmpcmd, flags, NULL, &expand_result); |
| 978 | /* We can't haveGLOB_APPEND on the first glob call, | ||
| 979 | * so put it there now */ | ||
| 980 | if (! (flags & GLOB_APPEND) ) | ||
| 981 | flags |= GLOB_APPEND; | ||
| 982 | |||
| 983 | if (retval == GLOB_NOSPACE) { | 980 | if (retval == GLOB_NOSPACE) { |
| 984 | /* Mem may have been allocated... */ | 981 | /* Mem may have been allocated... */ |
| 985 | globfree (&expand_result); | 982 | globfree (&expand_result); |
| 986 | error_msg("out of space during expansion"); | 983 | error_msg(out_of_space); |
| 987 | return FALSE; | 984 | return FALSE; |
| 988 | } | 985 | } else if (retval != 0) { |
| 989 | if (retval != 0 && retval != GLOB_NOMATCH) { | 986 | /* Some other error. GLOB_NOMATCH shouldn't |
| 990 | /* Some other error. */ | 987 | * happen because of the GLOB_NOCHECK flag in |
| 988 | * the glob call. */ | ||
| 991 | error_msg("syntax error"); | 989 | error_msg("syntax error"); |
| 992 | return FALSE; | 990 | return FALSE; |
| 993 | } | 991 | } else { |
| 994 | |||
| 995 | /* Convert from char** (one word per string) to a simple char*, | 992 | /* Convert from char** (one word per string) to a simple char*, |
| 996 | * but don't overflow command which is BUFSIZ in length */ | 993 | * but don't overflow command which is BUFSIZ in length */ |
| 997 | if ( expand_result.gl_pathc > 1) { | 994 | for (i=0; i < expand_result.gl_pathc; i++) { |
| 998 | *command = '\0'; | ||
| 999 | while (i < expand_result.gl_pathc && total_length < BUFSIZ) { | ||
| 1000 | length=strlen(expand_result.gl_pathv[i])+1; | 995 | length=strlen(expand_result.gl_pathv[i])+1; |
| 1001 | if (BUFSIZ-total_length-length <= 0) { | 996 | if (BUFSIZ-total_length-length <= 0) { |
| 1002 | error_msg("out of space during expansion"); | 997 | error_msg(out_of_space); |
| 1003 | return FALSE; | 998 | return FALSE; |
| 1004 | } | 999 | } |
| 1005 | strcat(command+total_length, expand_result.gl_pathv[i++]); | 1000 | strcat(command+total_length, expand_result.gl_pathv[i]); |
| 1006 | strcat(command+total_length, " "); | 1001 | strcat(command+total_length, " "); |
| 1007 | total_length+=length; | 1002 | total_length+=length; |
| 1008 | } | 1003 | } |
| 1004 | globfree (&expand_result); | ||
| 1009 | } | 1005 | } |
| 1010 | } | 1006 | } |
| 1011 | |||
| 1012 | free(cmd); | 1007 | free(cmd); |
| 1013 | globfree (&expand_result); | 1008 | trim(command); |
| 1014 | } | 1009 | } |
| 1015 | 1010 | ||
| 1016 | #endif | 1011 | #endif |
| 1017 | 1012 | ||
| 1018 | /* FIXME -- this routine (which is only used when folks | ||
| 1019 | * don't have a C library with wordexp) needs a bit of help | ||
| 1020 | * to handle things like 'echo $PATH$0' */ | ||
| 1021 | |||
| 1022 | /* Now do the shell variable substitutions which | 1013 | /* Now do the shell variable substitutions which |
| 1023 | * wordexp can't do for us, namely $? and $! */ | 1014 | * wordexp can't do for us, namely $? and $! */ |
| 1024 | src = command; | 1015 | src = command; |
| 1025 | while((dst = strchr(src,'$')) != NULL){ | 1016 | while((dst = strchr(src,'$')) != NULL){ |
| 1026 | /* Ok -- got a $ -- now clean up any trailing mess */ | 1017 | printf("dollar '%s'\n", dst); |
| 1027 | trim(dst); | 1018 | var = NULL; |
| 1028 | if (!(var = getenv(dst + 1))) { | 1019 | switch(*(dst+1)) { |
| 1029 | switch(*(dst+1)) { | 1020 | case '?': |
| 1030 | case '?': | 1021 | var = itoa(last_return_code); |
| 1031 | var = itoa(last_return_code); | 1022 | break; |
| 1032 | break; | 1023 | case '!': |
| 1033 | case '!': | 1024 | if (last_bg_pid==-1) |
| 1034 | if (last_bg_pid==-1) | 1025 | *(var)='\0'; |
| 1035 | *(var)='\0'; | 1026 | else |
| 1036 | else | 1027 | var = itoa(last_bg_pid); |
| 1037 | var = itoa(last_bg_pid); | 1028 | break; |
| 1038 | break; | ||
| 1039 | /* Everything else like $$, $#, $[0-9], etc should all be | 1029 | /* Everything else like $$, $#, $[0-9], etc should all be |
| 1040 | * expanded by wordexp(), so we can in theory skip that stuff | 1030 | * expanded by wordexp(), so we can in theory skip that stuff |
| 1041 | * here, but just to be on the safe side (i.e. since uClibc | 1031 | * here, but just to be on the safe side (i.e. since uClibc |
| 1042 | * wordexp doesn't do this stuff yet), lets leave it in for | 1032 | * wordexp doesn't do this stuff yet), lets leave it in for |
| 1043 | * now. */ | 1033 | * now. */ |
| 1044 | case '$': | 1034 | case '$': |
| 1045 | var = itoa(getpid()); | 1035 | var = itoa(getpid()); |
| 1046 | break; | 1036 | break; |
| 1047 | case '#': | 1037 | case '#': |
| 1048 | var = itoa(argc-1); | 1038 | var = itoa(argc-1); |
| 1049 | break; | 1039 | break; |
| 1050 | case '0':case '1':case '2':case '3':case '4': | 1040 | case '0':case '1':case '2':case '3':case '4': |
| 1051 | case '5':case '6':case '7':case '8':case '9': | 1041 | case '5':case '6':case '7':case '8':case '9': |
| 1052 | { | 1042 | { |
| 1053 | int index=*(dst + 1)-48; | 1043 | int index=*(dst + 1)-48; |
| 1054 | if (index >= argc) { | 1044 | if (index >= argc) { |
| 1055 | var='\0'; | 1045 | var='\0'; |
| 1056 | } else { | 1046 | } else { |
| 1057 | var = argv[index]; | 1047 | var = argv[index]; |
| 1058 | } | ||
| 1059 | } | 1048 | } |
| 1060 | break; | 1049 | } |
| 1050 | break; | ||
| 1061 | 1051 | ||
| 1062 | } | ||
| 1063 | } | 1052 | } |
| 1064 | if (var) { | 1053 | if (var) { |
| 1065 | int subst_len = strlen(var); | 1054 | /* a single character construction was found, and |
| 1066 | char *next_dst; | 1055 | * already handled in the case statement */ |
| 1067 | if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?.")) == NULL) { | 1056 | src=dst+2; |
| 1068 | next_dst = dst; | ||
| 1069 | } | ||
| 1070 | src = (char*)xrealloc(src, strlen(src) - strlen(next_dst)+strlen(var)+1); | ||
| 1071 | /* Move stuff to the end of the string to accommodate filling | ||
| 1072 | * the created gap with the new stuff */ | ||
| 1073 | memmove(dst+subst_len, next_dst+1, subst_len); | ||
| 1074 | /* Now copy in the new stuff */ | ||
| 1075 | strncpy(dst, var, subst_len+1); | ||
| 1076 | src = dst; | ||
| 1077 | src++; | ||
| 1078 | } else { | 1057 | } else { |
| 1058 | /* Looks like an environment variable */ | ||
| 1059 | char delim_hold; | ||
| 1060 | src=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?."); | ||
| 1061 | if (src == NULL) { | ||
| 1062 | src = dst+strlen(dst); | ||
| 1063 | } | ||
| 1064 | delim_hold=*src; | ||
| 1065 | *src='\0'; /* temporary */ | ||
| 1066 | var = getenv(dst + 1); | ||
| 1067 | *src=delim_hold; | ||
| 1068 | } | ||
| 1069 | if (var == NULL) { | ||
| 1079 | /* Seems we got an un-expandable variable. So delete it. */ | 1070 | /* Seems we got an un-expandable variable. So delete it. */ |
| 1080 | char *next_dst; | 1071 | var = ""; |
| 1081 | if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?.")) == NULL) { | 1072 | } |
| 1082 | next_dst=dst+1+strlen(dst); | 1073 | { |
| 1074 | int subst_len = strlen(var); | ||
| 1075 | int trail_len = strlen(src); | ||
| 1076 | if (dst+subst_len+trail_len >= command+BUFSIZ) { | ||
| 1077 | error_msg(out_of_space); | ||
| 1078 | return FALSE; | ||
| 1083 | } | 1079 | } |
| 1084 | /* Move stuff to the end of the string to accommodate filling | 1080 | /* Move stuff to the end of the string to accommodate |
| 1085 | * the created gap with the new stuff */ | 1081 | * filling the created gap with the new stuff */ |
| 1086 | memmove(dst, next_dst, next_dst-dst); | 1082 | memmove(dst+subst_len, src, trail_len); |
| 1083 | *(dst+subst_len+trail_len)='\0'; | ||
| 1084 | /* Now copy in the new stuff */ | ||
| 1085 | memcpy(dst, var, subst_len); | ||
| 1086 | src = dst+subst_len; | ||
| 1087 | } | 1087 | } |
| 1088 | } | 1088 | } |
| 1089 | 1089 | printf("expanded '%s'\n", command); | |
| 1090 | |||
| 1091 | |||
| 1092 | 1090 | ||
| 1093 | #endif | 1091 | #endif |
| 1094 | return TRUE; | 1092 | return TRUE; |
| @@ -916,6 +916,7 @@ static int expand_arguments(char *command) | |||
| 916 | expand_t expand_result; | 916 | expand_t expand_result; |
| 917 | char *src, *dst, *var; | 917 | char *src, *dst, *var; |
| 918 | int i=0, length, total_length=0, retval; | 918 | int i=0, length, total_length=0, retval; |
| 919 | const char *out_of_space = "out of space during expansion"; | ||
| 919 | #endif | 920 | #endif |
| 920 | 921 | ||
| 921 | /* get rid of the terminating \n */ | 922 | /* get rid of the terminating \n */ |
| @@ -931,7 +932,7 @@ static int expand_arguments(char *command) | |||
| 931 | if (retval == WRDE_NOSPACE) { | 932 | if (retval == WRDE_NOSPACE) { |
| 932 | /* Mem may have been allocated... */ | 933 | /* Mem may have been allocated... */ |
| 933 | wordfree (&expand_result); | 934 | wordfree (&expand_result); |
| 934 | error_msg("out of space during expansion"); | 935 | error_msg(out_of_space); |
| 935 | return FALSE; | 936 | return FALSE; |
| 936 | } | 937 | } |
| 937 | if (retval < 0) { | 938 | if (retval < 0) { |
| @@ -946,7 +947,7 @@ static int expand_arguments(char *command) | |||
| 946 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { | 947 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { |
| 947 | length=strlen(expand_result.we_wordv[i])+1; | 948 | length=strlen(expand_result.we_wordv[i])+1; |
| 948 | if (BUFSIZ-total_length-length <= 0) { | 949 | if (BUFSIZ-total_length-length <= 0) { |
| 949 | error_msg("out of space during expansion"); | 950 | error_msg(out_of_space); |
| 950 | return FALSE; | 951 | return FALSE; |
| 951 | } | 952 | } |
| 952 | strcat(command+total_length, expand_result.we_wordv[i++]); | 953 | strcat(command+total_length, expand_result.we_wordv[i++]); |
| @@ -956,139 +957,136 @@ static int expand_arguments(char *command) | |||
| 956 | wordfree (&expand_result); | 957 | wordfree (&expand_result); |
| 957 | #else | 958 | #else |
| 958 | 959 | ||
| 959 | /* Ok. They don't have glibc and they don't have uClibc. Chances are | 960 | /* Ok. They don't have a recent glibc and they don't have uClibc. Chances |
| 960 | * about 100% they don't have wordexp(), so instead, the best we can do is | 961 | * are about 100% they don't have wordexp(). So instead the best we can do |
| 961 | * use glob, which is better then nothing, but certainly not perfect */ | 962 | * is use glob and then fixup environment variables and such ourselves. |
| 963 | * This is better then nothing, but certainly not perfect */ | ||
| 962 | 964 | ||
| 963 | /* It turns out that glob is very stupid. We have to feed it | 965 | /* It turns out that glob is very stupid. We have to feed it one word at a |
| 964 | * one word at a time since it can't cope with a full string. | 966 | * time since it can't cope with a full string. Here we convert command |
| 965 | * Here we convert command (char*) into cmd (char**, one word | 967 | * (char*) into cmd (char**, one word per string) */ |
| 966 | * per string) */ | ||
| 967 | { | 968 | { |
| 968 | 969 | ||
| 969 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; | 970 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; |
| 970 | char * tmpcmd; | 971 | char * tmpcmd; |
| 971 | /* We need a clean copy, so strsep can mess up the copy while | 972 | /* We need a clean copy, so strsep can mess up the copy while |
| 972 | * we write stuff into the original in a minute */ | 973 | * we write stuff into the original (in a minute) */ |
| 973 | char * cmd = strdup(command); | 974 | char * cmd = strdup(command); |
| 975 | *command = '\0'; | ||
| 974 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { | 976 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { |
| 975 | if (*tmpcmd == '\0') | 977 | if (*tmpcmd == '\0') |
| 976 | break; | 978 | break; |
| 977 | retval = glob(tmpcmd, flags, NULL, &expand_result); | 979 | retval = glob(tmpcmd, flags, NULL, &expand_result); |
| 978 | /* We can't haveGLOB_APPEND on the first glob call, | ||
| 979 | * so put it there now */ | ||
| 980 | if (! (flags & GLOB_APPEND) ) | ||
| 981 | flags |= GLOB_APPEND; | ||
| 982 | |||
| 983 | if (retval == GLOB_NOSPACE) { | 980 | if (retval == GLOB_NOSPACE) { |
| 984 | /* Mem may have been allocated... */ | 981 | /* Mem may have been allocated... */ |
| 985 | globfree (&expand_result); | 982 | globfree (&expand_result); |
| 986 | error_msg("out of space during expansion"); | 983 | error_msg(out_of_space); |
| 987 | return FALSE; | 984 | return FALSE; |
| 988 | } | 985 | } else if (retval != 0) { |
| 989 | if (retval != 0 && retval != GLOB_NOMATCH) { | 986 | /* Some other error. GLOB_NOMATCH shouldn't |
| 990 | /* Some other error. */ | 987 | * happen because of the GLOB_NOCHECK flag in |
| 988 | * the glob call. */ | ||
| 991 | error_msg("syntax error"); | 989 | error_msg("syntax error"); |
| 992 | return FALSE; | 990 | return FALSE; |
| 993 | } | 991 | } else { |
| 994 | |||
| 995 | /* Convert from char** (one word per string) to a simple char*, | 992 | /* Convert from char** (one word per string) to a simple char*, |
| 996 | * but don't overflow command which is BUFSIZ in length */ | 993 | * but don't overflow command which is BUFSIZ in length */ |
| 997 | if ( expand_result.gl_pathc > 1) { | 994 | for (i=0; i < expand_result.gl_pathc; i++) { |
| 998 | *command = '\0'; | ||
| 999 | while (i < expand_result.gl_pathc && total_length < BUFSIZ) { | ||
| 1000 | length=strlen(expand_result.gl_pathv[i])+1; | 995 | length=strlen(expand_result.gl_pathv[i])+1; |
| 1001 | if (BUFSIZ-total_length-length <= 0) { | 996 | if (BUFSIZ-total_length-length <= 0) { |
| 1002 | error_msg("out of space during expansion"); | 997 | error_msg(out_of_space); |
| 1003 | return FALSE; | 998 | return FALSE; |
| 1004 | } | 999 | } |
| 1005 | strcat(command+total_length, expand_result.gl_pathv[i++]); | 1000 | strcat(command+total_length, expand_result.gl_pathv[i]); |
| 1006 | strcat(command+total_length, " "); | 1001 | strcat(command+total_length, " "); |
| 1007 | total_length+=length; | 1002 | total_length+=length; |
| 1008 | } | 1003 | } |
| 1004 | globfree (&expand_result); | ||
| 1009 | } | 1005 | } |
| 1010 | } | 1006 | } |
| 1011 | |||
| 1012 | free(cmd); | 1007 | free(cmd); |
| 1013 | globfree (&expand_result); | 1008 | trim(command); |
| 1014 | } | 1009 | } |
| 1015 | 1010 | ||
| 1016 | #endif | 1011 | #endif |
| 1017 | 1012 | ||
| 1018 | /* FIXME -- this routine (which is only used when folks | ||
| 1019 | * don't have a C library with wordexp) needs a bit of help | ||
| 1020 | * to handle things like 'echo $PATH$0' */ | ||
| 1021 | |||
| 1022 | /* Now do the shell variable substitutions which | 1013 | /* Now do the shell variable substitutions which |
| 1023 | * wordexp can't do for us, namely $? and $! */ | 1014 | * wordexp can't do for us, namely $? and $! */ |
| 1024 | src = command; | 1015 | src = command; |
| 1025 | while((dst = strchr(src,'$')) != NULL){ | 1016 | while((dst = strchr(src,'$')) != NULL){ |
| 1026 | /* Ok -- got a $ -- now clean up any trailing mess */ | 1017 | printf("dollar '%s'\n", dst); |
| 1027 | trim(dst); | 1018 | var = NULL; |
| 1028 | if (!(var = getenv(dst + 1))) { | 1019 | switch(*(dst+1)) { |
| 1029 | switch(*(dst+1)) { | 1020 | case '?': |
| 1030 | case '?': | 1021 | var = itoa(last_return_code); |
| 1031 | var = itoa(last_return_code); | 1022 | break; |
| 1032 | break; | 1023 | case '!': |
| 1033 | case '!': | 1024 | if (last_bg_pid==-1) |
| 1034 | if (last_bg_pid==-1) | 1025 | *(var)='\0'; |
| 1035 | *(var)='\0'; | 1026 | else |
| 1036 | else | 1027 | var = itoa(last_bg_pid); |
| 1037 | var = itoa(last_bg_pid); | 1028 | break; |
| 1038 | break; | ||
| 1039 | /* Everything else like $$, $#, $[0-9], etc should all be | 1029 | /* Everything else like $$, $#, $[0-9], etc should all be |
| 1040 | * expanded by wordexp(), so we can in theory skip that stuff | 1030 | * expanded by wordexp(), so we can in theory skip that stuff |
| 1041 | * here, but just to be on the safe side (i.e. since uClibc | 1031 | * here, but just to be on the safe side (i.e. since uClibc |
| 1042 | * wordexp doesn't do this stuff yet), lets leave it in for | 1032 | * wordexp doesn't do this stuff yet), lets leave it in for |
| 1043 | * now. */ | 1033 | * now. */ |
| 1044 | case '$': | 1034 | case '$': |
| 1045 | var = itoa(getpid()); | 1035 | var = itoa(getpid()); |
| 1046 | break; | 1036 | break; |
| 1047 | case '#': | 1037 | case '#': |
| 1048 | var = itoa(argc-1); | 1038 | var = itoa(argc-1); |
| 1049 | break; | 1039 | break; |
| 1050 | case '0':case '1':case '2':case '3':case '4': | 1040 | case '0':case '1':case '2':case '3':case '4': |
| 1051 | case '5':case '6':case '7':case '8':case '9': | 1041 | case '5':case '6':case '7':case '8':case '9': |
| 1052 | { | 1042 | { |
| 1053 | int index=*(dst + 1)-48; | 1043 | int index=*(dst + 1)-48; |
| 1054 | if (index >= argc) { | 1044 | if (index >= argc) { |
| 1055 | var='\0'; | 1045 | var='\0'; |
| 1056 | } else { | 1046 | } else { |
| 1057 | var = argv[index]; | 1047 | var = argv[index]; |
| 1058 | } | ||
| 1059 | } | 1048 | } |
| 1060 | break; | 1049 | } |
| 1050 | break; | ||
| 1061 | 1051 | ||
| 1062 | } | ||
| 1063 | } | 1052 | } |
| 1064 | if (var) { | 1053 | if (var) { |
| 1065 | int subst_len = strlen(var); | 1054 | /* a single character construction was found, and |
| 1066 | char *next_dst; | 1055 | * already handled in the case statement */ |
| 1067 | if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?.")) == NULL) { | 1056 | src=dst+2; |
| 1068 | next_dst = dst; | ||
| 1069 | } | ||
| 1070 | src = (char*)xrealloc(src, strlen(src) - strlen(next_dst)+strlen(var)+1); | ||
| 1071 | /* Move stuff to the end of the string to accommodate filling | ||
| 1072 | * the created gap with the new stuff */ | ||
| 1073 | memmove(dst+subst_len, next_dst+1, subst_len); | ||
| 1074 | /* Now copy in the new stuff */ | ||
| 1075 | strncpy(dst, var, subst_len+1); | ||
| 1076 | src = dst; | ||
| 1077 | src++; | ||
| 1078 | } else { | 1057 | } else { |
| 1058 | /* Looks like an environment variable */ | ||
| 1059 | char delim_hold; | ||
| 1060 | src=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?."); | ||
| 1061 | if (src == NULL) { | ||
| 1062 | src = dst+strlen(dst); | ||
| 1063 | } | ||
| 1064 | delim_hold=*src; | ||
| 1065 | *src='\0'; /* temporary */ | ||
| 1066 | var = getenv(dst + 1); | ||
| 1067 | *src=delim_hold; | ||
| 1068 | } | ||
| 1069 | if (var == NULL) { | ||
| 1079 | /* Seems we got an un-expandable variable. So delete it. */ | 1070 | /* Seems we got an un-expandable variable. So delete it. */ |
| 1080 | char *next_dst; | 1071 | var = ""; |
| 1081 | if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?.")) == NULL) { | 1072 | } |
| 1082 | next_dst=dst+1+strlen(dst); | 1073 | { |
| 1074 | int subst_len = strlen(var); | ||
| 1075 | int trail_len = strlen(src); | ||
| 1076 | if (dst+subst_len+trail_len >= command+BUFSIZ) { | ||
| 1077 | error_msg(out_of_space); | ||
| 1078 | return FALSE; | ||
| 1083 | } | 1079 | } |
| 1084 | /* Move stuff to the end of the string to accommodate filling | 1080 | /* Move stuff to the end of the string to accommodate |
| 1085 | * the created gap with the new stuff */ | 1081 | * filling the created gap with the new stuff */ |
| 1086 | memmove(dst, next_dst, next_dst-dst); | 1082 | memmove(dst+subst_len, src, trail_len); |
| 1083 | *(dst+subst_len+trail_len)='\0'; | ||
| 1084 | /* Now copy in the new stuff */ | ||
| 1085 | memcpy(dst, var, subst_len); | ||
| 1086 | src = dst+subst_len; | ||
| 1087 | } | 1087 | } |
| 1088 | } | 1088 | } |
| 1089 | 1089 | printf("expanded '%s'\n", command); | |
| 1090 | |||
| 1091 | |||
| 1092 | 1090 | ||
| 1093 | #endif | 1091 | #endif |
| 1094 | return TRUE; | 1092 | return TRUE; |
diff --git a/shell/lash.c b/shell/lash.c index e1bdc875a..865f10b39 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
| @@ -916,6 +916,7 @@ static int expand_arguments(char *command) | |||
| 916 | expand_t expand_result; | 916 | expand_t expand_result; |
| 917 | char *src, *dst, *var; | 917 | char *src, *dst, *var; |
| 918 | int i=0, length, total_length=0, retval; | 918 | int i=0, length, total_length=0, retval; |
| 919 | const char *out_of_space = "out of space during expansion"; | ||
| 919 | #endif | 920 | #endif |
| 920 | 921 | ||
| 921 | /* get rid of the terminating \n */ | 922 | /* get rid of the terminating \n */ |
| @@ -931,7 +932,7 @@ static int expand_arguments(char *command) | |||
| 931 | if (retval == WRDE_NOSPACE) { | 932 | if (retval == WRDE_NOSPACE) { |
| 932 | /* Mem may have been allocated... */ | 933 | /* Mem may have been allocated... */ |
| 933 | wordfree (&expand_result); | 934 | wordfree (&expand_result); |
| 934 | error_msg("out of space during expansion"); | 935 | error_msg(out_of_space); |
| 935 | return FALSE; | 936 | return FALSE; |
| 936 | } | 937 | } |
| 937 | if (retval < 0) { | 938 | if (retval < 0) { |
| @@ -946,7 +947,7 @@ static int expand_arguments(char *command) | |||
| 946 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { | 947 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { |
| 947 | length=strlen(expand_result.we_wordv[i])+1; | 948 | length=strlen(expand_result.we_wordv[i])+1; |
| 948 | if (BUFSIZ-total_length-length <= 0) { | 949 | if (BUFSIZ-total_length-length <= 0) { |
| 949 | error_msg("out of space during expansion"); | 950 | error_msg(out_of_space); |
| 950 | return FALSE; | 951 | return FALSE; |
| 951 | } | 952 | } |
| 952 | strcat(command+total_length, expand_result.we_wordv[i++]); | 953 | strcat(command+total_length, expand_result.we_wordv[i++]); |
| @@ -956,139 +957,136 @@ static int expand_arguments(char *command) | |||
| 956 | wordfree (&expand_result); | 957 | wordfree (&expand_result); |
| 957 | #else | 958 | #else |
| 958 | 959 | ||
| 959 | /* Ok. They don't have glibc and they don't have uClibc. Chances are | 960 | /* Ok. They don't have a recent glibc and they don't have uClibc. Chances |
| 960 | * about 100% they don't have wordexp(), so instead, the best we can do is | 961 | * are about 100% they don't have wordexp(). So instead the best we can do |
| 961 | * use glob, which is better then nothing, but certainly not perfect */ | 962 | * is use glob and then fixup environment variables and such ourselves. |
| 963 | * This is better then nothing, but certainly not perfect */ | ||
| 962 | 964 | ||
| 963 | /* It turns out that glob is very stupid. We have to feed it | 965 | /* It turns out that glob is very stupid. We have to feed it one word at a |
| 964 | * one word at a time since it can't cope with a full string. | 966 | * time since it can't cope with a full string. Here we convert command |
| 965 | * Here we convert command (char*) into cmd (char**, one word | 967 | * (char*) into cmd (char**, one word per string) */ |
| 966 | * per string) */ | ||
| 967 | { | 968 | { |
| 968 | 969 | ||
| 969 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; | 970 | int flags = GLOB_NOCHECK|GLOB_BRACE|GLOB_TILDE; |
| 970 | char * tmpcmd; | 971 | char * tmpcmd; |
| 971 | /* We need a clean copy, so strsep can mess up the copy while | 972 | /* We need a clean copy, so strsep can mess up the copy while |
| 972 | * we write stuff into the original in a minute */ | 973 | * we write stuff into the original (in a minute) */ |
| 973 | char * cmd = strdup(command); | 974 | char * cmd = strdup(command); |
| 975 | *command = '\0'; | ||
| 974 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { | 976 | for (tmpcmd = cmd; (tmpcmd = strsep(&cmd, " \t")) != NULL;) { |
| 975 | if (*tmpcmd == '\0') | 977 | if (*tmpcmd == '\0') |
| 976 | break; | 978 | break; |
| 977 | retval = glob(tmpcmd, flags, NULL, &expand_result); | 979 | retval = glob(tmpcmd, flags, NULL, &expand_result); |
| 978 | /* We can't haveGLOB_APPEND on the first glob call, | ||
| 979 | * so put it there now */ | ||
| 980 | if (! (flags & GLOB_APPEND) ) | ||
| 981 | flags |= GLOB_APPEND; | ||
| 982 | |||
| 983 | if (retval == GLOB_NOSPACE) { | 980 | if (retval == GLOB_NOSPACE) { |
| 984 | /* Mem may have been allocated... */ | 981 | /* Mem may have been allocated... */ |
| 985 | globfree (&expand_result); | 982 | globfree (&expand_result); |
| 986 | error_msg("out of space during expansion"); | 983 | error_msg(out_of_space); |
| 987 | return FALSE; | 984 | return FALSE; |
| 988 | } | 985 | } else if (retval != 0) { |
| 989 | if (retval != 0 && retval != GLOB_NOMATCH) { | 986 | /* Some other error. GLOB_NOMATCH shouldn't |
| 990 | /* Some other error. */ | 987 | * happen because of the GLOB_NOCHECK flag in |
| 988 | * the glob call. */ | ||
| 991 | error_msg("syntax error"); | 989 | error_msg("syntax error"); |
| 992 | return FALSE; | 990 | return FALSE; |
| 993 | } | 991 | } else { |
| 994 | |||
| 995 | /* Convert from char** (one word per string) to a simple char*, | 992 | /* Convert from char** (one word per string) to a simple char*, |
| 996 | * but don't overflow command which is BUFSIZ in length */ | 993 | * but don't overflow command which is BUFSIZ in length */ |
| 997 | if ( expand_result.gl_pathc > 1) { | 994 | for (i=0; i < expand_result.gl_pathc; i++) { |
| 998 | *command = '\0'; | ||
| 999 | while (i < expand_result.gl_pathc && total_length < BUFSIZ) { | ||
| 1000 | length=strlen(expand_result.gl_pathv[i])+1; | 995 | length=strlen(expand_result.gl_pathv[i])+1; |
| 1001 | if (BUFSIZ-total_length-length <= 0) { | 996 | if (BUFSIZ-total_length-length <= 0) { |
| 1002 | error_msg("out of space during expansion"); | 997 | error_msg(out_of_space); |
| 1003 | return FALSE; | 998 | return FALSE; |
| 1004 | } | 999 | } |
| 1005 | strcat(command+total_length, expand_result.gl_pathv[i++]); | 1000 | strcat(command+total_length, expand_result.gl_pathv[i]); |
| 1006 | strcat(command+total_length, " "); | 1001 | strcat(command+total_length, " "); |
| 1007 | total_length+=length; | 1002 | total_length+=length; |
| 1008 | } | 1003 | } |
| 1004 | globfree (&expand_result); | ||
| 1009 | } | 1005 | } |
| 1010 | } | 1006 | } |
| 1011 | |||
| 1012 | free(cmd); | 1007 | free(cmd); |
| 1013 | globfree (&expand_result); | 1008 | trim(command); |
| 1014 | } | 1009 | } |
| 1015 | 1010 | ||
| 1016 | #endif | 1011 | #endif |
| 1017 | 1012 | ||
| 1018 | /* FIXME -- this routine (which is only used when folks | ||
| 1019 | * don't have a C library with wordexp) needs a bit of help | ||
| 1020 | * to handle things like 'echo $PATH$0' */ | ||
| 1021 | |||
| 1022 | /* Now do the shell variable substitutions which | 1013 | /* Now do the shell variable substitutions which |
| 1023 | * wordexp can't do for us, namely $? and $! */ | 1014 | * wordexp can't do for us, namely $? and $! */ |
| 1024 | src = command; | 1015 | src = command; |
| 1025 | while((dst = strchr(src,'$')) != NULL){ | 1016 | while((dst = strchr(src,'$')) != NULL){ |
| 1026 | /* Ok -- got a $ -- now clean up any trailing mess */ | 1017 | printf("dollar '%s'\n", dst); |
| 1027 | trim(dst); | 1018 | var = NULL; |
| 1028 | if (!(var = getenv(dst + 1))) { | 1019 | switch(*(dst+1)) { |
| 1029 | switch(*(dst+1)) { | 1020 | case '?': |
| 1030 | case '?': | 1021 | var = itoa(last_return_code); |
| 1031 | var = itoa(last_return_code); | 1022 | break; |
| 1032 | break; | 1023 | case '!': |
| 1033 | case '!': | 1024 | if (last_bg_pid==-1) |
| 1034 | if (last_bg_pid==-1) | 1025 | *(var)='\0'; |
| 1035 | *(var)='\0'; | 1026 | else |
| 1036 | else | 1027 | var = itoa(last_bg_pid); |
| 1037 | var = itoa(last_bg_pid); | 1028 | break; |
| 1038 | break; | ||
| 1039 | /* Everything else like $$, $#, $[0-9], etc should all be | 1029 | /* Everything else like $$, $#, $[0-9], etc should all be |
| 1040 | * expanded by wordexp(), so we can in theory skip that stuff | 1030 | * expanded by wordexp(), so we can in theory skip that stuff |
| 1041 | * here, but just to be on the safe side (i.e. since uClibc | 1031 | * here, but just to be on the safe side (i.e. since uClibc |
| 1042 | * wordexp doesn't do this stuff yet), lets leave it in for | 1032 | * wordexp doesn't do this stuff yet), lets leave it in for |
| 1043 | * now. */ | 1033 | * now. */ |
| 1044 | case '$': | 1034 | case '$': |
| 1045 | var = itoa(getpid()); | 1035 | var = itoa(getpid()); |
| 1046 | break; | 1036 | break; |
| 1047 | case '#': | 1037 | case '#': |
| 1048 | var = itoa(argc-1); | 1038 | var = itoa(argc-1); |
| 1049 | break; | 1039 | break; |
| 1050 | case '0':case '1':case '2':case '3':case '4': | 1040 | case '0':case '1':case '2':case '3':case '4': |
| 1051 | case '5':case '6':case '7':case '8':case '9': | 1041 | case '5':case '6':case '7':case '8':case '9': |
| 1052 | { | 1042 | { |
| 1053 | int index=*(dst + 1)-48; | 1043 | int index=*(dst + 1)-48; |
| 1054 | if (index >= argc) { | 1044 | if (index >= argc) { |
| 1055 | var='\0'; | 1045 | var='\0'; |
| 1056 | } else { | 1046 | } else { |
| 1057 | var = argv[index]; | 1047 | var = argv[index]; |
| 1058 | } | ||
| 1059 | } | 1048 | } |
| 1060 | break; | 1049 | } |
| 1050 | break; | ||
| 1061 | 1051 | ||
| 1062 | } | ||
| 1063 | } | 1052 | } |
| 1064 | if (var) { | 1053 | if (var) { |
| 1065 | int subst_len = strlen(var); | 1054 | /* a single character construction was found, and |
| 1066 | char *next_dst; | 1055 | * already handled in the case statement */ |
| 1067 | if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?.")) == NULL) { | 1056 | src=dst+2; |
| 1068 | next_dst = dst; | ||
| 1069 | } | ||
| 1070 | src = (char*)xrealloc(src, strlen(src) - strlen(next_dst)+strlen(var)+1); | ||
| 1071 | /* Move stuff to the end of the string to accommodate filling | ||
| 1072 | * the created gap with the new stuff */ | ||
| 1073 | memmove(dst+subst_len, next_dst+1, subst_len); | ||
| 1074 | /* Now copy in the new stuff */ | ||
| 1075 | strncpy(dst, var, subst_len+1); | ||
| 1076 | src = dst; | ||
| 1077 | src++; | ||
| 1078 | } else { | 1057 | } else { |
| 1058 | /* Looks like an environment variable */ | ||
| 1059 | char delim_hold; | ||
| 1060 | src=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?."); | ||
| 1061 | if (src == NULL) { | ||
| 1062 | src = dst+strlen(dst); | ||
| 1063 | } | ||
| 1064 | delim_hold=*src; | ||
| 1065 | *src='\0'; /* temporary */ | ||
| 1066 | var = getenv(dst + 1); | ||
| 1067 | *src=delim_hold; | ||
| 1068 | } | ||
| 1069 | if (var == NULL) { | ||
| 1079 | /* Seems we got an un-expandable variable. So delete it. */ | 1070 | /* Seems we got an un-expandable variable. So delete it. */ |
| 1080 | char *next_dst; | 1071 | var = ""; |
| 1081 | if ((next_dst=strpbrk(dst+1, " \t~`!$^&*()=|\\{}[];\"'<>?.")) == NULL) { | 1072 | } |
| 1082 | next_dst=dst+1+strlen(dst); | 1073 | { |
| 1074 | int subst_len = strlen(var); | ||
| 1075 | int trail_len = strlen(src); | ||
| 1076 | if (dst+subst_len+trail_len >= command+BUFSIZ) { | ||
| 1077 | error_msg(out_of_space); | ||
| 1078 | return FALSE; | ||
| 1083 | } | 1079 | } |
| 1084 | /* Move stuff to the end of the string to accommodate filling | 1080 | /* Move stuff to the end of the string to accommodate |
| 1085 | * the created gap with the new stuff */ | 1081 | * filling the created gap with the new stuff */ |
| 1086 | memmove(dst, next_dst, next_dst-dst); | 1082 | memmove(dst+subst_len, src, trail_len); |
| 1083 | *(dst+subst_len+trail_len)='\0'; | ||
| 1084 | /* Now copy in the new stuff */ | ||
| 1085 | memcpy(dst, var, subst_len); | ||
| 1086 | src = dst+subst_len; | ||
| 1087 | } | 1087 | } |
| 1088 | } | 1088 | } |
| 1089 | 1089 | printf("expanded '%s'\n", command); | |
| 1090 | |||
| 1091 | |||
| 1092 | 1090 | ||
| 1093 | #endif | 1091 | #endif |
| 1094 | return TRUE; | 1092 | return TRUE; |
