aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Whitley <markw@lineo.com>2001-05-11 22:27:13 +0000
committerMark Whitley <markw@lineo.com>2001-05-11 22:27:13 +0000
commit1f3b9f297e948b70a82b82919d0ef4d4e1b61d7f (patch)
treea223a8f7031345c8eb68bd25f5dc204ad523d7fd
parentcfa88ecb7268006eb3d25260892b5b7f91d1e62b (diff)
downloadbusybox-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.c83
-rw-r--r--sed.c83
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
361static 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
354static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) 399static 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;
diff --git a/sed.c b/sed.c
index 1342a6643..156ad3ada 100644
--- a/sed.c
+++ b/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
361static 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
354static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) 399static 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;