diff options
| author | markw <markw@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-05-11 22:27:13 +0000 |
|---|---|---|
| committer | markw <markw@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-05-11 22:27:13 +0000 |
| commit | d75f0a74996ecf99d2db96b02fc3ddb2f81b4028 (patch) | |
| tree | a223a8f7031345c8eb68bd25f5dc204ad523d7fd | |
| parent | ddc90ed562c79cc86afe05c200ec2721c15c5f63 (diff) | |
| download | busybox-w32-d75f0a74996ecf99d2db96b02fc3ddb2f81b4028.tar.gz busybox-w32-d75f0a74996ecf99d2db96b02fc3ddb2f81b4028.tar.bz2 busybox-w32-d75f0a74996ecf99d2db96b02fc3ddb2f81b4028.zip | |
Added support for 'r' command in sed.
git-svn-id: svn://busybox.net/trunk/busybox@2621 69ca8d6d-28ef-0310-b511-8ec308f3f277
| -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; |
