1 /*
2   jargrep.c - main functions for jargrep utility
3   Copyright (C) 2002, 2003, 2006 Free Software Foundation
4   Copyright (C) 1999, 2000 Bryan Burns
5   Copyright (C) 2000 Cory Hollingsworth
6 
7   Parts of this program are base on Bryan Burns work with fastjar
8   Copyright (C) 1999.
9 
10   This program is free software; you can redistribute it and/or
11   modify it under the terms of the GNU General Public License
12   as published by the Free Software Foundation; either version 2
13   of the License, or (at your option) any later version.
14 
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19 
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23 */
24 
25 /* Id: jargrep.c,v 1.5 2002/01/03 04:57:56 rodrigc Exp
26 
27 Log: jargrep.c,v
28 Revision 1.5  2002/01/03 04:57:56  rodrigc
29 2001-01-02  Craig Rodrigues  <rodrigc@gcc.gnu.org>
30 
31         PR bootstrap/5117
32         * configure.in (AC_CHECK_HEADERS): Check for stdlib.h.
33         * Makefile.am: Move grepjar to bin_PROGRAMS.
34         * config.h.in: Regenerated.
35         * Makefile.in: Regenerated.
36         * aclocal.m4: Regenerated.
37         * jargrep.c: Eliminate some signed/unsigned and default
38         uninitialized warnings. Use HAVE_STDLIB_H instead of
39         STDC_HEADERS macro.
40         * jartool.c: Likewise.
41         * compress.c: Likewise.
42 
43 Revision 1.4  2000/12/15 18:45:09  tromey
44 	* jargrep.c: Include getopt.h if it exists.
45 	(optind): Declare.
46 	* configure, config.h: Rebuilt.
47 	* configure.in: Check for getopt.h.
48 
49 Revision 1.3  2000/12/14 18:45:35  ghazi
50 Warning fixes:
51 
52 	* compress.c: Include stdlib.h and compress.h.
53 	(rcsid): Delete.
54 	(report_str_error): Make static.
55 	(ez_inflate_str): Delete unused variable.  Add parens in if-stmt.
56 	(hrd_inflate_str): Likewise.
57 
58 	* compress.h (init_compression, end_compression, init_inflation,
59 	end_inflation): Prototype void arguments.
60 
61 	* dostime.c (rcsid): Delete.
62 
63 	* jargrep.c: Include ctype.h, stdlib.h, zlib.h and compress.h.
64 	Make functions static.  Cast ctype function argument to `unsigned
65 	char'.  Add parens in if-stmts.  Constify.
66 	(Usage): Change into a macro.
67 	(jargrep): Remove unused parameter.
68 
69 	* jartool.c: Constify.  Add parens in if-stmts.  Align
70 	signed/unsigned char pointers in functions calls using casts.
71 	(rcsid): Delete.
72 	(list_jar): Fix printf format specifier.
73 	(usage): Chop long string into bits.  Reformat.
74 
75 	* pushback.c (rcsid): Delete.
76 
77 Revision 1.2  2000/12/11 02:59:55  apbianco
78 2000-12-10  Robert Lipe <robertlipe@usa.net>
79 
80 	* jargrep.c (jargrep): Added null statement after case.
81 
82 2000-12-10  Alexandre Petit-Bianco  <apbianco@cygnus.com>
83 
84 	* Makefile: Removed.
85 	* Makefile.in: Rebuilt with `-i' and `--enable-foreign'.
86 
87 (http://gcc.gnu.org/ml/gcc/2000-12/msg00294.html)
88 
89 Revision 1.1  2000/12/09 03:08:23  apbianco
90 2000-12-08  Alexandre Petit-Bianco  <apbianco@cygnus.com>
91 
92         * fastjar: Imported.
93 
94 Revision 1.8  2000/09/13 14:02:02  cory
95 Reformatted some of the code to more closly match the layout of the orriginal
96 fastjar utility.
97 
98 Revision 1.7  2000/09/12 22:29:36  cory
99 Jargrep now seems to do what I want it to do.  Performs properly on Linux x86,
100 will test some other platforms later.
101 
102 
103 */
104 
105 #include "config.h"
106 #include <stdio.h>
107 #include <unistd.h>
108 #include <errno.h>
109 #include <string.h>
110 #include <sys/types.h>
111 #include <sys/stat.h>
112 #include <fcntl.h>
113 #include <ctype.h>
114 #ifdef HAVE_STDLIB_H
115 #include <stdlib.h>
116 #endif
117 
118 #include "regex.h"
119 
120 #include "jargrep.h"
121 #include "jartool.h"
122 #include "pushback.h"
123 #include "zipfile.h"
124 #include "zlib.h"
125 #include "compress.h"
126 #include <getopt.h>
127 
128 void version(void);
129 void help(const char *name);
130 
131 #define Usage "Usage: %s [-bcinsVw] [--version|--help] <-e PATTERN | PATTERN> FILE ...\n"
132 
133 /*
134 Function name: opt_valid
135 arg:	options	Bitfield flag that contains the command line options of grepjar.
136 purpose:	To guard agains the occurance of certain incompatible flags being used
137 together.
138 returns: TRUE if options are valid, FALSE otherwise.
139 */
140 
opt_valid(int options)141 static int opt_valid(int options) {
142 	int retflag;
143 
144 	if((options & JG_PRINT_COUNT) &&
145 		(options & (JG_PRINT_BYTEOFFSET | JG_PRINT_LINE_NUMBER)))
146 	{
147 		retflag = FALSE;
148 	}
149 	else retflag = TRUE;
150 
151 	return retflag;
152 }
153 
154 /*
155 Function name: create_regexp
156 args:	regstr	String containing the uncompiled regular expression.  This may be the
157 				expression as is passed in through argv.
158 		options	This is the flag containing the commandline options that have been
159 				parsed by getopt.
160 purpose: Handle the exception handling involved with setting upt a new regular
161 expression.
162 returns: Newly allocated compile regular expression ready to be used in an regexec call.
163 */
164 
create_regexp(const char * regstr,int options)165 static regex_t *create_regexp(const char *regstr, int options) {
166 	regex_t *exp;
167 	int errcode;
168 	int msgsize;
169 	char *errmsg;
170 
171 	if((exp = (regex_t *) malloc(sizeof(regex_t))))
172 	{
173 		if((errcode = regcomp(exp, regstr, (options & JG_IGNORE_CASE) ? REG_ICASE : 0))) {
174 			fprintf(stderr, "regcomp of regex failed,\n");
175 			if((errmsg = (char *) malloc(msgsize = regerror(errcode, exp, NULL, 0) + 1))) {
176 				regerror(errcode, exp, errmsg, msgsize);
177 				fprintf(stderr, "Error: %s\n", errmsg);
178 				free(exp);
179 				free(errmsg);
180 				exit(1);
181 			}
182 			else {
183 				fprintf(stderr, "Malloc of errmsg failed.\n");
184 				fprintf(stderr, "Error: %s\n", strerror(errno));
185 				free(exp);
186 				exit(1);
187 			}
188 		}
189 	}
190 	else {
191 		fprintf(stderr, "Malloc of regex failed,\n");
192 		fprintf(stderr, "Error: %s\n", strerror(errno));
193 		exit(1);
194 	}
195 
196 	return exp;
197 }
198 
199 /*
200 Function name: check_sig
201 args:	scratch	Pointer to array of bytes containing signature.
202 		pbf		Pointer to push back handle for jar file.
203 purpose: 	Verify that checksum is correct.
204 returns: 0, 1, or 2.  0 means we are ready to read embedded file information.  1 means
205 we have read beyound the embedded file list and can exit knowing we have read all the
206 relevent information.  2 means we still haven't reached embdedded file list and need to
207 do some more reading.
208 */
check_sig(ub1 * scratch,pb_file * pbfp)209 static int check_sig(ub1 *scratch, pb_file *pbfp) {
210 	ub4 signature;
211 	int retflag = 0;
212 
213 	signature = UNPACK_UB4(scratch, 0);
214 
215 #ifdef DEBUG
216     printf("signature is %x\n", signature);
217 #endif
218     if(signature == 0x08074b50){
219 #ifdef DEBUG
220       printf("skipping data descriptor\n");
221 #endif
222       pb_read(pbfp, scratch, 12);
223       retflag = 2;
224     } else if(signature == 0x02014b50){
225 #ifdef DEBUG
226       printf("Central header reached.. we're all done!\n");
227 #endif
228       retflag = 1;
229     }else if(signature != 0x04034b50){
230       printf("Ick! %#x\n", signature);
231       retflag = 1;
232     }
233 
234 	return retflag;
235 }
236 
237 /*
238 Function name: decd_siz
239 args	csize		Pointer to embedded file's compressed size.
240 		usize		Pointer to embedded file's uncmpressed size.
241 		fnlen		Pointer to embedded file's file name length.
242 		elfen		Pointer to length of extra fields in jar file.
243 		flags		Pointer to bitmapped flags.
244 		method		Pointer to indicator of storage method of embedded file.
245 		file_header	Pointer to string containing the above values to be unbacked.
246 Purpose: Unpack the series of values from file_header.
247 */
248 
decd_siz(ub4 * csize,ub4 * usize,ub2 * fnlen,ub2 * eflen,ub2 * flags,ub2 * method,ub1 * file_header)249 static void decd_siz(ub4 *csize, ub4 *usize, ub2 *fnlen, ub2 *eflen, ub2 *flags, ub2 *method, ub1 *file_header) {
250     *csize = UNPACK_UB4(file_header, LOC_CSIZE);
251 #ifdef DEBUG
252     printf("Compressed size is %u\n", *csize);
253 #endif
254 
255 	*usize = UNPACK_UB4(file_header, LOC_USIZE);
256 #ifdef DEBUG
257 	printf("Uncompressed size is %u\n", *usize);
258 #endif
259 
260     *fnlen = UNPACK_UB2(file_header, LOC_FNLEN);
261 #ifdef DEBUG
262     printf("Filename length is %hu\n", *fnlen);
263 #endif
264 
265     *eflen = UNPACK_UB2(file_header, LOC_EFLEN);
266 #ifdef DEBUG
267     printf("Extra field length is %hu\n", *eflen);
268 #endif
269 
270     *flags = UNPACK_UB2(file_header, LOC_EXTRA);
271 #ifdef DEBUG
272     printf("Flags are %#hx\n", *flags);
273 #endif
274 
275     *method = UNPACK_UB2(file_header, LOC_COMP);
276 #ifdef DEBUG
277     printf("Compression method is %#hx\n", *method);
278 #endif
279 
280 }
281 
282 /*
283 Function name: new_filename
284 args:	pbf		Pointer to push back file handle.  Used for reading input file.
285 		len		Length of file name to be read.
286 purpose:	Read in the embedded file name from jar file.
287 returns: Pointer to newly allocated string containing file name.
288 */
289 
new_filename(pb_file * pbf,ub4 len)290 static char *new_filename(pb_file *pbf, ub4 len) {
291 	char *filename;
292 
293 	if(!(filename = (char *) malloc(len + 1))) {
294 		fprintf(stderr, "Malloc failed of filename\n");
295 		fprintf(stderr, "Error: %s\n", strerror(errno));
296 	}
297     pb_read(pbf, filename, len);
298     filename[len] = '\0';
299 
300 #ifdef DEBUG
301     printf("filename is %s\n", filename);
302 #endif
303 
304 	return filename;
305 }
306 
307 /*
308 Funtion name: read_string
309 args:	pbf		Pointer to push back file handle.  Used for reading input file.
310 		size	Size of embedded file in bytes.
311 purpose:	Create a string containing the contents of the embedded noncompressed file.
312 returns: Pointer to newly allocated string containing embedded file contents.
313 */
314 
read_string(pb_file * pbf,int size)315 static char *read_string(pb_file *pbf, int size) {
316 	char *page;
317 
318 	if((page = (char *) malloc(size + 1))) {
319 		pb_read(pbf, page, size);
320 		page[size] = '\0';
321 	}
322 	else {
323 		fprintf(stderr, "Malloc of page buffer failed.\n");
324 		fprintf(stderr, "Error: %s\n", strerror(errno));
325 		exit(1);
326 	}
327 
328 	return page;
329 }
330 
331 /*
332 Function name: extract_line
333 args:	stream	String containing the full contents of a file which is to be substringed
334 				in order to provide line representing our grep output.
335 		begin	Index into stream which regular expression first matches.
336 		end		Index into stream which end of match to the regular expression.
337 		b		Pointer to the index of what will be the beginning of the line when
338 				string is returned.  Used for -b option.
339 purpose:	Create a string that can be printed by jargrep from the long string stream.
340 The matching line that is printed out by jargrep is generated by this function.
341 returns: Pointer to newly allocated string containing matched expression.
342 */
343 
extract_line(const char * stream,regoff_t begin,regoff_t end,int * b)344 static char *extract_line(const char *stream, regoff_t begin, regoff_t end, int *b) {
345 	int e;
346 	int length;
347 	char *retstr;
348 
349 	for(*b = begin; *b >= 0 && !iscntrl((unsigned char)stream[*b]); (*b)--);
350 	(*b)++;
351 	for(e = end; stream[e] == '\t' || !iscntrl((unsigned char)stream[e]); e++);
352 	length = e - *b;
353 	if((retstr = (char *) malloc(length + 1))) {
354 		sprintf(retstr, "%d:", *b);
355 		strncpy(retstr, &(stream[*b]), length);
356 		retstr[length] = '\0';
357 	}
358 	else {
359 		fprintf(stderr, "Malloc failed of output string.\n");
360 		fprintf(stderr, "Error: %s\n", strerror(errno));
361 		exit(1);
362 	}
363 
364 	return retstr;
365 }
366 
367 /*
368 Function name: chk_wrd
369 args:	exp		Pointer to compiled POSIX style regular expression of search target.
370 		str		String known to contain at least one match of exp.
371 purpose: Verify that the occurance of the regular expression in str occurs as a whole
372 word and not a substring of another word.
373 returns: TRUE if it is a word, FALSE of it is a substring.
374 */
375 
chk_wrd(regex_t * exp,const char * str)376 static int chk_wrd(regex_t *exp, const char *str) {
377 	int wrd_fnd = FALSE;
378 	int frnt_ok;
379 	int bck_ok;
380 	const char *str2;
381 	regmatch_t match;
382 
383 	str2 = str;
384 	frnt_ok = bck_ok = FALSE;
385 	while(!wrd_fnd && !regexec(exp, str2, 1, &match, 0)) {
386 		if(!match.rm_so && (str2 == str)) frnt_ok = TRUE;
387 		else if(!isalnum((unsigned char)str2[match.rm_so - 1])
388 			&& str2[match.rm_so - 1] != '_')
389 			frnt_ok = TRUE;
390 		else frnt_ok = FALSE;
391 		if(frnt_ok) {
392 			if(str2[match.rm_eo] == '\0') bck_ok = TRUE;
393 			else if(!isalnum((unsigned char)str2[match.rm_eo])
394 				&& str2[match.rm_eo] != '_')
395 				bck_ok = TRUE;
396 			else bck_ok = FALSE;
397 		}
398 		wrd_fnd = frnt_ok && bck_ok;
399 		str2 = &(str2[match.rm_eo]);
400 	}
401 
402 	return wrd_fnd;
403 }
404 
405 /*
406 Function name: prnt_mtchs
407 args:	exp			Pointer to compiled POSIX style regular expression of search target.
408 		filename	String containing the name of the embedded file which matches have
409 					been found in.
410 		stream		String containing the processed contents of the embedded jar file
411 					represended with filename.
412 		pmatch		Array of regmatch_t matches into stream.
413 		nl_offset	Array of offsets of '\n' characters in stream.  May be NULL if -n is
414 					not set on command line.
415 		num			Number of matches in pmatch array.
416 		lines		Number of lines in file.  Not set if -n is not set on command line.
417 		options		Bitwise flag containing flags set to represent the command line
418 					options.
419 purpose:	Control output of jargrep.  Output is controlled by which options have been
420 set at the command line.
421 */
422 
prnt_mtchs(regex_t * exp,const char * filename,const char * stream,regmatch_t * pmatch,regmatch_t * nl_offset,int num,int lines,int options)423 static void prnt_mtchs(regex_t *exp, const char *filename, const char *stream, regmatch_t *pmatch, regmatch_t *nl_offset, int num, int lines, int options) {
424 	int i;
425 	int j = 0;
426 	int ln_cnt;
427 	int begin;
428 	int o_begin;
429 	char *str;
430 
431 	o_begin = -1;
432 	ln_cnt = 0;
433 	for(i = 0; i < num; i++) {
434 		str = extract_line(stream, pmatch[i].rm_so, pmatch[i].rm_eo, &begin);
435 		if(begin > o_begin) {
436 			if(!(options & JG_WORD_EXPRESSIONS) || chk_wrd(exp, str)) {
437 				ln_cnt++;
438 				if(!(options & JG_PRINT_COUNT)) {
439 					printf("%s:", filename);
440 					if(options & JG_PRINT_LINE_NUMBER) {
441 						for(; j < lines && nl_offset[j].rm_so < begin; j++);
442 						printf("%d:", j + 1);
443 					}
444 					if(options & JG_PRINT_BYTEOFFSET) printf("%d:", begin);
445 					printf("%s\n", str);
446 				}
447 			}
448 		}
449 		o_begin = begin;
450 		free(str);
451 	}
452 	if(options & JG_PRINT_COUNT) printf("%s:%d\n", filename, ln_cnt);
453 }
454 
455 /*
456 Function name: check_crc
457 args:	pbf		Pointer to pushback file pointer for jar file.
458 		stream	String containing the non modified contents fo the extraced file entry.
459 		usize	Size of file in bytes.
460 purpose:	Verify the CRC matches that as what is stored in the jar file.
461 */
462 
check_crc(pb_file * pbf,const char * stream,ub4 usize)463 static void check_crc(pb_file *pbf, const char *stream, ub4 usize) {
464 	ub4 crc=0;
465 	ub4 lcrc;
466 	ub1 scratch[16];
467 
468 	crc = crc32(crc, NULL, 0);
469 	crc = crc32(crc, (const unsigned char *)stream, usize);
470 	if(pb_read(pbf, scratch, 16) != 16) {
471 		perror("read");
472         exit(1);
473 	}
474 	if(UNPACK_UB4(scratch, 0) != 0x08074b50) {
475 		fprintf(stderr, "Error! Missing data descriptor!\n");
476 		exit(1);
477 	}
478 	lcrc = UNPACK_UB4(scratch, 4);
479 	if(crc != lcrc){
480     	fprintf(stderr, "Error! CRCs do not match! Got %x, expected %x\n",
481               crc, lcrc);
482       	exit(1);
483     }
484 }
485 
486 /*
487 Function name mk_ascii
488 args:	stream	String that contains the contents of the extraced file entry.
489 		usize	String size.
490 purpose:	Make certain that the contents of the file are ASCII, not binary.  This
491 permits grepping of binary files as well by converting non ASCII and control characters
492 into '\n'.
493 */
494 
mk_ascii(char * stream,size_t usize)495 static void mk_ascii(char *stream, size_t usize) {
496 	size_t i;
497 
498 	for(i = 0; i < usize; i++)
499 		if(stream[i] != '\t'
500 		   && (iscntrl((unsigned char)stream[i])
501 		       || (unsigned char) stream[i] >= 128))
502 			stream[i] = '\n';
503 }
504 
505 /*
506 Funtion name: fnd_match
507 args:	exp			Pointer to compiled POSIX style regular expression of search target.
508 		str_stream	String that contains the contents of the extracted file entry.
509 		i			Pointer to counter and index of matches.
510 purpose:	Search str_stream for occurances of the regular expression exp and create
511 an array of matches.
512 returns:  Pointer to newly allocated array of regmatch_t which gives indexes to start
513 and end of matches.  NULL is returned upon no matches found.
514 */
515 
fnd_match(regex_t * exp,const char * str_stream,int * i)516 static regmatch_t *fnd_match(regex_t *exp, const char *str_stream, int *i) {
517 	int regflag;
518 	regmatch_t match;
519 	regmatch_t *match_array;
520 	regmatch_t *tmp;
521 
522 	match_array = NULL;
523 	for(*i = 0, regflag = regexec(exp, str_stream, 1, &match, 0); !regflag;
524 		regflag = regexec(exp, &(str_stream[match.rm_eo]), 1, &match, 0), (*i)++)
525 	{
526 		if((tmp = (regmatch_t *)
527 		    realloc(match_array, sizeof(regmatch_t) * ((*i) + 1))))
528 		{
529 			match_array = tmp;
530 			if(*i) {
531 				match.rm_so += match_array[(*i) - 1].rm_eo;
532 				match.rm_eo += match_array[(*i) - 1].rm_eo;
533 			}
534 			match_array[*i] = match;
535 		}
536 		else {
537 			fprintf(stderr, "Realloc of match_array failed.\n");
538 			fprintf(stderr, "Error: %s\n", strerror(errno));
539 			exit(1);
540 		}
541 	}
542 
543 	return match_array;
544 }
545 
546 /*
547 Function name: cont_grep
548 args:	exp		Pointer to compiled POSIX style regular expression of search target.
549 		nl_exp	Pointer to compiled POSIX style regular expression of newlines.  This
550 				argument is NULL unless the -n option is used on the command line.
551 		fd		File descriptor of the jar file being grepped.
552 		pbf		Pointer to pushback file style file stream.  This is for use with
553 				the pushback.c file io funtions.
554 		options	Bitwise flag containing flags set to represent the command line options.
555 purpose:	This function handles single entries in an open jar file.  The header is
556 read and then the embeded file is extracted and grepped.
557 returns: FALSE upon failure, TRUE otherwise.
558 */
559 
cont_grep(regex_t * exp,regex_t * nl_exp,int fd,pb_file * pbf,int options)560 static int cont_grep(regex_t *exp, regex_t *nl_exp, int fd, pb_file *pbf, int options) {
561 	int retflag = TRUE;
562 	int i;
563 	int j;
564 	ub4 csize;
565 	ub4 usize;
566 	ub2 fnlen;
567 	ub2 eflen;
568 	ub2 flags;
569 	ub2 method;
570 	ub1 file_header[30];
571 	char *filename;
572 	char *str_stream;
573 	regmatch_t *match_array;
574 	regmatch_t *nl_offsets=0;
575 
576 	if(pb_read(pbf, (file_header + 4), 26) != 26) {
577 		perror("read");
578 		retflag = FALSE;
579    	}
580 	else {
581 		decd_siz(&csize, &usize, &fnlen, &eflen, &flags, &method, file_header);
582 		filename = new_filename(pbf, fnlen);
583 		lseek(fd, eflen, SEEK_CUR);
584 		if(filename[fnlen - 1] != '/') {
585 			str_stream = (method == 8 || (flags & 0x0008)) ?
586 				(char *) inflate_string(pbf, &csize, &usize) :
587 					read_string(pbf, csize);
588 			if(flags & 0x008) check_crc(pbf, str_stream, usize);
589 			mk_ascii(str_stream, usize);
590 			match_array = fnd_match(exp, str_stream, &i);
591 			if((options & JG_PRINT_LINE_NUMBER) && i)
592 				nl_offsets = fnd_match(nl_exp, str_stream, &j);
593 			prnt_mtchs(exp, filename, str_stream, match_array, nl_offsets, i, j, options);
594 			if(match_array) free(match_array);
595 			free(str_stream);
596 		}
597 		free(filename);
598 		retflag = TRUE;
599 	}
600 
601 	return retflag;
602 }
603 
604 /*
605 Funtion name: jargrep
606 args:	exp		Pointer to compiled POSIX style regular expression of search target.
607 		nl_exp	Pointer to compiled regular expression for newlines or NULL.  Only set
608 				if -n option is present at command line.
609 		jarfile	Filename of jar file to be searched.
610 		options	Bitwise flag containing flags set to represent the command line options.
611 purpose:	Open jar file.  Check signatures.  When right signature is found go to deeper
612 grep routine.
613 */
614 
jargrep(regex_t * exp,regex_t * nl_exp,const char * jarfile,int options)615 static void jargrep(regex_t *exp, regex_t *nl_exp, const char *jarfile, int options){
616 	int fd;
617 	int floop = TRUE;
618 	pb_file pbf;
619 	ub1 scratch[16];
620 
621 	if((fd = open(jarfile, O_RDONLY)) == -1) {
622 		if(!(options & JG_SUPRESS_ERROR))
623 			fprintf(stderr, "Error reading file '%s': %s\n", jarfile, strerror(errno));
624 	}
625 	else {
626 		pb_init(&pbf, fd);
627 
628 		do {
629 			if(pb_read(&pbf, scratch, 4) != 4) {
630 				perror("read");
631 				floop = FALSE;
632 			}
633 			else {
634 				switch (check_sig(scratch, &pbf)) {
635 				case 0:
636 					floop = cont_grep(exp, nl_exp, fd, &pbf, options);
637 					break;
638 				case 1:
639 					floop = FALSE;
640 					break;
641 				case 2:
642 					/* fall through continue */
643 					;
644 				}
645 			}
646 		} while(floop);
647 	}
648 }
649 
650 /* This is used to mark options with no short value.  */
651 #define LONG_OPT(Num)  ((Num) + 128)
652 
653 #define OPT_HELP     LONG_OPT (0)
654 
655 static const struct option option_vec[] =
656 {
657   { "help", no_argument, NULL, OPT_HELP },
658   { "version", no_argument, NULL, 'V' },
659   { NULL, no_argument, NULL, 0 }
660 };
661 
662 /*
663 Funtion Name: main
664 args:	argc	number of in coming args.
665 		argv	array of strings.
666 purpose: Entry point of the program.  Parse command line arguments and set options.
667 Set up regular expressions.  Call grep routines for each file as input.
668 returns: 1 on error 0 on success.
669 */
670 
main(int argc,char ** argv)671 int main(int argc, char **argv) {
672 	int c;
673 	int retval = 0;
674 	int fileindex;
675 	int options = 0;
676 	regex_t *regexp;
677 	regex_t *nl_exp = NULL;
678 	char *regexpstr = NULL;
679 
680 	while((c = getopt_long(argc, argv, "bce:insVw",
681 			       option_vec, NULL)) != -1) {
682 		switch(c) {
683 			case 'b':
684 				options |= JG_PRINT_BYTEOFFSET;
685 				break;
686 			case 'c':
687 				options |= JG_PRINT_COUNT;
688 				break;
689 			case 'e':
690 				if(!(regexpstr = (char *) malloc(strlen(optarg) + 1))) {
691 					fprintf(stderr, "Malloc failure.\n");
692 					fprintf(stderr, "Error: %s\n", strerror(errno));
693 					exit(1);
694 				}
695 				strcpy(regexpstr, optarg);
696 				break;
697 			case 'i':
698 				options |= JG_IGNORE_CASE;
699 				break;
700 			case 'n':
701 				options |= JG_PRINT_LINE_NUMBER;
702 				break;
703 			case 's':
704 				options |= JG_SUPRESS_ERROR;
705 				break;
706 			case 'v':
707 				options |= JG_INVERT;
708 				break;
709 			case 'V':
710 				version ();
711 				break;
712 			case 'w':
713 				options |= JG_WORD_EXPRESSIONS;
714 				break;
715 			case OPT_HELP:
716 				help(argv[0]);
717 				break;
718 			default:
719 				fprintf(stderr, Usage, argv[0]);
720 				exit(1);
721 		}
722 	}
723 	if(!regexpstr){
724 		if(((argc - optind) >= 2)) {
725 			regexpstr = argv[optind];
726 			fileindex = optind + 1;
727 		}
728 		else {
729 			fprintf(stderr, "Invalid arguments.\n");
730 			fprintf(stderr, Usage, argv[0]);
731 			exit(1);
732 		}
733 	}
734 	else if((argc - optind) == 1) {
735 		fileindex = optind;
736 	}
737 	else {
738 		fprintf(stderr, "Invalid arguments.\n");
739 		fprintf(stderr, Usage, argv[0]);
740 		exit(1);
741 	}
742 
743 	if(opt_valid(options)) {
744 		regexp = create_regexp(regexpstr, options);
745 		if(options & JG_PRINT_LINE_NUMBER) nl_exp = create_regexp("\n", 0);
746 		init_inflation();
747 		for(; fileindex < argc; fileindex++)
748 			jargrep(regexp, nl_exp, argv[fileindex], options);
749 		regfree(regexp);
750 		if(options & JG_PRINT_LINE_NUMBER) regfree(nl_exp);
751 	}
752 	else {
753 		retval = 1;
754 		fprintf(stderr, "Error: Invalid combination of options.\n");
755 	}
756 
757 	return retval;
758 }
759 
help(const char * filename)760 void help(const char *filename)
761 {
762   printf (Usage, filename);
763   printf ("\
764 \n\
765 Search files in a jar file for a pattern.\n\
766 \n\
767    -b                print byte offset of match\n\
768    -c                print number of matches\n\
769    -i                compare case-insensitively\n\
770    -n                print line number of each match\n\
771    -s                suppress error messages\n\
772    -w                force PATTERN to match only whole words\n\
773    -e PATTERN        use PATTERN as regular expression\n\
774    -V|--version      print version number and exit\n\
775    --help            print help\n\
776 ");
777 
778   exit (0);
779 }
780 
version()781 void version ()
782 {
783   printf("grepjar (%s) %s\n\n", PACKAGE, VERSION);
784   printf("Copyright 1999, 2000, 2001  Bryan Burns\n");
785   printf("Copyright 2000 Cory Hollingsworth\n");
786   printf("Copyright 2006 Free Software Foundation\n");
787   printf("\
788 This is free software; see the source for copying conditions.  There is NO\n\
789 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
790   exit (0);
791 }
792