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 fatalerr ("got signal %d\n", sig); 144 } 145 146 #if defined(USG) || (defined(i386) && defined(SYSV)) || defined(WIN32) || defined(OS2) || defined(Lynx_22) 147 #define USGISH 148 #endif 149 150 #ifndef USGISH 151 #ifndef _POSIX_SOURCE 152 #define sigaction sigvec 153 #define sa_handler sv_handler 154 #define sa_mask sv_mask 155 #define sa_flags sv_flags 156 #endif 157 struct sigaction sig_act; 158 #endif /* USGISH */ 159 160 boolean native_win_slashes = FALSE; 161 162 int main(argc, argv) 163 int argc; 164 char **argv; 165 { 166 register char **fp = filelist; 167 register char **incp = includedirs; 168 register char *p; 169 register struct inclist *ip; 170 char *makefile = NULL; 171 struct filepointer *filecontent; 172 struct pair *psymp = predefs; 173 char *endmarker = NULL; 174 char *defincdir = NULL; 175 struct IncludesCollection* incCollection; 176 177 ProgramName = argv[0]; 178 179 while (psymp->p_name) 180 { 181 hash_define(psymp->p_name, psymp->p_value, &maininclist); 182 psymp++; 183 } 184 if (argc == 2 && argv[1][0] == '@') { 185 struct stat ast; 186 int afd; 187 char *args; 188 char **nargv; 189 int nargc; 190 char quotechar = '\0'; 191 192 nargc = 1; 193 if ((afd = open(argv[1]+1, O_RDONLY)) < 0) 194 fatalerr("cannot open \"%s\"\n", argv[1]+1); 195 fstat(afd, &ast); 196 args = (char *)malloc(ast.st_size + 1); 197 if ((ast.st_size = read(afd, args, (size_t) ast.st_size)) < 0) 198 fatalerr("failed to read %s\n", argv[1]+1); 199 args[ast.st_size] = '\0'; 200 close(afd); 201 for (p = args; *p; p++) { 202 if (quotechar) { 203 if (quotechar == '\\' || 204 (*p == quotechar && p[-1] != '\\')) 205 quotechar = '\0'; 206 continue; 207 } 208 switch (*p) { 209 case '\\': 210 case '"': 211 case '\'': 212 quotechar = *p; 213 break; 214 case ' ': 215 case '\n': 216 *p = '\0'; 217 if (p > args && p[-1]) 218 nargc++; 219 break; 220 } 221 } 222 if (p[-1]) 223 nargc++; 224 nargv = (char **)malloc(nargc * sizeof(char *)); 225 nargv[0] = argv[0]; 226 argc = 1; 227 for (p = args; argc < nargc; p += strlen(p) + 1) 228 if (*p) nargv[argc++] = p; 229 argv = nargv; 230 } 231 for(argc--, argv++; argc; argc--, argv++) { 232 /* if looking for endmarker then check before parsing */ 233 if (endmarker && strcmp (endmarker, *argv) == 0) { 234 endmarker = NULL; 235 continue; 236 } 237 if (**argv != '-') { 238 /* treat +thing as an option for C++ */ 239 if (endmarker && **argv == '+') 240 continue; 241 *fp++ = argv[0]; 242 continue; 243 } 244 switch(argv[0][1]) { 245 case '-': 246 endmarker = &argv[0][2]; 247 if (endmarker[0] == '\0') endmarker = "--"; 248 break; 249 case 'D': 250 if (argv[0][2] == '\0') { 251 argv++; 252 argc--; 253 } 254 for (p=argv[0] + 2; *p ; p++) 255 if (*p == '=') { 256 *p = ' '; 257 break; 258 } 259 define(argv[0] + 2, &maininclist); 260 break; 261 case 'I': 262 if (incp >= includedirs + MAXDIRS) 263 fatalerr("Too many -I flags.\n"); 264 *incp++ = argv[0]+2; 265 if (**(incp-1) == '\0') { 266 *(incp-1) = *(++argv); 267 argc--; 268 } 269 break; 270 case 'Y': 271 defincdir = argv[0]+2; 272 break; 273 /* do not use if endmarker processing */ 274 case 'a': 275 if (endmarker) break; 276 append = TRUE; 277 break; 278 case 'w': 279 if (endmarker) break; 280 if (argv[0][2] == '\0') { 281 argv++; 282 argc--; 283 width = atoi(argv[0]); 284 } else 285 width = atoi(argv[0]+2); 286 break; 287 case 'n': 288 // Use "-n" switch to generate dependencies with windows-native slash style 289 native_win_slashes = TRUE; 290 break; 291 case 'o': 292 if (endmarker) break; 293 if (argv[0][2] == '\0') { 294 argv++; 295 argc--; 296 objsuffix = argv[0]; 297 } else 298 objsuffix = argv[0]+2; 299 break; 300 case 'p': 301 if (endmarker) break; 302 if (argv[0][2] == '\0') { 303 argv++; 304 argc--; 305 objprefix = argv[0]; 306 } else 307 objprefix = argv[0]+2; 308 break; 309 case 'v': 310 if (endmarker) break; 311 verbose = TRUE; 312 #ifdef DEBUG 313 if (argv[0][2]) 314 _debugmask = atoi(argv[0]+2); 315 #endif 316 break; 317 case 's': 318 if (endmarker) break; 319 startat = argv[0]+2; 320 if (*startat == '\0') { 321 startat = *(++argv); 322 argc--; 323 } 324 if (*startat != '#') 325 fatalerr("-s flag's value should start %s\n", 326 "with '#'."); 327 break; 328 case 'f': 329 if (endmarker) break; 330 makefile = argv[0]+2; 331 if (*makefile == '\0') { 332 makefile = *(++argv); 333 argc--; 334 } 335 break; 336 337 case 'm': 338 warn_multiple = TRUE; 339 break; 340 341 /* Ignore -O, -g so we can just pass ${CFLAGS} to 342 makedepend 343 */ 344 case 'O': 345 case 'g': 346 break; 347 default: 348 if (endmarker) break; 349 /* fatalerr("unknown opt = %s\n", argv[0]); */ 350 warning("ignoring option %s\n", argv[0]); 351 } 352 } 353 354 convert_slashes(objprefix); 355 objprefix = append_slash(objprefix); 356 357 if (!defincdir) { 358 #ifdef PREINCDIR 359 if (incp >= includedirs + MAXDIRS) 360 fatalerr("Too many -I flags.\n"); 361 *incp++ = PREINCDIR; 362 #endif 363 if (incp >= includedirs + MAXDIRS) 364 fatalerr("Too many -I flags.\n"); 365 *incp++ = INCLUDEDIR; 366 #ifdef POSTINCDIR 367 if (incp >= includedirs + MAXDIRS) 368 fatalerr("Too many -I flags.\n"); 369 *incp++ = POSTINCDIR; 370 #endif 371 } else if (*defincdir) { 372 if (incp >= includedirs + MAXDIRS) 373 fatalerr("Too many -I flags.\n"); 374 *incp++ = defincdir; 375 } 376 377 redirect(startat, makefile); 378 379 /* 380 * catch signals. 381 */ 382 #ifdef USGISH 383 /* should really reset SIGINT to SIG_IGN if it was. */ 384 #ifdef SIGHUP 385 signal (SIGHUP, catch); 386 #endif 387 signal (SIGINT, catch); 388 #ifdef SIGQUIT 389 signal (SIGQUIT, catch); 390 #endif 391 signal (SIGILL, catch); 392 #ifdef SIGBUS 393 signal (SIGBUS, catch); 394 #endif 395 signal (SIGSEGV, catch); 396 #ifdef SIGSYS 397 signal (SIGSYS, catch); 398 #endif 399 signal (SIGFPE, catch); 400 #else 401 sig_act.sa_handler = catch; 402 #ifdef _POSIX_SOURCE 403 sigemptyset(&sig_act.sa_mask); 404 sigaddset(&sig_act.sa_mask, SIGINT); 405 sigaddset(&sig_act.sa_mask, SIGQUIT); 406 #ifdef SIGBUS 407 sigaddset(&sig_act.sa_mask, SIGBUS); 408 #endif 409 sigaddset(&sig_act.sa_mask, SIGILL); 410 sigaddset(&sig_act.sa_mask, SIGSEGV); 411 sigaddset(&sig_act.sa_mask, SIGHUP); 412 sigaddset(&sig_act.sa_mask, SIGPIPE); 413 #ifdef SIGSYS 414 sigaddset(&sig_act.sa_mask, SIGSYS); 415 #endif 416 #else 417 sig_act.sa_mask = ((1<<(SIGINT -1)) 418 |(1<<(SIGQUIT-1)) 419 #ifdef SIGBUS 420 |(1<<(SIGBUS-1)) 421 #endif 422 |(1<<(SIGILL-1)) 423 |(1<<(SIGSEGV-1)) 424 |(1<<(SIGHUP-1)) 425 |(1<<(SIGPIPE-1)) 426 #ifdef SIGSYS 427 |(1<<(SIGSYS-1)) 428 #endif 429 ); 430 #endif /* _POSIX_SOURCE */ 431 sig_act.sa_flags = 0; 432 sigaction(SIGHUP, &sig_act, (struct sigaction *)0); 433 sigaction(SIGINT, &sig_act, (struct sigaction *)0); 434 sigaction(SIGQUIT, &sig_act, (struct sigaction *)0); 435 sigaction(SIGILL, &sig_act, (struct sigaction *)0); 436 #ifdef SIGBUS 437 sigaction(SIGBUS, &sig_act, (struct sigaction *)0); 438 #endif 439 sigaction(SIGSEGV, &sig_act, (struct sigaction *)0); 440 #ifdef SIGSYS 441 sigaction(SIGSYS, &sig_act, (struct sigaction *)0); 442 #endif 443 #endif /* USGISH */ 444 445 /* 446 * now peruse through the list of files. 447 */ 448 incCollection = create_IncludesCollection(); 449 450 for(fp=filelist; *fp; fp++) { 451 struct symhash *includes; 452 filecontent = getfile(*fp); 453 ip = newinclude(*fp, (char *)NULL); 454 455 includes = hash_copy( maininclist ); 456 find_includes(filecontent, ip, ip, 0, FALSE, incCollection, includes); 457 hash_free( includes ); 458 459 freefile(filecontent); 460 recursive_pr_include(ip, ip->i_file, base_name(*fp)); 461 inc_clean(); 462 } 463 if (printed) 464 printf("\n"); 465 466 delete_IncludesCollection(incCollection); 467 468 exit(0); 469 } 470 471 struct filepointer *getfile(file) 472 char *file; 473 { 474 register int fd; 475 struct filepointer *content; 476 struct stat st; 477 off_t size_backup; 478 ssize_t bytes_read; 479 size_t malloc_size; 480 481 content = (struct filepointer *)malloc(sizeof(struct filepointer)); 482 if ((fd = open(file, O_RDONLY)) < 0) { 483 warning("makedepend: Cannot open file \"%s\"\n", file); 484 content->f_p = content->f_base = content->f_end = (char *)malloc(1); 485 *content->f_p = '\0'; 486 return(content); 487 } 488 fstat(fd, &st); 489 490 size_backup = st.st_size; 491 malloc_size = size_backup; 492 /* Since off_t is larger than size_t, need to test for 493 * truncation. 494 */ 495 if ( (off_t)malloc_size != size_backup ) 496 { 497 close( fd ); 498 warning("makedepend: File \"%s\" size larger than can fit in size_t. Cannot allocate memory for contents.\n", file); 499 content->f_p = content->f_base = content->f_end = (char *)malloc(1); 500 *content->f_p = '\0'; 501 return(content); 502 } 503 504 content->f_base = (char *)malloc(malloc_size+1); 505 if (content->f_base == NULL) 506 fatalerr("makedepend: Cannot allocate memory to process file \"%s\"\n", file); 507 if ((bytes_read = read(fd, content->f_base, malloc_size)) < 0) 508 if ( st.st_mode & S_IFREG ) 509 fatalerr("makedepend: Failed to read file \"%s\"\n", file); 510 511 close(fd); 512 content->f_len = bytes_read+1; 513 content->f_p = content->f_base; 514 content->f_end = content->f_base + bytes_read; 515 *content->f_end = '\0'; 516 content->f_line = 0; 517 return(content); 518 } 519 520 void freefile(fp) 521 struct filepointer *fp; 522 { 523 free(fp->f_base); 524 free(fp); 525 } 526 527 char *copy(str) 528 register char *str; 529 { 530 register char *p = (char *)malloc(strlen(str) + 1); 531 532 strcpy(p, str); 533 return(p); 534 } 535 536 int match(str, list) 537 register char *str, **list; 538 { 539 register int i; 540 541 for (i=0; *list; i++, list++) 542 if (strcmp(str, *list) == 0) 543 return(i); 544 return(-1); 545 } 546 547 /* 548 * Get the next line. We only return lines beginning with '#' since that 549 * is all this program is ever interested in. 550 */ 551 char *get_line(filep) 552 register struct filepointer *filep; 553 { 554 register char *p, /* walking pointer */ 555 *eof, /* end of file pointer */ 556 *bol; /* beginning of line pointer */ 557 register int lineno; /* line number */ 558 559 p = filep->f_p; 560 eof = filep->f_end; 561 if (p >= eof) 562 return((char *)NULL); 563 lineno = filep->f_line; 564 565 for(bol = p--; ++p < eof; ) { 566 if (*p == '/' && *(p+1) == '*') { /* consume comments */ 567 *p++ = ' ', *p++ = ' '; 568 while (*p) { 569 if (*p == '*' && *(p+1) == '/') { 570 *p++ = ' ', *p = ' '; 571 break; 572 } 573 else if (*p == '\n') 574 lineno++; 575 *p++ = ' '; 576 } 577 continue; 578 } 579 else if (*p == '/' && *(p+1) == '/') { /* consume comments */ 580 *p++ = ' ', *p++ = ' '; 581 while (*p && *p != '\n') 582 *p++ = ' '; 583 if ( *p == '\n' ) 584 p--; 585 lineno++; 586 continue; 587 } 588 else if (*p == '\\') { 589 if (*(p+1) == '\n') { 590 *p = ' '; 591 *(p+1) = ' '; 592 lineno++; 593 } 594 } 595 else if (*p == '\n') { 596 lineno++; 597 if (*bol == '#') { 598 register char *cp; 599 600 *p++ = '\0'; 601 /* punt lines with just # (yacc generated) */ 602 for (cp = bol+1; 603 *cp && (*cp == ' ' || *cp == '\t'); cp++); 604 if (*cp) goto done; 605 } 606 bol = p+1; 607 } 608 } 609 if (*bol != '#') 610 bol = NULL; 611 done: 612 filep->f_p = p; 613 filep->f_line = lineno; 614 return(bol); 615 } 616 617 /* 618 * Strip the file name down to what we want to see in the Makefile. 619 * It will have objprefix and objsuffix around it. 620 */ 621 char *base_name(file) 622 register char *file; 623 { 624 register char *p; 625 626 file = copy(file); 627 for(p=file+strlen(file); p>file && *p != '.'; p--) ; 628 629 if (*p == '.') 630 *p = '\0'; 631 632 while (p > file) { 633 if ( *p == '/' || *p == '\\') { 634 file = p + 1; 635 break; 636 }; 637 p--; 638 }; 639 return(file); 640 } 641 642 #if defined(USG) && !defined(CRAY) && !defined(SVR4) 643 int rename (from, to) 644 char *from, *to; 645 { 646 (void) unlink (to); 647 if (link (from, to) == 0) { 648 unlink (from); 649 return 0; 650 } else { 651 return -1; 652 } 653 } 654 #endif /* USGISH */ 655 656 void redirect(line, makefile) 657 char *line, 658 *makefile; 659 { 660 struct stat st; 661 FILE *fdin, *fdout; 662 char backup[ BUFSIZ ], 663 buf[ BUFSIZ ]; 664 boolean found = FALSE; 665 int len; 666 667 /* 668 * if makefile is "-" then let it pour onto stdout. 669 */ 670 if (makefile && *makefile == '-' && *(makefile+1) == '\0') 671 return; 672 673 /* 674 * use a default makefile is not specified. 675 */ 676 if (!makefile) { 677 if (stat("Makefile", &st) == 0) 678 makefile = "Makefile"; 679 else if (stat("makefile", &st) == 0) 680 makefile = "makefile"; 681 else 682 fatalerr("[mM]akefile is not present\n"); 683 } 684 else 685 stat(makefile, &st); 686 if ((fdin = fopen(makefile, "r")) == NULL) 687 fatalerr("cannot open \"%s\"\n", makefile); 688 sprintf(backup, "%s.bak", makefile); 689 unlink(backup); 690 #if defined(WIN32) || defined(OS2) 691 fclose(fdin); 692 #endif 693 if (rename(makefile, backup) < 0) 694 fatalerr("cannot rename %s to %s\n", makefile, backup); 695 #if defined(WIN32) || defined(OS2) 696 if ((fdin = fopen(backup, "r")) == NULL) 697 fatalerr("cannot open \"%s\"\n", backup); 698 #endif 699 if ((fdout = freopen(makefile, "w", stdout)) == NULL) 700 fatalerr("cannot open \"%s\"\n", backup); 701 len = strlen(line); 702 while (!found && fgets(buf, BUFSIZ, fdin)) { 703 if (*buf == '#' && strncmp(line, buf, len) == 0) 704 found = TRUE; 705 fputs(buf, fdout); 706 } 707 if (!found) { 708 if (verbose) 709 warning("Adding new delimiting line \"%s\" and dependencies...\n", 710 line); 711 puts(line); /* same as fputs(fdout); but with newline */ 712 } else if (append) { 713 while (fgets(buf, BUFSIZ, fdin)) { 714 fputs(buf, fdout); 715 } 716 } 717 fflush(fdout); 718 #if defined(USGISH) || defined(_SEQUENT_) || defined(USE_CHMOD) 719 chmod(makefile, st.st_mode); 720 #else 721 fchmod(fileno(fdout), st.st_mode); 722 #endif /* USGISH */ 723 fclose(fdin); 724 } 725 726 void fatalerr(char *msg, ...) 727 { 728 va_list args; 729 fprintf(stderr, "%s: error: ", ProgramName); 730 va_start(args, msg); 731 vfprintf(stderr, msg, args); 732 va_end(args); 733 exit (1); 734 } 735 736 void warning(char *msg, ...) 737 { 738 #ifdef DEBUG_MKDEPEND 739 va_list args; 740 fprintf(stderr, "%s: warning: ", ProgramName); 741 va_start(args, msg); 742 vfprintf(stderr, msg, args); 743 va_end(args); 744 #else 745 (void)msg; 746 #endif /* DEBUG_MKDEPEND */ 747 } 748 749 void warning1(char *msg, ...) 750 { 751 #ifdef DEBUG_MKDEPEND 752 va_list args; 753 va_start(args, msg); 754 vfprintf(stderr, msg, args); 755 va_end(args); 756 #else 757 (void)msg; 758 #endif /* DEBUG_MKDEPEND */ 759 } 760 761 void convert_slashes(path) 762 char* path; 763 { 764 #if defined (WNT) || defined(OS2) 765 /* 766 * Convert backslashes to slashes 767 */ 768 char *ptr; 769 if (native_win_slashes) { 770 for (ptr = (char*)path; *ptr; ++ptr) 771 if (*ptr == '/') 772 *ptr = '\\'; 773 } else { 774 for (ptr = (char*)path; *ptr; ++ptr) 775 if (*ptr == '\\') 776 *ptr = '/'; 777 }; 778 #else 779 (void)path; 780 #endif 781 } 782 783 char* append_slash(path) 784 char* path; 785 { 786 char *new_string; 787 if ((path[strlen(path) - 1] == '/') || (path[strlen(path) - 1] == '\\')) { 788 new_string = path; 789 } else { 790 new_string = (char*)malloc(sizeof(char) * (strlen(path) + 2)); 791 strcpy(new_string, path); 792 if (native_win_slashes) 793 strcat(new_string, "\\"); 794 else 795 strcat(new_string, "/"); 796 }; 797 return new_string; 798 } 799 800