1 /* $XConsortium: main.c,v 1.84 94/11/30 16:10:44 kaleb Exp $ */ 2 /* $XFree86: xc/config/makedepend/main.c,v 3.4 1995/07/15 14:53:49 dawes Exp $ */ 3 /* 4 5 Copyright (c) 1993, 1994 X Consortium 6 7 Permission is hereby granted, free of charge, to any person obtaining a copy 8 of this software and associated documentation files (the "Software"), to deal 9 in the Software without restriction, including without limitation the rights 10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 copies of the Software, and to permit persons to whom the Software is 12 furnished to do so, subject to the following conditions: 13 14 The above copyright notice and this permission notice shall be included in 15 all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 Except as contained in this notice, the name of the X Consortium shall not be 25 used in advertising or otherwise to promote the sale, use or other dealings 26 in this Software without prior written authorization from the X Consortium. 27 28 */ 29 30 #if defined(FREEBSD) || defined(MACOSX) 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #endif 34 35 #ifdef _MSC_VER /* Define ssize_t */ 36 37 #if !defined(_W64) 38 #if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 39 #define _W64 __w64 40 #else 41 #define _W64 42 #endif 43 #endif 44 45 #ifdef _WIN64 46 typedef __int64 ssize_t; 47 #else 48 typedef _W64 int ssize_t; 49 #endif 50 51 #endif 52 53 #include "def.h" 54 #include <string.h> 55 #ifdef hpux 56 #define sigvec sigvector 57 #endif /* hpux */ 58 59 #ifdef X_POSIX_C_SOURCE 60 #define _POSIX_C_SOURCE X_POSIX_C_SOURCE 61 #include <signal.h> 62 #undef _POSIX_C_SOURCE 63 #else 64 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) 65 #include <signal.h> 66 #else 67 #define _POSIX_SOURCE 68 #include <signal.h> 69 #undef _POSIX_SOURCE 70 #endif 71 #endif 72 73 #include <stdarg.h> 74 75 #ifdef MINIX 76 #define USE_CHMOD 1 77 #endif 78 79 #ifdef DEBUG 80 int _debugmask; 81 #endif 82 83 char *ProgramName; 84 85 #define OBJSUFFIX ".obj" 86 #define INCLUDEDIR "." 87 88 char *directives[] = { 89 "if", 90 "ifdef", 91 "ifndef", 92 "else", 93 "endif", 94 "define", 95 "undef", 96 "include", 97 "line", 98 "pragma", 99 "error", 100 "ident", 101 "sccs", 102 "elif", 103 "eject", 104 NULL 105 }; 106 107 #define MAKEDEPEND 108 #include "imakemdep.h" /* from config sources */ 109 #undef MAKEDEPEND 110 111 /******* function declarations ********/ 112 /******* added by -Wall project *******/ 113 void redirect(char * line, char * makefile ); 114 115 struct inclist inclist[ MAXFILES ], 116 *inclistp = inclist; 117 118 struct symhash *maininclist = NULL; 119 120 char *filelist[ MAXFILES ]; 121 char *includedirs[ MAXDIRS + 1 ]; 122 char *notdotdot[ MAXDIRS ]; 123 char *objprefix = ""; 124 char *objsuffix = OBJSUFFIX; 125 char *startat = "# DO NOT DELETE"; 126 int width = 78; 127 boolean append = FALSE; 128 boolean printed = FALSE; 129 boolean verbose = FALSE; 130 boolean show_where_not = FALSE; 131 boolean warn_multiple = FALSE; /* Warn on multiple includes of same file */ 132 133 static 134 #ifdef SIGNALRETURNSINT 135 int 136 #else 137 void 138 #endif 139 catch (sig) 140 int sig; 141 { 142 fflush (stdout); 143 abort(); 144 fatalerr ("got signal %d\n", sig); 145 } 146 147 #if defined(USG) || (defined(i386) && defined(SYSV)) || defined(WIN32) || defined(OS2) || defined(Lynx_22) 148 #define USGISH 149 #endif 150 151 #ifndef USGISH 152 #ifndef _POSIX_SOURCE 153 #define sigaction sigvec 154 #define sa_handler sv_handler 155 #define sa_mask sv_mask 156 #define sa_flags sv_flags 157 #endif 158 struct sigaction sig_act; 159 #endif /* USGISH */ 160 161 boolean native_win_slashes = FALSE; 162 163 int main(argc, argv) 164 int argc; 165 char **argv; 166 { 167 register char **fp = filelist; 168 register char **incp = includedirs; 169 register char *p; 170 register struct inclist *ip; 171 char *makefile = NULL; 172 struct filepointer *filecontent; 173 struct pair *psymp = predefs; 174 char *endmarker = NULL; 175 char *defincdir = NULL; 176 struct IncludesCollection* incCollection; 177 178 ProgramName = argv[0]; 179 180 while (psymp->p_name) 181 { 182 hash_define(psymp->p_name, psymp->p_value, &maininclist); 183 psymp++; 184 } 185 if (argc == 2 && argv[1][0] == '@') { 186 struct stat ast; 187 int afd; 188 char *args; 189 char **nargv; 190 int nargc; 191 char quotechar = '\0'; 192 193 nargc = 1; 194 if ((afd = open(argv[1]+1, O_RDONLY)) < 0) 195 fatalerr("cannot open \"%s\"\n", argv[1]+1); 196 fstat(afd, &ast); 197 args = (char *)malloc(ast.st_size + 1); 198 if ((ast.st_size = read(afd, args, (size_t) ast.st_size)) < 0) 199 fatalerr("failed to read %s\n", argv[1]+1); 200 args[ast.st_size] = '\0'; 201 close(afd); 202 for (p = args; *p; p++) { 203 if (quotechar) { 204 if (quotechar == '\\' || 205 (*p == quotechar && p[-1] != '\\')) 206 quotechar = '\0'; 207 continue; 208 } 209 switch (*p) { 210 case '\\': 211 case '"': 212 case '\'': 213 quotechar = *p; 214 break; 215 case ' ': 216 case '\n': 217 *p = '\0'; 218 if (p > args && p[-1]) 219 nargc++; 220 break; 221 } 222 } 223 if (p[-1]) 224 nargc++; 225 nargv = (char **)malloc(nargc * sizeof(char *)); 226 nargv[0] = argv[0]; 227 argc = 1; 228 for (p = args; argc < nargc; p += strlen(p) + 1) 229 if (*p) nargv[argc++] = p; 230 argv = nargv; 231 } 232 for(argc--, argv++; argc; argc--, argv++) { 233 /* if looking for endmarker then check before parsing */ 234 if (endmarker && strcmp (endmarker, *argv) == 0) { 235 endmarker = NULL; 236 continue; 237 } 238 if (**argv != '-') { 239 /* treat +thing as an option for C++ */ 240 if (endmarker && **argv == '+') 241 continue; 242 *fp++ = argv[0]; 243 continue; 244 } 245 switch(argv[0][1]) { 246 case '-': 247 endmarker = &argv[0][2]; 248 if (endmarker[0] == '\0') endmarker = "--"; 249 break; 250 case 'D': 251 if (argv[0][2] == '\0') { 252 argv++; 253 argc--; 254 } 255 for (p=argv[0] + 2; *p ; p++) 256 if (*p == '=') { 257 *p = ' '; 258 break; 259 } 260 define(argv[0] + 2, &maininclist); 261 break; 262 case 'I': 263 if (incp >= includedirs + MAXDIRS) 264 fatalerr("Too many -I flags.\n"); 265 *incp++ = argv[0]+2; 266 if (**(incp-1) == '\0') { 267 *(incp-1) = *(++argv); 268 argc--; 269 } 270 break; 271 case 'Y': 272 defincdir = argv[0]+2; 273 break; 274 /* do not use if endmarker processing */ 275 case 'a': 276 if (endmarker) break; 277 append = TRUE; 278 break; 279 case 'w': 280 if (endmarker) break; 281 if (argv[0][2] == '\0') { 282 argv++; 283 argc--; 284 width = atoi(argv[0]); 285 } else 286 width = atoi(argv[0]+2); 287 break; 288 case 'n': 289 // Use "-n" switch to generate dependencies with windows-native slash style 290 native_win_slashes = TRUE; 291 break; 292 case 'o': 293 if (endmarker) break; 294 if (argv[0][2] == '\0') { 295 argv++; 296 argc--; 297 objsuffix = argv[0]; 298 } else 299 objsuffix = argv[0]+2; 300 break; 301 case 'p': 302 if (endmarker) break; 303 if (argv[0][2] == '\0') { 304 argv++; 305 argc--; 306 objprefix = argv[0]; 307 } else 308 objprefix = argv[0]+2; 309 break; 310 case 'v': 311 if (endmarker) break; 312 verbose = TRUE; 313 #ifdef DEBUG 314 if (argv[0][2]) 315 _debugmask = atoi(argv[0]+2); 316 #endif 317 break; 318 case 's': 319 if (endmarker) break; 320 startat = argv[0]+2; 321 if (*startat == '\0') { 322 startat = *(++argv); 323 argc--; 324 } 325 if (*startat != '#') 326 fatalerr("-s flag's value should start %s\n", 327 "with '#'."); 328 break; 329 case 'f': 330 if (endmarker) break; 331 makefile = argv[0]+2; 332 if (*makefile == '\0') { 333 makefile = *(++argv); 334 argc--; 335 } 336 break; 337 338 case 'm': 339 warn_multiple = TRUE; 340 break; 341 342 /* Ignore -O, -g so we can just pass ${CFLAGS} to 343 makedepend 344 */ 345 case 'O': 346 case 'g': 347 break; 348 default: 349 if (endmarker) break; 350 /* fatalerr("unknown opt = %s\n", argv[0]); */ 351 warning("ignoring option %s\n", argv[0]); 352 } 353 } 354 355 convert_slashes(objprefix); 356 objprefix = append_slash(objprefix); 357 358 if (!defincdir) { 359 #ifdef PREINCDIR 360 if (incp >= includedirs + MAXDIRS) 361 fatalerr("Too many -I flags.\n"); 362 *incp++ = PREINCDIR; 363 #endif 364 if (incp >= includedirs + MAXDIRS) 365 fatalerr("Too many -I flags.\n"); 366 *incp++ = INCLUDEDIR; 367 #ifdef POSTINCDIR 368 if (incp >= includedirs + MAXDIRS) 369 fatalerr("Too many -I flags.\n"); 370 *incp++ = POSTINCDIR; 371 #endif 372 } else if (*defincdir) { 373 if (incp >= includedirs + MAXDIRS) 374 fatalerr("Too many -I flags.\n"); 375 *incp++ = defincdir; 376 } 377 378 redirect(startat, makefile); 379 380 /* 381 * catch signals. 382 */ 383 #ifdef USGISH 384 /* should really reset SIGINT to SIG_IGN if it was. */ 385 #ifdef SIGHUP 386 signal (SIGHUP, catch); 387 #endif 388 signal (SIGINT, catch); 389 #ifdef SIGQUIT 390 signal (SIGQUIT, catch); 391 #endif 392 signal (SIGILL, catch); 393 #ifdef SIGBUS 394 signal (SIGBUS, catch); 395 #endif 396 signal (SIGSEGV, catch); 397 #ifdef SIGSYS 398 signal (SIGSYS, catch); 399 #endif 400 signal (SIGFPE, catch); 401 #else 402 sig_act.sa_handler = catch; 403 #ifdef _POSIX_SOURCE 404 sigemptyset(&sig_act.sa_mask); 405 sigaddset(&sig_act.sa_mask, SIGINT); 406 sigaddset(&sig_act.sa_mask, SIGQUIT); 407 #ifdef SIGBUS 408 sigaddset(&sig_act.sa_mask, SIGBUS); 409 #endif 410 sigaddset(&sig_act.sa_mask, SIGILL); 411 sigaddset(&sig_act.sa_mask, SIGSEGV); 412 sigaddset(&sig_act.sa_mask, SIGHUP); 413 sigaddset(&sig_act.sa_mask, SIGPIPE); 414 #ifdef SIGSYS 415 sigaddset(&sig_act.sa_mask, SIGSYS); 416 #endif 417 #else 418 sig_act.sa_mask = ((1<<(SIGINT -1)) 419 |(1<<(SIGQUIT-1)) 420 #ifdef SIGBUS 421 |(1<<(SIGBUS-1)) 422 #endif 423 |(1<<(SIGILL-1)) 424 |(1<<(SIGSEGV-1)) 425 |(1<<(SIGHUP-1)) 426 |(1<<(SIGPIPE-1)) 427 #ifdef SIGSYS 428 |(1<<(SIGSYS-1)) 429 #endif 430 ); 431 #endif /* _POSIX_SOURCE */ 432 sig_act.sa_flags = 0; 433 sigaction(SIGHUP, &sig_act, (struct sigaction *)0); 434 sigaction(SIGINT, &sig_act, (struct sigaction *)0); 435 sigaction(SIGQUIT, &sig_act, (struct sigaction *)0); 436 sigaction(SIGILL, &sig_act, (struct sigaction *)0); 437 #ifdef SIGBUS 438 sigaction(SIGBUS, &sig_act, (struct sigaction *)0); 439 #endif 440 sigaction(SIGSEGV, &sig_act, (struct sigaction *)0); 441 #ifdef SIGSYS 442 sigaction(SIGSYS, &sig_act, (struct sigaction *)0); 443 #endif 444 #endif /* USGISH */ 445 446 /* 447 * now peruse through the list of files. 448 */ 449 incCollection = create_IncludesCollection(); 450 451 for(fp=filelist; *fp; fp++) { 452 struct symhash *includes; 453 filecontent = getfile(*fp); 454 ip = newinclude(*fp, (char *)NULL); 455 456 includes = hash_copy( maininclist ); 457 find_includes(filecontent, ip, ip, 0, FALSE, incCollection, includes); 458 hash_free( includes ); 459 460 freefile(filecontent); 461 recursive_pr_include(ip, ip->i_file, base_name(*fp)); 462 inc_clean(); 463 } 464 if (printed) 465 printf("\n"); 466 467 delete_IncludesCollection(incCollection); 468 469 exit(0); 470 } 471 472 struct filepointer *getfile(file) 473 char *file; 474 { 475 register int fd; 476 struct filepointer *content; 477 struct stat st; 478 off_t size_backup; 479 ssize_t bytes_read; 480 size_t malloc_size; 481 482 content = (struct filepointer *)malloc(sizeof(struct filepointer)); 483 if ((fd = open(file, O_RDONLY)) < 0) { 484 warning("makedepend: Cannot open file \"%s\"\n", file); 485 content->f_p = content->f_base = content->f_end = (char *)malloc(1); 486 *content->f_p = '\0'; 487 return(content); 488 } 489 fstat(fd, &st); 490 491 size_backup = st.st_size; 492 malloc_size = size_backup; 493 /* Since off_t is larger than size_t, need to test for 494 * truncation. 495 */ 496 if ( (off_t)malloc_size != size_backup ) 497 { 498 close( fd ); 499 warning("makedepend: File \"%s\" size larger than can fit in size_t. Cannot allocate memory for contents.\n", file); 500 content->f_p = content->f_base = content->f_end = (char *)malloc(1); 501 *content->f_p = '\0'; 502 return(content); 503 } 504 505 content->f_base = (char *)malloc(malloc_size+1); 506 if (content->f_base == NULL) 507 fatalerr("makedepend: Cannot allocate memory to process file \"%s\"\n", file); 508 if ((bytes_read = read(fd, content->f_base, malloc_size)) < 0) 509 if ( st.st_mode & S_IFREG ) 510 fatalerr("makedepend: Failed to read file \"%s\"\n", file); 511 512 close(fd); 513 content->f_len = bytes_read+1; 514 content->f_p = content->f_base; 515 content->f_end = content->f_base + bytes_read; 516 *content->f_end = '\0'; 517 content->f_line = 0; 518 return(content); 519 } 520 521 void freefile(fp) 522 struct filepointer *fp; 523 { 524 free(fp->f_base); 525 free(fp); 526 } 527 528 char *copy(str) 529 register char *str; 530 { 531 register char *p = (char *)malloc(strlen(str) + 1); 532 533 strcpy(p, str); 534 return(p); 535 } 536 537 int match(str, list) 538 register char *str, **list; 539 { 540 register int i; 541 542 for (i=0; *list; i++, list++) 543 if (strcmp(str, *list) == 0) 544 return(i); 545 return(-1); 546 } 547 548 /* 549 * Get the next line. We only return lines beginning with '#' since that 550 * is all this program is ever interested in. 551 */ 552 char *get_line(filep) 553 register struct filepointer *filep; 554 { 555 register char *p, /* walking pointer */ 556 *eof, /* end of file pointer */ 557 *bol; /* beginning of line pointer */ 558 register int lineno; /* line number */ 559 560 p = filep->f_p; 561 eof = filep->f_end; 562 if (p >= eof) 563 return((char *)NULL); 564 lineno = filep->f_line; 565 566 for(bol = p--; ++p < eof; ) { 567 if (*p == '/' && *(p+1) == '*') { /* consume comments */ 568 *p++ = ' ', *p++ = ' '; 569 while (*p) { 570 if (*p == '*' && *(p+1) == '/') { 571 *p++ = ' ', *p = ' '; 572 break; 573 } 574 else if (*p == '\n') 575 lineno++; 576 *p++ = ' '; 577 } 578 continue; 579 } 580 else if (*p == '/' && *(p+1) == '/') { /* consume comments */ 581 *p++ = ' ', *p++ = ' '; 582 while (*p && *p != '\n') 583 *p++ = ' '; 584 if ( *p == '\n' ) 585 p--; 586 lineno++; 587 continue; 588 } 589 else if (*p == '\\') { 590 if (*(p+1) == '\n') { 591 *p = ' '; 592 *(p+1) = ' '; 593 lineno++; 594 } 595 } 596 else if (*p == '\n') { 597 lineno++; 598 if (*bol == '#') { 599 register char *cp; 600 601 *p++ = '\0'; 602 /* punt lines with just # (yacc generated) */ 603 for (cp = bol+1; 604 *cp && (*cp == ' ' || *cp == '\t'); cp++); 605 if (*cp) goto done; 606 } 607 bol = p+1; 608 } 609 } 610 if (*bol != '#') 611 bol = NULL; 612 done: 613 filep->f_p = p; 614 filep->f_line = lineno; 615 return(bol); 616 } 617 618 /* 619 * Strip the file name down to what we want to see in the Makefile. 620 * It will have objprefix and objsuffix around it. 621 */ 622 char *base_name(file) 623 register char *file; 624 { 625 register char *p; 626 627 file = copy(file); 628 for(p=file+strlen(file); p>file && *p != '.'; p--) ; 629 630 if (*p == '.') 631 *p = '\0'; 632 633 while (p > file) { 634 if ( *p == '/' || *p == '\\') { 635 file = p + 1; 636 break; 637 } 638 p--; 639 } 640 return(file); 641 } 642 643 #if defined(USG) && !defined(CRAY) && !defined(SVR4) 644 int rename (from, to) 645 char *from, *to; 646 { 647 (void) unlink (to); 648 if (link (from, to) == 0) { 649 unlink (from); 650 return 0; 651 } else { 652 return -1; 653 } 654 } 655 #endif /* USGISH */ 656 657 void redirect(line, makefile) 658 char *line, 659 *makefile; 660 { 661 struct stat st; 662 FILE *fdin, *fdout; 663 char backup[ OURBUFSIZ ], 664 buf[ OURBUFSIZ ]; 665 boolean found = FALSE; 666 int len; 667 668 /* 669 * if makefile is "-" then let it pour onto stdout. 670 */ 671 if (makefile && *makefile == '-' && *(makefile+1) == '\0') 672 return; 673 674 /* 675 * use a default makefile is not specified. 676 */ 677 if (!makefile) { 678 if (stat("Makefile", &st) == 0) 679 makefile = "Makefile"; 680 else if (stat("makefile", &st) == 0) 681 makefile = "makefile"; 682 else 683 fatalerr("[mM]akefile is not present\n"); 684 } 685 else 686 stat(makefile, &st); 687 if ((fdin = fopen(makefile, "r")) == NULL) 688 fatalerr("cannot open \"%s\"\n", makefile); 689 sprintf(backup, "%s.bak", makefile); 690 unlink(backup); 691 #if defined(WIN32) || defined(OS2) 692 fclose(fdin); 693 #endif 694 if (rename(makefile, backup) < 0) 695 fatalerr("cannot rename %s to %s\n", makefile, backup); 696 #if defined(WIN32) || defined(OS2) 697 if ((fdin = fopen(backup, "r")) == NULL) 698 fatalerr("cannot open \"%s\"\n", backup); 699 #endif 700 if ((fdout = freopen(makefile, "w", stdout)) == NULL) 701 fatalerr("cannot open \"%s\"\n", backup); 702 len = strlen(line); 703 while (!found && fgets(buf, OURBUFSIZ, fdin)) { 704 if (*buf == '#' && strncmp(line, buf, len) == 0) 705 found = TRUE; 706 fputs(buf, fdout); 707 } 708 if (!found) { 709 if (verbose) 710 warning("Adding new delimiting line \"%s\" and dependencies...\n", 711 line); 712 puts(line); /* same as fputs(fdout); but with newline */ 713 } else if (append) { 714 while (fgets(buf, OURBUFSIZ, fdin)) { 715 fputs(buf, fdout); 716 } 717 } 718 fflush(fdout); 719 #if defined(USGISH) || defined(_SEQUENT_) || defined(USE_CHMOD) 720 chmod(makefile, st.st_mode); 721 #else 722 fchmod(fileno(fdout), st.st_mode); 723 #endif /* USGISH */ 724 fclose(fdin); 725 } 726 727 void fatalerr(char *msg, ...) 728 { 729 va_list args; 730 fprintf(stderr, "%s: error: ", ProgramName); 731 va_start(args, msg); 732 vfprintf(stderr, msg, args); 733 va_end(args); 734 exit (1); 735 } 736 737 void warning(char *msg, ...) 738 { 739 #ifdef DEBUG_MKDEPEND 740 va_list args; 741 fprintf(stderr, "%s: warning: ", ProgramName); 742 va_start(args, msg); 743 vfprintf(stderr, msg, args); 744 va_end(args); 745 #else 746 (void)msg; 747 #endif /* DEBUG_MKDEPEND */ 748 } 749 750 void warning1(char *msg, ...) 751 { 752 #ifdef DEBUG_MKDEPEND 753 va_list args; 754 va_start(args, msg); 755 vfprintf(stderr, msg, args); 756 va_end(args); 757 #else 758 (void)msg; 759 #endif /* DEBUG_MKDEPEND */ 760 } 761 762 void convert_slashes(path) 763 char* path; 764 { 765 #if defined (WNT) || defined(OS2) 766 /* 767 * Convert backslashes to slashes 768 */ 769 char *ptr; 770 if (native_win_slashes) { 771 for (ptr = (char*)path; *ptr; ++ptr) 772 if (*ptr == '/') 773 *ptr = '\\'; 774 } else { 775 for (ptr = (char*)path; *ptr; ++ptr) 776 if (*ptr == '\\') 777 *ptr = '/'; 778 } 779 #else 780 (void)path; 781 #endif 782 } 783 784 char* append_slash(path) 785 char* path; 786 { 787 char *new_string; 788 if ((path[strlen(path) - 1] == '/') || (path[strlen(path) - 1] == '\\')) { 789 new_string = path; 790 } else { 791 new_string = (char*)malloc(sizeof(char) * (strlen(path) + 2)); 792 strcpy(new_string, path); 793 if (native_win_slashes) 794 strcat(new_string, "\\"); 795 else 796 strcat(new_string, "/"); 797 } 798 return new_string; 799 } 800 801