diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-03-09 19:21:37 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-03-09 19:21:37 +0000 |
commit | 195743f195ad4a74735e4aec1d801c498a60f371 (patch) | |
tree | 0f7dbc3b592232f49a6696e46dded7b721289391 /sh.c | |
parent | eba8ed71f08f334bc94ac8eeedcd998fcdd05897 (diff) | |
download | busybox-w32-195743f195ad4a74735e4aec1d801c498a60f371.tar.gz busybox-w32-195743f195ad4a74735e4aec1d801c498a60f371.tar.bz2 busybox-w32-195743f195ad4a74735e4aec1d801c498a60f371.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
Diffstat (limited to 'sh.c')
-rw-r--r-- | sh.c | 168 |
1 files changed, 83 insertions, 85 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; |