aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Whitley <markw@lineo.com>2000-07-14 19:06:30 +0000
committerMark Whitley <markw@lineo.com>2000-07-14 19:06:30 +0000
commit70705d7c9681b4ea870ea11d0c569d81e5822169 (patch)
tree30440bb277ef34bf5cd15b0c3db27f0024da105b
parentadd09fd558c8a336554fbf8b381ab0f8e180382a (diff)
downloadbusybox-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.c103
-rw-r--r--sed.c103
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 */
141static char *trim_str(const char *str) 143static 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 */
173static 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
228static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) 247static 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
298out:
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
281static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) 307static 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
337static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) 365static 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
374static void add_cmd_str(const char *cmdstr) 406static 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
diff --git a/sed.c b/sed.c
index 3a7360fc5..40400fe3a 100644
--- a/sed.c
+++ b/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 */
141static char *trim_str(const char *str) 143static 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 */
173static 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
228static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) 247static 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
298out:
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
281static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) 307static 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
337static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) 365static 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
374static void add_cmd_str(const char *cmdstr) 406static 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