X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=sed.c;h=25777243d9994f7a25fde185e7867e5385649d73;hb=ce5b466bcce4edbd8a57ed3fa91911936bd11927;hp=0df53a7f84aee8babf074284c1c3d0c68d91057c;hpb=24d8e7d787aa1940030a1beaabdd4388588ca512;p=oweals%2Fbusybox.git diff --git a/sed.c b/sed.c index 0df53a7f8..25777243d 100644 --- a/sed.c +++ b/sed.c @@ -5,6 +5,11 @@ * Copyright (C) 1999 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 @@ -31,35 +36,144 @@ #include #include -static const char sed_usage[] = -"sed [-n] [-e script] [file...]\n" -"Allowed scripts come in the following form:\n\n" -"'s/regexp/replacement/[gp]'\n" -"\tattempt to match regexp against the pattern space\n" -"\tand if successful replaces the matched portion with replacement.\n\n" -"Options:\n" -"-e\tadd the script to the commands to be executed\n" -"-n\tsuppress automatic printing of pattern space\n\n" +static const char sed_usage[] = + "sed [-n] -e script [file...]\n\n" + "Allowed 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 regexps.\n"; + "This version of sed matches full regular expresions.\n"; #else -"This version of sed matches strings (not full regexps).\n"; + "This version of sed matches strings (not full regular expresions).\n"; #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 { + char 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) +extern int sed_main(int argc, char **argv) { FILE *fp; - char *needle=NULL, *newNeedle=NULL; + char *needle = NULL, *newNeedle = NULL; char *name; char *cp; - int ignoreCase=FALSE; - int foundOne=FALSE; - int noprintFlag=FALSE; + int ignoreCase = FALSE; + int printFlag = FALSE; + int quietFlag = FALSE; int stopNow; - char *haystack; + char *line_s = NULL, saved; + char *appendline = NULL; + char *pos; + sed_function sed_f = f_none; argc--; argv++; @@ -70,93 +184,169 @@ extern int sed_main (int argc, char **argv) if (**argv == '-') { argc--; cp = *argv++; - stopNow=FALSE; + stopNow = FALSE; - while (*++cp && stopNow==FALSE) + while (*++cp && stopNow == FALSE) { switch (*cp) { case 'n': - noprintFlag = TRUE; + quietFlag = TRUE; break; case 'e': - if (*(cp+1)==0 && --argc < 0) { - fprintf(stderr, "A\n"); - usage( sed_usage); + if (*(cp + 1) == 0 && --argc < 0) { + usage(sed_usage); } - cp = *argv++; - while( *cp ) { - if (*cp == 's' && strlen(cp) > 3 && *(cp+1) == '/') { - char* pos=needle=cp+2; - for(;;) { - pos = strchr(pos, '/'); - if (pos==NULL) { - fprintf(stderr, "B\n"); - usage( sed_usage); - } - if (*(pos-1) == '\\') { - pos++; - continue; - } - break; + 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; } - *pos=0; - newNeedle=++pos; - for(;;) { - pos = strchr(pos, '/'); - if (pos==NULL) { - fprintf(stderr, "C\n"); - usage( sed_usage); - } - if (*(pos-1) == '\\') { - pos++; - continue; + } 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); } - break; } - *pos=0; } - cp++; + 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; } - fprintf(stderr, "replace '%s' with '%s'\n", needle, newNeedle); - stopNow=TRUE; + + stopNow = TRUE; break; default: - fprintf(stderr, "D\n"); usage(sed_usage); } + } } - while (argc-- > 0) { - name = *argv++; - - fp = fopen (name, "r"); - if (fp == NULL) { - perror (name); - continue; + 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++; - haystack = (char*)malloc( BUF_SIZE); - while (fgets (haystack, BUF_SIZE-1, fp)) { - - foundOne = replace_match(haystack, needle, newNeedle, ignoreCase); - if (noprintFlag==TRUE && foundOne==TRUE) - fputs (haystack, stdout); - else - fputs (haystack, stdout); - /* Avoid any mem leaks */ - free(haystack); - haystack = (char*)malloc( BUF_SIZE); - } + fp = fopen(name, "r"); + if (fp == NULL) { + perror(name); + continue; + } - if (ferror (fp)) - perror (name); + 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; + } - fclose (fp); + if (ferror(fp)) + perror(name); + + fclose(fp); + } } - exit( TRUE); + exit(TRUE); } /* END CODE */ - -