Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2 
      3 Copyright (c) 1993, 1994, 1998 The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in 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
     41 int _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 
     54 static const char *ProgramName;
     55 
     56 #include "imakemdep.h"
     57 
     58 struct inclist  inclist[MAXFILES],
     59                 *inclistp = inclist,
     60                 *inclistnext = inclist,
     61                 maininclist;
     62 
     63 static char     *filelist[MAXFILES];
     64 const char      *includedirs[MAXDIRS + 1],
     65                 **includedirsnext = includedirs;
     66 char            *notdotdot[MAXDIRS];
     67 static int      cmdinc_count = 0;
     68 static char     *cmdinc_list[2 * MAXINCFILES];
     69 const char      *objprefix = "";
     70 const char      *objsuffix = OBJSUFFIX;
     71 static const char *startat = "# DO NOT DELETE";
     72 int             width = 78;
     73 static boolean  append = FALSE;
     74 boolean         printed = FALSE;
     75 boolean         verbose = FALSE;
     76 boolean         show_where_not = FALSE;
     77 
     78 /* Warn on multiple includes of same file */
     79 boolean         warn_multiple = FALSE;
     80 
     81 static void setfile_cmdinc(struct filepointer *filep, long count, char **list);
     82 static char *base_name(const char *file);
     83 static void redirect(const char *line, const char *makefile);
     84 
     85 static void _X_NORETURN
     86 catch(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
    103 static struct sigaction sig_act;
    104 #endif /* USGISH */
    105 
    106 int
    107 main(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 
    501 struct filepointer *
    502 getfile(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 
    538 void
    539 setfile_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 
    546 void
    547 freefile(struct filepointer *fp)
    548 {
    549     free(fp->f_base);
    550     free(fp);
    551 }
    552 
    553 int
    554 match(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  */
    568 char *
    569 getnextline(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  */
    690 char *
    691 base_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
    707 int
    708 rename(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 
    721 static void
    722 redirect(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 
    795 void
    796 fatalerr(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 
    807 void
    808 warning(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 
    818 void
    819 warning1(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