1 /******************************************************************************
2 * This file is Copyright 1992 by Philip G. Richards. All Rights Reserved.
3 * See the file README that came with this distribution for permissions on
4 * code usage, copying, and distribution. It comes with absolutely no warranty.
5 ******************************************************************************/
6
7 #include "client.h"
8 #include "main.h"
9 #include "parse.h"
10 #include <ctype.h>
11 #include <stdlib.h>
12
13 extern char **environ;
14
15 #define ISMAGIC 0x80
16 #define ISPROT 0x40
17
18 void
freemyargs(int argc,char ** argv)19 freemyargs(int argc, char **argv)
20 {
21 int i;
22
23 if (argv == NULL)
24 return;
25
26 #ifdef MALLOCDEBUG
27 {
28 int oldlvl = malloc_debug(0);
29 #endif
30
31 for (i = 0; i < argc && argv[i]; i++)
32 (void)free(argv[i]);
33
34 #ifdef MALLOCDEBUG
35 (void)malloc_debug(oldlvl);
36 if (!malloc_verify())
37 {
38 ffprintf(STDERR, "??freemyargs() has screwed up malloc()\n");
39 abort();
40 }
41 }
42 #endif
43 }
44
45 /**********************************************************************
46 * create an argument list from a command line; the original line is
47 * undamaged by this function, and the values returned in the pargv
48 * are all malloc'd and should be free'd with freemyargs()
49 **********************************************************************/
50 int
parsemyargs(char * comm,char *** pargv,unsigned int * pmaxargc,int gargc,char ** gargv)51 parsemyargs(char *comm, char ***pargv, unsigned int *pmaxargc, int gargc, char **gargv)
52 {
53 int j, rdsp, inquotes;
54 unsigned int argc,i;
55 char *buff, *magic;
56
57 if ((buff = strdup(comm)) == (char*)0)
58 {
59 ffprintf(STDERR, "??out of memory in parsemyargs()\n");
60 return 0;
61 }
62
63 /* count words -- ok, I know this can be done better, but I'm lazy */
64 for (i = 0, argc = 0, rdsp = 1, inquotes = 0; buff[i]; i++)
65 {
66 /* buff[i] != 0 => next test can only succeed if inquotes != 0 */
67 if (inquotes == '\\' || buff[i] == inquotes)
68 {
69 inquotes = 0;
70 rdsp = 0;
71 }
72 else if (inquotes)
73 {
74 ;
75 }
76 else if (isspace(buff[i]))
77 {
78 if (!rdsp)
79 buff[i] = '\0';
80 while (isspace(buff[i+1]))
81 i++;
82 rdsp = 1;
83 }
84 else
85 {
86 if (rdsp)
87 {
88 /* check if we are starting a comment */
89 if (buff[i] == '#')
90 break;
91
92 /***********************************************************
93 * if we have a single character command, pretend we have
94 * spaces after it, even if we don't (true for first word only)
95 ***********************************************************/
96 rdsp = (argc == 0)
97 && (buff[i] == '!' || buff[i] == '@');
98
99 argc++;
100
101 /***********************************************************
102 * if the first character in the word is an unquoted `|', then
103 * consider that as the beginning of the final word (which
104 * will take the rest of the line)
105 ***********************************************************/
106 if (buff[i] == '|')
107 break;
108 }
109
110 if (buff[i] == '"' || buff[i] == '\'' || buff[i] == '\\')
111 inquotes = buff[i];
112 }
113 }
114
115 if (inquotes)
116 {
117 ffprintf(STDERR, "?unclosed quotes\n");
118 (void)free(buff);
119 return 0;
120 }
121
122 if (argc > *pmaxargc - 1)
123 {
124 *pmaxargc = argc + 1;
125
126 if (*pargv == (char**)0)
127 *pargv = (char**)malloc(*pmaxargc * sizeof(char*));
128 else
129 *pargv = (char**)realloc((char*)*pargv, *pmaxargc * sizeof(char*));
130
131 if (*pargv == (char**)0)
132 {
133 ffprintf(STDERR, "??out of memory in parsemyargs()\n");
134 *pmaxargc = 0;
135 return 0;
136 }
137 }
138
139 if ((magic = strdup(comm)) == (char*)0)
140 {
141 ffprintf(STDERR, "??out of memory in parsemyargs() for magic\n");
142 (void)free(buff);
143 *pmaxargc = 0;
144 return 0;
145 }
146
147 /* set up *pargv[] */
148 for (i = 0, j = 0; i < argc; i++, j++)
149 {
150 int k, d;
151
152 while (isspace(buff[j]))
153 j++;
154
155 if (i == 0 && (buff[j] == '!' || buff[j] == '@'))
156 switch (buff[j])
157 {
158 case '!':
159 (*pargv)[i] = "shell";
160 break;
161 case '@':
162 (*pargv)[i] = BUILTIN;
163 break;
164 default:
165 (*pargv)[i] = "error";
166 break;
167 }
168 else if (i == argc - 1 && buff[j] == '|')
169 (*pargv)[i] = buff + j;
170 else
171 {
172 (*pargv)[i] = buff + j;
173 k = j;
174 while (buff[j])
175 j++;
176
177 /***********************************************************
178 * at this point, (*pargv)[i] to buff+j is the word, still with
179 * quote characters in it; at this point we remove the quotes
180 * we mark magic characters (non-8bit clean) with a 0x80 top
181 * bit; outside of quotes, ?*{[$\ are all magic; inside `"'s
182 * just $\ are magic; inside "'"s nothing is magic; a magic \
183 * turns off the magic ability of the next character
184 ***********************************************************/
185 for (inquotes = 0, d = k; k <= j; k++)
186 if ((inquotes & 0x7f) == '\\')
187 {
188 inquotes = (inquotes & ISMAGIC)? '"': 0;
189 buff[d] = buff[k];
190 magic[d++] = ISPROT;
191 }
192 else if (inquotes)
193 {
194 if (inquotes == '"' && buff[k] == '\\')
195 inquotes |= ISMAGIC;
196 else
197 {
198 if (buff[k] != inquotes)
199 {
200 buff[d] = buff[k];
201 magic[d++] = (inquotes != '\''
202 && buff[k] == '$')? ISMAGIC: 0;
203 }
204 else
205 inquotes = 0;
206 }
207 }
208 else if (buff[k] == '"' || buff[k] == '\'' || buff[k] == '\\')
209 inquotes = buff[k];
210 else
211 {
212 buff[d] = buff[k];
213 magic[d++] = (inquotes != '\'' &&
214 (buff[k] == '?' || buff[k] == '*' ||
215 buff[k] == '{' || buff[k] == '[' ||
216 buff[k] == '$'))? ISMAGIC: 0;
217 }
218 }
219 }
220
221 for (i = 0; i < argc; i++)
222 (*pargv)[i] = strdup((*pargv)[i]);
223
224 (*pargv)[argc] = (char*)0;
225 (void)free(buff);
226 (void)free(magic);
227
228 return argc;
229 }
230