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