grep.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       grep.c (4866B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <regex.h>
            3 #include <stdio.h>
            4 #include <stdlib.h>
            5 #include <string.h>
            6 #include <strings.h>
            7 
            8 #include "queue.h"
            9 #include "util.h"
           10 
           11 enum { Match = 0, NoMatch = 1, Error = 2 };
           12 
           13 static void addpattern(const char *);
           14 static void addpatternfile(FILE *);
           15 static int grep(FILE *, const char *);
           16 
           17 static int Eflag;
           18 static int Fflag;
           19 static int Hflag;
           20 static int eflag;
           21 static int fflag;
           22 static int hflag;
           23 static int iflag;
           24 static int sflag;
           25 static int vflag;
           26 static int wflag;
           27 static int xflag;
           28 static int many;
           29 static int mode;
           30 
           31 struct pattern {
           32         regex_t preg;
           33         SLIST_ENTRY(pattern) entry;
           34         char pattern[];
           35 };
           36 
           37 static SLIST_HEAD(phead, pattern) phead;
           38 
           39 static void
           40 addpattern(const char *pattern)
           41 {
           42         struct pattern *pnode;
           43         size_t patlen;
           44 
           45         patlen = strlen(pattern);
           46 
           47         pnode = enmalloc(Error, sizeof(*pnode) + patlen + 9);
           48         SLIST_INSERT_HEAD(&phead, pnode, entry);
           49 
           50         if (Fflag || (!xflag && !wflag)) {
           51                 memcpy(pnode->pattern, pattern, patlen + 1);
           52         } else {
           53                 sprintf(pnode->pattern, "%s%s%s%s%s",
           54                         xflag ? "^" : "\\<",
           55                         Eflag ? "(" : "\\(",
           56                         pattern,
           57                         Eflag ? ")" : "\\)",
           58                         xflag ? "$" : "\\>");
           59         }
           60 }
           61 
           62 static void
           63 addpatternfile(FILE *fp)
           64 {
           65         static char *buf = NULL;
           66         static size_t size = 0;
           67         ssize_t len = 0;
           68 
           69         while ((len = getline(&buf, &size, fp)) > 0) {
           70                 if (buf[len - 1] == '\n')
           71                         buf[len - 1] = '\0';
           72                 addpattern(buf);
           73         }
           74         if (ferror(fp))
           75                 enprintf(Error, "read error:");
           76 }
           77 
           78 static int
           79 grep(FILE *fp, const char *str)
           80 {
           81         static char *buf = NULL;
           82         static size_t size = 0;
           83         ssize_t len = 0;
           84         long c = 0, n;
           85         struct pattern *pnode;
           86         int match, result = NoMatch;
           87 
           88         for (n = 1; (len = getline(&buf, &size, fp)) > 0; n++) {
           89                 /* Remove the trailing newline if one is present. */
           90                 if (buf[len - 1] == '\n')
           91                         buf[len - 1] = '\0';
           92                 match = 0;
           93                 SLIST_FOREACH(pnode, &phead, entry) {
           94                         if (Fflag) {
           95                                 if (xflag) {
           96                                         if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) {
           97                                                 match = 1;
           98                                                 break;
           99                                         }
          100                                 } else {
          101                                         if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) {
          102                                                 match = 1;
          103                                                 break;
          104                                         }
          105                                 }
          106                         } else {
          107                                 if (regexec(&pnode->preg, buf, 0, NULL, 0) == 0) {
          108                                         match = 1;
          109                                         break;
          110                                 }
          111                         }
          112                 }
          113                 if (match != vflag) {
          114                         result = Match;
          115                         switch (mode) {
          116                         case 'c':
          117                                 c++;
          118                                 break;
          119                         case 'l':
          120                                 puts(str);
          121                                 goto end;
          122                         case 'q':
          123                                 exit(Match);
          124                         default:
          125                                 if (!hflag && (many || Hflag))
          126                                         printf("%s:", str);
          127                                 if (mode == 'n')
          128                                         printf("%ld:", n);
          129                                 puts(buf);
          130                                 break;
          131                         }
          132                 }
          133         }
          134         if (mode == 'c')
          135                 printf("%ld\n", c);
          136 end:
          137         if (ferror(fp)) {
          138                 weprintf("%s: read error:", str);
          139                 result = Error;
          140         }
          141         return result;
          142 }
          143 
          144 static void
          145 usage(void)
          146 {
          147         enprintf(Error, "usage: %s [-EFHchilnqsvwx] [-e pattern] [-f file] "
          148                  "[pattern] [file ...]\n", argv0);
          149 }
          150 
          151 int
          152 main(int argc, char *argv[])
          153 {
          154         struct pattern *pnode;
          155         int m, flags = REG_NOSUB, match = NoMatch;
          156         FILE *fp;
          157         char *arg;
          158 
          159         SLIST_INIT(&phead);
          160 
          161         ARGBEGIN {
          162         case 'E':
          163                 Eflag = 1;
          164                 Fflag = 0;
          165                 flags |= REG_EXTENDED;
          166                 break;
          167         case 'F':
          168                 Fflag = 1;
          169                 Eflag = 0;
          170                 flags &= ~REG_EXTENDED;
          171                 break;
          172         case 'H':
          173                 Hflag = 1;
          174                 hflag = 0;
          175                 break;
          176         case 'e':
          177                 arg = EARGF(usage());
          178                 if (!(fp = fmemopen(arg, strlen(arg) + 1, "r")))
          179                         eprintf("fmemopen:");
          180                 addpatternfile(fp);
          181                 efshut(fp, arg);
          182                 eflag = 1;
          183                 break;
          184         case 'f':
          185                 arg = EARGF(usage());
          186                 fp = fopen(arg, "r");
          187                 if (!fp)
          188                         enprintf(Error, "fopen %s:", arg);
          189                 addpatternfile(fp);
          190                 efshut(fp, arg);
          191                 fflag = 1;
          192                 break;
          193         case 'h':
          194                 hflag = 1;
          195                 Hflag = 0;
          196                 break;
          197         case 'c':
          198         case 'l':
          199         case 'n':
          200         case 'q':
          201                 mode = ARGC();
          202                 break;
          203         case 'i':
          204                 flags |= REG_ICASE;
          205                 iflag = 1;
          206                 break;
          207         case 's':
          208                 sflag = 1;
          209                 break;
          210         case 'v':
          211                 vflag = 1;
          212                 break;
          213         case 'w':
          214                 wflag = 1;
          215                 break;
          216         case 'x':
          217                 xflag = 1;
          218                 break;
          219         default:
          220                 usage();
          221         } ARGEND
          222 
          223         if (argc == 0 && !eflag && !fflag)
          224                 usage(); /* no pattern */
          225 
          226         /* just add literal pattern to list */
          227         if (!eflag && !fflag) {
          228                 if (!(fp = fmemopen(argv[0], strlen(argv[0]) + 1, "r")))
          229                         eprintf("fmemopen:");
          230                 addpatternfile(fp);
          231                 efshut(fp, argv[0]);
          232                 argc--;
          233                 argv++;
          234         }
          235 
          236         if (!Fflag)
          237                 /* Compile regex for all search patterns */
          238                 SLIST_FOREACH(pnode, &phead, entry)
          239                         enregcomp(Error, &pnode->preg, pnode->pattern, flags);
          240         many = (argc > 1);
          241         if (argc == 0) {
          242                 match = grep(stdin, "<stdin>");
          243         } else {
          244                 for (; *argv; argc--, argv++) {
          245                         if (!strcmp(*argv, "-")) {
          246                                 *argv = "<stdin>";
          247                                 fp = stdin;
          248                         } else if (!(fp = fopen(*argv, "r"))) {
          249                                 if (!sflag)
          250                                         weprintf("fopen %s:", *argv);
          251                                 match = Error;
          252                                 continue;
          253                         }
          254                         m = grep(fp, *argv);
          255                         if (m == Error || (match != Error && m == Match))
          256                                 match = m;
          257                         if (fp != stdin && fshut(fp, *argv))
          258                                 match = Error;
          259                 }
          260         }
          261 
          262         if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
          263                 match = Error;
          264 
          265         return match;
          266 }