/* vi: set sw=4 ts=4: */ /* * Mini sed implementation for busybox * * * Copyright (C) 1999,2000 by Lineo, inc. * Written by Erik Andersen , * * Modifications for addresses and append command have been * written by Marco Pantaleoni , * and are: * Copyright (C) 1999 Marco Pantaleoni. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "internal.h" #include "regexp.h" #include #include #include #include #include #include #include static const char sed_usage[] = "sed [-n] -e script [file...]\n" #ifndef BB_FEATURE_TRIVIAL_HELP "\nAllowed sed scripts come in the following form:\n" "\t'ADDR [!] COMMAND'\n\n" "\twhere address ADDR can be:\n" "\t NUMBER Match specified line number\n" "\t $ Match last line\n" "\t /REGEXP/ Match specified regexp\n" "\t (! inverts the meaning of the match)\n\n" "\tand COMMAND can be:\n" "\t s/regexp/replacement/[igp]\n" "\t which attempt to match regexp against the pattern space\n" "\t and if successful replaces the matched portion with replacement.\n\n" "\t aTEXT\n" "\t which appends TEXT after the pattern space\n" "Options:\n" "-e\tadd the script to the commands to be executed\n" "-n\tsuppress automatic printing of pattern space\n\n" #if defined BB_REGEXP "This version of sed matches full regular expressions.\n"; #else "This version of sed matches strings (not full regular expressions).\n" #endif #endif ; /* Flags & variables */ typedef enum { f_none, f_replace, f_append } sed_function; #define NO_LINE -2 #define LAST_LINE -1 static int addr_line = NO_LINE; static char *addr_pattern = NULL; static int negated = 0; #define SKIPSPACES(p) do { while (isspace(*(p))) (p)++; } while (0) #define BUFSIZE 1024 static inline int at_last(FILE * fp) { int res = 0; if (feof(fp)) return 1; else { int ch; if ((ch = fgetc(fp)) == EOF) res++; ungetc(ch, fp); } return res; } static void do_sed_repl(FILE * fp, char *needle, char *newNeedle, int ignoreCase, int printFlag, int quietFlag) { int foundOne = FALSE; char haystack[BUFSIZE]; int line = 1, doit; while (fgets(haystack, BUFSIZE - 1, fp)) { doit = 0; if (addr_pattern) { doit = !find_match(haystack, addr_pattern, FALSE); } else if (addr_line == NO_LINE) doit = 1; else if (addr_line == LAST_LINE) { if (at_last(fp)) doit = 1; } else { if (line == addr_line) doit = 1; } if (negated) doit = 1 - doit; if (doit) { foundOne = replace_match(haystack, needle, newNeedle, ignoreCase); if (foundOne == TRUE && printFlag == TRUE) { fprintf(stdout, haystack); } } if (quietFlag == FALSE) { fprintf(stdout, haystack); } line++; } } static void do_sed_append(FILE * fp, char *appendline, int quietFlag) { char buffer[BUFSIZE]; int line = 1, doit; while (fgets(buffer, BUFSIZE - 1, fp)) { doit = 0; if (addr_pattern) { doit = !find_match(buffer, addr_pattern, FALSE); } else if (addr_line == NO_LINE) doit = 1; else if (addr_line == LAST_LINE) { if (at_last(fp)) doit = 1; } else { if (line == addr_line) doit = 1; } if (negated) doit = 1 - doit; if (quietFlag == FALSE) { fprintf(stdout, buffer); } if (doit) { fputs(appendline, stdout); fputc('\n', stdout); } line++; } } extern int sed_main(int argc, char **argv) { FILE *fp; char *needle = NULL, *newNeedle = NULL; char *name; char *cp; int ignoreCase = FALSE; int printFlag = FALSE; int quietFlag = FALSE; int stopNow; char *line_s = NULL, saved; char *appendline = NULL; char *pos; sed_function sed_f = f_none; argc--; argv++; if (argc < 1) { usage(sed_usage); } while (argc > 1) { if (**argv != '-') usage(sed_usage); argc--; cp = *argv++; stopNow = FALSE; while (*++cp && stopNow == FALSE) { switch (*cp) { case 'n': quietFlag = TRUE; break; case 'e': if (*(cp + 1) == 0 && --argc < 0) { usage(sed_usage); } if (*++cp != 's') cp = *argv++; /* Read address if present */ SKIPSPACES(cp); if (*cp == '$') { addr_line = LAST_LINE; cp++; } else { if (isdigit(*cp)) { /* LINE ADDRESS */ line_s = cp; while (isdigit(*cp)) cp++; if (cp > line_s) { /* numeric line */ saved = *cp; *cp = '\0'; addr_line = atoi(line_s); *cp = saved; } } else if (*cp == '/') { /* PATTERN ADDRESS */ pos = addr_pattern = cp + 1; pos = strchr(pos, '/'); if (!pos) usage(sed_usage); *pos = '\0'; cp = pos + 1; } } SKIPSPACES(cp); if (*cp == '!') { negated++; cp++; } /* Read command */ SKIPSPACES(cp); switch (*cp) { case 's': /* REPLACE */ if (strlen(cp) <= 3 || *(cp + 1) != '/') break; sed_f = f_replace; pos = needle = cp + 2; for (;;) { pos = strchr(pos, '/'); if (pos == NULL) { usage(sed_usage); } if (*(pos - 1) == '\\') { pos++; continue; } break; } *pos = 0; newNeedle = ++pos; for (;;) { pos = strchr(pos, '/'); if (pos == NULL) { usage(sed_usage); } if (*(pos - 1) == '\\') { pos++; continue; } break; } *pos = 0; if (pos + 2 != 0) { while (*++pos) { switch (*pos) { case 'i': ignoreCase = TRUE; break; case 'p': printFlag = TRUE; break; case 'g': break; default: usage(sed_usage); } } } cp = pos; /* fprintf(stderr, "replace '%s' with '%s'\n", needle, newNeedle); */ break; case 'a': /* APPEND */ if (strlen(cp) < 2) break; sed_f = f_append; appendline = ++cp; /* fprintf(stderr, "append '%s'\n", appendline); */ break; } stopNow = TRUE; break; default: usage(sed_usage); } } } if (argc == 0) { switch (sed_f) { case f_none: break; case f_replace: do_sed_repl(stdin, needle, newNeedle, ignoreCase, printFlag, quietFlag); break; case f_append: do_sed_append(stdin, appendline, quietFlag); break; } } else { while (argc-- > 0) { name = *argv++; fp = fopen(name, "r"); if (fp == NULL) { perror(name); continue; } switch (sed_f) { case f_none: break; case f_replace: do_sed_repl(fp, needle, newNeedle, ignoreCase, printFlag, quietFlag); break; case f_append: do_sed_append(fp, appendline, quietFlag); break; } if (ferror(fp)) perror(name); fclose(fp); } } return(TRUE); } /* END CODE */