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