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