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 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
main(argc,argv)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
getfile(file)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
freefile(fp)520 void freefile(fp)
521 struct filepointer *fp;
522 {
523 free(fp->f_base);
524 free(fp);
525 }
526
copy(str)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
match(str,list)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 */
get_line(filep)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 */
base_name(file)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)
rename(from,to)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
redirect(line,makefile)656 void redirect(line, makefile)
657 char *line,
658 *makefile;
659 {
660 struct stat st;
661 FILE *fdin, *fdout;
662 char backup[ OURBUFSIZ ],
663 buf[ OURBUFSIZ ];
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, OURBUFSIZ, 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, OURBUFSIZ, 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
fatalerr(char * msg,...)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
warning(char * msg,...)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
warning1(char * msg,...)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
convert_slashes(path)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
append_slash(path)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