1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 /* All Java Virtual Machine Specs are from
25 * "The Java Virtual Machine Specification", T. Lindholm, F. Yellin
26 * (JVMS)
27 */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <limits.h>
36
37 #if defined(UNX) || defined(OS2)
38 #include <unistd.h>
39 #include <netinet/in.h> /* ntohl(), ntohs() */
40 #elif defined(WNT)
41 #include <io.h>
42 #define access _access
43 #define vsnprintf _vsnprintf
44 #define CDECL _cdecl
45 #define F_OK 00
46 #define PATH_MAX _MAX_PATH
47 #define ntohl(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
48 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
49
50 #define ntohs(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
51 #endif
52
53 #if defined(OS2)
54 #define CDECL
55 #endif
56
57 /* max. length of line in response file */
58 #define RES_FILE_BUF 65536
59
60 struct file {
61 char *pname;
62 FILE *pfs;
63 };
64
65 struct growable {
66 int ncur;
67 int nmax;
68 char **parray;
69 };
70
71 typedef struct file file_t;
72 typedef unsigned char uint8;
73 typedef unsigned short uint16;
74 typedef unsigned int uint32;
75
76 struct utf8 {
77 uint16 nlen;
78 void *pdata;
79 };
80
81 typedef struct utf8 utf8_t;
82
83 /* The contents of the Constant_pool is described in JVMS p. 93
84 */
85 enum {
86 CONSTANT_Class = 7,
87 CONSTANT_Fieldref = 9,
88 CONSTANT_Methodref = 10,
89 CONSTANT_InterfaceMethodref = 11,
90 CONSTANT_String = 8,
91 CONSTANT_Integer = 3,
92 CONSTANT_Float = 4,
93 CONSTANT_Long = 5,
94 CONSTANT_Double = 6,
95 CONSTANT_NameAndType = 12,
96 CONSTANT_Utf8 = 1
97 };
98
99 enum { NGROW_INIT = 10, NGROW = 2 };
100
101 static char *pprogname = "javadep";
102 static char csep = ';';
103 #if defined (UNX) || defined(OS2)
104 #define CDECL
105 static char cpathsep = '/';
106 #elif defined (WNT) || defined(OS2)
107 static char cpathsep = '\\';
108 #endif
109 static FILE *pfsout = NULL;
110 static char *pout_file = NULL;
111
112
113 /* prototypes */
114 uint8 read_uint8(const file_t *pfile);
115 uint16 read_uint16(const file_t *pfile);
116 uint32 read_uint32(const file_t *pfile);
117 void skip_bytes(const file_t *pfile, const size_t nnum);
118 char *escape_slash(const char *pstr);
119 int is_inner(const char *pstr);
120 void print_dependencies(const struct growable *pdep,
121 const char* pclass_file);
122 void process_class_file(const char *pfilenamem,
123 const struct growable *pfilt);
124 char *utf8tolatin1(const utf8_t a_utf8);
125 void *xmalloc(size_t size);
126 void *xcalloc(size_t nmemb, size_t size);
127 void *xrealloc(void *ptr, size_t size);
128 void grow_if_needed (struct growable *pgrow);
129 int append_to_growable(struct growable *, char *);
130 struct growable *allocate_growable(void);
131 void free_growable(struct growable *pgrowvoid);
132 void create_filters(struct growable *pfilt, const struct growable *pinc);
133 void usage(void);
134 void err_quit(const char *, ...);
135 void silent_quit(void);
136
137 #ifdef WNT
138 /* poor man's getopt() */
139 int simple_getopt(char *pargv[], const char *poptstring);
140 char *optarg = NULL;
141 int optind = 1;
142 int optopt = 0;
143 int opterr = 0;
144 #endif
145
146 uint8
read_uint8(const file_t * pfile)147 read_uint8(const file_t *pfile)
148 {
149 /* read a byte from classfile */
150 int nread;
151 uint8 ndata;
152 nread = fread(&ndata, sizeof(uint8), 1, pfile->pfs);
153 if ( !nread ) {
154 fclose(pfile->pfs);
155 err_quit("%s: truncated class file", pfile->pname);
156 }
157 return ndata;
158 }
159
160 uint16
read_uint16(const file_t * pfile)161 read_uint16(const file_t *pfile)
162 {
163 /* read a short from classfile and convert it to host format */
164 int nread;
165 uint16 ndata;
166 nread = fread(&ndata, sizeof(uint16), 1, pfile->pfs);
167 if ( !nread ) {
168 fclose(pfile->pfs);
169 err_quit("%s: truncated class file", pfile->pname);
170 }
171 ndata = ntohs(ndata);
172 return ndata;
173 }
174
175 uint32
read_uint32(const file_t * pfile)176 read_uint32(const file_t *pfile)
177 {
178 /* read an int from classfile and convert it to host format */
179 int nread;
180 uint32 ndata;
181 nread = fread(&ndata, sizeof(uint32), 1, pfile->pfs);
182 if ( !nread ) {
183 fclose(pfile->pfs);
184 err_quit("%s: truncated class file", pfile->pname);
185 }
186 ndata = ntohl(ndata);
187 return ndata;
188 }
189
190 utf8_t
read_utf8(const file_t * pfile)191 read_utf8(const file_t *pfile)
192 {
193 /* Read a java utf-8-string with uint16 length prependend
194 * from class file. Returns utf8 struct
195 * with fresh allocated datablock,
196 * caller is responsible for freeing.
197 * Data is still in network byteorder
198 */
199
200 utf8_t a_utf8;
201 int nread;
202
203 a_utf8.pdata = NULL;
204
205 a_utf8.nlen = read_uint16(pfile);
206 if (a_utf8.nlen > 0) {
207 a_utf8.pdata = xmalloc(a_utf8.nlen*sizeof(char));
208 nread = fread(a_utf8.pdata, a_utf8.nlen*sizeof(char), 1, pfile->pfs);
209 if ( !nread ) {
210 fclose(pfile->pfs);
211 err_quit("%s: truncated class file", pfile->pname);
212 }
213 }
214
215 return a_utf8;
216 }
217
utf8tolatin1(const utf8_t a_utf8)218 char *utf8tolatin1(const utf8_t a_utf8)
219 {
220 /* function returns fresh allocated zero terminated string,
221 * caller is responsible for freeing
222 */
223
224 /* JVMS p. 101: the null byte is encoded using a two byte format,
225 * Java Virtual Machine Utf8 strings differ in this respect from
226 * standard UTF-8 strings
227 */
228
229 /* Multibyte data is in network byte order */
230
231 char *p;
232 char *pp;
233 char *pstr;
234
235 pstr = pp = xmalloc((a_utf8.nlen+1) * sizeof(char));
236
237 for ( p = (char*)a_utf8.pdata;
238 p < (char*)a_utf8.pdata+a_utf8.nlen;
239 p++ ) {
240 if ( *p & 0x80 ) {
241 err_quit("sorry, real UTF8 decoding not yet implemented\n");
242 } else {
243 *pp++ = *p;
244 }
245 }
246 *pp = '\0';
247
248 return pstr;
249 }
250
251
252 void
skip_bytes(const file_t * pfile,const size_t nnumber)253 skip_bytes(const file_t *pfile, const size_t nnumber)
254 {
255 /* skip a nnumber of bytes in classfile */
256 if ( fseek(pfile->pfs, nnumber, SEEK_CUR) == -1 )
257 err_quit("%s: %s", pfile->pname, strerror(errno));
258 }
259
260 void
add_to_dependencies(struct growable * pdep,const struct growable * pfilt,char * pdepstr,const char * pclass_file)261 add_to_dependencies(struct growable *pdep,
262 const struct growable *pfilt,
263 char *pdepstr,
264 const char *pclass_file)
265 {
266 /* create dependencies */
267 int i;
268 int nlen_filt, nlen_str, nlen_pdepstr;
269 char *pstr, *ptrunc;
270 char path[PATH_MAX+1];
271 char cnp_class_file[PATH_MAX+1];
272 char cnp_str[PATH_MAX+1];
273
274 nlen_pdepstr = strlen(pdepstr);
275 pstr = xmalloc((nlen_pdepstr+6+1)*sizeof(char));
276 memcpy(pstr, pdepstr, nlen_pdepstr+1);
277 strncat(pstr, ".class", 6);
278
279 if ( pfilt->ncur == 0 ) { /* no filters */
280 if ( access(pstr, F_OK) == 0 ) {
281 append_to_growable(pdep, strdup(pstr));
282 }
283 } else {
284 nlen_str = strlen(pstr);
285 for ( i = 0; i < pfilt->ncur; i++ ) {
286 nlen_filt = strlen(pfilt->parray[i]);
287 if ( nlen_filt + 1 + nlen_str > PATH_MAX )
288 err_quit("path to long");
289 memcpy(path, pfilt->parray[i], nlen_filt);
290 path[nlen_filt] = '/';
291 memcpy( path+nlen_filt+1, pstr, nlen_str+1);
292
293 if ( access(path, F_OK) != 0 ) {
294 free(pstr);
295 pstr = NULL;
296 return; /* path doesn't represent a real file, don't bother */
297 }
298
299 /* get the canonical path */
300 #if defined (UNX) || defined(OS2)
301 if ( !(realpath(pclass_file, cnp_class_file)
302 && realpath(path, cnp_str) ) ) {
303 err_quit("can't get the canonical path");
304 }
305 #else
306 if ( !(_fullpath(cnp_class_file, pclass_file, sizeof(cnp_class_file))
307 && _fullpath(cnp_str, path, sizeof(cnp_str)) ) ) {
308 err_quit("can't get the canonical path");
309 }
310 #endif
311
312 /* truncate so that only the package prefix remains */
313 ptrunc = strrchr(cnp_str, cpathsep);
314 *ptrunc = '\0';
315 ptrunc = strrchr(cnp_class_file, cpathsep);
316 *ptrunc = '\0';
317
318 if ( !strcmp(cnp_str, cnp_class_file) ) {
319 free(pstr);
320 pstr = NULL;
321 return; /* identical, don't bother with this one */
322 }
323
324 append_to_growable(pdep, strdup(path));
325 }
326 }
327 free(pstr);
328 return;
329 }
330
331 char *
escape_slash(const char * pstr)332 escape_slash(const char *pstr)
333 {
334 /* returns a fresh allocated string with all cpathsep escaped exchanged
335 * with "$/"
336 *
337 * caller is responsible for freeing
338 */
339
340 const char *pp = pstr;
341 char *p, *pnp;
342 char *pnew_str;
343 int nlen_pnp, nlen_pp;
344 int i = 0;
345
346 while ( (p=strchr(pp, cpathsep)) != NULL ) {
347 ++i;
348 pp = ++p;
349 }
350
351 nlen_pnp = strlen(pstr) + i;
352 pnp = pnew_str = xmalloc((nlen_pnp+1) * sizeof(char));
353
354 pp = pstr;
355
356 if ( i > 0 ) {
357 while ( (p=strchr(pp, cpathsep)) != NULL ) {
358 memcpy(pnp, pp, p-pp);
359 pnp += p-pp;
360 *pnp++ = '$';
361 *pnp++ = '/';
362 pp = ++p;
363 }
364 }
365 nlen_pp = strlen(pp);
366 memcpy(pnp, pp, nlen_pp+1);
367
368 return pnew_str;
369 }
370
371
372 void
print_dependencies(const struct growable * pdep,const char * pclass_file)373 print_dependencies(const struct growable *pdep, const char* pclass_file)
374 {
375 char *pstr;
376 int i;
377
378 pstr = escape_slash(pclass_file);
379 fprintf(pfsout, "%s:", pstr);
380 free(pstr);
381
382 for( i=0; i<pdep->ncur; ++i) {
383 fprintf(pfsout, " \\\n");
384 pstr=escape_slash(pdep->parray[i]);
385 fprintf(pfsout, "\t%s", pstr);
386 free(pstr);
387 }
388
389 fprintf(pfsout,"\n\n");
390 return;
391 }
392
393 int
is_inner(const char * pstr)394 is_inner(const char *pstr)
395 {
396 /* return true if character '$' is found in classname */
397
398 /*
399 * note that a '$' in a classname is not an exact indicator
400 * for an inner class. Java identifier may legally contain
401 * this character, and so may classnames. In the context
402 * of javadep this doesn't matter since the makefile system
403 * can't cope with classfiles with '$'s in the filename
404 * anyway.
405 *
406 */
407
408 if ( strchr(pstr, '$') != NULL )
409 return 1;
410
411 return 0;
412 }
413
414 void
process_class_file(const char * pfilename,const struct growable * pfilt)415 process_class_file(const char *pfilename, const struct growable *pfilt)
416 {
417 /* read class file and extract object information
418 * java class files are in bigendian data format
419 * (JVMS, p. 83)
420 */
421 int i;
422 uint32 nmagic;
423 uint16 nminor, nmajor;
424 uint16 ncnt;
425 uint16 nclass_cnt;
426 utf8_t* pc_pool;
427 uint16* pc_class;
428 file_t file;
429
430 struct growable *pdepen;
431
432 file.pname = (char*)pfilename;
433
434 file.pfs = fopen(file.pname,"rb");
435 if ( !file.pfs )
436 silent_quit();
437
438 nmagic = read_uint32(&file);
439
440 if ( nmagic != 0xCAFEBABE ) {
441 fclose(file.pfs);
442 err_quit("%s: invalid magic", file.pname);
443 }
444
445 nminor = read_uint16(&file);
446 nmajor = read_uint16(&file);
447
448 /* get number of entries in constant pool */
449 ncnt = read_uint16(&file);
450
451 #ifdef DEBUG
452 printf("Magic: %p\n", (void*)nmagic);
453 printf("Major %d, Minor %d\n", nmajor, nminor);
454 printf("Const_pool_count %d\n", ncnt);
455 #endif
456
457 /* There can be ncount entries in the constant_pool table
458 * so at most ncount-1 of them can be of type CONSTANT_Class
459 * (at leat one CONSTANT_Utf8 entry must exist).
460 * Usually way less CONSTANT_Class entries exists, of course
461 */
462
463 pc_pool = xcalloc(ncnt,sizeof(utf8_t));
464 pc_class = xmalloc((ncnt-1)*sizeof(uint16));
465
466 /* pc_pool[0] is reserved to the java virtual machine and does
467 * not exist in the class file
468 */
469
470 nclass_cnt = 0;
471
472 for (i = 1; i < ncnt; i++) {
473 uint8 ntag;
474 uint16 nindex;
475 utf8_t a_utf8;
476
477 ntag = read_uint8(&file);
478
479 /* we are only interested in CONSTANT_Class entries and
480 * Utf8 string entries, because they might belong to
481 * CONSTANT_Class entries
482 */
483 switch(ntag) {
484 case CONSTANT_Class:
485 nindex = read_uint16(&file);
486 pc_class[nclass_cnt++] = nindex;
487 break;
488 case CONSTANT_Fieldref:
489 case CONSTANT_Methodref:
490 case CONSTANT_InterfaceMethodref:
491 skip_bytes(&file, 4L);
492 break;
493 case CONSTANT_String:
494 skip_bytes(&file, 2L);
495 break;
496 case CONSTANT_Integer:
497 case CONSTANT_Float:
498 skip_bytes(&file, 4L);
499 break;
500 case CONSTANT_Long:
501 case CONSTANT_Double:
502 skip_bytes(&file, 8L);
503 /* Long and Doubles take 2(!)
504 * entries in constant_pool_table
505 */
506 i++;
507 break;
508 case CONSTANT_NameAndType:
509 skip_bytes(&file, 4L);
510 break;
511 case CONSTANT_Utf8:
512 a_utf8 = read_utf8(&file);
513 pc_pool[i] = a_utf8;
514 break;
515 default:
516 /* Unknown Constant_pool entry, this means we are
517 * in trouble
518 */
519 err_quit("corrupted class file\n");
520 break;
521
522 }
523 }
524
525 fclose(file.pfs);
526
527 pdepen = allocate_growable();
528
529 for (i = 0; i < nclass_cnt; i++) {
530 char *pstr, *ptmpstr;
531 pstr = ptmpstr = utf8tolatin1(pc_pool[pc_class[i]]);
532 /* we are not interested in inner classes */
533 if ( is_inner(pstr) ) {
534 free(pstr);
535 pstr = NULL;
536 continue;
537 }
538 /* strip off evt. array indicators */
539 if ( *ptmpstr == '[' ) {
540 while ( *ptmpstr == '[' )
541 ptmpstr++;
542 /* we only interested in obj. arrays, which are marked with 'L' */
543 if ( *ptmpstr == 'L' ) {
544 char *p = pstr;
545 pstr = strdup(++ptmpstr);
546 /* remove final ';' from object array name */
547 pstr[strlen(pstr)-1] = '\0';
548 free(p);
549 } else {
550 free(pstr);
551 pstr = NULL;
552 }
553 }
554
555 if (pstr) {
556 add_to_dependencies(pdepen, pfilt, pstr, file.pname);
557 free(pstr);
558 }
559 }
560
561 print_dependencies(pdepen, file.pname);
562 free_growable(pdepen);
563 pdepen = NULL;
564
565 for (i = 0; i < ncnt; i++)
566 free(pc_pool[i].pdata);
567
568 free(pc_class);
569 free(pc_pool);
570 }
571
572 void *
xmalloc(size_t size)573 xmalloc(size_t size)
574 {
575 void *ptr;
576
577 ptr = malloc(size);
578
579 if ( !ptr )
580 err_quit("out of memory");
581
582 return ptr;
583 }
584
585
586 void *
xcalloc(size_t nmemb,size_t size)587 xcalloc(size_t nmemb, size_t size)
588 {
589 void *ptr;
590
591 ptr = calloc(nmemb, size);
592
593 if ( !ptr )
594 err_quit("out of memory");
595
596 return ptr;
597 }
598
599 void *
xrealloc(void * ptr,size_t size)600 xrealloc(void *ptr, size_t size)
601 {
602 ptr = realloc(ptr, size);
603
604 if ( !ptr )
605 err_quit("out of memory");
606
607 return ptr;
608 }
609
610 void
err_quit(const char * fmt,...)611 err_quit(const char* fmt, ...)
612 {
613 /* No dependency file must be generated for any error condition,
614 * just print message and exit.
615 */
616 va_list args;
617 char buffer[PATH_MAX];
618
619 va_start(args, fmt);
620
621 if ( pprogname )
622 fprintf(stderr, "%s: ", pprogname);
623 vsnprintf(buffer, sizeof(buffer), fmt, args);
624 fputs(buffer, stderr);
625 fputc('\n', stderr);
626
627 va_end(args);
628
629 /* clean up */
630 if ( pfsout && pfsout != stdout ) {
631 fclose(pfsout);
632 unlink(pout_file);
633 }
634 exit(1);
635 }
636
637 void
silent_quit()638 silent_quit()
639 {
640 /* In some cases we should just do a silent exit */
641
642 /* clean up */
643 if ( pfsout && pfsout != stdout ) {
644 fclose(pfsout);
645 unlink(pout_file);
646 }
647 exit(0);
648 }
649
append_to_growable(struct growable * pgrow,char * pstr)650 int append_to_growable(struct growable *pgrow, char *pstr)
651 {
652 /* append an element pstr to pgrow,
653 * return new number of elements
654 */
655 grow_if_needed(pgrow);
656 pgrow->parray[pgrow->ncur++] = pstr;
657 return pgrow->ncur;
658 }
659
660 void
grow_if_needed(struct growable * pgrow)661 grow_if_needed(struct growable *pgrow)
662 {
663 /* grow growable arrays */
664
665 if ( pgrow->ncur >= pgrow->nmax ) {
666 pgrow->parray = xrealloc(pgrow->parray,
667 (NGROW*pgrow->nmax)*sizeof(char*));
668 pgrow->nmax *= NGROW;
669 }
670 return;
671 }
672
allocate_growable(void)673 struct growable *allocate_growable(void)
674 {
675 /* allocate an growable array,
676 * initialize with NGROW_INIT elements
677 */
678
679 struct growable *pgrow;
680
681 pgrow = xmalloc(sizeof(struct growable));
682 pgrow->parray = xmalloc(NGROW_INIT*sizeof(char *));
683 pgrow->nmax = NGROW_INIT;
684 pgrow->ncur = 0;
685 return pgrow;
686 }
687
688 void
free_growable(struct growable * pgrow)689 free_growable(struct growable *pgrow)
690 {
691 int i;
692 for( i = 0; i < pgrow->ncur; i++ )
693 free(pgrow->parray[i]);
694 free(pgrow->parray);
695 free(pgrow);
696 }
697
698 void
create_filters(struct growable * pfilt,const struct growable * pinc)699 create_filters(struct growable *pfilt, const struct growable *pinc)
700 {
701 char *p, *pp, *pstr;
702 int i, nlen, nlen_pstr;
703 /* break up includes into filter list */
704 for ( i = 0; i < pinc->ncur; i++ ) {
705 pp = pinc->parray[i];
706
707 while ( (p = strchr(pp, csep)) != NULL) {
708 nlen = p - pp;
709 pstr = xmalloc((nlen+1)*sizeof(char*));
710 memcpy(pstr, pp, nlen);
711 pstr[nlen] = '\0';
712 append_to_growable(pfilt, pstr);
713 pp = p + 1;
714 }
715 nlen_pstr = strlen(pp);
716 pstr = xmalloc((nlen_pstr+1)*sizeof(char*));
717 memcpy(pstr, pp, nlen_pstr+1);
718 append_to_growable(pfilt, pstr);
719 }
720
721 }
722
723 void
usage()724 usage()
725 {
726 fprintf(stderr,
727 "usage: %s [-i|-I includepath ... -s|-S seperator "
728 "-o|-O outpath -v|-V -h|-H] <file> ....\n",
729 pprogname);
730 }
731
732 #ifdef WNT
733 /* my very simple minded implementation of getopt()
734 * it's to sad that getopt() is not available everywhere
735 * note: this is not a full POSIX conforming getopt()
736 */
simple_getopt(char * pargv[],const char * poptstring)737 int simple_getopt(char *pargv[], const char *poptstring)
738 {
739 char *parg = pargv[optind];
740
741 /* skip all response file arguments */
742 if ( parg ) {
743 while ( *parg == '@' )
744 parg = pargv[++optind];
745
746 if ( parg[0] == '-' && parg[1] != '\0' ) {
747 char *popt;
748 int c = parg[1];
749 if ( (popt = strchr(poptstring, c)) == NULL ) {
750 optopt = c;
751 if ( opterr )
752 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
753 return '?';
754 }
755 if ( *(++popt) == ':') {
756 if ( parg[2] != '\0' ) {
757 optarg = ++parg;
758 } else {
759 optarg = pargv[++optind];
760 }
761 } else {
762 optarg = NULL;
763 }
764 ++optind;
765 return c;
766 }
767 }
768 return -1;
769 }
770 #endif
771
772 int CDECL
main(int argc,char * argv[])773 main(int argc, char *argv[])
774 {
775 int bv_flag = 0;
776 struct growable *presp, *pincs, *pfilters;
777 int c, i, nall_argc;
778 char **pall_argv;
779
780 presp = allocate_growable();
781
782 /* FIXME: cleanup the option parsing */
783 /* search for response file, read it */
784 for ( i = 1; i < argc; i++ ) {
785 char *parg = argv[i];
786 char buffer[RES_FILE_BUF];
787
788 if ( *parg == '@' ) {
789 FILE *pfile = fopen(++parg, "r");
790 if ( !pfile )
791 err_quit("%s: %s", parg, strerror(errno));
792 while ( !feof(pfile) ) {
793 char *p, *token;
794
795 if ( fgets(buffer, RES_FILE_BUF, pfile) ) {;
796 p = buffer;
797 while ( (token = strtok(p, " \t\n")) != NULL ) {
798 p = NULL;
799 append_to_growable(presp, strdup(token));
800 }
801 }
802 }
803 fclose(pfile);
804 }
805 }
806
807 /* copy all arguments incl. response file in one array
808 * for parsing with getopt
809 */
810 nall_argc = argc + presp->ncur;
811 pall_argv = xmalloc((nall_argc+1)*sizeof(char *));
812 memcpy(pall_argv, argv, argc*sizeof(char *));
813 memcpy(pall_argv+argc, presp->parray, presp->ncur*sizeof(char *));
814 *(pall_argv+argc+presp->ncur) = '\0'; /* terminate */
815
816 opterr = 0;
817 pincs = allocate_growable();
818
819 #ifdef WNT
820 while( (c = simple_getopt(pall_argv, ":i:I:s:S:o:OhHvV")) != -1 ) {
821 #else
822 while( (c = getopt(nall_argc, pall_argv, ":i:I:s:S:o:OhHvV")) != -1 ) {
823 #endif
824 switch(c) {
825 case 'i':
826 case 'I':
827 append_to_growable(pincs, strdup(optarg));
828 break;
829 case 's':
830 case 'S':
831 csep = optarg[0];
832 break;
833 case 'o':
834 case 'O':
835 pout_file = optarg;
836 break;
837 case 'h':
838 case 'H':
839 usage();
840 return 0;
841 break;
842 case 'v':
843 case 'V':
844 bv_flag = 1;
845 break;
846 case '?':
847 if (isprint (optopt))
848 fprintf (stderr,
849 "Unknown option `-%c'.\n", optopt);
850 else
851 fprintf (stderr,
852 "Unknown option character `\\x%x'.\n",
853 optopt);
854 usage();
855 return 1;
856 break;
857 case ':':
858 fprintf(stderr, "Missing parameter.\n");
859 usage();
860 return 1;
861 break;
862 default:
863 usage();
864 return 1;
865 break;
866 }
867 }
868
869 pfilters = allocate_growable();
870 create_filters(pfilters, pincs);
871 free_growable(pincs);
872 pincs = NULL;
873
874 if ( pout_file ) {
875 pfsout = fopen(pout_file, "w");
876 if ( !pfsout )
877 err_quit("%s: %s", pout_file, strerror(errno));
878 } else {
879 pfsout = stdout;
880 }
881
882 /* the remaining arguments are either class file
883 * names or response files, ignore response file
884 * since they have already been included
885 */
886 for ( i = optind; i < nall_argc; i++ ) {
887 char *parg = pall_argv[i];
888 if ( *parg != '@' ) {
889 process_class_file(parg, pfilters);
890 if ( pfsout != stdout ) {
891 if ( bv_flag )
892 printf("Processed %s ...\n", parg);
893 }
894 }
895 }
896
897 free_growable(pfilters);
898 pfilters = NULL;
899 free(pall_argv);
900 pall_argv = NULL;
901 free_growable(presp);
902 presp = NULL;
903
904 fclose(pfsout);
905 exit(0);
906 }
907
908