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