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