mkdep.c revision 1.10
190075Sobrien/* $NetBSD: mkdep.c,v 1.10 2002/01/31 22:43:55 tv Exp $ */
290075Sobrien
3132718Skan/*-
490075Sobrien * Copyright (c) 1999 The NetBSD Foundation, Inc.
590075Sobrien * All rights reserved.
690075Sobrien *
790075Sobrien * This code is derived from software contributed to The NetBSD Foundation
890075Sobrien * by Matthias Scheler.
990075Sobrien *
1090075Sobrien * Redistribution and use in source and binary forms, with or without
1190075Sobrien * modification, are permitted provided that the following conditions
1290075Sobrien * are met:
1390075Sobrien * 1. Redistributions of source code must retain the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer.
1590075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1690075Sobrien *    notice, this list of conditions and the following disclaimer in the
1790075Sobrien *    documentation and/or other materials provided with the distribution.
1890075Sobrien * 3. All advertising materials mentioning features or use of this software
1990075Sobrien *    must display the following acknowledgement:
2090075Sobrien *	This product includes software developed by the NetBSD
2190075Sobrien *	Foundation, Inc. and its contributors.
2290075Sobrien * 4. Neither the name of The NetBSD Foundation nor the names of its
2390075Sobrien *    contributors may be used to endorse or promote products derived
2490075Sobrien *    from this software without specific prior written permission.
2590075Sobrien *
2690075Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2790075Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2890075Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2990075Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
3090075Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3190075Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3290075Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3390075Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3490075Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3590075Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3690075Sobrien * POSSIBILITY OF SUCH DAMAGE.
3790075Sobrien */
3890075Sobrien
3990075Sobrien#include <sys/cdefs.h>
40132718Skan#if defined(__COPYRIGHT) && !defined(lint)
41132718Skan__COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\n\
4290075Sobrien	All rights reserved.\n");
4390075Sobrien#endif /* not lint */
44132718Skan
45132718Skan#if defined(__RCSID) && !defined(lint)
4690075Sobrien__RCSID("$NetBSD: mkdep.c,v 1.10 2002/01/31 22:43:55 tv Exp $");
4790075Sobrien#endif /* not lint */
4890075Sobrien
4990075Sobrien#if HAVE_CONFIG_H
5090075Sobrien#include "config.h"
5190075Sobrien#endif
52132718Skan
53132718Skan#include <sys/param.h>
5490075Sobrien#include <sys/wait.h>
55#include <ctype.h>
56#include <err.h>
57#include <locale.h>
58#include <paths.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <unistd.h>
63
64#define DEFAULT_CC		"cc"
65#define DEFAULT_PATH		_PATH_DEFPATH
66#define DEFAULT_FILENAME	".depend"
67
68static void	usage __P((void));
69static char    *findcc __P((const char *));
70int		main __P((int, char **));
71
72static void
73usage()
74{
75	(void)fprintf(stderr,
76	    "usage: %s [-a] [-p] [-f file] flags file ...\n",
77	    getprogname());
78	exit(EXIT_FAILURE);
79}
80
81static char *
82findcc(progname)
83	const char	*progname;
84{
85	char   *path, *dir, *next;
86	char   buffer[MAXPATHLEN];
87
88	if ((next = strchr(progname, ' ')) != NULL) {
89		*next = '\0';
90	}
91
92	if (strchr(progname, '/') != NULL)
93		return access(progname, X_OK) ? NULL : strdup(progname);
94
95	if (((path = getenv("PATH")) == NULL) ||
96	    ((path = strdup(path)) == NULL))
97		return NULL;
98
99	dir = path;
100	while (dir != NULL) {
101		if ((next = strchr(dir, ':')) != NULL)
102			*next++ = '\0';
103
104		if (snprintf(buffer, sizeof(buffer),
105		    "%s/%s", dir, progname) < sizeof(buffer)) {
106			if (!access(buffer, X_OK)) {
107				free(path);
108				return strdup(buffer);
109			}
110		}
111		dir = next;
112	}
113
114	free(path);
115	return NULL;
116}
117
118int
119main(argc, argv)
120	int     argc;
121	char  **argv;
122{
123	/* LINTED local definition of index */
124	int 	aflag, pflag, index, tmpfd, status;
125	pid_t	cpid, pid;
126	char   *filename, *CC, *pathname, tmpfilename[MAXPATHLEN], **args;
127	const char *tmpdir;
128	/* LINTED local definition of tmpfile */
129	FILE   *tmpfile, *dependfile;
130	char	buffer[32768];
131
132	setlocale(LC_ALL, "");
133	setprogname(argv[0]);
134
135	aflag = 0;
136	pflag = 0;
137	filename = DEFAULT_FILENAME;
138
139	/* XXX should use getopt(). */
140	for (index = 1; index < argc; index++) {
141		if (strcmp(argv[index], "-a") == 0)
142			aflag = 1;
143		else if (strcmp(argv[index], "-f") == 0) {
144			if (++index < argc)
145				filename = argv[index];
146		} else if (strcmp(argv[index], "-p") == 0)
147			pflag = 1;
148		else
149			break;
150	}
151
152	argc -= index;
153	argv += index;
154	if (argc == 0)
155		usage();
156
157	if ((CC = getenv("CC")) == NULL)
158		CC = DEFAULT_CC;
159	if ((pathname = findcc(CC)) == NULL)
160		if (!setenv("PATH", DEFAULT_PATH, 1))
161			pathname = findcc(CC);
162	if (pathname == NULL) {
163		(void)fprintf(stderr, "%s: %s: not found\n", getprogname(), CC);
164		exit(EXIT_FAILURE);
165	}
166
167	if ((args = malloc((argc + 3) * sizeof(char *))) == NULL) {
168		perror(getprogname());
169		exit(EXIT_FAILURE);
170	}
171	args[0] = CC;
172	args[1] = "-M";
173	(void)memcpy(&args[2], argv, (argc + 1) * sizeof(char *));
174
175	if ((tmpdir = getenv("TMPDIR")) == NULL)
176		tmpdir = _PATH_TMP;
177	(void)snprintf(tmpfilename, sizeof (tmpfilename), "%s/%s", tmpdir,
178	    "mkdepXXXXXX");
179	if ((tmpfd = mkstemp (tmpfilename)) < 0) {
180		warn("unable to create temporary file %s", tmpfilename);
181		exit(EXIT_FAILURE);
182	}
183
184	switch (cpid = vfork()) {
185	case 0:
186		(void)dup2(tmpfd, STDOUT_FILENO);
187		(void)close(tmpfd);
188
189		(void)execv(pathname, args);
190		_exit(EXIT_FAILURE);
191		/* NOTREACHED */
192
193	case -1:
194		(void)fprintf(stderr, "%s: unable to fork.\n", getprogname());
195		(void)close(tmpfd);
196		(void)unlink(tmpfilename);
197		exit(EXIT_FAILURE);
198	}
199
200	while (((pid = wait(&status)) != cpid) && (pid >= 0))
201		continue;
202
203	if (status) {
204		(void)fprintf(stderr, "%s: compile failed.\n", getprogname());
205		(void)close(tmpfd);
206		(void)unlink(tmpfilename);
207		exit(EXIT_FAILURE);
208	}
209
210	(void)lseek(tmpfd, (off_t)0, SEEK_SET);
211	if ((tmpfile = fdopen(tmpfd, "r")) == NULL) {
212		(void)fprintf(stderr, "%s: unable to read temporary file %s\n",
213		    getprogname(), tmpfilename);
214		(void)close(tmpfd);
215		(void)unlink(tmpfilename);
216		exit(EXIT_FAILURE);
217	}
218
219	if ((dependfile = fopen(filename, aflag ? "a" : "w")) == NULL) {
220		(void)fprintf(stderr, "%s: unable to %s to file %s\n",
221		    getprogname(), aflag ? "append" : "write", filename);
222		(void)fclose(tmpfile);
223		(void)unlink(tmpfilename);
224		exit(EXIT_FAILURE);
225	}
226
227	while (fgets(buffer, sizeof(buffer), tmpfile) != NULL) {
228		char   *ptr;
229
230		if (pflag && ((ptr = strstr(buffer, ".o")) != NULL)) {
231			char   *colon;
232
233			colon = ptr + 2;
234			while (isspace(*colon)) colon++;
235			if (*colon == ':')
236				(void)strcpy(ptr, colon);
237		}
238
239		ptr = buffer;
240		while (*ptr) {
241			if (isspace(*ptr++))
242				if ((ptr[0] == '.') && (ptr[1] == '/'))
243					(void)strcpy(ptr, ptr + 2);
244		}
245
246		(void)fputs(buffer, dependfile);
247	}
248
249	(void)fclose(dependfile);
250	(void)fclose(tmpfile);
251	(void)unlink(tmpfilename);
252
253	exit(EXIT_SUCCESS);
254}
255