Fixed segfault with 'cut -f 1 -d:' and added 'cut -s' suport.
[oweals/busybox.git] / sed.c
diff --git a/sed.c b/sed.c
index 25777243d9994f7a25fde185e7867e5385649d73..d4b721e4944fc57226053f886730c60cdc332101 100644 (file)
--- a/sed.c
+++ b/sed.c
@@ -1,8 +1,9 @@
+/* vi: set sw=4 ts=4: */
 /*
  * Mini sed implementation for busybox
  *
  *
- * Copyright (C) 1999 by Lineo, inc.
+ * Copyright (C) 1999,2000 by Lineo, inc.
  * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
  *
  * Modifications for addresses and append command have been
 #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'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"
+       "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 expresions.\n";
+       "This version of sed matches full regular expressions.\n";
 #else
-    "This version of sed matches strings (not full regular expresions).\n";
+       "This version of sed matches strings (not full regular expressions).\n"
 #endif
+#endif
+       ;
 
 /* Flags & variables */
 
@@ -76,276 +80,279 @@ static int negated = 0;
 
 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;
+       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 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);
-           }
-       }
+       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);
-       }
+               if (quietFlag == FALSE) {
+                       fprintf(stdout, haystack);
+               }
 
-       line++;
-    }
+               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);
-       }
+       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++;
-    }
+               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);
-    }
+       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;
 
-    if (**argv == '-') {
        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;
-                   }
-               }
+       argv++;
+       if (argc < 1) {
+               usage(sed_usage);
+       }
 
-               SKIPSPACES(cp);
-               if (*cp == '!') {
-                   negated++;
-                   cp++;
-               }
+       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;
 
-               /* Read command */
+                       default:
+                               usage(sed_usage);
+                       }
+               }
+    }
 
-               SKIPSPACES(cp);
-               switch (*cp) {
-               case 's':       /* REPLACE */
-                   if (strlen(cp) <= 3 || *(cp + 1) != '/')
+       if (argc == 0) {
+               switch (sed_f) {
+               case f_none:
                        break;
-                   sed_f = f_replace;
-
-                   pos = needle = cp + 2;
-
-                   for (;;) {
-                       pos = strchr(pos, '/');
-                       if (pos == NULL) {
-                           usage(sed_usage);
-                       }
-                       if (*(pos - 1) == '\\') {
-                           pos++;
-                           continue;
-                       }
+               case f_replace:
+                       do_sed_repl(stdin, needle, newNeedle, ignoreCase, printFlag,
+                                               quietFlag);
                        break;
-                   }
-                   *pos = 0;
-                   newNeedle = ++pos;
-                   for (;;) {
-                       pos = strchr(pos, '/');
-                       if (pos == NULL) {
-                           usage(sed_usage);
-                       }
-                       if (*(pos - 1) == '\\') {
-                           pos++;
-                           continue;
-                       }
+               case f_append:
+                       do_sed_append(stdin, appendline, quietFlag);
                        break;
-                   }
-                   *pos = 0;
-                   if (pos + 2 != 0) {
-                       while (*++pos) {
-                           switch (*pos) {
-                           case 'i':
-                               ignoreCase = TRUE;
+               }
+       } else {
+               while (argc-- > 0) {
+                       name = *argv++;
+
+                       fp = fopen(name, "r");
+                       if (fp == NULL) {
+                               perror(name);
+                               continue;
+                       }
+
+                       switch (sed_f) {
+                       case f_none:
                                break;
-                           case 'p':
-                               printFlag = TRUE;
+                       case f_replace:
+                               do_sed_repl(fp, needle, newNeedle, ignoreCase, printFlag,
+                                                       quietFlag);
                                break;
-                           case 'g':
+                       case f_append:
+                               do_sed_append(fp, appendline, quietFlag);
                                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;
+                       if (ferror(fp))
+                               perror(name);
 
-           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);
+                       fclose(fp);
+               }
        }
-    }
-    exit(TRUE);
+       return(TRUE);
 }