Bump for 3.6-28
[LibreOffice.git] / soltools / javadep / javadep.c
blob351177a76c6cbe23ae78f855c1f757da2990eb07
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 /* All Java Virtual Machine Specs are from
30 * "The Java Virtual Machine Specification", T. Lindholm, F. Yellin
31 * (JVMS)
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #include <limits.h>
42 #if defined(UNX)
43 #include <unistd.h>
44 #include <netinet/in.h> /* ntohl(), ntohs() */
45 #elif defined(WNT)
46 #include <io.h>
47 #define access _access
48 #define vsnprintf _vsnprintf
49 #define CDECL _cdecl
50 #define F_OK 00
51 #define PATH_MAX _MAX_PATH
52 #define ntohl(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
53 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
55 #define ntohs(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
56 #endif
58 /* max. length of line in response file */
59 #define RES_FILE_BUF 65536
61 struct file {
62 char *pname;
63 FILE *pfs;
66 struct growable {
67 int ncur;
68 int nmax;
69 char **parray;
72 typedef struct file file_t;
73 typedef unsigned char uint8;
74 typedef unsigned short uint16;
75 typedef unsigned int uint32;
77 struct utf8 {
78 uint16 nlen;
79 void *pdata;
82 typedef struct utf8 utf8_t;
84 /* The contents of the Constant_pool is described in JVMS p. 93
86 enum {
87 CONSTANT_Class = 7,
88 CONSTANT_Fieldref = 9,
89 CONSTANT_Methodref = 10,
90 CONSTANT_InterfaceMethodref = 11,
91 CONSTANT_String = 8,
92 CONSTANT_Integer = 3,
93 CONSTANT_Float = 4,
94 CONSTANT_Long = 5,
95 CONSTANT_Double = 6,
96 CONSTANT_NameAndType = 12,
97 CONSTANT_Utf8 = 1
100 enum { NGROW_INIT = 10, NGROW = 2 };
102 static char *pprogname = "javadep";
103 static char csep = ';';
104 #if defined (UNX)
105 #define CDECL
106 static char cpathsep = '/';
107 #elif defined (WNT)
108 static char cpathsep = '\\';
109 #endif
110 static FILE *pfsout = NULL;
111 static char *pout_file = NULL;
114 /* prototypes */
115 uint8 read_uint8(const file_t *pfile);
116 uint16 read_uint16(const file_t *pfile);
117 uint32 read_uint32(const file_t *pfile);
118 void skip_bytes(const file_t *pfile, const long nnum);
119 char *escape_slash(const char *pstr);
120 int is_inner(const char *pstr);
121 void print_dependencies(const struct growable *pdep,
122 const char* pclass_file);
123 void process_class_file(const char *pfilenamem,
124 const struct growable *pfilt);
125 char *utf8tolatin1(const utf8_t a_utf8);
126 void *xmalloc(size_t size);
127 void *xcalloc(size_t nmemb, size_t size);
128 void *xrealloc(void *ptr, size_t size);
129 void grow_if_needed (struct growable *pgrow);
130 int append_to_growable(struct growable *, char *);
131 struct growable *allocate_growable(void);
132 void free_growable(struct growable *pgrowvoid);
133 void create_filters(struct growable *pfilt, const struct growable *pinc);
134 void usage(void);
135 void err_quit(const char *, ...);
136 void silent_quit(void);
138 #ifdef WNT
139 /* poor man's getopt() */
140 int simple_getopt(char *pargv[], const char *poptstring);
141 char *optarg = NULL;
142 int optind = 1;
143 int optopt = 0;
144 int opterr = 0;
145 #endif
147 uint8
148 read_uint8(const file_t *pfile)
150 /* read a byte from classfile */
151 size_t nread;
152 uint8 ndata;
153 nread = fread(&ndata, sizeof(uint8), 1, pfile->pfs);
154 if ( !nread ) {
155 fclose(pfile->pfs);
156 err_quit("%s: truncated class file", pfile->pname);
158 return ndata;
161 uint16
162 read_uint16(const file_t *pfile)
164 /* read a short from classfile and convert it to host format */
165 size_t nread;
166 uint16 ndata;
167 nread = fread(&ndata, sizeof(uint16), 1, pfile->pfs);
168 if ( !nread ) {
169 fclose(pfile->pfs);
170 err_quit("%s: truncated class file", pfile->pname);
172 ndata = ntohs(ndata);
173 return ndata;
176 uint32
177 read_uint32(const file_t *pfile)
179 /* read an int from classfile and convert it to host format */
180 size_t nread;
181 uint32 ndata;
182 nread = fread(&ndata, sizeof(uint32), 1, pfile->pfs);
183 if ( !nread ) {
184 fclose(pfile->pfs);
185 err_quit("%s: truncated class file", pfile->pname);
187 ndata = ntohl(ndata);
188 return ndata;
191 utf8_t
192 read_utf8(const file_t *pfile)
194 /* Read a java utf-8-string with uint16 length prependend
195 * from class file. Returns utf8 struct
196 * with fresh allocated datablock,
197 * caller is responsible for freeing.
198 * Data is still in network byteorder
201 utf8_t a_utf8;
202 size_t nread;
204 a_utf8.pdata = NULL;
206 a_utf8.nlen = read_uint16(pfile);
207 if (a_utf8.nlen > 0) {
208 a_utf8.pdata = xmalloc(a_utf8.nlen*sizeof(char));
209 nread = fread(a_utf8.pdata, a_utf8.nlen*sizeof(char), 1, pfile->pfs);
210 if ( !nread ) {
211 fclose(pfile->pfs);
212 err_quit("%s: truncated class file", pfile->pname);
216 return a_utf8;
219 char *utf8tolatin1(const utf8_t a_utf8)
221 /* function returns fresh allocated zero terminated string,
222 * caller is responsible for freeing
225 /* JVMS p. 101: the null byte is encoded using a two byte format,
226 * Java Virtual Machine Utf8 strings differ in this respect from
227 * standard UTF-8 strings
230 /* Multibyte data is in network byte order */
232 char *p;
233 char *pp;
234 char *pstr;
236 pstr = pp = xmalloc((a_utf8.nlen+1) * sizeof(char));
238 for ( p = (char*)a_utf8.pdata;
239 p < (char*)a_utf8.pdata+a_utf8.nlen;
240 p++ ) {
241 if ( *p & 0x80 ) {
242 err_quit("sorry, real UTF8 decoding not yet implemented\n");
243 } else {
244 *pp++ = *p;
247 *pp = '\0';
249 return pstr;
253 void
254 skip_bytes(const file_t *pfile, const long nnumber)
256 /* skip a nnumber of bytes in classfile */
257 if ( fseek(pfile->pfs, nnumber, SEEK_CUR) == -1 )
258 err_quit("%s: %s", pfile->pname, strerror(errno));
261 void
262 add_to_dependencies(struct growable *pdep,
263 const struct growable *pfilt,
264 char *pdepstr,
265 const char *pclass_file)
267 /* create dependencies */
268 int i;
269 size_t nlen_filt, nlen_str, nlen_pdepstr;
270 char *pstr, *ptrunc;
271 char path[PATH_MAX+1];
272 char cnp_class_file[PATH_MAX+1];
273 char cnp_str[PATH_MAX+1];
275 nlen_pdepstr = strlen(pdepstr);
276 pstr = xmalloc((nlen_pdepstr+6+1)*sizeof(char));
277 memcpy(pstr, pdepstr, nlen_pdepstr+1);
278 strncat(pstr, ".class", 6);
280 if ( pfilt->ncur == 0 ) { /* no filters */
281 if ( access(pstr, F_OK) == 0 ) {
282 append_to_growable(pdep, strdup(pstr));
284 } else {
285 nlen_str = strlen(pstr);
286 for ( i = 0; i < pfilt->ncur; i++ ) {
287 nlen_filt = strlen(pfilt->parray[i]);
288 if ( nlen_filt + 1 + nlen_str > PATH_MAX )
289 err_quit("path to long");
290 memcpy(path, pfilt->parray[i], nlen_filt);
291 path[nlen_filt] = '/';
292 memcpy( path+nlen_filt+1, pstr, nlen_str+1);
294 if ( access(path, F_OK) != 0 ) {
295 free(pstr);
296 pstr = NULL;
297 return; /* path doesn't represent a real file, don't bother */
300 /* get the canonical path */
301 #if defined (UNX)
302 if ( !(realpath(pclass_file, cnp_class_file)
303 && realpath(path, cnp_str) ) ) {
304 err_quit("can't get the canonical path");
306 #else
307 if ( !(_fullpath(cnp_class_file, pclass_file, sizeof(cnp_class_file))
308 && _fullpath(cnp_str, path, sizeof(cnp_str)) ) ) {
309 err_quit("can't get the canonical path");
311 #endif
313 /* truncate so that only the package prefix remains */
314 ptrunc = strrchr(cnp_str, cpathsep);
315 *ptrunc = '\0';
316 ptrunc = strrchr(cnp_class_file, cpathsep);
317 *ptrunc = '\0';
319 if ( !strcmp(cnp_str, cnp_class_file) ) {
320 free(pstr);
321 pstr = NULL;
322 return; /* identical, don't bother with this one */
325 append_to_growable(pdep, strdup(path));
328 free(pstr);
329 return;
332 char *
333 escape_slash(const char *pstr)
335 /* returns a fresh allocated string with all cpathsep escaped exchanged
336 * with "$/"
338 * caller is responsible for freeing
341 const char *pp = pstr;
342 char *p, *pnp;
343 char *pnew_str;
344 size_t nlen_pnp, nlen_pp;
345 int i = 0;
347 while ( (p=strchr(pp, cpathsep)) != NULL ) {
348 ++i;
349 pp = ++p;
352 nlen_pnp = strlen(pstr) + i;
353 pnp = pnew_str = xmalloc((nlen_pnp+1) * sizeof(char));
355 pp = pstr;
357 if ( i > 0 ) {
358 while ( (p=strchr(pp, cpathsep)) != NULL ) {
359 memcpy(pnp, pp, p-pp);
360 pnp += p-pp;
361 *pnp++ = '$';
362 *pnp++ = '/';
363 pp = ++p;
366 nlen_pp = strlen(pp);
367 memcpy(pnp, pp, nlen_pp+1);
369 return pnew_str;
373 void
374 print_dependencies(const struct growable *pdep, const char* pclass_file)
376 char *pstr;
377 int i;
379 pstr = escape_slash(pclass_file);
380 fprintf(pfsout, "%s:", pstr);
381 free(pstr);
383 for( i=0; i<pdep->ncur; ++i) {
384 fprintf(pfsout, " \\\n");
385 pstr=escape_slash(pdep->parray[i]);
386 fprintf(pfsout, "\t%s", pstr);
387 free(pstr);
390 fprintf(pfsout,"\n\n");
391 return;
395 is_inner(const char *pstr)
397 /* return true if character '$' is found in classname */
400 * note that a '$' in a classname is not an exact indicator
401 * for an inner class. Java identifier may legally contain
402 * this chararcter, and so may classnames. In the context
403 * of javadep this doesn't matter since the makefile system
404 * can't cope with classfiles with '$'s in the filename
405 * anyway.
409 if ( strchr(pstr, '$') != NULL )
410 return 1;
412 return 0;
415 void
416 process_class_file(const char *pfilename, const struct growable *pfilt)
418 /* read class file and extract object information
419 * java class files are in bigendian data format
420 * (JVMS, p. 83)
422 int i;
423 uint32 nmagic;
424 uint16 nminor, nmajor;
425 uint16 ncnt;
426 uint16 nclass_cnt;
427 utf8_t* pc_pool;
428 uint16* pc_class;
429 file_t file;
431 struct growable *pdepen;
433 file.pname = (char*)pfilename;
435 file.pfs = fopen(file.pname,"rb");
436 if ( !file.pfs )
437 silent_quit();
439 nmagic = read_uint32(&file);
441 if ( nmagic != 0xCAFEBABE ) {
442 fclose(file.pfs);
443 err_quit("%s: invalid magic", file.pname);
446 nminor = read_uint16(&file);
447 nmajor = read_uint16(&file);
449 /* get number of entries in constant pool */
450 ncnt = read_uint16(&file);
452 #ifdef DEBUG
453 printf("Magic: %x\n", nmagic);
454 printf("Major %d, Minor %d\n", nmajor, nminor);
455 printf("Const_pool_count %d\n", ncnt);
456 #else
457 (void)nmajor;
458 (void)nminor;
459 #endif
461 /* There can be ncount entries in the constant_pool table
462 * so at most ncount-1 of them can be of type CONSTANT_Class
463 * (at leat one CONSTANT_Utf8 entry must exist).
464 * Usually way less CONSTANT_Class entries exists, of course
467 pc_pool = xcalloc(ncnt,sizeof(utf8_t));
468 pc_class = xmalloc((ncnt-1)*sizeof(uint16));
470 /* pc_pool[0] is reserved to the java virtual machine and does
471 * not exist in the class file
474 nclass_cnt = 0;
476 for (i = 1; i < ncnt; i++) {
477 uint8 ntag;
478 uint16 nindex;
479 utf8_t a_utf8;
481 ntag = read_uint8(&file);
483 /* we are only interested in CONSTANT_Class entries and
484 * Utf8 string entries, because they might belong to
485 * CONSTANT_Class entries
487 switch(ntag) {
488 case CONSTANT_Class:
489 nindex = read_uint16(&file);
490 pc_class[nclass_cnt++] = nindex;
491 break;
492 case CONSTANT_Fieldref:
493 case CONSTANT_Methodref:
494 case CONSTANT_InterfaceMethodref:
495 skip_bytes(&file, 4L);
496 break;
497 case CONSTANT_String:
498 skip_bytes(&file, 2L);
499 break;
500 case CONSTANT_Integer:
501 case CONSTANT_Float:
502 skip_bytes(&file, 4L);
503 break;
504 case CONSTANT_Long:
505 case CONSTANT_Double:
506 skip_bytes(&file, 8L);
507 /* Long and Doubles take 2(!)
508 * entries in constant_pool_table
510 i++;
511 break;
512 case CONSTANT_NameAndType:
513 skip_bytes(&file, 4L);
514 break;
515 case CONSTANT_Utf8:
516 a_utf8 = read_utf8(&file);
517 pc_pool[i] = a_utf8;
518 break;
519 default:
520 /* Unknown Constant_pool entry, this means we are
521 * in trouble
523 err_quit("corrupted class file\n");
524 break;
529 fclose(file.pfs);
531 pdepen = allocate_growable();
533 for (i = 0; i < nclass_cnt; i++) {
534 char *pstr, *ptmpstr;
535 pstr = ptmpstr = utf8tolatin1(pc_pool[pc_class[i]]);
536 /* we are not interested in inner classes */
537 if ( is_inner(pstr) ) {
538 free(pstr);
539 pstr = NULL;
540 continue;
542 /* strip off evt. array indicators */
543 if ( *ptmpstr == '[' ) {
544 while ( *ptmpstr == '[' )
545 ptmpstr++;
546 /* we only interested in obj. arrays, which are marked with 'L' */
547 if ( *ptmpstr == 'L' ) {
548 char *p = pstr;
549 pstr = strdup(++ptmpstr);
550 /* remove final ';' from object array name */
551 pstr[strlen(pstr)-1] = '\0';
552 free(p);
553 } else {
554 free(pstr);
555 pstr = NULL;
559 if (pstr) {
560 add_to_dependencies(pdepen, pfilt, pstr, file.pname);
561 free(pstr);
565 print_dependencies(pdepen, file.pname);
566 free_growable(pdepen);
567 pdepen = NULL;
569 for (i = 0; i < ncnt; i++)
570 free(pc_pool[i].pdata);
572 free(pc_class);
573 free(pc_pool);
576 void *
577 xmalloc(size_t size)
579 void *ptr;
581 ptr = malloc(size);
583 if ( !ptr )
584 err_quit("out of memory");
586 return ptr;
590 void *
591 xcalloc(size_t nmemb, size_t size)
593 void *ptr;
595 ptr = calloc(nmemb, size);
597 if ( !ptr )
598 err_quit("out of memory");
600 return ptr;
603 void *
604 xrealloc(void *ptr, size_t size)
606 void *newptr = realloc(ptr, size);
608 if (newptr)
609 ptr = newptr;
610 else
611 err_quit("out of memory");
613 return ptr;
616 void
617 err_quit(const char* fmt, ...)
619 /* No dependency file must be generated for any error condition,
620 * just print message and exit.
622 va_list args;
623 char buffer[PATH_MAX];
625 va_start(args, fmt);
627 if ( pprogname )
628 fprintf(stderr, "%s: ", pprogname);
629 vsnprintf(buffer, sizeof(buffer), fmt, args);
630 fputs(buffer, stderr);
631 fputc('\n', stderr);
633 va_end(args);
635 /* clean up */
636 if ( pfsout && pfsout != stdout ) {
637 fclose(pfsout);
638 unlink(pout_file);
640 exit(1);
643 void
644 silent_quit()
646 /* In some cases we should just do a silent exit */
648 /* clean up */
649 if ( pfsout && pfsout != stdout ) {
650 fclose(pfsout);
651 unlink(pout_file);
653 exit(0);
656 int append_to_growable(struct growable *pgrow, char *pstr)
658 /* append an element pstr to pgrow,
659 * return new number of elements
661 grow_if_needed(pgrow);
662 pgrow->parray[pgrow->ncur++] = pstr;
663 return pgrow->ncur;
666 void
667 grow_if_needed(struct growable *pgrow)
669 /* grow growable arrays */
671 if ( pgrow->ncur >= pgrow->nmax ) {
672 pgrow->parray = xrealloc(pgrow->parray,
673 (NGROW*pgrow->nmax)*sizeof(char*));
674 pgrow->nmax *= NGROW;
676 return;
679 struct growable *allocate_growable(void)
681 /* allocate an growable array,
682 * initialize with NGROW_INIT elements
685 struct growable *pgrow;
687 pgrow = xmalloc(sizeof(struct growable));
688 pgrow->parray = xmalloc(NGROW_INIT*sizeof(char *));
689 pgrow->nmax = NGROW_INIT;
690 pgrow->ncur = 0;
691 return pgrow;
694 void
695 free_growable(struct growable *pgrow)
697 int i;
698 for( i = 0; i < pgrow->ncur; i++ )
699 free(pgrow->parray[i]);
700 free(pgrow->parray);
701 free(pgrow);
704 void
705 create_filters(struct growable *pfilt, const struct growable *pinc)
707 char *p, *pp, *pstr;
708 int i;
709 size_t nlen, nlen_pstr;
710 /* break up includes into filter list */
711 for ( i = 0; i < pinc->ncur; i++ ) {
712 pp = pinc->parray[i];
714 while ( (p = strchr(pp, csep)) != NULL) {
715 nlen = p - pp;
716 pstr = xmalloc((nlen+1)*sizeof(char*));
717 memcpy(pstr, pp, nlen);
718 pstr[nlen] = '\0';
719 append_to_growable(pfilt, pstr);
720 pp = p + 1;
722 nlen_pstr = strlen(pp);
723 pstr = xmalloc((nlen_pstr+1)*sizeof(char*));
724 memcpy(pstr, pp, nlen_pstr+1);
725 append_to_growable(pfilt, pstr);
730 void
731 usage()
733 fprintf(stderr,
734 "usage: %s [-i|-I includepath ... -s|-S seperator "
735 "-o|-O outpath -v|-V -h|-H] <file> ....\n",
736 pprogname);
739 #ifdef WNT
740 /* my very simple minded implementation of getopt()
741 * it's to sad that getopt() is not available everywhere
742 * note: this is not a full POSIX conforming getopt()
744 int simple_getopt(char *pargv[], const char *poptstring)
746 char *parg = pargv[optind];
748 /* skip all response file arguments */
749 if ( parg ) {
750 while ( *parg == '@' )
751 parg = pargv[++optind];
753 if ( parg[0] == '-' && parg[1] != '\0' ) {
754 char *popt;
755 int c = parg[1];
756 if ( (popt = strchr(poptstring, c)) == NULL ) {
757 optopt = c;
758 if ( opterr )
759 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
760 return '?';
762 if ( *(++popt) == ':') {
763 if ( parg[2] != '\0' ) {
764 optarg = ++parg;
765 } else {
766 optarg = pargv[++optind];
768 } else {
769 optarg = NULL;
771 ++optind;
772 return c;
775 return -1;
777 #endif
779 int CDECL
780 main(int argc, char *argv[])
782 int bv_flag = 0;
783 struct growable *presp, *pincs, *pfilters;
784 int c, i, nall_argc;
785 char **pall_argv;
787 presp = allocate_growable();
789 /* FIXME: cleanup the option parsing */
790 /* search for response file, read it */
791 for ( i = 1; i < argc; i++ ) {
792 char *parg = argv[i];
793 char buffer[RES_FILE_BUF];
795 if ( *parg == '@' ) {
796 FILE *pfile = fopen(++parg, "r");
797 if ( !pfile )
798 err_quit("%s: %s", parg, strerror(errno));
799 while ( !feof(pfile) ) {
800 char *p, *token;
802 if ( fgets(buffer, RES_FILE_BUF, pfile) ) {;
803 p = buffer;
804 while ( (token = strtok(p, " \t\n")) != NULL ) {
805 p = NULL;
806 append_to_growable(presp, strdup(token));
810 fclose(pfile);
814 /* copy all arguments incl. response file in one array
815 * for parsing with getopt
817 nall_argc = argc + presp->ncur;
818 pall_argv = xmalloc((nall_argc+1)*sizeof(char *));
819 memcpy(pall_argv, argv, argc*sizeof(char *));
820 memcpy(pall_argv+argc, presp->parray, presp->ncur*sizeof(char *));
821 *(pall_argv+argc+presp->ncur) = '\0'; /* terminate */
823 opterr = 0;
824 pincs = allocate_growable();
826 #ifdef WNT
827 while( (c = simple_getopt(pall_argv, ":i:I:s:S:o:OhHvV")) != -1 ) {
828 #else
829 while( (c = getopt(nall_argc, pall_argv, ":i:I:s:S:o:OhHvV")) != -1 ) {
830 #endif
831 switch(c) {
832 case 'i':
833 case 'I':
834 append_to_growable(pincs, strdup(optarg));
835 break;
836 case 's':
837 case 'S':
838 csep = optarg[0];
839 break;
840 case 'o':
841 case 'O':
842 pout_file = optarg;
843 break;
844 case 'h':
845 case 'H':
846 usage();
847 return 0;
848 break;
849 case 'v':
850 case 'V':
851 bv_flag = 1;
852 break;
853 case '?':
854 if (isprint (optopt))
855 fprintf (stderr,
856 "Unknown option `-%c'.\n", optopt);
857 else
858 fprintf (stderr,
859 "Unknown option character `\\x%x'.\n",
860 optopt);
861 usage();
862 return 1;
863 break;
864 case ':':
865 fprintf(stderr, "Missing parameter.\n");
866 usage();
867 return 1;
868 break;
869 default:
870 usage();
871 return 1;
872 break;
876 pfilters = allocate_growable();
877 create_filters(pfilters, pincs);
878 free_growable(pincs);
879 pincs = NULL;
881 if ( pout_file ) {
882 pfsout = fopen(pout_file, "w");
883 if ( !pfsout )
884 err_quit("%s: %s", pout_file, strerror(errno));
885 } else {
886 pfsout = stdout;
889 /* the remaining arguments are either class file
890 * names or response files, ignore response file
891 * since they have already been included
893 for ( i = optind; i < nall_argc; i++ ) {
894 char *parg = pall_argv[i];
895 if ( *parg != '@' ) {
896 process_class_file(parg, pfilters);
897 if ( pfsout != stdout ) {
898 if ( bv_flag )
899 printf("Processed %s ...\n", parg);
904 free_growable(pfilters);
905 pfilters = NULL;
906 free(pall_argv);
907 pall_argv = NULL;
908 free_growable(presp);
909 presp = NULL;
911 fclose(pfsout);
912 exit(0);
915 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */