diff options
author | Mark Whitley <markw@lineo.com> | 2000-07-14 19:06:30 +0000 |
---|---|---|
committer | Mark Whitley <markw@lineo.com> | 2000-07-14 19:06:30 +0000 |
commit | 70705d7c9681b4ea870ea11d0c569d81e5822169 (patch) | |
tree | 30440bb277ef34bf5cd15b0c3db27f0024da105b | |
parent | add09fd558c8a336554fbf8b381ab0f8e180382a (diff) | |
download | busybox-w32-70705d7c9681b4ea870ea11d0c569d81e5822169.tar.gz busybox-w32-70705d7c9681b4ea870ea11d0c569d81e5822169.tar.bz2 busybox-w32-70705d7c9681b4ea870ea11d0c569d81e5822169.zip |
- Added support for semicolon delimited command lines. (woo-hoo!)
- Obsoleted the trim_str function (#if 0'ed out -- maybedelete later) in
favor of strrspn.
- Obsoleted the strrspn function (#if 0'ed out as well) as soon as I
discovered that it wasn't needed either.
- Fixed a subtle bug in parse_subst_cmd where it would choke with an error if
there was any trailing space after the s/match/replace/ expression.
-rw-r--r-- | editors/sed.c | 103 | ||||
-rw-r--r-- | sed.c | 103 |
2 files changed, 144 insertions, 62 deletions
diff --git a/editors/sed.c b/editors/sed.c index 3a7360fc5..40400fe3a 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -132,11 +132,13 @@ static void destroy_cmd_strs() | |||
132 | } | 132 | } |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | #if 0 | ||
135 | /* | 136 | /* |
136 | * trim_str - trims leading and trailing space from a string | 137 | * trim_str - trims leading and trailing space from a string |
137 | * | 138 | * |
138 | * Note: This returns a malloc'ed string so you must store and free it | 139 | * Note: This returns a malloc'ed string so you must store and free it |
139 | * XXX: This should be in the utility.c file. | 140 | * XXX: This should be in the utility.c file. |
141 | * XXX: This is now obsolete. Maybe it belongs nowhere. | ||
140 | */ | 142 | */ |
141 | static char *trim_str(const char *str) | 143 | static char *trim_str(const char *str) |
142 | { | 144 | { |
@@ -156,11 +158,28 @@ static char *trim_str(const char *str) | |||
156 | * | 158 | * |
157 | * you know, a strrspn() would really be nice cuz then we could say: | 159 | * you know, a strrspn() would really be nice cuz then we could say: |
158 | * | 160 | * |
159 | * retstr[strlen(retstr) - strrspn(retstr, " \n\t\v") + 1] = 0; | 161 | * retstr[strrspn(retstr, " \n\t\v") + 1] = 0; |
160 | */ | 162 | */ |
161 | 163 | ||
162 | return retstr; | 164 | return retstr; |
163 | } | 165 | } |
166 | #endif | ||
167 | |||
168 | #if 0 | ||
169 | /* | ||
170 | * strrspn - works just like strspn() but goes from right to left instead of | ||
171 | * left to right | ||
172 | */ | ||
173 | static size_t strrspn(const char *s, const char *accept) | ||
174 | { | ||
175 | size_t i = strlen(s); | ||
176 | |||
177 | while (strchr(accept, s[--i])) | ||
178 | ; | ||
179 | |||
180 | return i; | ||
181 | } | ||
182 | #endif | ||
164 | 183 | ||
165 | /* | 184 | /* |
166 | * index_of_unescaped_slash - walks left to right through a string beginning | 185 | * index_of_unescaped_slash - walks left to right through a string beginning |
@@ -225,7 +244,7 @@ static char *strdup_substr(const char *str, int start, int end) | |||
225 | return newstr; | 244 | return newstr; |
226 | } | 245 | } |
227 | 246 | ||
228 | static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | 247 | static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) |
229 | { | 248 | { |
230 | int oldidx, cflags = REG_NEWLINE; | 249 | int oldidx, cflags = REG_NEWLINE; |
231 | char *match; | 250 | char *match; |
@@ -261,24 +280,31 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | |||
261 | /* process the flags */ | 280 | /* process the flags */ |
262 | while (substr[++idx]) { | 281 | while (substr[++idx]) { |
263 | switch (substr[idx]) { | 282 | switch (substr[idx]) { |
264 | case 'g': | 283 | case 'g': |
265 | sed_cmd->sub_g = 1; | 284 | sed_cmd->sub_g = 1; |
266 | break; | 285 | break; |
267 | case 'I': | 286 | case 'I': |
268 | cflags |= REG_ICASE; | 287 | cflags |= REG_ICASE; |
269 | break; | 288 | break; |
270 | default: | 289 | default: |
271 | fatalError("bad option in substitution expression\n"); | 290 | /* any whitespace or semicolon trailing after a s/// is ok */ |
291 | if (strchr("; \t\v\n\r", substr[idx])) | ||
292 | goto out; | ||
293 | /* else */ | ||
294 | fatalError("bad option in substitution expression\n"); | ||
272 | } | 295 | } |
273 | } | 296 | } |
274 | 297 | ||
298 | out: | ||
275 | /* compile the regex */ | 299 | /* compile the regex */ |
276 | sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); | 300 | sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); |
277 | xregcomp(sed_cmd->sub_match, match, cflags); | 301 | xregcomp(sed_cmd->sub_match, match, cflags); |
278 | free(match); | 302 | free(match); |
303 | |||
304 | return idx; | ||
279 | } | 305 | } |
280 | 306 | ||
281 | static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) | 307 | static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) |
282 | { | 308 | { |
283 | int idx = 0; | 309 | int idx = 0; |
284 | char *ptr; /* shorthand */ | 310 | char *ptr; /* shorthand */ |
@@ -322,7 +348,7 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) | |||
322 | if (!ptr[idx]) { | 348 | if (!ptr[idx]) { |
323 | ptr[idx] = '\n'; | 349 | ptr[idx] = '\n'; |
324 | ptr[idx+1] = 0; | 350 | ptr[idx+1] = 0; |
325 | return; | 351 | return idx; |
326 | } | 352 | } |
327 | } | 353 | } |
328 | /* move the newline over the '\' before it (effectively eats the '\') */ | 354 | /* move the newline over the '\' before it (effectively eats the '\') */ |
@@ -332,9 +358,11 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) | |||
332 | if (ptr[idx] == '\r') | 358 | if (ptr[idx] == '\r') |
333 | ptr[idx] = '\n'; | 359 | ptr[idx] = '\n'; |
334 | } | 360 | } |
361 | |||
362 | return idx; | ||
335 | } | 363 | } |
336 | 364 | ||
337 | static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | 365 | static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) |
338 | { | 366 | { |
339 | int idx = 0; | 367 | int idx = 0; |
340 | 368 | ||
@@ -344,6 +372,7 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
344 | * part1 part2 part3 | 372 | * part1 part2 part3 |
345 | */ | 373 | */ |
346 | 374 | ||
375 | |||
347 | /* first part (if present) is an address: either a number or a /regex/ */ | 376 | /* first part (if present) is an address: either a number or a /regex/ */ |
348 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') | 377 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') |
349 | idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); | 378 | idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); |
@@ -360,33 +389,45 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
360 | sed_cmd->cmd = cmdstr[idx]; | 389 | sed_cmd->cmd = cmdstr[idx]; |
361 | 390 | ||
362 | /* special-case handling for (s)ubstitution */ | 391 | /* special-case handling for (s)ubstitution */ |
363 | if (sed_cmd->cmd == 's') | 392 | if (sed_cmd->cmd == 's') { |
364 | parse_subst_cmd(sed_cmd, &cmdstr[idx]); | 393 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); |
365 | 394 | } | |
366 | /* special-case handling for (a)ppend, (i)nsert, and (c)hange */ | 395 | /* special-case handling for (a)ppend, (i)nsert, and (c)hange */ |
367 | if (strchr("aic", cmdstr[idx])) { | 396 | else if (strchr("aic", cmdstr[idx])) { |
368 | if (sed_cmd->end_line || sed_cmd->end_match) | 397 | if (sed_cmd->end_line || sed_cmd->end_match) |
369 | fatalError("only a beginning address can be specified for edit commands\n"); | 398 | fatalError("only a beginning address can be specified for edit commands\n"); |
370 | parse_edit_cmd(sed_cmd, &cmdstr[idx]); | 399 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); |
371 | } | 400 | } |
401 | |||
402 | /* give back whatever's left over */ | ||
403 | return (char *)&cmdstr[++idx]; | ||
372 | } | 404 | } |
373 | 405 | ||
374 | static void add_cmd_str(const char *cmdstr) | 406 | static void add_cmd_str(const char *cmdstr) |
375 | { | 407 | { |
376 | char *my_cmdstr = trim_str(cmdstr); | 408 | char *mystr = (char *)cmdstr; |
377 | 409 | ||
378 | /* if this is a comment, don't even bother */ | 410 | do { |
379 | if (my_cmdstr[0] == '#') { | ||
380 | free(my_cmdstr); | ||
381 | return; | ||
382 | } | ||
383 | 411 | ||
384 | /* grow the array */ | 412 | /* trim leading whitespace and semicolons */ |
385 | sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); | 413 | memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr)); |
386 | /* zero new element */ | 414 | /* if we ate the whole thing, that means there was just trailing |
387 | memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); | 415 | * whitespace or a final semicolon. either way, get out */ |
388 | /* load command string into new array element */ | 416 | if (strlen(mystr) == 0) |
389 | parse_cmd_str(&sed_cmds[ncmds-1], my_cmdstr); | 417 | return; |
418 | /* if this is a comment, jump past it and keep going */ | ||
419 | if (mystr[0] == '#') { | ||
420 | mystr = strpbrk(mystr, ";\n\r"); | ||
421 | continue; | ||
422 | } | ||
423 | /* grow the array */ | ||
424 | sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); | ||
425 | /* zero new element */ | ||
426 | memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); | ||
427 | /* load command string into new array element, get remainder */ | ||
428 | mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr); | ||
429 | |||
430 | } while (mystr); | ||
390 | } | 431 | } |
391 | 432 | ||
392 | 433 | ||
@@ -132,11 +132,13 @@ static void destroy_cmd_strs() | |||
132 | } | 132 | } |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | #if 0 | ||
135 | /* | 136 | /* |
136 | * trim_str - trims leading and trailing space from a string | 137 | * trim_str - trims leading and trailing space from a string |
137 | * | 138 | * |
138 | * Note: This returns a malloc'ed string so you must store and free it | 139 | * Note: This returns a malloc'ed string so you must store and free it |
139 | * XXX: This should be in the utility.c file. | 140 | * XXX: This should be in the utility.c file. |
141 | * XXX: This is now obsolete. Maybe it belongs nowhere. | ||
140 | */ | 142 | */ |
141 | static char *trim_str(const char *str) | 143 | static char *trim_str(const char *str) |
142 | { | 144 | { |
@@ -156,11 +158,28 @@ static char *trim_str(const char *str) | |||
156 | * | 158 | * |
157 | * you know, a strrspn() would really be nice cuz then we could say: | 159 | * you know, a strrspn() would really be nice cuz then we could say: |
158 | * | 160 | * |
159 | * retstr[strlen(retstr) - strrspn(retstr, " \n\t\v") + 1] = 0; | 161 | * retstr[strrspn(retstr, " \n\t\v") + 1] = 0; |
160 | */ | 162 | */ |
161 | 163 | ||
162 | return retstr; | 164 | return retstr; |
163 | } | 165 | } |
166 | #endif | ||
167 | |||
168 | #if 0 | ||
169 | /* | ||
170 | * strrspn - works just like strspn() but goes from right to left instead of | ||
171 | * left to right | ||
172 | */ | ||
173 | static size_t strrspn(const char *s, const char *accept) | ||
174 | { | ||
175 | size_t i = strlen(s); | ||
176 | |||
177 | while (strchr(accept, s[--i])) | ||
178 | ; | ||
179 | |||
180 | return i; | ||
181 | } | ||
182 | #endif | ||
164 | 183 | ||
165 | /* | 184 | /* |
166 | * index_of_unescaped_slash - walks left to right through a string beginning | 185 | * index_of_unescaped_slash - walks left to right through a string beginning |
@@ -225,7 +244,7 @@ static char *strdup_substr(const char *str, int start, int end) | |||
225 | return newstr; | 244 | return newstr; |
226 | } | 245 | } |
227 | 246 | ||
228 | static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | 247 | static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) |
229 | { | 248 | { |
230 | int oldidx, cflags = REG_NEWLINE; | 249 | int oldidx, cflags = REG_NEWLINE; |
231 | char *match; | 250 | char *match; |
@@ -261,24 +280,31 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) | |||
261 | /* process the flags */ | 280 | /* process the flags */ |
262 | while (substr[++idx]) { | 281 | while (substr[++idx]) { |
263 | switch (substr[idx]) { | 282 | switch (substr[idx]) { |
264 | case 'g': | 283 | case 'g': |
265 | sed_cmd->sub_g = 1; | 284 | sed_cmd->sub_g = 1; |
266 | break; | 285 | break; |
267 | case 'I': | 286 | case 'I': |
268 | cflags |= REG_ICASE; | 287 | cflags |= REG_ICASE; |
269 | break; | 288 | break; |
270 | default: | 289 | default: |
271 | fatalError("bad option in substitution expression\n"); | 290 | /* any whitespace or semicolon trailing after a s/// is ok */ |
291 | if (strchr("; \t\v\n\r", substr[idx])) | ||
292 | goto out; | ||
293 | /* else */ | ||
294 | fatalError("bad option in substitution expression\n"); | ||
272 | } | 295 | } |
273 | } | 296 | } |
274 | 297 | ||
298 | out: | ||
275 | /* compile the regex */ | 299 | /* compile the regex */ |
276 | sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); | 300 | sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); |
277 | xregcomp(sed_cmd->sub_match, match, cflags); | 301 | xregcomp(sed_cmd->sub_match, match, cflags); |
278 | free(match); | 302 | free(match); |
303 | |||
304 | return idx; | ||
279 | } | 305 | } |
280 | 306 | ||
281 | static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) | 307 | static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) |
282 | { | 308 | { |
283 | int idx = 0; | 309 | int idx = 0; |
284 | char *ptr; /* shorthand */ | 310 | char *ptr; /* shorthand */ |
@@ -322,7 +348,7 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) | |||
322 | if (!ptr[idx]) { | 348 | if (!ptr[idx]) { |
323 | ptr[idx] = '\n'; | 349 | ptr[idx] = '\n'; |
324 | ptr[idx+1] = 0; | 350 | ptr[idx+1] = 0; |
325 | return; | 351 | return idx; |
326 | } | 352 | } |
327 | } | 353 | } |
328 | /* move the newline over the '\' before it (effectively eats the '\') */ | 354 | /* move the newline over the '\' before it (effectively eats the '\') */ |
@@ -332,9 +358,11 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) | |||
332 | if (ptr[idx] == '\r') | 358 | if (ptr[idx] == '\r') |
333 | ptr[idx] = '\n'; | 359 | ptr[idx] = '\n'; |
334 | } | 360 | } |
361 | |||
362 | return idx; | ||
335 | } | 363 | } |
336 | 364 | ||
337 | static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | 365 | static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) |
338 | { | 366 | { |
339 | int idx = 0; | 367 | int idx = 0; |
340 | 368 | ||
@@ -344,6 +372,7 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
344 | * part1 part2 part3 | 372 | * part1 part2 part3 |
345 | */ | 373 | */ |
346 | 374 | ||
375 | |||
347 | /* first part (if present) is an address: either a number or a /regex/ */ | 376 | /* first part (if present) is an address: either a number or a /regex/ */ |
348 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') | 377 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') |
349 | idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); | 378 | idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); |
@@ -360,33 +389,45 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
360 | sed_cmd->cmd = cmdstr[idx]; | 389 | sed_cmd->cmd = cmdstr[idx]; |
361 | 390 | ||
362 | /* special-case handling for (s)ubstitution */ | 391 | /* special-case handling for (s)ubstitution */ |
363 | if (sed_cmd->cmd == 's') | 392 | if (sed_cmd->cmd == 's') { |
364 | parse_subst_cmd(sed_cmd, &cmdstr[idx]); | 393 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); |
365 | 394 | } | |
366 | /* special-case handling for (a)ppend, (i)nsert, and (c)hange */ | 395 | /* special-case handling for (a)ppend, (i)nsert, and (c)hange */ |
367 | if (strchr("aic", cmdstr[idx])) { | 396 | else if (strchr("aic", cmdstr[idx])) { |
368 | if (sed_cmd->end_line || sed_cmd->end_match) | 397 | if (sed_cmd->end_line || sed_cmd->end_match) |
369 | fatalError("only a beginning address can be specified for edit commands\n"); | 398 | fatalError("only a beginning address can be specified for edit commands\n"); |
370 | parse_edit_cmd(sed_cmd, &cmdstr[idx]); | 399 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); |
371 | } | 400 | } |
401 | |||
402 | /* give back whatever's left over */ | ||
403 | return (char *)&cmdstr[++idx]; | ||
372 | } | 404 | } |
373 | 405 | ||
374 | static void add_cmd_str(const char *cmdstr) | 406 | static void add_cmd_str(const char *cmdstr) |
375 | { | 407 | { |
376 | char *my_cmdstr = trim_str(cmdstr); | 408 | char *mystr = (char *)cmdstr; |
377 | 409 | ||
378 | /* if this is a comment, don't even bother */ | 410 | do { |
379 | if (my_cmdstr[0] == '#') { | ||
380 | free(my_cmdstr); | ||
381 | return; | ||
382 | } | ||
383 | 411 | ||
384 | /* grow the array */ | 412 | /* trim leading whitespace and semicolons */ |
385 | sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); | 413 | memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr)); |
386 | /* zero new element */ | 414 | /* if we ate the whole thing, that means there was just trailing |
387 | memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); | 415 | * whitespace or a final semicolon. either way, get out */ |
388 | /* load command string into new array element */ | 416 | if (strlen(mystr) == 0) |
389 | parse_cmd_str(&sed_cmds[ncmds-1], my_cmdstr); | 417 | return; |
418 | /* if this is a comment, jump past it and keep going */ | ||
419 | if (mystr[0] == '#') { | ||
420 | mystr = strpbrk(mystr, ";\n\r"); | ||
421 | continue; | ||
422 | } | ||
423 | /* grow the array */ | ||
424 | sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); | ||
425 | /* zero new element */ | ||
426 | memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); | ||
427 | /* load command string into new array element, get remainder */ | ||
428 | mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr); | ||
429 | |||
430 | } while (mystr); | ||
390 | } | 431 | } |
391 | 432 | ||
392 | 433 | ||