diff options
Diffstat (limited to 'sed.c')
-rw-r--r-- | sed.c | 338 |
1 files changed, 254 insertions, 84 deletions
@@ -5,6 +5,11 @@ * Copyright (C) 1999 by Lineo, inc. * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> * + * Modifications for addresses and append command have been + * written by Marco Pantaleoni <panta@prosa.it>, <panta@elasticworld.org> + * 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,48 +36,144 @@ #include <time.h> #include <ctype.h> -static const char sed_usage[] = -"sed [-n] [-e script] [file...]\n\n" -"Allowed sed scripts come in the following form:\n" -"\t's/regexp/replacement/[gp]'\n" -"which attempt to match regexp against the pattern space\n" -"and 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/[gp]\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 expresions.\n"; + "This version of sed matches full regular expresions.\n"; #else -"This version of sed matches strings (not full regular expresions).\n"; + "This version of sed matches strings (not full regular expresions).\n"; #endif - -static void do_sed(FILE *fp, char *needle, char *newNeedle, int ignoreCase, int printFlag, int quietFlag) +/* 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 foundOne=FALSE; - char haystack[1024]; + int res = 0; - while (fgets (haystack, 1023, fp)) { - foundOne = replace_match(haystack, needle, newNeedle, ignoreCase); - if (foundOne==TRUE && printFlag==TRUE) { - fprintf(stdout, haystack); + 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) { + + 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 printFlag=FALSE; - int quietFlag=FALSE; + 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++; @@ -83,68 +184,119 @@ 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': quietFlag = TRUE; break; case 'e': - if (*(cp+1)==0 && --argc < 0) { - usage( sed_usage); + if (*(cp + 1) == 0 && --argc < 0) { + usage(sed_usage); } - if ( *++cp != 's') + if (*++cp != 's') cp = *argv++; - while( *cp ) { - if (*cp == 's' && strlen(cp) > 3 && *(cp+1) == '/') { - char* pos=needle=cp+2; - for(;;) { - pos = strchr(pos, '/'); - if (pos==NULL) { - usage( sed_usage); - } - if (*(pos-1) == '\\') { - pos++; - continue; - } - break; + + /* 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) { - usage( sed_usage); - } - if (*(pos-1) == '\\') { - pos++; - continue; - } - break; + } 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; } - *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; + 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++; + 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: @@ -153,30 +305,48 @@ extern int sed_main (int argc, char **argv) } } - if (argc==0) { - do_sed( stdin, needle, newNeedle, ignoreCase, printFlag, quietFlag); + 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"); + fp = fopen(name, "r"); if (fp == NULL) { - perror (name); + perror(name); continue; } - do_sed( fp, needle, newNeedle, ignoreCase, printFlag, quietFlag); + 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); + if (ferror(fp)) + perror(name); - fclose (fp); + fclose(fp); } } - exit( TRUE); + exit(TRUE); } /* END CODE */ - - |