Print this page
4701 would like grep context options (-A, -B, -C)

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/grep_xpg4/grep.c
          +++ new/usr/src/cmd/grep_xpg4/grep.c
↓ open down ↓ 56 lines elided ↑ open up ↑
  57   57  #include <wctype.h>
  58   58  #include <ftw.h>
  59   59  #include <sys/param.h>
  60   60  
  61   61  #define STDIN_FILENAME gettext("(standard input)")
  62   62  
  63   63  #define BSIZE           512             /* Size of block for -b */
  64   64  #define BUFSIZE         8192            /* Input buffer size */
  65   65  #define MAX_DEPTH       1000            /* how deep to recurse */
  66   66  
       67 +#define AFTER   1                       /* 'After' Context */
       68 +#define BEFORE  2                       /* 'Before' Context */
       69 +#define CONTEXT (AFTER|BEFORE)          /* Full Context */
       70 +
  67   71  #define M_CSETSIZE      256             /* singlebyte chars */
  68   72  static int      bmglen;                 /* length of BMG pattern */
  69   73  static char     *bmgpat;                /* BMG pattern */
  70   74  static int      bmgtab[M_CSETSIZE];     /* BMG delta1 table */
  71   75  
  72   76  typedef struct  _PATTERN        {
  73   77          char    *pattern;               /* original pattern */
  74   78          wchar_t *wpattern;              /* wide, lowercased pattern */
  75   79          struct  _PATTERN        *next;
  76   80          regex_t re;                     /* compiled pattern */
↓ open down ↓ 16 lines elided ↑ open up ↑
  93   97  static uchar_t  rflag;                  /* Search directories recursively */
  94   98  static uchar_t  bflag;                  /* Preccede matches by block number */
  95   99  static uchar_t  sflag;                  /* Suppress file error messages */
  96  100  static uchar_t  qflag;                  /* Suppress standard output */
  97  101  static uchar_t  wflag;                  /* Search for expression as a word */
  98  102  static uchar_t  xflag;                  /* Anchoring */
  99  103  static uchar_t  Eflag;                  /* Egrep or -E flag */
 100  104  static uchar_t  Fflag;                  /* Fgrep or -F flag */
 101  105  static uchar_t  Rflag;                  /* Like rflag, but follow symlinks */
 102  106  static uchar_t  outfn;                  /* Put out file name */
      107 +static uchar_t  conflag;                /* show context of matches */
 103  108  static char     *cmdname;
 104  109  
 105  110  static int      use_wchar, use_bmg, mblocale;
 106  111  
 107      -static size_t   outbuflen, prntbuflen;
 108      -static char     *prntbuf;
      112 +static size_t   outbuflen, prntbuflen, conbuflen;
      113 +static unsigned long    conalen, conblen, conmatches;
      114 +static char     *prntbuf, *conbuf;
 109  115  static wchar_t  *outline;
 110  116  
 111  117  static void     addfile(const char *fn);
 112  118  static void     addpattern(char *s);
 113  119  static void     fixpatterns(void);
 114  120  static void     usage(void);
 115  121  static int      grep(int, const char *);
 116  122  static void     bmgcomp(char *, int);
 117  123  static char     *bmgexec(char *, char *);
 118  124  static int      recursive(const char *, const struct stat *, int, struct FTW *);
 119  125  static void     process_path(const char *);
 120  126  static void     process_file(const char *, int);
 121  127  
 122  128  /*
 123  129   * mainline for grep
 124  130   */
 125  131  int
 126  132  main(int argc, char **argv)
 127  133  {
 128      -        char    *ap;
      134 +        char    *ap, *test;
 129  135          int     c;
 130  136          int     fflag = 0;
 131  137          int     i, n_pattern = 0, n_file = 0;
 132  138          char    **pattern_list = NULL;
 133  139          char    **file_list = NULL;
 134  140  
 135  141          (void) setlocale(LC_ALL, "");
 136  142  #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 137  143  #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it weren't */
 138  144  #endif
↓ open down ↓ 16 lines elided ↑ open up ↑
 155  161           */
 156  162          if (*ap == 'e' || *ap == 'E') {
 157  163                  regflags |= REG_EXTENDED;
 158  164                  egrep++;
 159  165          } else {
 160  166                  if (*ap == 'f' || *ap == 'F') {
 161  167                          fgrep++;
 162  168                  }
 163  169          }
 164  170  
 165      -        while ((c = getopt(argc, argv, "vwchHilnrbse:f:qxEFIR")) != EOF) {
      171 +        /* check for non-standard "-line-count" option */
      172 +        for (i = 1; i < argc; i++) {
      173 +                if (strcmp(argv[i], "--") == 0)
      174 +                        break;
      175 +
      176 +                if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
      177 +                        if (strlen(&argv[i][1]) !=
      178 +                            strspn(&argv[i][1], "0123456789")) {
      179 +                                (void) fprintf(stderr, gettext(
      180 +                                    "%s: Bad number flag\n"), argv[0]);
      181 +                                usage();
      182 +                        }
      183 +
      184 +                        conalen = conblen = strtoul(&argv[i][1], (char **)NULL,
      185 +                            10);
      186 +
      187 +                        /* isdigit() check prevents negative arguments */
      188 +                        if (conalen >= ULONG_MAX) {
      189 +                                (void) fprintf(stderr, gettext(
      190 +                                    "%s: Bad context argument\n"), argv[0]);
      191 +                        }
      192 +
      193 +                        if (conalen)
      194 +                                conflag = CONTEXT;
      195 +
      196 +                        while (i < argc) {
      197 +                                argv[i] = argv[i + 1];
      198 +                                i++;
      199 +                        }
      200 +                        argc--;
      201 +                }
      202 +        }
      203 +
      204 +        while ((c = getopt(argc, argv, "vwchHilnrbse:f:qxEFIRA:B:C:")) != EOF) {
      205 +                unsigned long tval;
 166  206                  switch (c) {
 167  207                  case 'v':       /* POSIX: negate matches */
 168  208                          nvflag = 0;
 169  209                          break;
 170  210  
 171  211                  case 'c':       /* POSIX: write count */
 172  212                          cflag++;
 173  213                          break;
 174  214  
 175  215                  case 'i':       /* POSIX: ignore case */
↓ open down ↓ 79 lines elided ↑ open up ↑
 255  295  
 256  296                  case 'F':       /* POSIX: strings, not RE's */
 257  297                          Fflag++;
 258  298                          break;
 259  299  
 260  300                  case 'R':       /* Solaris: like rflag, but follow symlinks */
 261  301                          Rflag++;
 262  302                          rflag++;
 263  303                          break;
 264  304  
      305 +                case 'A':       /* print N lines after each match */
      306 +                        conalen = strtoul(optarg, &test, 10);
      307 +                        /* *test will be non-null if optarg is negative */
      308 +                        if (*test != '\0' || conalen >= ULONG_MAX) {
      309 +                                (void) fprintf(stderr, gettext(
      310 +                                    "%s: Bad context argument\n"), argv[0]);
      311 +                                exit(2);
      312 +                        }
      313 +                        if (conalen)
      314 +                                conflag |= AFTER;
      315 +                        else
      316 +                                conflag &= ~AFTER;
      317 +                        break;
      318 +                case 'B':       /* print N lines before each match */
      319 +                        conblen = strtoul(optarg, &test, 10);
      320 +                        /* *test will be non-null if optarg is negative */
      321 +                        if (*test != '\0' || conblen >= ULONG_MAX) {
      322 +                                (void) fprintf(stderr, gettext(
      323 +                                    "%s: Bad context argument\n"), argv[0]);
      324 +                                exit(2);
      325 +                        }
      326 +                        if (conblen)
      327 +                                conflag |= BEFORE;
      328 +                        else
      329 +                                conflag &= ~BEFORE;
      330 +                        break;
      331 +                case 'C':       /* print N lines around each match */
      332 +                        tval = strtoul(optarg, &test, 10);
      333 +                        /* *test will be non-null if optarg is negative */
      334 +                        if (*test != '\0' || tval >= ULONG_MAX) {
      335 +                                (void) fprintf(stderr, gettext(
      336 +                                    "%s: Bad context argument\n"), argv[0]);
      337 +                                exit(2);
      338 +                        }
      339 +                        if (tval) {
      340 +                                if (!(conflag & BEFORE))
      341 +                                        conblen = tval;
      342 +                                if (!(conflag & AFTER))
      343 +                                        conalen = tval;
      344 +                                conflag = CONTEXT;
      345 +                        }
      346 +                        break;
      347 +
 265  348                  default:
 266  349                          usage();
 267  350                  }
 268  351          }
 269  352          /*
 270  353           * If we're invoked as egrep or fgrep we need to do some checks
 271  354           */
 272  355  
 273  356          if (egrep || fgrep) {
 274  357                  /*
↓ open down ↓ 260 lines elided ↑ open up ↑
 535  618                  }
 536  619                  if (bufp[buflen - 1] == '\n') {
 537  620                          bufp[--buflen] = '\0';
 538  621                  }
 539  622                  addpattern(inbuf);
 540  623  
 541  624                  bufp = inbuf;
 542  625                  bufused = 0;
 543  626          }
 544  627          free(inbuf);
      628 +        free(prntbuf);
      629 +        free(conbuf);
 545  630          (void) fclose(fp);
 546  631  }
 547  632  
 548  633  /*
 549  634   * Add a string to the pattern list.
 550  635   */
 551  636  static void
 552  637  addpattern(char *s)
 553  638  {
 554  639          PATTERN *pp;
↓ open down ↓ 156 lines elided ↑ open up ↑
 711  796          /*
 712  797           * Decide if we are able to run the Boyer-Moore-Gosper algorithm.
 713  798           * Use the Boyer-Moore-Gosper algorithm if:
 714  799           * - fgrep                      (Fflag)
 715  800           * - singlebyte locale          (!mblocale)
 716  801           * - no ignoring case           (!iflag)
 717  802           * - no printing line numbers   (!nflag)
 718  803           * - no negating the output     (nvflag)
 719  804           * - only one pattern           (npatterns == 1)
 720  805           * - non zero length pattern    (strlen(patterns->pattern) != 0)
      806 +         * - no context required        (!conflag)
 721  807           *
 722  808           * It's guaranteed patterns->pattern is still alive
 723  809           * when Fflag && !mblocale.
 724  810           */
 725  811          use_bmg = Fflag && !mblocale && !iflag && !nflag && nvflag &&
 726      -            (npatterns == 1) && (strlen(patterns->pattern) != 0);
      812 +            (npatterns == 1) && (strlen(patterns->pattern) != 0) && !conflag;
 727  813  }
 728  814  
 729  815  /*
 730  816   * Search a newline from the beginning of the string
 731  817   */
 732  818  static char *
 733  819  find_nl(const char *ptr, size_t len)
 734  820  {
 735  821          while (len-- != 0) {
 736  822                  if (*ptr++ == '\n') {
↓ open down ↓ 60 lines elided ↑ open up ↑
 797  883   * Otherwise we split the buffer into lines,
 798  884   * and check for a match on each line.
 799  885   */
 800  886  static int
 801  887  grep(int fd, const char *fn)
 802  888  {
 803  889          PATTERN *pp;
 804  890          off_t   data_len;       /* length of the data chunk */
 805  891          off_t   line_len;       /* length of the current line */
 806  892          off_t   line_offset;    /* current line's offset from the beginning */
 807      -        long long       lineno;
      893 +        off_t   blkoffset;      /* line_offset but context-compatible */
      894 +        long long       lineno, linenum;
 808  895          long long       matches = 0;    /* Number of matching lines */
      896 +        long long       conacnt = 0, conbcnt = 0;       /* context line count */
 809  897          int     newlinep;       /* 0 if the last line of file has no newline */
 810      -        char    *ptr, *ptrend;
      898 +        char    *ptr, *ptrend, *prntptr, *prntptrend;
      899 +        char    *nextptr = NULL, *nextend = NULL;
      900 +        char    *conptr = NULL, *conptrend = NULL;
      901 +        char    *matchptr = NULL;
      902 +        int     conaprnt = 0, conbprnt = 0, lastmatch = 0;
      903 +        int     nearmatch = conmatches ? 1 : 0; /* w/in N+1 of last match */
      904 +        size_t  prntlen;
 811  905  
 812      -
 813  906          if (patterns == NULL)
 814  907                  return (0);     /* no patterns to match -- just return */
 815  908  
 816  909          pp = patterns;
 817  910  
 818  911          if (use_bmg) {
 819  912                  bmgcomp(pp->pattern, strlen(pp->pattern));
 820  913          }
 821  914  
 822  915          if (use_wchar && outline == NULL) {
↓ open down ↓ 8 lines elided ↑ open up ↑
 831  924  
 832  925          if (prntbuf == NULL) {
 833  926                  prntbuflen = BUFSIZE;
 834  927                  if ((prntbuf = malloc(prntbuflen + 1)) == NULL) {
 835  928                          (void) fprintf(stderr, gettext("%s: out of memory\n"),
 836  929                              cmdname);
 837  930                          exit(2);
 838  931                  }
 839  932          }
 840  933  
 841      -        line_offset = 0;
      934 +        if (conflag && (conbuf == NULL)) {
      935 +                conbuflen = BUFSIZE;
      936 +                if ((conbuf = malloc(BUFSIZE+1)) == NULL) {
      937 +                        (void) fprintf(stderr, gettext("%s: out of memory\n"),
      938 +                            cmdname);
      939 +                        exit(2);
      940 +                }
      941 +        }
      942 +
      943 +        blkoffset = line_offset = 0;
 842  944          lineno = 0;
      945 +        linenum = 1;
 843  946          newlinep = 1;
 844  947          data_len = 0;
 845  948          for (; ; ) {
 846  949                  long    count;
 847  950                  off_t   offset = 0;
      951 +                int     eof = 0, rv = REG_NOMATCH;
      952 +                char    separate;
 848  953  
 849  954                  if (data_len == 0) {
 850  955                          /*
 851  956                           * If no data in the buffer, reset ptr
 852  957                           */
 853  958                          ptr = prntbuf;
      959 +                        if (conptr == NULL)
      960 +                                conptrend = conptr = conbuf;
 854  961                  }
 855  962                  if (ptr == prntbuf) {
 856  963                          /*
 857  964                           * The current data chunk starts from prntbuf.
 858  965                           * This means either the buffer has no data
 859  966                           * or the buffer has no newline.
 860  967                           * So, read more data from input.
 861  968                           */
 862  969                          count = read(fd, ptr + data_len, prntbuflen - data_len);
 863  970                          if (count < 0) {
↓ open down ↓ 4 lines elided ↑ open up ↑
 868  975                                                      "%s:", fn);
 869  976                                          }
 870  977                                          if (!qflag && !rflag) {
 871  978                                                  (void) fprintf(stdout, "%lld\n",
 872  979                                                      matches);
 873  980                                          }
 874  981                                  }
 875  982                                  return (0);
 876  983                          } else if (count == 0) {
 877  984                                  /* no new data */
      985 +                                eof = 1;
      986 +
      987 +                                /* we never want to match EOF */
      988 +                                pp = (PATTERN *) !nvflag;
      989 +
 878  990                                  if (data_len == 0) {
 879  991                                          /* end of file already reached */
 880      -                                        break;
      992 +                                        if (conflag) {
      993 +                                                *conptrend = '\n';
      994 +                                                goto L_next_line;
      995 +                                        } else {
      996 +                                                goto out;
      997 +                                        }
 881  998                                  }
 882  999                                  /* last line of file has no newline */
 883 1000                                  ptrend = ptr + data_len;
 884 1001                                  newlinep = 0;
 885 1002                                  goto L_start_process;
 886 1003                          }
 887 1004                          offset = data_len;
 888 1005                          data_len += count;
 889 1006                  }
 890 1007  
↓ open down ↓ 8 lines elided ↑ open up ↑
 899 1016                                  /*
 900 1017                                   * Move remaining data to the beginning
 901 1018                                   * of the buffer.
 902 1019                                   * Remaining data lie from ptr for
 903 1020                                   * data_len bytes.
 904 1021                                   */
 905 1022                                  (void) memmove(prntbuf, ptr, data_len);
 906 1023                          }
 907 1024                          if (data_len == prntbuflen) {
 908 1025                                  /*
 909      -                                 * No enough room in the buffer
     1026 +                                 * Not enough room in the buffer
 910 1027                                   */
 911 1028                                  prntbuflen += BUFSIZE;
 912 1029                                  prntbuf = realloc(prntbuf, prntbuflen + 1);
 913 1030                                  if (prntbuf == NULL) {
 914 1031                                          (void) fprintf(stderr,
 915 1032                                              gettext("%s: out of memory\n"),
 916 1033                                              cmdname);
 917 1034                                          exit(2);
 918 1035                                  }
 919 1036                          }
↓ open down ↓ 113 lines elided ↑ open up ↑
1033 1150                                          *cp = towlower((wint_t)*cp);
1034 1151                                  }
1035 1152                          }
1036 1153  
1037 1154                          if (xflag) {
1038 1155                                  for (pp = patterns; pp; pp = pp->next) {
1039 1156                                          if (outline[0] == pp->wpattern[0] &&
1040 1157                                              wcscmp(outline,
1041 1158                                              pp->wpattern) == 0) {
1042 1159                                                  /* matched */
     1160 +                                                rv = REG_OK;
1043 1161                                                  break;
1044 1162                                          }
1045 1163                                  }
1046 1164                          } else {
1047 1165                                  for (pp = patterns; pp; pp = pp->next) {
1048 1166                                          if (wcswcs(outline, pp->wpattern)
1049 1167                                              != NULL) {
1050 1168                                                  /* matched */
     1169 +                                                rv = REG_OK;
1051 1170                                                  break;
1052 1171                                          }
1053 1172                                  }
1054 1173                          }
1055 1174                  } else if (Fflag) {
1056 1175                          /* fgrep in byte-oriented handling */
1057 1176                          char    *fptr;
1058 1177                          if (iflag) {
1059 1178                                  fptr = istrdup(ptr);
1060 1179                          } else {
1061 1180                                  fptr = ptr;
1062 1181                          }
1063 1182                          if (xflag) {
1064 1183                                  /* fgrep -x */
1065 1184                                  for (pp = patterns; pp; pp = pp->next) {
1066 1185                                          if (fptr[0] == pp->pattern[0] &&
1067 1186                                              strcmp(fptr, pp->pattern) == 0) {
1068 1187                                                  /* matched */
     1188 +                                                rv = REG_OK;
1069 1189                                                  break;
1070 1190                                          }
1071 1191                                  }
1072 1192                          } else {
1073 1193                                  for (pp = patterns; pp; pp = pp->next) {
1074 1194                                          if (strstr(fptr, pp->pattern) != NULL) {
1075 1195                                                  /* matched */
     1196 +                                                rv = REG_OK;
1076 1197                                                  break;
1077 1198                                          }
1078 1199                                  }
1079 1200                          }
1080 1201                  } else {
1081 1202                          /* grep or egrep */
1082 1203                          for (pp = patterns; pp; pp = pp->next) {
1083      -                                int     rv;
1084      -
1085 1204                                  rv = regexec(&pp->re, ptr, 0, NULL, 0);
1086 1205                                  if (rv == REG_OK) {
1087 1206                                          /* matched */
1088 1207                                          break;
1089 1208                                  }
1090 1209  
1091 1210                                  switch (rv) {
1092 1211                                  case REG_NOMATCH:
1093 1212                                          break;
1094 1213                                  case REG_ECHAR:
↓ open down ↓ 5 lines elided ↑ open up ↑
1100 1219                                          (void) regerror(rv, &pp->re, errstr,
1101 1220                                              sizeof (errstr));
1102 1221                                          (void) fprintf(stderr, gettext(
1103 1222              "%s: input file \"%s\": line %lld: %s\n"),
1104 1223                                              cmdname, fn, lineno, errstr);
1105 1224                                          exit(2);
1106 1225                                  }
1107 1226                          }
1108 1227                  }
1109 1228  
     1229 +                /*
     1230 +                 * Context is set up as follows:
     1231 +                 * For a 'Before' context, we maintain a set of pointers
     1232 +                 * containing 'N' lines of context. If the current number of
     1233 +                 * lines contained is greater than N, and N isn't a match, the
     1234 +                 * start pointer is moved forward to the next newline.
     1235 +                 *
     1236 +                 * If we ever find a match, we print out immediately.
     1237 +                 * 'nearmatch' tells us if we're within N+1 lines of the last
     1238 +                 * match ; if we are, and we find another match, we don't
     1239 +                 * separate the matches. 'nearmatch' becomes false when
     1240 +                 * a line gets rotated out of the context.
     1241 +                 *
     1242 +                 * For an 'After' context, we simply wait until we've found a
     1243 +                 * match, then create a context N+1 lines big. If we don't find
     1244 +                 * a match within the context, we print out the current context.
     1245 +                 * Otherwise, we save a reference to the new matching line,
     1246 +                 * print out the other context, and reset our context pointers
     1247 +                 * to the new matching line.
     1248 +                 *
     1249 +                 * 'nearmatch' becomes false when we find a non-matching line
     1250 +                 * that isn't a part of any context.
     1251 +                 *
     1252 +                 * A full-context is implemented as a combination of the
     1253 +                 * 'Before' and 'After' context logic. Before we find a match,
     1254 +                 * we follow the Before logic. When we find a match, we
     1255 +                 * follow the After logic. 'nearmatch' is handled by the Before
     1256 +                 * logic.
     1257 +                 */
     1258 +
     1259 +                if (!conflag)
     1260 +                        goto L_next_line;
     1261 +
     1262 +                if (line_len + (conptrend - conbuf) > conbuflen) {
     1263 +                        char *oldconbuf = conbuf;
     1264 +                        char *oldconptr = conptr;
     1265 +                        long tmp = matchptr - conptr;
     1266 +
     1267 +                        conbuflen += BUFSIZE;
     1268 +                        conbuf = realloc(conbuf, conbuflen + 1);
     1269 +                        if (conbuf == NULL) {
     1270 +                                (void) fprintf(stderr,
     1271 +                                    gettext("%s: out of memory\n"),
     1272 +                                    cmdname);
     1273 +                                exit(2);
     1274 +                        }
     1275 +
     1276 +                        conptr = conbuf + (conptr - oldconbuf);
     1277 +                        conptrend = conptr + (conptrend - oldconptr);
     1278 +                        if (matchptr)
     1279 +                                matchptr = conptr + tmp;
     1280 +                }
     1281 +                (void) memcpy((conptrend > conptr) ?
     1282 +                    conptrend + 1 : conptrend, ptr, line_len);
     1283 +                conptrend += line_len + (conptrend > conptr);
     1284 +                *conptrend = '\n';
     1285 +
     1286 +                if (!nvflag == rv) {
     1287 +                        /* matched */
     1288 +                        if (lastmatch) {
     1289 +                                if (conflag & AFTER) {
     1290 +                                        conaprnt = 1;
     1291 +                                        nextend = conptrend;
     1292 +                                        conptrend = conptr + lastmatch;
     1293 +                                        nextptr = conptrend + 1;
     1294 +                                        *nextend = '\n';
     1295 +                                }
     1296 +                        } else {
     1297 +                                if (conflag == AFTER) {
     1298 +                                        conptr = conptrend - (line_len);
     1299 +                                        linenum = lineno;
     1300 +                                        blkoffset = line_offset;
     1301 +                                }
     1302 +                                blkoffset = line_offset -
     1303 +                                    (conptrend - conptr - line_len);
     1304 +                        }
     1305 +
     1306 +                        if (conflag == BEFORE)
     1307 +                                conbprnt = 1;
     1308 +
     1309 +                        lastmatch = conptrend - conptr;
     1310 +                        goto L_next_line;
     1311 +                }
     1312 +
     1313 +                if (!lastmatch) {
     1314 +                        if (conflag & BEFORE) {
     1315 +                                if (conbcnt >= conblen) {
     1316 +                                        char *tmp = conptr;
     1317 +                                        conptr = find_nl(conptr,
     1318 +                                            conptrend - conptr) + 1;
     1319 +                                        if (bflag)
     1320 +                                                blkoffset += conptr - tmp;
     1321 +                                        linenum++;
     1322 +                                        nearmatch = 1;
     1323 +                                } else {
     1324 +                                        conbcnt++;
     1325 +                                }
     1326 +                        }
     1327 +                        if (conflag == AFTER)
     1328 +                                nearmatch = 1;
     1329 +                } else  {
     1330 +                        if (++conacnt >= conalen && !conaprnt && conalen)
     1331 +                                conaprnt = 1;
     1332 +                        else
     1333 +                                lastmatch = conptrend - conptr;
     1334 +                }
     1335 +
1110 1336  L_next_line:
1111 1337                  /*
1112 1338                   * Here, if pp points to non-NULL, something has been matched
1113 1339                   * to the pattern.
1114 1340                   */
1115 1341                  if (nvflag == (pp != NULL)) {
1116 1342                          matches++;
     1343 +                        if (!nextend)
     1344 +                                matchptr = conflag ? conptrend : ptrend;
     1345 +                }
     1346 +
     1347 +                /*
     1348 +                 * Set up some print context so that we can treat
     1349 +                 * single-line matches as a zero-N context.
     1350 +                 * Apply CLI flags to each line of the context.
     1351 +                 *
     1352 +                 * For context, we only print if we both have a match and are
     1353 +                 * either at the end of the data stream, or we've previously
     1354 +                 * declared that we want to print for a particular context.
     1355 +                 */
     1356 +                if (lastmatch && (eof || conaprnt || conbprnt)) {
     1357 +
1117 1358                          /*
     1359 +                         * We'd normally do this earlier, but we had to
     1360 +                         * escape early because we reached the end of the data.
     1361 +                         */
     1362 +                        if (eof && nextptr)
     1363 +                                conptrend = nextend;
     1364 +
     1365 +                        prntlen = conptrend - conptr + 1;
     1366 +                        prntptrend = prntptr = conptr;
     1367 +                        if (conmatches++ && nearmatch && !cflag)
     1368 +                                (void) fwrite("--\n", 1, 3, stdout);
     1369 +                } else if (!conflag && nvflag == (pp != NULL)) {
     1370 +                        *ptrend = '\n';
     1371 +                        prntlen = line_len + 1;
     1372 +                        prntptrend = prntptr = ptr;
     1373 +                        linenum = lineno;
     1374 +                        blkoffset = line_offset;
     1375 +                } else if (eof) {
     1376 +                        /* No match and no more data */
     1377 +                        goto out;
     1378 +                } else {
     1379 +                        /* No match, or we're not done building context */
     1380 +                        goto L_skip_line;
     1381 +                }
     1382 +
     1383 +                while ((prntptrend = find_nl(prntptrend+1, prntlen)) != NULL) {
     1384 +
     1385 +                        /*
     1386 +                         * GNU grep uses '-' for context lines and ':' for
     1387 +                         * matching lines, so replicate that here.
     1388 +                         */
     1389 +                        if (prntptrend == matchptr) {
     1390 +                                if (eof && nextptr) {
     1391 +                                        matchptr = nextend;
     1392 +                                        nextptr = NULL;
     1393 +                                } else {
     1394 +                                        matchptr = NULL;
     1395 +                                }
     1396 +                                separate = ':';
     1397 +                        } else {
     1398 +                                separate = '-';
     1399 +                        }
     1400 +
     1401 +                        /*
1118 1402                           * Handle q, l, and c flags.
1119 1403                           */
1120 1404                          if (qflag) {
1121 1405                                  /* no need to continue */
1122 1406                                  /*
1123 1407                                   * End of this line is ptrend.
1124 1408                                   * We have read up to ptr + data_len.
1125 1409                                   */
1126 1410                                  off_t   pos;
1127 1411                                  pos = ptr + data_len - (ptrend + 1);
1128 1412                                  (void) lseek(fd, -pos, SEEK_CUR);
1129 1413                                  exit(0);
1130 1414                          }
1131 1415                          if (lflag) {
1132 1416                                  (void) printf("%s\n", fn);
1133      -                                break;
     1417 +                                goto out;
1134 1418                          }
1135 1419                          if (!cflag) {
1136 1420                                  if (Hflag || outfn) {
1137      -                                        (void) printf("%s:", fn);
     1421 +                                        (void) printf("%s%c", fn, separate);
1138 1422                                  }
1139 1423                                  if (bflag) {
1140      -                                        (void) printf("%lld:", (offset_t)
1141      -                                            (line_offset / BSIZE));
     1424 +                                        (void) printf("%lld%c", (offset_t)
     1425 +                                            (blkoffset / BSIZE), separate);
1142 1426                                  }
1143 1427                                  if (nflag) {
1144      -                                        (void) printf("%lld:", lineno);
     1428 +                                        (void) printf("%lld%c", linenum,
     1429 +                                            separate);
1145 1430                                  }
1146      -                                *ptrend = '\n';
1147      -                                (void) fwrite(ptr, 1, line_len + 1, stdout);
     1431 +                                (void) fwrite(prntptr, 1,
     1432 +                                    prntptrend - prntptr + 1, stdout);
1148 1433                          }
1149 1434                          if (ferror(stdout)) {
1150 1435                                  return (0);
1151 1436                          }
     1437 +                        linenum++;
     1438 +                        prntlen -= prntptrend - prntptr + 1;
     1439 +                        blkoffset += prntptrend - prntptr + 1;
     1440 +                        prntptr = prntptrend + 1;
1152 1441                  }
     1442 +
     1443 +                if (eof)
     1444 +                        goto out;
     1445 +
     1446 +                /*
     1447 +                 * Update context buffer and variables post-print
     1448 +                 */
     1449 +                if (conflag) {
     1450 +                        conptr = conbuf;
     1451 +                        conaprnt = conbprnt = 0;
     1452 +                        nearmatch = 0;
     1453 +                        conacnt = conbcnt = 0;
     1454 +
     1455 +                        if (nextptr) {
     1456 +                                (void) memmove(conbuf, nextptr,
     1457 +                                    nextend - nextptr + 1);
     1458 +                                blkoffset += nextptr - conptrend - 1;
     1459 +                                conptrend = conptr + (nextend - nextptr);
     1460 +                                matchptr = conptrend;
     1461 +                                linenum = lineno;
     1462 +                                lastmatch = conptrend - conptr;
     1463 +                        } else {
     1464 +                                conptrend = conptr;
     1465 +                                conacnt = 0;
     1466 +                                lastmatch = 0;
     1467 +                        }
     1468 +                        nextptr = nextend = NULL;
     1469 +                }
     1470 +
1153 1471  L_skip_line:
1154 1472                  if (!newlinep)
1155 1473                          break;
1156 1474  
1157 1475                  data_len -= line_len + 1;
1158 1476                  line_offset += line_len + 1;
1159 1477                  ptr = ptrend + 1;
1160 1478          }
1161 1479  
     1480 +out:
1162 1481          if (cflag) {
1163 1482                  if (Hflag || outfn) {
1164 1483                          (void) printf("%s:", fn);
1165 1484                  }
1166 1485                  if (!qflag) {
1167 1486                          (void) printf("%lld\n", matches);
1168 1487                  }
1169 1488          }
1170 1489          return (matches != 0);
1171 1490  }
1172 1491  
1173 1492  /*
1174 1493   * usage message for grep
1175 1494   */
1176 1495  static void
1177 1496  usage(void)
1178 1497  {
1179 1498          if (egrep || fgrep) {
1180 1499                  (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1181 1500                  (void) fprintf(stderr,
1182      -                    gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1183      -                    "pattern_list [file ...]\n"));
     1501 +                    gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
     1502 +                    "[-bhHinsvx] pattern_list [file ...]\n"));
