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 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 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 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 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 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 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 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 * 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 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 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 chararcter, 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 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 */ 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 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