static void free_and_close_stuff(void) { sed_cmd_t *sed_cmd = sed_cmd_head.next; while(append_head) { append_tail=append_head->next; free(append_head->string); free(append_head); append_head=append_tail; } while (sed_cmd) { sed_cmd_t *sed_cmd_next = sed_cmd->next; if(sed_cmd->file) bb_xprint_and_close_file(sed_cmd->file); if (sed_cmd->beg_match) { regfree(sed_cmd->beg_match); free(sed_cmd->beg_match); } if (sed_cmd->end_match) { regfree(sed_cmd->end_match); free(sed_cmd->end_match); } if (sed_cmd->sub_match) { regfree(sed_cmd->sub_match); free(sed_cmd->sub_match); } free(sed_cmd->string); free(sed_cmd); sed_cmd = sed_cmd_next; } }
extern int bb_xprint_file_by_name(const char *filename) { FILE *f; #if 0 /* This check shouldn't be necessary for linux, but is left * here disabled just in case. */ struct stat statBuf; if(is_directory(filename, TRUE, &statBuf)) { bb_error_msg("%s: Is directory", filename); } else #endif if ((f = bb_wfopen(filename, "r")) != NULL) { bb_xprint_and_close_file(f); return 0; } return -1; }
static void process_file(FILE * file) { char *pattern_space, *next_line, *hold_space=NULL; static int linenum = 0, missing_newline=0; int no_newline,next_no_newline=0; next_line = get_next_line(file,&next_no_newline); /* go through every line in the file */ for(;;) { sed_cmd_t *sed_cmd; int substituted=0; /* Advance to next line. Stop if out of lines. */ if(!(pattern_space=next_line)) break; no_newline=next_no_newline; /* Read one line in advance so we can act on the last line, the '$' address */ next_line = get_next_line(file,&next_no_newline); linenum++; restart: /* for every line, go through all the commands */ for (sed_cmd = sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { int old_matched, matched; old_matched = sed_cmd->in_match; /* Determine if this command matches this line: */ /* Are we continuing a previous multi-line match? */ sed_cmd->in_match = sed_cmd->in_match /* Or is no range necessary? */ || (!sed_cmd->beg_line && !sed_cmd->end_line && !sed_cmd->beg_match && !sed_cmd->end_match) /* Or did we match the start of a numerical range? */ || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum)) /* Or does this line match our begin address regex? */ || (sed_cmd->beg_match && !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0)) /* Or did we match last line of input? */ || (sed_cmd->beg_line == -1 && next_line == NULL); /* Snapshot the value */ matched = sed_cmd->in_match; /* Is this line the end of the current match? */ if(matched) { sed_cmd->in_match = !( /* has the ending line come, or is this a single address command? */ (sed_cmd->end_line ? sed_cmd->end_line==-1 ? !next_line : sed_cmd->end_line<=linenum : !sed_cmd->end_match) /* or does this line matches our last address regex */ || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, pattern_space, 0, NULL, 0) == 0)) ); } /* Skip blocks of commands we didn't match. */ if (sed_cmd->cmd == '{') { if(sed_cmd->invert ? matched : !matched) while(sed_cmd && sed_cmd->cmd!='}') sed_cmd=sed_cmd->next; if(!sed_cmd) bb_error_msg_and_die("Unterminated {"); continue; } /* Okay, so did this line match? */ if (sed_cmd->invert ? !matched : matched) { /* Update last used regex in case a blank substitute BRE is found */ if (sed_cmd->beg_match) { previous_regex_ptr = sed_cmd->beg_match; } /* actual sedding */ switch (sed_cmd->cmd) { /* Print line number */ case '=': printf("%d\n", linenum); break; /* Write the current pattern space up to the first newline */ case 'P': { char *tmp = strchr(pattern_space, '\n'); if (tmp) { *tmp = '\0'; sed_puts(pattern_space,1); *tmp = '\n'; break; } /* Fall Through */ } /* Write the current pattern space to output */ case 'p': sed_puts(pattern_space,no_newline); break; /* Delete up through first newline */ case 'D': { char *tmp = strchr(pattern_space,'\n'); if(tmp) { tmp=bb_xstrdup(tmp+1); free(pattern_space); pattern_space=tmp; goto restart; } } /* discard this line. */ case 'd': goto discard_line; /* Substitute with regex */ case 's': if(do_subst_command(sed_cmd, &pattern_space)) { substituted|=1; /* handle p option */ if(sed_cmd->sub_p) sed_puts(pattern_space,no_newline); /* handle w option */ if(sed_cmd->file) sed_cmd->no_newline=puts_maybe_newline(pattern_space, sed_cmd->file, sed_cmd->no_newline, no_newline); } break; /* Append line to linked list to be printed later */ case 'a': { append(sed_cmd->string); break; } /* Insert text before this line */ case 'i': sed_puts(sed_cmd->string,1); break; /* Cut and paste text (replace) */ case 'c': /* Only triggers on last line of a matching range. */ if (!sed_cmd->in_match) sed_puts(sed_cmd->string,1); goto discard_line; /* Read file, append contents to output */ case 'r': { FILE *outfile; outfile = fopen(sed_cmd->string, "r"); if (outfile) { char *line; while ((line = bb_get_chomped_line_from_file(outfile)) != NULL) append(line); bb_xprint_and_close_file(outfile); } break; } /* Write pattern space to file. */ case 'w': sed_cmd->no_newline=puts_maybe_newline(pattern_space,sed_cmd->file, sed_cmd->no_newline,no_newline); break; /* Read next line from input */ case 'n': if (!be_quiet) sed_puts(pattern_space,no_newline); if (next_line) { free(pattern_space); pattern_space = next_line; no_newline=next_no_newline; next_line = get_next_line(file,&next_no_newline); linenum++; break; } /* fall through */ /* Quit. End of script, end of input. */ case 'q': /* Exit the outer while loop */ free(next_line); next_line = NULL; goto discard_commands; /* Append the next line to the current line */ case 'N': { /* If no next line, jump to end of script and exit. */ if (next_line == NULL) { /* Jump to end of script and exit */ free(next_line); next_line = NULL; goto discard_line; /* append next_line, read new next_line. */ } else { int len=strlen(pattern_space); pattern_space = realloc(pattern_space, len + strlen(next_line) + 2); pattern_space[len]='\n'; strcpy(pattern_space+len+1, next_line); no_newline=next_no_newline; next_line = get_next_line(file,&next_no_newline); linenum++; } break; } /* Test if substition worked, branch if so. */ case 't': if (!substituted) break; substituted=0; /* Fall through */ /* Branch to label */ case 'b': if (!sed_cmd->string) goto discard_commands; else sed_cmd = branch_to(sed_cmd->string); break; /* Transliterate characters */ case 'y': { int i; for (i = 0; pattern_space[i]; i++) { int j; for (j = 0; sed_cmd->string[j]; j += 2) { if (pattern_space[i] == sed_cmd->string[j]) { pattern_space[i] = sed_cmd->string[j + 1]; } } } break; } case 'g': /* Replace pattern space with hold space */ free(pattern_space); if (hold_space) { pattern_space = strdup(hold_space); no_newline=0; } break; case 'G': /* Append newline and hold space to pattern space */ { int pattern_space_size = 2; int hold_space_size = 0; if (pattern_space) pattern_space_size += strlen(pattern_space); if (hold_space) hold_space_size = strlen(hold_space); pattern_space = xrealloc(pattern_space, pattern_space_size + hold_space_size); if (pattern_space_size == 2) pattern_space[0]=0; strcat(pattern_space, "\n"); if (hold_space) strcat(pattern_space, hold_space); no_newline=0; break; } case 'h': /* Replace hold space with pattern space */ free(hold_space); hold_space = strdup(pattern_space); break; case 'H': /* Append newline and pattern space to hold space */ { int hold_space_size = 2; int pattern_space_size = 0; if (hold_space) hold_space_size += strlen(hold_space); if (pattern_space) pattern_space_size = strlen(pattern_space); hold_space = xrealloc(hold_space, hold_space_size + pattern_space_size); if (hold_space_size == 2) hold_space[0]=0; strcat(hold_space, "\n"); if (pattern_space) strcat(hold_space, pattern_space); break; } case 'x': /* Exchange hold and pattern space */ { char *tmp = pattern_space; pattern_space = hold_space; no_newline=0; hold_space = tmp; break; } } } } /* * exit point from sedding... */ discard_commands: /* we will print the line unless we were told to be quiet ('-n') or if the line was suppressed (ala 'd'elete) */ if (!be_quiet) sed_puts(pattern_space,no_newline); /* Delete and such jump here. */ discard_line: flush_append(); free(pattern_space); } }
extern int sed_main(int argc, char **argv) { int opt, status = EXIT_SUCCESS; #ifdef CONFIG_FEATURE_CLEAN_UP /* destroy command strings on exit */ if (atexit(free_and_close_stuff) == -1) bb_perror_msg_and_die("atexit"); #endif #define LIE_TO_AUTOCONF #ifdef LIE_TO_AUTOCONF if(argc==2 && !strcmp(argv[1],"--version")) { printf("This is not GNU sed version 4.0\n"); exit(0); } #endif /* do normal option parsing */ while ((opt = getopt(argc, argv, "ne:f:")) > 0) { switch (opt) { case 'n': be_quiet++; break; case 'e': add_cmd_block(optarg); break; case 'f': { FILE *cmdfile; char *line; cmdfile = bb_xfopen(optarg, "r"); while ((line = bb_get_chomped_line_from_file(cmdfile)) != NULL) { add_cmd(line); free(line); } bb_xprint_and_close_file(cmdfile); break; } default: bb_show_usage(); } } /* if we didn't get a pattern from a -e and no command file was specified, * argv[optind] should be the pattern. no pattern, no worky */ if (sed_cmd_head.next == NULL) { if (argv[optind] == NULL) bb_show_usage(); else add_cmd_block(argv[optind++]); } /* Flush any unfinished commands. */ add_cmd(""); /* argv[(optind)..(argc-1)] should be names of file to process. If no * files were specified or '-' was specified, take input from stdin. * Otherwise, we process all the files specified. */ if (argv[optind] == NULL) { process_file(stdin); } else { int i; FILE *file; for (i = optind; i < argc; i++) { if(!strcmp(argv[i], "-")) { process_file(stdin); } else { file = bb_wfopen(argv[i], "r"); if (file) { process_file(file); fclose(file); } else { status = EXIT_FAILURE; } } } } return status; }