aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Whitley <markw@lineo.com>2000-07-14 00:00:15 +0000
committerMark Whitley <markw@lineo.com>2000-07-14 00:00:15 +0000
commit94074a980c3f72e3765fcb43f1056b509ec800b5 (patch)
tree122b1a641314cb1cb56846d67245a1010f4ed967
parent496e33feeb2d0eb4aa2bf3cc2f34f6e29987c1bd (diff)
downloadbusybox-w32-94074a980c3f72e3765fcb43f1056b509ec800b5.tar.gz
busybox-w32-94074a980c3f72e3765fcb43f1056b509ec800b5.tar.bz2
busybox-w32-94074a980c3f72e3765fcb43f1056b509ec800b5.zip
Added support for (a)ppend, (i)nsert, and (c)hange commands to sed.
-rw-r--r--editors/sed.c95
-rw-r--r--sed.c95
2 files changed, 176 insertions, 14 deletions
diff --git a/editors/sed.c b/editors/sed.c
index bf8ca1b29..1eea128d5 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -24,8 +24,9 @@
24 Supported features and commands in this version of sed: 24 Supported features and commands in this version of sed:
25 25
26 - comments ('#') 26 - comments ('#')
27 - Address matching: num|/matchstr/[,num|/matchstr/|$]command 27 - address matching: num|/matchstr/[,num|/matchstr/|$]command
28 - Commands: p, d, s/match/replace/[g] 28 - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
29 - edit commands: (a)ppend, (i)nsert, (c)hange
29 30
30 (Note: Specifying an address (range) to match is *optional*; commands 31 (Note: Specifying an address (range) to match is *optional*; commands
31 default to the whole pattern space if no specific address match was 32 default to the whole pattern space if no specific address match was
@@ -73,6 +74,9 @@ struct sed_cmd {
73 regex_t *sub_match; /* sed -e 's/sub_match/replace/' */ 74 regex_t *sub_match; /* sed -e 's/sub_match/replace/' */
74 char *replace; /* sed -e 's/sub_match/replace/' XXX: who will hold the \1 \2 \3s? */ 75 char *replace; /* sed -e 's/sub_match/replace/' XXX: who will hold the \1 \2 \3s? */
75 unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */ 76 unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */
77
78 /* edit command (a,i,c) speicific field */
79 char *editline;
76}; 80};
77 81
78/* globals */ 82/* globals */
@@ -274,6 +278,59 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
274 free(match); 278 free(match);
275} 279}
276 280
281static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
282{
283 int idx = 0;
284 char *ptr; /* shorthand */
285
286 /*
287 * the string that gets passed to this function should look like this:
288 *
289 * need one of these
290 * |
291 * | this backslash (immediately following the edit command) is mandatory
292 * | |
293 * [aic]\
294 * TEXT1\
295 * TEXT2\
296 * TEXTN
297 *
298 * as soon as we hit a TEXT line that has no trailing '\', we're done.
299 * this means a command like:
300 *
301 * i\
302 * INSERTME
303 *
304 * is a-ok.
305 *
306 */
307
308 if (editstr[1] != '\\' && (editstr[2] != '\n' || editstr[2] != '\r'))
309 fatalError("bad format in edit expression\n");
310
311 /* store the edit line text */
312 sed_cmd->editline = strdup(&editstr[3]);
313 ptr = sed_cmd->editline;
314
315 /* now we need to go through * and: s/\\[\r\n]$/\n/g on the edit line */
316 while (ptr[idx]) {
317 while (ptr[idx] != '\\' && (ptr[idx+1] != '\n' || ptr[idx+1] != '\r')) {
318 idx++;
319 if (!ptr[idx]) {
320 ptr[idx] = '\n';
321 ptr[idx+1] = 0;
322 return;
323 }
324 }
325 /* move the newline over the '\' before it (effectively eats the '\') */
326 memmove(&ptr[idx], &ptr[idx+1], strlen(&ptr[idx+1]));
327 ptr[strlen(ptr)-1] = 0;
328 /* substitue \r for \n if needed */
329 if (ptr[idx] == '\r')
330 ptr[idx] = '\n';
331 }
332}
333
277static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) 334static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
278{ 335{
279 int idx = 0; 336 int idx = 0;
@@ -295,13 +352,17 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
295 /* last part (mandatory) will be a command */ 352 /* last part (mandatory) will be a command */
296 if (cmdstr[idx] == '\0') 353 if (cmdstr[idx] == '\0')
297 fatalError("missing command\n"); 354 fatalError("missing command\n");
298 if (!strchr("pds", cmdstr[idx])) /* <-- XXX add new commands here */ 355 if (!strchr("pdsaic", cmdstr[idx])) /* <-- XXX add new commands here */
299 fatalError("invalid command\n"); 356 fatalError("invalid command\n");
300 sed_cmd->cmd = cmdstr[idx]; 357 sed_cmd->cmd = cmdstr[idx];
301 358
302 /* special-case handling for (s)ubstitution */ 359 /* special-case handling for (s)ubstitution */
303 if (sed_cmd->cmd == 's') 360 if (sed_cmd->cmd == 's')
304 parse_subst_cmd(sed_cmd, &cmdstr[idx]); 361 parse_subst_cmd(sed_cmd, &cmdstr[idx]);
362
363 /* special-case handling for (a)ppend, (i)nsert, and (c)hange */
364 if (strchr("aic", cmdstr[idx]))
365 parse_edit_cmd(sed_cmd, &cmdstr[idx]);
305} 366}
306 367
307static void add_cmd_str(const char *cmdstr) 368static void add_cmd_str(const char *cmdstr)
@@ -327,13 +388,19 @@ static void load_cmd_file(char *filename)
327{ 388{
328 FILE *cmdfile; 389 FILE *cmdfile;
329 char *line; 390 char *line;
391 char *nextline;
330 392
331 cmdfile = fopen(filename, "r"); 393 cmdfile = fopen(filename, "r");
332 if (cmdfile == NULL) 394 if (cmdfile == NULL)
333 fatalError(strerror(errno)); 395 fatalError(strerror(errno));
334 396
335 while ((line = get_line_from_file(cmdfile)) != NULL) { 397 while ((line = get_line_from_file(cmdfile)) != NULL) {
336 line[strlen(line)-1] = 0; /* eat newline */ 398 /* if a line ends with '\' it needs the next line appended to it */
399 while (line[strlen(line)-2] == '\\' &&
400 (nextline = get_line_from_file(cmdfile)) != NULL) {
401 line = realloc(line, strlen(line) + strlen(nextline) + 1);
402 strcat(line, nextline);
403 }
337 add_cmd_str(line); 404 add_cmd_str(line);
338 free(line); 405 free(line);
339 } 406 }
@@ -359,8 +426,7 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line)
359 fputs(sed_cmd->replace, stdout); 426 fputs(sed_cmd->replace, stdout);
360 /* then advance past the match */ 427 /* then advance past the match */
361 ptr += regmatch.rm_eo; 428 ptr += regmatch.rm_eo;
362 /* and let the calling function know that something 429 /* and flag that something has changed */
363 * has been changed */
364 altered++; 430 altered++;
365 431
366 /* if we're not doing this globally... */ 432 /* if we're not doing this globally... */
@@ -398,6 +464,21 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line)
398 case 's': 464 case 's':
399 altered = do_subst_command(sed_cmd, line); 465 altered = do_subst_command(sed_cmd, line);
400 break; 466 break;
467
468 case 'a':
469 fputs(line, stdout);
470 fputs(sed_cmd->editline, stdout);
471 altered++;
472 break;
473
474 case 'i':
475 fputs(sed_cmd->editline, stdout);
476 break;
477
478 case 'c':
479 fputs(sed_cmd->editline, stdout);
480 altered++;
481 break;
401 } 482 }
402 483
403 return altered; 484 return altered;
@@ -483,7 +564,7 @@ extern int sed_main(int argc, char **argv)
483 while ((opt = getopt(argc, argv, "Vhne:f:")) > 0) { 564 while ((opt = getopt(argc, argv, "Vhne:f:")) > 0) {
484 switch (opt) { 565 switch (opt) {
485 case 'V': 566 case 'V':
486 printf("Print Busybox version here\n"); 567 printf("BusyBox v%s (%s)\n", BB_VER, BB_BT);
487 exit(0); 568 exit(0);
488 break; 569 break;
489 case 'h': 570 case 'h':
diff --git a/sed.c b/sed.c
index bf8ca1b29..1eea128d5 100644
--- a/sed.c
+++ b/sed.c
@@ -24,8 +24,9 @@
24 Supported features and commands in this version of sed: 24 Supported features and commands in this version of sed:
25 25
26 - comments ('#') 26 - comments ('#')
27 - Address matching: num|/matchstr/[,num|/matchstr/|$]command 27 - address matching: num|/matchstr/[,num|/matchstr/|$]command
28 - Commands: p, d, s/match/replace/[g] 28 - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
29 - edit commands: (a)ppend, (i)nsert, (c)hange
29 30
30 (Note: Specifying an address (range) to match is *optional*; commands 31 (Note: Specifying an address (range) to match is *optional*; commands
31 default to the whole pattern space if no specific address match was 32 default to the whole pattern space if no specific address match was
@@ -73,6 +74,9 @@ struct sed_cmd {
73 regex_t *sub_match; /* sed -e 's/sub_match/replace/' */ 74 regex_t *sub_match; /* sed -e 's/sub_match/replace/' */
74 char *replace; /* sed -e 's/sub_match/replace/' XXX: who will hold the \1 \2 \3s? */ 75 char *replace; /* sed -e 's/sub_match/replace/' XXX: who will hold the \1 \2 \3s? */
75 unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */ 76 unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */
77
78 /* edit command (a,i,c) speicific field */
79 char *editline;
76}; 80};
77 81
78/* globals */ 82/* globals */
@@ -274,6 +278,59 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
274 free(match); 278 free(match);
275} 279}
276 280
281static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
282{
283 int idx = 0;
284 char *ptr; /* shorthand */
285
286 /*
287 * the string that gets passed to this function should look like this:
288 *
289 * need one of these
290 * |
291 * | this backslash (immediately following the edit command) is mandatory
292 * | |
293 * [aic]\
294 * TEXT1\
295 * TEXT2\
296 * TEXTN
297 *
298 * as soon as we hit a TEXT line that has no trailing '\', we're done.
299 * this means a command like:
300 *
301 * i\
302 * INSERTME
303 *
304 * is a-ok.
305 *
306 */
307
308 if (editstr[1] != '\\' && (editstr[2] != '\n' || editstr[2] != '\r'))
309 fatalError("bad format in edit expression\n");
310
311 /* store the edit line text */
312 sed_cmd->editline = strdup(&editstr[3]);
313 ptr = sed_cmd->editline;
314
315 /* now we need to go through * and: s/\\[\r\n]$/\n/g on the edit line */
316 while (ptr[idx]) {
317 while (ptr[idx] != '\\' && (ptr[idx+1] != '\n' || ptr[idx+1] != '\r')) {
318 idx++;
319 if (!ptr[idx]) {
320 ptr[idx] = '\n';
321 ptr[idx+1] = 0;
322 return;
323 }
324 }
325 /* move the newline over the '\' before it (effectively eats the '\') */
326 memmove(&ptr[idx], &ptr[idx+1], strlen(&ptr[idx+1]));
327 ptr[strlen(ptr)-1] = 0;
328 /* substitue \r for \n if needed */
329 if (ptr[idx] == '\r')
330 ptr[idx] = '\n';
331 }
332}
333
277static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) 334static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
278{ 335{
279 int idx = 0; 336 int idx = 0;
@@ -295,13 +352,17 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
295 /* last part (mandatory) will be a command */ 352 /* last part (mandatory) will be a command */
296 if (cmdstr[idx] == '\0') 353 if (cmdstr[idx] == '\0')
297 fatalError("missing command\n"); 354 fatalError("missing command\n");
298 if (!strchr("pds", cmdstr[idx])) /* <-- XXX add new commands here */ 355 if (!strchr("pdsaic", cmdstr[idx])) /* <-- XXX add new commands here */
299 fatalError("invalid command\n"); 356 fatalError("invalid command\n");
300 sed_cmd->cmd = cmdstr[idx]; 357 sed_cmd->cmd = cmdstr[idx];
301 358
302 /* special-case handling for (s)ubstitution */ 359 /* special-case handling for (s)ubstitution */
303 if (sed_cmd->cmd == 's') 360 if (sed_cmd->cmd == 's')
304 parse_subst_cmd(sed_cmd, &cmdstr[idx]); 361 parse_subst_cmd(sed_cmd, &cmdstr[idx]);
362
363 /* special-case handling for (a)ppend, (i)nsert, and (c)hange */
364 if (strchr("aic", cmdstr[idx]))
365 parse_edit_cmd(sed_cmd, &cmdstr[idx]);
305} 366}
306 367
307static void add_cmd_str(const char *cmdstr) 368static void add_cmd_str(const char *cmdstr)
@@ -327,13 +388,19 @@ static void load_cmd_file(char *filename)
327{ 388{
328 FILE *cmdfile; 389 FILE *cmdfile;
329 char *line; 390 char *line;
391 char *nextline;
330 392
331 cmdfile = fopen(filename, "r"); 393 cmdfile = fopen(filename, "r");
332 if (cmdfile == NULL) 394 if (cmdfile == NULL)
333 fatalError(strerror(errno)); 395 fatalError(strerror(errno));
334 396
335 while ((line = get_line_from_file(cmdfile)) != NULL) { 397 while ((line = get_line_from_file(cmdfile)) != NULL) {
336 line[strlen(line)-1] = 0; /* eat newline */ 398 /* if a line ends with '\' it needs the next line appended to it */
399 while (line[strlen(line)-2] == '\\' &&
400 (nextline = get_line_from_file(cmdfile)) != NULL) {
401 line = realloc(line, strlen(line) + strlen(nextline) + 1);
402 strcat(line, nextline);
403 }
337 add_cmd_str(line); 404 add_cmd_str(line);
338 free(line); 405 free(line);
339 } 406 }
@@ -359,8 +426,7 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line)
359 fputs(sed_cmd->replace, stdout); 426 fputs(sed_cmd->replace, stdout);
360 /* then advance past the match */ 427 /* then advance past the match */
361 ptr += regmatch.rm_eo; 428 ptr += regmatch.rm_eo;
362 /* and let the calling function know that something 429 /* and flag that something has changed */
363 * has been changed */
364 altered++; 430 altered++;
365 431
366 /* if we're not doing this globally... */ 432 /* if we're not doing this globally... */
@@ -398,6 +464,21 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line)
398 case 's': 464 case 's':
399 altered = do_subst_command(sed_cmd, line); 465 altered = do_subst_command(sed_cmd, line);
400 break; 466 break;
467
468 case 'a':
469 fputs(line, stdout);
470 fputs(sed_cmd->editline, stdout);
471 altered++;
472 break;
473
474 case 'i':
475 fputs(sed_cmd->editline, stdout);
476 break;
477
478 case 'c':
479 fputs(sed_cmd->editline, stdout);
480 altered++;
481 break;
401 } 482 }
402 483
403 return altered; 484 return altered;
@@ -483,7 +564,7 @@ extern int sed_main(int argc, char **argv)
483 while ((opt = getopt(argc, argv, "Vhne:f:")) > 0) { 564 while ((opt = getopt(argc, argv, "Vhne:f:")) > 0) {
484 switch (opt) { 565 switch (opt) {
485 case 'V': 566 case 'V':
486 printf("Print Busybox version here\n"); 567 printf("BusyBox v%s (%s)\n", BB_VER, BB_BT);
487 exit(0); 568 exit(0);
488 break; 569 break;
489 case 'h': 570 case 'h':