1/************************************************* 2* PCRE grep program * 3*************************************************/ 4 5#include <stdio.h> 6#include <string.h> 7#include <stdlib.h> 8#include <errno.h> 9#include "config.h" 10#include "pcre.h" 11 12#define FALSE 0 13#define TRUE 1 14 15typedef int BOOL; 16 17 18 19/************************************************* 20* Global variables * 21*************************************************/ 22 23static pcre *pattern; 24static pcre_extra *hints; 25 26static BOOL count_only = FALSE; 27static BOOL filenames_only = FALSE; 28static BOOL invert = FALSE; 29static BOOL number = FALSE; 30static BOOL silent = FALSE; 31static BOOL whole_lines = FALSE; 32 33 34 35#if ! HAVE_STRERROR 36/************************************************* 37* Provide strerror() for non-ANSI libraries * 38*************************************************/ 39 40/* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror() 41in their libraries, but can provide the same facility by this simple 42alternative function. */ 43 44extern int sys_nerr; 45extern char *sys_errlist[]; 46 47char * 48strerror(int n) 49{ 50if (n < 0 || n >= sys_nerr) return "unknown error number"; 51return sys_errlist[n]; 52} 53#endif /* HAVE_STRERROR */ 54 55 56 57/************************************************* 58* Grep an individual file * 59*************************************************/ 60 61static int 62pgrep(FILE *in, char *name) 63{ 64int rc = 1; 65int linenumber = 0; 66int count = 0; 67int offsets[99]; 68char buffer[BUFSIZ]; 69 70while (fgets(buffer, sizeof(buffer), in) != NULL) 71 { 72 BOOL match; 73 int length = (int)strlen(buffer); 74 if (length > 0 && buffer[length-1] == '\n') buffer[--length] = 0; 75 linenumber++; 76 77 match = pcre_exec(pattern, hints, buffer, length, 0, 0, offsets, 99) >= 0; 78 if (match && whole_lines && offsets[1] != length) match = FALSE; 79 80 if (match != invert) 81 { 82 if (count_only) count++; 83 84 else if (filenames_only) 85 { 86 fprintf(stdout, "%s\n", (name == NULL)? "<stdin>" : name); 87 return 0; 88 } 89 90 else if (silent) return 0; 91 92 else 93 { 94 if (name != NULL) fprintf(stdout, "%s:", name); 95 if (number) fprintf(stdout, "%d:", linenumber); 96 fprintf(stdout, "%s\n", buffer); 97 } 98 99 rc = 0; 100 } 101 } 102 103if (count_only) 104 { 105 if (name != NULL) fprintf(stdout, "%s:", name); 106 fprintf(stdout, "%d\n", count); 107 } 108 109return rc; 110} 111 112 113 114 115/************************************************* 116* Usage function * 117*************************************************/ 118 119static int 120usage(int rc) 121{ 122fprintf(stderr, "Usage: pgrep [-Vchilnsvx] pattern [file] ...\n"); 123return rc; 124} 125 126 127 128 129/************************************************* 130* Main program * 131*************************************************/ 132 133int 134main(int argc, char **argv) 135{ 136int i; 137int rc = 1; 138int options = 0; 139int errptr; 140const char *error; 141BOOL filenames = TRUE; 142 143/* Process the options */ 144 145for (i = 1; i < argc; i++) 146 { 147 char *s; 148 if (argv[i][0] != '-') break; 149 s = argv[i] + 1; 150 while (*s != 0) 151 { 152 switch (*s++) 153 { 154 case 'c': count_only = TRUE; break; 155 case 'h': filenames = FALSE; break; 156 case 'i': options |= PCRE_CASELESS; break; 157 case 'l': filenames_only = TRUE; 158 case 'n': number = TRUE; break; 159 case 's': silent = TRUE; break; 160 case 'v': invert = TRUE; break; 161 case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break; 162 163 case 'V': 164 fprintf(stderr, "PCRE version %s\n", pcre_version()); 165 break; 166 167 default: 168 fprintf(stderr, "pgrep: unknown option %c\n", s[-1]); 169 return usage(2); 170 } 171 } 172 } 173 174/* There must be at least a regexp argument */ 175 176if (i >= argc) return usage(0); 177 178/* Compile the regular expression. */ 179 180pattern = pcre_compile(argv[i++], options, &error, &errptr, NULL); 181if (pattern == NULL) 182 { 183 fprintf(stderr, "pgrep: error in regex at offset %d: %s\n", errptr, error); 184 return 2; 185 } 186 187/* Study the regular expression, as we will be running it may times */ 188 189hints = pcre_study(pattern, 0, &error); 190if (error != NULL) 191 { 192 fprintf(stderr, "pgrep: error while studing regex: %s\n", error); 193 return 2; 194 } 195 196/* If there are no further arguments, do the business on stdin and exit */ 197 198if (i >= argc) return pgrep(stdin, NULL); 199 200/* Otherwise, work through the remaining arguments as files. If there is only 201one, don't give its name on the output. */ 202 203if (i == argc - 1) filenames = FALSE; 204if (filenames_only) filenames = TRUE; 205 206for (; i < argc; i++) 207 { 208 FILE *in = fopen(argv[i], "r"); 209 if (in == NULL) 210 { 211 fprintf(stderr, "%s: failed to open: %s\n", argv[i], strerror(errno)); 212 rc = 2; 213 } 214 else 215 { 216 int frc = pgrep(in, filenames? argv[i] : NULL); 217 if (frc == 0 && rc == 1) rc = 0; 218 fclose(in); 219 } 220 } 221 222return rc; 223} 224 225/* End */ 226