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
catch(sig)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
main(argc,argv)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
getfile(file)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
freefile(fp)521 void freefile(fp)
522 struct filepointer *fp;
523 {
524 free(fp->f_base);
525 free(fp);
526 }
527
copy(str)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
match(str,list)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 */
get_line(filep)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 */
base_name(file)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)
rename(from,to)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
redirect(line,makefile)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
fatalerr(char * msg,...)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
warning(char * msg,...)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
warning1(char * msg,...)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
convert_slashes(path)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
append_slash(path)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