diff options
author | Mark Whitley <markw@lineo.com> | 2001-05-11 22:27:13 +0000 |
---|---|---|
committer | Mark Whitley <markw@lineo.com> | 2001-05-11 22:27:13 +0000 |
commit | 1f3b9f297e948b70a82b82919d0ef4d4e1b61d7f (patch) | |
tree | a223a8f7031345c8eb68bd25f5dc204ad523d7fd | |
parent | cfa88ecb7268006eb3d25260892b5b7f91d1e62b (diff) | |
download | busybox-w32-1f3b9f297e948b70a82b82919d0ef4d4e1b61d7f.tar.gz busybox-w32-1f3b9f297e948b70a82b82919d0ef4d4e1b61d7f.tar.bz2 busybox-w32-1f3b9f297e948b70a82b82919d0ef4d4e1b61d7f.zip |
Added support for 'r' command in sed.
-rw-r--r-- | editors/sed.c | 83 | ||||
-rw-r--r-- | sed.c | 83 |
2 files changed, 146 insertions, 20 deletions
diff --git a/editors/sed.c b/editors/sed.c index 1342a6643..156ad3ada 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -27,6 +27,7 @@ | |||
27 | - address matching: num|/matchstr/[,num|/matchstr/|$]command | 27 | - address matching: num|/matchstr/[,num|/matchstr/|$]command |
28 | - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) | 28 | - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) |
29 | - edit commands: (a)ppend, (i)nsert, (c)hange | 29 | - edit commands: (a)ppend, (i)nsert, (c)hange |
30 | - file commands: (r)ead | ||
30 | - backreferences in substitution expressions (\1, \2...\9) | 31 | - backreferences in substitution expressions (\1, \2...\9) |
31 | 32 | ||
32 | (Note: Specifying an address (range) to match is *optional*; commands | 33 | (Note: Specifying an address (range) to match is *optional*; commands |
@@ -90,6 +91,11 @@ struct sed_cmd { | |||
90 | /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ | 91 | /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ |
91 | 92 | ||
92 | char *editline; | 93 | char *editline; |
94 | |||
95 | |||
96 | /* FILE COMMAND (r) SPEICIFIC FIELDS */ | ||
97 | |||
98 | char *filename; | ||
93 | }; | 99 | }; |
94 | 100 | ||
95 | /* globals */ | 101 | /* globals */ |
@@ -351,6 +357,45 @@ out: | |||
351 | return idx; | 357 | return idx; |
352 | } | 358 | } |
353 | 359 | ||
360 | |||
361 | static int parse_file_cmd(struct sed_cmd *sed_cmd, const char *filecmdstr) | ||
362 | { | ||
363 | int idx = 0; | ||
364 | int filenamelen = 0; | ||
365 | |||
366 | /* | ||
367 | * the string that gets passed to this function should look like this: | ||
368 | * '[ ]filename' | ||
369 | * | | | ||
370 | * | a filename | ||
371 | * | | ||
372 | * optional whitespace | ||
373 | |||
374 | * re: the file to be read, the GNU manual says the following: "Note that | ||
375 | * if filename cannot be read, it is treated as if it were an empty file, | ||
376 | * without any error indication." Thus, all of the following commands are | ||
377 | * perfectly leagal: | ||
378 | * | ||
379 | * sed -e '1r noexist' | ||
380 | * sed -e '1r ;' | ||
381 | * sed -e '1r' | ||
382 | */ | ||
383 | |||
384 | /* the file command may be followed by whitespace; move past it. */ | ||
385 | while (isspace(filecmdstr[++idx])) | ||
386 | { ; } | ||
387 | |||
388 | /* the first non-whitespace we get is a filename. the filename ends when we | ||
389 | * hit a normal sed command terminator or end of string */ | ||
390 | filenamelen = strcspn(&filecmdstr[idx], "; \n\r\t\v\0"); | ||
391 | sed_cmd->filename = xmalloc(sizeof(char) * filenamelen + 1); | ||
392 | strncpy(sed_cmd->filename, &filecmdstr[idx], filenamelen); | ||
393 | sed_cmd->filename[filenamelen] = 0; | ||
394 | |||
395 | return idx + filenamelen; | ||
396 | } | ||
397 | |||
398 | |||
354 | static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | 399 | static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) |
355 | { | 400 | { |
356 | int idx = 0; | 401 | int idx = 0; |
@@ -361,7 +406,6 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
361 | * part1 part2 part3 | 406 | * part1 part2 part3 |
362 | */ | 407 | */ |
363 | 408 | ||
364 | |||
365 | /* first part (if present) is an address: either a number or a /regex/ */ | 409 | /* first part (if present) is an address: either a number or a /regex/ */ |
366 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') | 410 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') |
367 | idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); | 411 | idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); |
@@ -373,24 +417,32 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
373 | /* last part (mandatory) will be a command */ | 417 | /* last part (mandatory) will be a command */ |
374 | if (cmdstr[idx] == '\0') | 418 | if (cmdstr[idx] == '\0') |
375 | error_msg_and_die("missing command"); | 419 | error_msg_and_die("missing command"); |
376 | if (!strchr("pdsaic", cmdstr[idx])) /* <-- XXX add new commands here */ | ||
377 | error_msg_and_die("invalid command"); | ||
378 | sed_cmd->cmd = cmdstr[idx]; | 420 | sed_cmd->cmd = cmdstr[idx]; |
379 | 421 | ||
380 | /* special-case handling for (s)ubstitution */ | 422 | /* if it was a single-letter command that takes no arguments (such as 'p' |
381 | if (sed_cmd->cmd == 's') { | 423 | * or 'd') all we need to do is increment the index past that command */ |
424 | if (strchr("pd", cmdstr[idx])) { | ||
425 | idx++; | ||
426 | } | ||
427 | /* handle (s)ubstitution */ | ||
428 | else if (sed_cmd->cmd == 's') { | ||
382 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); | 429 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); |
383 | } | 430 | } |
384 | /* special-case handling for (a)ppend, (i)nsert, and (c)hange */ | 431 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ |
385 | else if (strchr("aic", cmdstr[idx])) { | 432 | else if (strchr("aic", cmdstr[idx])) { |
386 | if (sed_cmd->end_line || sed_cmd->end_match) | 433 | if (sed_cmd->end_line || sed_cmd->end_match) |
387 | error_msg_and_die("only a beginning address can be specified for edit commands"); | 434 | error_msg_and_die("only a beginning address can be specified for edit commands"); |
388 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); | 435 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); |
389 | } | 436 | } |
390 | /* if it was a single-letter command (such as 'p' or 'd') we need to | 437 | /* handle file cmds: (r)ead */ |
391 | * increment the index past that command */ | 438 | else if (sed_cmd->cmd == 'r') { |
392 | else | 439 | if (sed_cmd->end_line || sed_cmd->end_match) |
393 | idx++; | 440 | error_msg_and_die("Command only uses one address"); |
441 | idx += parse_file_cmd(sed_cmd, &cmdstr[idx]); | ||
442 | } | ||
443 | else { | ||
444 | error_msg_and_die("invalid command"); | ||
445 | } | ||
394 | 446 | ||
395 | /* give back whatever's left over */ | 447 | /* give back whatever's left over */ |
396 | return (char *)&cmdstr[idx]; | 448 | return (char *)&cmdstr[idx]; |
@@ -598,6 +650,17 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line) | |||
598 | fputs(sed_cmd->editline, stdout); | 650 | fputs(sed_cmd->editline, stdout); |
599 | altered++; | 651 | altered++; |
600 | break; | 652 | break; |
653 | |||
654 | case 'r': { | ||
655 | FILE *file; | ||
656 | fputs(line, stdout); | ||
657 | file = fopen(sed_cmd->filename, "r"); | ||
658 | if (file) | ||
659 | print_file(file); | ||
660 | /* else if we couldn't open the file, no biggie, just don't print anything */ | ||
661 | altered++; | ||
662 | } | ||
663 | break; | ||
601 | } | 664 | } |
602 | 665 | ||
603 | return altered; | 666 | return altered; |
@@ -27,6 +27,7 @@ | |||
27 | - address matching: num|/matchstr/[,num|/matchstr/|$]command | 27 | - address matching: num|/matchstr/[,num|/matchstr/|$]command |
28 | - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) | 28 | - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) |
29 | - edit commands: (a)ppend, (i)nsert, (c)hange | 29 | - edit commands: (a)ppend, (i)nsert, (c)hange |
30 | - file commands: (r)ead | ||
30 | - backreferences in substitution expressions (\1, \2...\9) | 31 | - backreferences in substitution expressions (\1, \2...\9) |
31 | 32 | ||
32 | (Note: Specifying an address (range) to match is *optional*; commands | 33 | (Note: Specifying an address (range) to match is *optional*; commands |
@@ -90,6 +91,11 @@ struct sed_cmd { | |||
90 | /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ | 91 | /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ |
91 | 92 | ||
92 | char *editline; | 93 | char *editline; |
94 | |||
95 | |||
96 | /* FILE COMMAND (r) SPEICIFIC FIELDS */ | ||
97 | |||
98 | char *filename; | ||
93 | }; | 99 | }; |
94 | 100 | ||
95 | /* globals */ | 101 | /* globals */ |
@@ -351,6 +357,45 @@ out: | |||
351 | return idx; | 357 | return idx; |
352 | } | 358 | } |
353 | 359 | ||
360 | |||
361 | static int parse_file_cmd(struct sed_cmd *sed_cmd, const char *filecmdstr) | ||
362 | { | ||
363 | int idx = 0; | ||
364 | int filenamelen = 0; | ||
365 | |||
366 | /* | ||
367 | * the string that gets passed to this function should look like this: | ||
368 | * '[ ]filename' | ||
369 | * | | | ||
370 | * | a filename | ||
371 | * | | ||
372 | * optional whitespace | ||
373 | |||
374 | * re: the file to be read, the GNU manual says the following: "Note that | ||
375 | * if filename cannot be read, it is treated as if it were an empty file, | ||
376 | * without any error indication." Thus, all of the following commands are | ||
377 | * perfectly leagal: | ||
378 | * | ||
379 | * sed -e '1r noexist' | ||
380 | * sed -e '1r ;' | ||
381 | * sed -e '1r' | ||
382 | */ | ||
383 | |||
384 | /* the file command may be followed by whitespace; move past it. */ | ||
385 | while (isspace(filecmdstr[++idx])) | ||
386 | { ; } | ||
387 | |||
388 | /* the first non-whitespace we get is a filename. the filename ends when we | ||
389 | * hit a normal sed command terminator or end of string */ | ||
390 | filenamelen = strcspn(&filecmdstr[idx], "; \n\r\t\v\0"); | ||
391 | sed_cmd->filename = xmalloc(sizeof(char) * filenamelen + 1); | ||
392 | strncpy(sed_cmd->filename, &filecmdstr[idx], filenamelen); | ||
393 | sed_cmd->filename[filenamelen] = 0; | ||
394 | |||
395 | return idx + filenamelen; | ||
396 | } | ||
397 | |||
398 | |||
354 | static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | 399 | static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) |
355 | { | 400 | { |
356 | int idx = 0; | 401 | int idx = 0; |
@@ -361,7 +406,6 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
361 | * part1 part2 part3 | 406 | * part1 part2 part3 |
362 | */ | 407 | */ |
363 | 408 | ||
364 | |||
365 | /* first part (if present) is an address: either a number or a /regex/ */ | 409 | /* first part (if present) is an address: either a number or a /regex/ */ |
366 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') | 410 | if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') |
367 | idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); | 411 | idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); |
@@ -373,24 +417,32 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) | |||
373 | /* last part (mandatory) will be a command */ | 417 | /* last part (mandatory) will be a command */ |
374 | if (cmdstr[idx] == '\0') | 418 | if (cmdstr[idx] == '\0') |
375 | error_msg_and_die("missing command"); | 419 | error_msg_and_die("missing command"); |
376 | if (!strchr("pdsaic", cmdstr[idx])) /* <-- XXX add new commands here */ | ||
377 | error_msg_and_die("invalid command"); | ||
378 | sed_cmd->cmd = cmdstr[idx]; | 420 | sed_cmd->cmd = cmdstr[idx]; |
379 | 421 | ||
380 | /* special-case handling for (s)ubstitution */ | 422 | /* if it was a single-letter command that takes no arguments (such as 'p' |
381 | if (sed_cmd->cmd == 's') { | 423 | * or 'd') all we need to do is increment the index past that command */ |
424 | if (strchr("pd", cmdstr[idx])) { | ||
425 | idx++; | ||
426 | } | ||
427 | /* handle (s)ubstitution */ | ||
428 | else if (sed_cmd->cmd == 's') { | ||
382 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); | 429 | idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); |
383 | } | 430 | } |
384 | /* special-case handling for (a)ppend, (i)nsert, and (c)hange */ | 431 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ |
385 | else if (strchr("aic", cmdstr[idx])) { | 432 | else if (strchr("aic", cmdstr[idx])) { |
386 | if (sed_cmd->end_line || sed_cmd->end_match) | 433 | if (sed_cmd->end_line || sed_cmd->end_match) |
387 | error_msg_and_die("only a beginning address can be specified for edit commands"); | 434 | error_msg_and_die("only a beginning address can be specified for edit commands"); |
388 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); | 435 | idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); |
389 | } | 436 | } |
390 | /* if it was a single-letter command (such as 'p' or 'd') we need to | 437 | /* handle file cmds: (r)ead */ |
391 | * increment the index past that command */ | 438 | else if (sed_cmd->cmd == 'r') { |
392 | else | 439 | if (sed_cmd->end_line || sed_cmd->end_match) |
393 | idx++; | 440 | error_msg_and_die("Command only uses one address"); |
441 | idx += parse_file_cmd(sed_cmd, &cmdstr[idx]); | ||
442 | } | ||
443 | else { | ||
444 | error_msg_and_die("invalid command"); | ||
445 | } | ||
394 | 446 | ||
395 | /* give back whatever's left over */ | 447 | /* give back whatever's left over */ |
396 | return (char *)&cmdstr[idx]; | 448 | return (char *)&cmdstr[idx]; |
@@ -598,6 +650,17 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line) | |||
598 | fputs(sed_cmd->editline, stdout); | 650 | fputs(sed_cmd->editline, stdout); |
599 | altered++; | 651 | altered++; |
600 | break; | 652 | break; |
653 | |||
654 | case 'r': { | ||
655 | FILE *file; | ||
656 | fputs(line, stdout); | ||
657 | file = fopen(sed_cmd->filename, "r"); | ||
658 | if (file) | ||
659 | print_file(file); | ||
660 | /* else if we couldn't open the file, no biggie, just don't print anything */ | ||
661 | altered++; | ||
662 | } | ||
663 | break; | ||
601 | } | 664 | } |
602 | 665 | ||
603 | return altered; | 666 | return altered; |