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