1184 1503  
1185 1504                  (void) fprintf(stderr, "\t%s", cmdname);
1186 1505                  (void) fprintf(stderr,
1187      -                    gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1188      -                    "[-e pattern_list]... "
     1506 +                    gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
     1507 +                    "[-bhHinsvx] [-e pattern_list]... "
1189 1508                      "[-f pattern_file]... [file...]\n"));
1190 1509          } else {
1191 1510                  (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1192 1511                  (void) fprintf(stderr,
1193      -                    gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvwx] "
1194      -                    "pattern_list [file ...]\n"));
     1512 +                    gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
     1513 +                    "[-bhHinsvx] pattern_list [file ...]\n"));
1195 1514  
1196 1515                  (void) fprintf(stderr, "\t%s", cmdname);
1197 1516                  (void) fprintf(stderr,
1198      -                    gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvwx] "
1199      -                    "[-e pattern_list]... "
     1517 +                    gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
     1518 +                    "[-bhHinsvx] [-e pattern_list]... "
1200 1519                      "[-f pattern_file]... [file...]\n"));
1201 1520  
1202 1521                  (void) fprintf(stderr, "\t%s", cmdname);
1203 1522                  (void) fprintf(stderr,
1204      -                    gettext(" -E [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1205      -                    "pattern_list [file ...]\n"));
     1523 +                    gettext(" -E [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
     1524 +                    "[-bhHinsvx] pattern_list [file ...]\n"));
1206 1525  
1207 1526                  (void) fprintf(stderr, "\t%s", cmdname);
1208 1527                  (void) fprintf(stderr,
1209      -                    gettext(" -E [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1210      -                    "[-e pattern_list]... "
     1528 +                    gettext(" -E [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
     1529 +                    "[-bhHinsvx] [-e pattern_list]... "
1211 1530                      "[-f pattern_file]... [file...]\n"));
1212 1531  
1213 1532                  (void) fprintf(stderr, "\t%s", cmdname);
1214 1533                  (void) fprintf(stderr,
1215      -                    gettext(" -F [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1216      -                    "pattern_list [file ...]\n"));
     1534 +                    gettext(" -F [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
     1535 +                    "[-bhHinsvx] pattern_list [file ...]\n"));
1217 1536  
1218 1537                  (void) fprintf(stderr, "\t%s", cmdname);
1219 1538                  (void) fprintf(stderr,
1220      -                    gettext(" -F [-c|-l|-q] [-bhHinsvx] [-e pattern_list]... "
     1539 +                    gettext(" -F [-c|-l|-q] [-A #|-B #|-C #|-#] "
     1540 +                    "[-bhHinsvx] [-e pattern_list]... "
1221 1541                      "[-f pattern_file]... [file...]\n"));
1222 1542          }
1223 1543          exit(2);
1224 1544          /* NOTREACHED */
1225 1545  }
1226 1546  
1227 1547  /*
1228 1548   * Compile literal pattern into BMG tables
1229 1549   */
1230 1550  static void
↓ open down ↓ 49 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX