1e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake/* grep.c - print lines what match given regular expression 2e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake * 3e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake * Copyright 2013 CE Strake <strake888 at gmail.com> 4e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake * 5dad378bb17f1910014383bf196e87028e98d81d6Rob Landley * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html 673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley * 773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley * TODO: -ABC 8e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 936aed25f3f54f7871d5810adfe99d96944e0afb4Rob LandleyUSE_GREP(NEWTOY(grep, "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN)) 10c49b9a97559d2009e9076e063b2e9acbc13fb9efRob LandleyUSE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN)) 11c49b9a97559d2009e9076e063b2e9acbc13fb9efRob LandleyUSE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN)) 12e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 13e999ca008416e3d41c1079bcb4d151b43c95dc3aStrakeconfig GREP 14e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake bool "grep" 15205b496e42ceb72bf0755fec4f4675a467c401e1Rob Landley default y 16e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake help 17b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley usage: grep [-EFivwcloqsHbhn] [-A NUM] [-m MAX] [-e REGEX]... [-f REGFILE] [FILE]... 18f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley 19f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley Show lines matching regular expressions. If no -e, first argument is 20f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley regular expression to match. With no files (or "-" filename) read stdin. 21f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley Returns 0 if matched, 1 if no match found. 22f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley 23f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley -e Regex to match. (May be repeated.) 24f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley -f File containing regular expressions to match. 25f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley 26f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley match type: 2736aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley -A Show NUM lines after -B Show NUM lines before match 2836aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley -C NUM lines context (A+B) -E extended regex syntax 2936aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley -F fixed (literal match) -i case insensitive 3036aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley -m match MAX many lines -r recursive (on dir) 3136aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley -v invert match -w whole word (implies -E) 3236aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley -x whole line -z input NUL terminated 33f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley 34f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley display modes: (default: matched line) 35f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley -c count of matching lines -l show matching filenames 36f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley -o only matching part -q quiet (errors only) 37d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley -s silent (no error msg) -Z output NUL terminated 38f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley 39d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley output prefix (default: filename if checking more than 1 file) 40f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley -H force filename -b byte offset of match 41f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley -h hide filename -n line number of match 42c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley 43c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landleyconfig EGREP 44c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley bool 45c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley default y 46c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley depends on GREP 47c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley 48c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landleyconfig FGREP 49c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley bool 50c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley default y 51c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley depends on GREP 52e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake*/ 53e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 54e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#define FOR_grep 55e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#include "toys.h" 56e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#include <regex.h> 57e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 58e999ca008416e3d41c1079bcb4d151b43c95dc3aStrakeGLOBALS( 59dad378bb17f1910014383bf196e87028e98d81d6Rob Landley long m; 60dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley struct arg_list *f; 61dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley struct arg_list *e; 62b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley long a; 6336aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley long b; 6436aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley long c; 65c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley 66c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley char indelim, outdelim; 67e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake) 68e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 69c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley// Emit line with various potential prefixes and delimiter 70c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landleystatic void outline(char *line, char dash, char *name, long lcount, long bcount, 71c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley int trim) 72c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley{ 73c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley if (name && (toys.optflags&FLAG_H)) printf("%s%c", name, dash); 74c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley if (!line || (lcount && (toys.optflags&FLAG_n))) 75c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley printf("%ld%c", lcount, line ? dash : TT.outdelim); 76c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley if (bcount && (toys.optflags&FLAG_b)) printf("%ld%c", bcount-1, dash); 7793e27d0d4723d57082463c4d70e6443060a8732bRob Landley if (line) xprintf("%.*s%c", trim ? trim : INT_MAX/2, line, TT.outdelim); 78c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley} 79c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley 8073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley// Show matches in one file 81f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landleystatic void do_grep(int fd, char *name) 82f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{ 8336aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley struct double_list *dlb = 0; 84dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley FILE *file = fdopen(fd, "r"); 85c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley long lcount = 0, mcount = 0, offset = 0, after = 0, before = 0; 86c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley char *bars = 0; 87e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 8831f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley if (!fd) name = "(standard input)"; 8931f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley 90dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley if (!file) { 91d3a435e53c94ec25b4ae5fa2614f49ef8884e08aRob Landley perror_msg_raw(name); 92dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley return; 93dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } 94dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 9573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley // Loop through lines of input 96e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake for (;;) { 976c64f5f186d26d4c95d408979d33831935e026f1Rob Landley char *line = 0, *start; 9873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley regmatch_t matches; 99dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley size_t unused; 100dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley long len; 101030970bd70e14849b0f2598bfa0982402fc7e2e7Rob Landley int mmatch = 0; 102e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 103dad378bb17f1910014383bf196e87028e98d81d6Rob Landley lcount++; 104c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley if (0 > (len = getdelim(&line, &unused, TT.indelim, file))) break; 105c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley if (line[len-1] == TT.indelim) line[len-1] = 0; 106dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 107dad378bb17f1910014383bf196e87028e98d81d6Rob Landley start = line; 108e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 10973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley // Loop through matches in this line 11073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley do { 111dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley int rc = 0, skip = 0; 112dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 11373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley // Handle non-regex matches 114dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley if (toys.optflags & FLAG_F) { 115fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley struct arg_list *seek, fseek; 116dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley char *s = 0; 117dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 118dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley for (seek = TT.e; seek; seek = seek->next) { 119e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley if (toys.optflags & FLAG_x) { 120e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley int i = (toys.optflags & FLAG_i); 121e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley 122e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley if ((i ? strcasecmp : strcmp)(seek->arg, line)) s = line; 123e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley } else if (!*seek->arg) { 124fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley seek = &fseek; 125fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley fseek.arg = s = line; 126fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley break; 127fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley } 128f435f0412aa4ca631aa178d10ed33008e34f37cbRob Landley if (toys.optflags & FLAG_i) s = strnstr(line, seek->arg); 129f435f0412aa4ca631aa178d10ed33008e34f37cbRob Landley else s = strstr(line, seek->arg); 130dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley if (s) break; 131dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } 132dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 133dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley if (s) { 13473e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley matches.rm_so = (s-line); 13573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley skip = matches.rm_eo = (s-line)+strlen(seek->arg); 136dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } else rc = 1; 137dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } else { 13873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley rc = regexec((regex_t *)toybuf, start, 1, &matches, 139dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley start==line ? 0 : REG_NOTBOL); 14073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley skip = matches.rm_eo; 141dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } 142dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 143dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley if (toys.optflags & FLAG_x) 14473e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (matches.rm_so || line[matches.rm_eo]) rc = 1; 14573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley 14673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (!rc && (toys.optflags & FLAG_w)) { 14773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley char c = 0; 14873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley 14973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if ((start+matches.rm_so)!=line) { 15073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley c = start[matches.rm_so-1]; 15173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (!isalnum(c) && c != '_') c = 0; 15273e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley } 15373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (!c) { 15473e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley c = start[matches.rm_eo]; 15573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (!isalnum(c) && c != '_') c = 0; 15673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley } 15773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (c) { 15873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley start += matches.rm_so+1; 15973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley 16073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley continue; 16173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley } 16273e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley } 163dad378bb17f1910014383bf196e87028e98d81d6Rob Landley 164dad378bb17f1910014383bf196e87028e98d81d6Rob Landley if (toys.optflags & FLAG_v) { 165dad378bb17f1910014383bf196e87028e98d81d6Rob Landley if (toys.optflags & FLAG_o) { 16673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (rc) skip = matches.rm_eo = strlen(start); 16773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley else if (!matches.rm_so) { 168dad378bb17f1910014383bf196e87028e98d81d6Rob Landley start += skip; 169dad378bb17f1910014383bf196e87028e98d81d6Rob Landley continue; 17073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley } else matches.rm_eo = matches.rm_so; 171dad378bb17f1910014383bf196e87028e98d81d6Rob Landley } else { 172dad378bb17f1910014383bf196e87028e98d81d6Rob Landley if (!rc) break; 17373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley matches.rm_eo = strlen(start); 174dad378bb17f1910014383bf196e87028e98d81d6Rob Landley } 17573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley matches.rm_so = 0; 176dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } else if (rc) break; 1776c64f5f186d26d4c95d408979d33831935e026f1Rob Landley 17836aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley // At least one line we didn't print since match while -ABC active 179b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley if (bars) { 180b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley xputs(bars); 181b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley bars = 0; 182b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley } 183030970bd70e14849b0f2598bfa0982402fc7e2e7Rob Landley mmatch++; 184e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley toys.exitval = 0; 185e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley if (toys.optflags & FLAG_q) xexit(); 186dad378bb17f1910014383bf196e87028e98d81d6Rob Landley if (toys.optflags & FLAG_l) { 187c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley xprintf("%s%c", name, TT.outdelim); 1886c64f5f186d26d4c95d408979d33831935e026f1Rob Landley free(line); 1896c64f5f186d26d4c95d408979d33831935e026f1Rob Landley fclose(file); 1906c64f5f186d26d4c95d408979d33831935e026f1Rob Landley return; 191dad378bb17f1910014383bf196e87028e98d81d6Rob Landley } 192fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley if (toys.optflags & FLAG_o) 19373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (matches.rm_eo == matches.rm_so) 194fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley break; 195fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 1966c64f5f186d26d4c95d408979d33831935e026f1Rob Landley if (!(toys.optflags & FLAG_c)) { 197c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley long bcount = 1 + offset + (start-line) + 198c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley ((toys.optflags & FLAG_o) ? matches.rm_so : 0); 199c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley 200b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley if (!(toys.optflags & FLAG_o)) { 20136aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley while (dlb) { 20236aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley struct double_list *dl = dlist_pop(&dlb); 20336aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley 204c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley outline(dl->data, '-', name, lcount-before, 0, 0); 20536aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley free(dl->data); 20636aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley free(dl); 20736aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley before--; 20836aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley } 20936aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley 210c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley outline(line, ':', name, lcount, bcount, 0); 21136aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley if (TT.a) after = TT.a+1; 212c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley } else outline(start+matches.rm_so, ':', name, lcount, bcount, 213c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley matches.rm_eo-matches.rm_so); 214e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake } 215dad378bb17f1910014383bf196e87028e98d81d6Rob Landley 216dad378bb17f1910014383bf196e87028e98d81d6Rob Landley start += skip; 21773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (!(toys.optflags & FLAG_o)) break; 21873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley } while (*start); 219dad378bb17f1910014383bf196e87028e98d81d6Rob Landley offset += len; 2206c64f5f186d26d4c95d408979d33831935e026f1Rob Landley 221b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley if (mmatch) mcount++; 22236aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley else { 22336aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley int discard = (after || TT.b); 22436aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley 22536aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley if (after && --after) { 226c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley outline(line, '-', name, lcount, 0, 0); 22736aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley discard = 0; 22836aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley } 22936aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley if (discard && TT.b) { 23036aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley dlist_add(&dlb, line); 23136aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley line = 0; 23236aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley if (++before>TT.b) { 23336aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley struct double_list *dl; 23436aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley 23536aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley dl = dlist_pop(&dlb); 23636aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley free(dl->data); 23736aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley free(dl); 23836aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley before--; 23936aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley } else discard = 0; 24036aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley } 241c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley // If we discarded a line while displaying context, show bars before next 242c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley // line (but don't show them now in case that was last match in file) 24336aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley if (discard && mcount) bars = "--"; 244b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley } 245dad378bb17f1910014383bf196e87028e98d81d6Rob Landley free(line); 246dad378bb17f1910014383bf196e87028e98d81d6Rob Landley 247dad378bb17f1910014383bf196e87028e98d81d6Rob Landley if ((toys.optflags & FLAG_m) && mcount >= TT.m) break; 248dad378bb17f1910014383bf196e87028e98d81d6Rob Landley } 249e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 250c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley if (toys.optflags & FLAG_c) outline(0, ':', name, mcount, 0, 0); 251e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 252dad378bb17f1910014383bf196e87028e98d81d6Rob Landley // loopfiles will also close the fd, but this frees an (opaque) struct. 253dad378bb17f1910014383bf196e87028e98d81d6Rob Landley fclose(file); 254e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake} 255e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 256dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landleystatic void parse_regex(void) 257f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{ 25831f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley struct arg_list *al, *new, *list = NULL; 259dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley long len = 0; 260dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley char *s, *ss; 261dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 262dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley // Add all -f lines to -e list. (Yes, this is leaking allocation context for 263dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley // exit to free. Not supporting nofork for this command any time soon.) 26431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley al = TT.f ? TT.f : TT.e; 26531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley while (al) { 266dc3731783ead154d5a0d8d318566468474b43013Rob Landley if (TT.f) s = ss = xreadfile(al->arg, 0, 0); 26731f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley else s = ss = al->arg; 268dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 26973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley // Split lines at \n, add individual lines to new list. 270fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley do { 271dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley ss = strchr(s, '\n'); 27231f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley if (ss) *(ss++) = 0; 27331f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley new = xmalloc(sizeof(struct arg_list)); 27431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley new->next = list; 27531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley new->arg = s; 27631f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley list = new; 277dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley s = ss; 278fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley } while (ss && *s); 27973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley 28073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley // Advance, when we run out of -f switch to -e. 28131f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley al = al->next; 28231f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley if (!al && TT.f) { 28331f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley TT.f = 0; 28431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley al = TT.e; 28531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley } 286e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake } 28731f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley TT.e = list; 288f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley 289dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley if (!(toys.optflags & FLAG_F)) { 290fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley char *regstr; 29173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley int i; 292e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 29331f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley // Convert strings to one big regex 2943ad73e1344afa7812671d08456591b8cde952775William Haddon for (al = TT.e; al; al = al->next) 2953ad73e1344afa7812671d08456591b8cde952775William Haddon len += strlen(al->arg)+1+!(toys.optflags & FLAG_E); 296e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 297fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley regstr = s = xmalloc(len); 298dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley for (al = TT.e; al; al = al->next) { 299dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley s = stpcpy(s, al->arg); 30031f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley if (!(toys.optflags & FLAG_E)) *(s++) = '\\'; 301dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley *(s++) = '|'; 302e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake } 30331f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley *(s-=(1+!(toys.optflags & FLAG_E))) = 0; 304e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 30573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley i = regcomp((regex_t *)toybuf, regstr, 306dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley ((toys.optflags & FLAG_E) ? REG_EXTENDED : 0) | 307dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley ((toys.optflags & FLAG_i) ? REG_ICASE : 0)); 3087b7b284ce4c1bd53d442927d9a570fcf84e0187cStrake 30973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (i) { 31073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley regerror(i, (regex_t *)toybuf, toybuf+sizeof(regex_t), 311dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley sizeof(toybuf)-sizeof(regex_t)); 312dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley error_exit("bad REGEX: %s", toybuf); 313dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } 314e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake } 315e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake} 316e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 317fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landleystatic int do_grep_r(struct dirtree *new) 318fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley{ 319fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley char *name; 320fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 321fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley if (new->parent && !dirtree_notdotdot(new)) return 0; 322fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley if (S_ISDIR(new->st.st_mode)) return DIRTREE_RECURSE; 323fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 324fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley // "grep -r onefile" doesn't show filenames, but "grep -r onedir" should. 325fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley if (new->parent && !(toys.optflags & FLAG_h)) toys.optflags |= FLAG_H; 326fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 327fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley name = dirtree_path(new, 0); 328fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley do_grep(openat(dirtree_parentfd(new), new->name, 0), name); 329fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley free(name); 330fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 331fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley return 0; 332fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley} 333fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 334f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landleyvoid grep_main(void) 335f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{ 336adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley char **ss = toys.optargs; 337fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 33836aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley if (!TT.a) TT.a = TT.c; 33936aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley if (!TT.b) TT.b = TT.c; 34036aed25f3f54f7871d5810adfe99d96944e0afb4Rob Landley 341c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley TT.indelim = '\n' * !(toys.optflags&FLAG_z); 342c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley TT.outdelim = '\n' * !(toys.optflags&FLAG_Z); 343c02619bbc0acbb2b4588933ec1bbb7b7026adbb6Rob Landley 344dad378bb17f1910014383bf196e87028e98d81d6Rob Landley // Handle egrep and fgrep 34573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley if (*toys.which->name == 'e') toys.optflags |= FLAG_E; 346dad378bb17f1910014383bf196e87028e98d81d6Rob Landley if (*toys.which->name == 'f') toys.optflags |= FLAG_F; 3471fa68247345fa6e2cefe4fb4d88ef75f614b18c4M. Farkas-Dyck 348dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley if (!TT.e && !TT.f) { 349adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley if (!*ss) error_exit("no REGEX"); 350dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley TT.e = xzalloc(sizeof(struct arg_list)); 351adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley TT.e->arg = *(ss++); 352dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley toys.optc--; 353dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley } 354dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley 355dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley parse_regex(); 356e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 357fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley if (!(toys.optflags & FLAG_h) && toys.optc>1) toys.optflags |= FLAG_H; 358e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake 359174ba2bed2f33fe90926b08a3e9ec4e3ce7febabStrake toys.exitval = 1; 360dad378bb17f1910014383bf196e87028e98d81d6Rob Landley if (toys.optflags & FLAG_s) { 361dad378bb17f1910014383bf196e87028e98d81d6Rob Landley close(2); 362dad378bb17f1910014383bf196e87028e98d81d6Rob Landley xopen("/dev/null", O_RDWR); 363dad378bb17f1910014383bf196e87028e98d81d6Rob Landley } 364fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley 365fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley if (toys.optflags & FLAG_r) { 36673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley // Iterate through -r arguments. Use "." as default if none provided. 367adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley for (ss = *ss ? ss : (char *[]){".", 0}; *ss; ss++) { 368fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley if (!strcmp(*ss, "-")) do_grep(0, *ss); 369fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley else dirtree_read(*ss, do_grep_r); 370fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley } 37194983f2dddde86e8f121abe97a28aa1f6c87a3dbRob Landley } else loopfiles_rw(ss, O_RDONLY, 0, 1, do_grep); 372e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake} 373