1*0a6a1f1dSLionel Sambuc /* $NetBSD: mkdep.c,v 1.44 2015/06/16 22:54:10 christos Exp $ */
206617e7fSArun Thomas
306617e7fSArun Thomas /*-
406617e7fSArun Thomas * Copyright (c) 1999 The NetBSD Foundation, Inc.
506617e7fSArun Thomas * All rights reserved.
606617e7fSArun Thomas *
706617e7fSArun Thomas * This code is derived from software contributed to The NetBSD Foundation
806617e7fSArun Thomas * by Matthias Scheler.
906617e7fSArun Thomas *
1006617e7fSArun Thomas * Redistribution and use in source and binary forms, with or without
1106617e7fSArun Thomas * modification, are permitted provided that the following conditions
1206617e7fSArun Thomas * are met:
1306617e7fSArun Thomas * 1. Redistributions of source code must retain the above copyright
1406617e7fSArun Thomas * notice, this list of conditions and the following disclaimer.
1506617e7fSArun Thomas * 2. Redistributions in binary form must reproduce the above copyright
1606617e7fSArun Thomas * notice, this list of conditions and the following disclaimer in the
1706617e7fSArun Thomas * documentation and/or other materials provided with the distribution.
1806617e7fSArun Thomas *
1906617e7fSArun Thomas * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2006617e7fSArun Thomas * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2106617e7fSArun Thomas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2206617e7fSArun Thomas * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2306617e7fSArun Thomas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2406617e7fSArun Thomas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2506617e7fSArun Thomas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2606617e7fSArun Thomas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2706617e7fSArun Thomas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2806617e7fSArun Thomas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2906617e7fSArun Thomas * POSSIBILITY OF SUCH DAMAGE.
3006617e7fSArun Thomas */
3106617e7fSArun Thomas
3206617e7fSArun Thomas #if HAVE_NBTOOL_CONFIG_H
3306617e7fSArun Thomas #include "nbtool_config.h"
3406617e7fSArun Thomas #endif
3506617e7fSArun Thomas
3606617e7fSArun Thomas #include <sys/cdefs.h>
3706617e7fSArun Thomas #if !defined(lint)
3806617e7fSArun Thomas __COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\
3906617e7fSArun Thomas All rights reserved.");
40*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: mkdep.c,v 1.44 2015/06/16 22:54:10 christos Exp $");
4106617e7fSArun Thomas #endif /* not lint */
4206617e7fSArun Thomas
4306617e7fSArun Thomas #include <sys/mman.h>
4406617e7fSArun Thomas #include <sys/param.h>
4506617e7fSArun Thomas #include <sys/wait.h>
4606617e7fSArun Thomas #include <ctype.h>
4706617e7fSArun Thomas #include <err.h>
4806617e7fSArun Thomas #include <fcntl.h>
4984d9c625SLionel Sambuc #include <getopt.h>
5006617e7fSArun Thomas #include <locale.h>
5106617e7fSArun Thomas #include <paths.h>
5206617e7fSArun Thomas #include <stdio.h>
5306617e7fSArun Thomas #include <stdlib.h>
5406617e7fSArun Thomas #include <string.h>
5506617e7fSArun Thomas #include <unistd.h>
5606617e7fSArun Thomas
5706617e7fSArun Thomas #include "findcc.h"
5806617e7fSArun Thomas
5906617e7fSArun Thomas typedef struct opt opt_t;
6006617e7fSArun Thomas struct opt {
6106617e7fSArun Thomas opt_t *left;
6206617e7fSArun Thomas opt_t *right;
6306617e7fSArun Thomas int len;
6406617e7fSArun Thomas int count;
6506617e7fSArun Thomas char name[4];
6606617e7fSArun Thomas };
6706617e7fSArun Thomas
6884d9c625SLionel Sambuc typedef struct suff_list {
6906617e7fSArun Thomas size_t len;
7084d9c625SLionel Sambuc char *suff;
7184d9c625SLionel Sambuc struct suff_list *next;
7206617e7fSArun Thomas } suff_list_t;
7306617e7fSArun Thomas
7406617e7fSArun Thomas /* tree of includes for -o processing */
7584d9c625SLionel Sambuc static opt_t *opt;
7684d9c625SLionel Sambuc static int width;
7784d9c625SLionel Sambuc static int verbose;
7806617e7fSArun Thomas
7906617e7fSArun Thomas #define DEFAULT_PATH _PATH_DEFPATH
8006617e7fSArun Thomas #define DEFAULT_FILENAME ".depend"
8106617e7fSArun Thomas
8206617e7fSArun Thomas static void save_for_optional(const char *, const char *);
8384d9c625SLionel Sambuc static size_t write_optional(int, opt_t *, size_t);
8406617e7fSArun Thomas
8506617e7fSArun Thomas static inline void *
deconst(const void * p)8606617e7fSArun Thomas deconst(const void *p)
8706617e7fSArun Thomas {
8806617e7fSArun Thomas return (const char *)p - (const char *)0 + (char *)0;
8906617e7fSArun Thomas }
9006617e7fSArun Thomas
9184d9c625SLionel Sambuc __dead static void
usage(void)9206617e7fSArun Thomas usage(void)
9306617e7fSArun Thomas {
9406617e7fSArun Thomas (void)fprintf(stderr,
9584d9c625SLionel Sambuc "usage: %s [-aDdiopqv] [-f file] [-P prefix] [-s suffixes] "
9684d9c625SLionel Sambuc "-- [flags] file ...\n",
9706617e7fSArun Thomas getprogname());
9806617e7fSArun Thomas exit(EXIT_FAILURE);
9906617e7fSArun Thomas }
10006617e7fSArun Thomas
10106617e7fSArun Thomas static int
run_cc(int argc,char ** argv,const char ** fname)10206617e7fSArun Thomas run_cc(int argc, char **argv, const char **fname)
10306617e7fSArun Thomas {
10406617e7fSArun Thomas const char *CC, *tmpdir;
10506617e7fSArun Thomas char * volatile pathname;
10606617e7fSArun Thomas static char tmpfilename[MAXPATHLEN];
10706617e7fSArun Thomas char **args;
10806617e7fSArun Thomas int tmpfd;
10906617e7fSArun Thomas pid_t pid, cpid;
11006617e7fSArun Thomas int status;
11106617e7fSArun Thomas
11206617e7fSArun Thomas if ((CC = getenv("CC")) == NULL)
11306617e7fSArun Thomas CC = DEFAULT_CC;
11406617e7fSArun Thomas if ((pathname = findcc(CC)) == NULL)
11506617e7fSArun Thomas if (!setenv("PATH", DEFAULT_PATH, 1))
11606617e7fSArun Thomas pathname = findcc(CC);
11706617e7fSArun Thomas if (pathname == NULL)
11806617e7fSArun Thomas err(EXIT_FAILURE, "%s: not found", CC);
11906617e7fSArun Thomas if ((args = malloc((argc + 3) * sizeof(char *))) == NULL)
12006617e7fSArun Thomas err(EXIT_FAILURE, "malloc");
12106617e7fSArun Thomas
12206617e7fSArun Thomas args[0] = deconst(CC);
12306617e7fSArun Thomas args[1] = deconst("-M");
12406617e7fSArun Thomas (void)memcpy(&args[2], argv, (argc + 1) * sizeof(char *));
12506617e7fSArun Thomas
12606617e7fSArun Thomas if ((tmpdir = getenv("TMPDIR")) == NULL)
12706617e7fSArun Thomas tmpdir = _PATH_TMP;
12806617e7fSArun Thomas (void)snprintf(tmpfilename, sizeof (tmpfilename), "%s/%s", tmpdir,
12906617e7fSArun Thomas "mkdepXXXXXX");
13084d9c625SLionel Sambuc if ((tmpfd = mkstemp(tmpfilename)) < 0)
13184d9c625SLionel Sambuc err(EXIT_FAILURE, "Unable to create temporary file %s",
13284d9c625SLionel Sambuc tmpfilename);
13306617e7fSArun Thomas (void)unlink(tmpfilename);
13406617e7fSArun Thomas *fname = tmpfilename;
13506617e7fSArun Thomas
13684d9c625SLionel Sambuc if (verbose) {
13784d9c625SLionel Sambuc char **a;
13884d9c625SLionel Sambuc for (a = args; *a; a++)
13984d9c625SLionel Sambuc printf("%s ", *a);
14084d9c625SLionel Sambuc printf("\n");
14184d9c625SLionel Sambuc }
14284d9c625SLionel Sambuc
14306617e7fSArun Thomas switch (cpid = vfork()) {
14406617e7fSArun Thomas case 0:
14506617e7fSArun Thomas (void)dup2(tmpfd, STDOUT_FILENO);
14606617e7fSArun Thomas (void)close(tmpfd);
14706617e7fSArun Thomas
14806617e7fSArun Thomas (void)execv(pathname, args);
14906617e7fSArun Thomas _exit(EXIT_FAILURE);
15006617e7fSArun Thomas /* NOTREACHED */
15106617e7fSArun Thomas
15206617e7fSArun Thomas case -1:
15306617e7fSArun Thomas err(EXIT_FAILURE, "unable to fork");
15406617e7fSArun Thomas }
15506617e7fSArun Thomas
15606617e7fSArun Thomas free(pathname);
15706617e7fSArun Thomas free(args);
15806617e7fSArun Thomas
15906617e7fSArun Thomas while (((pid = wait(&status)) != cpid) && (pid >= 0))
16006617e7fSArun Thomas continue;
16106617e7fSArun Thomas
16206617e7fSArun Thomas if (status)
16306617e7fSArun Thomas errx(EXIT_FAILURE, "compile failed.");
16406617e7fSArun Thomas
16506617e7fSArun Thomas return tmpfd;
16606617e7fSArun Thomas }
16706617e7fSArun Thomas
16806617e7fSArun Thomas static const char *
read_fname(void)16906617e7fSArun Thomas read_fname(void)
17006617e7fSArun Thomas {
17106617e7fSArun Thomas static char *fbuf;
17206617e7fSArun Thomas static int fbuflen;
17306617e7fSArun Thomas int len, ch;
17406617e7fSArun Thomas
17506617e7fSArun Thomas for (len = 0; (ch = getchar()) != EOF; len++) {
17606617e7fSArun Thomas if (isspace(ch)) {
17706617e7fSArun Thomas if (len != 0)
17806617e7fSArun Thomas break;
17906617e7fSArun Thomas len--;
18006617e7fSArun Thomas continue;
18106617e7fSArun Thomas }
18206617e7fSArun Thomas if (len >= fbuflen - 1) {
18306617e7fSArun Thomas fbuf = realloc(fbuf, fbuflen += 32);
18406617e7fSArun Thomas if (fbuf == NULL)
18506617e7fSArun Thomas err(EXIT_FAILURE, "no memory");
18606617e7fSArun Thomas }
18706617e7fSArun Thomas fbuf[len] = ch;
18806617e7fSArun Thomas }
18906617e7fSArun Thomas if (len == 0)
19006617e7fSArun Thomas return NULL;
19106617e7fSArun Thomas fbuf[len] = 0;
19206617e7fSArun Thomas return fbuf;
19306617e7fSArun Thomas }
19406617e7fSArun Thomas
19584d9c625SLionel Sambuc static struct option longopt[] = {
19684d9c625SLionel Sambuc { "sysroot", 1, NULL, 'R' },
19784d9c625SLionel Sambuc { NULL, 0, NULL, '\0' },
19884d9c625SLionel Sambuc };
19984d9c625SLionel Sambuc
20084d9c625SLionel Sambuc static void
addsuff(suff_list_t ** l,const char * s,size_t len)20184d9c625SLionel Sambuc addsuff(suff_list_t **l, const char *s, size_t len)
20284d9c625SLionel Sambuc {
20384d9c625SLionel Sambuc suff_list_t *p = calloc(1, sizeof(*p));
20484d9c625SLionel Sambuc if (p == NULL)
20584d9c625SLionel Sambuc err(1, "calloc");
20684d9c625SLionel Sambuc p->suff = malloc(len + 1);
20784d9c625SLionel Sambuc if (p->suff == NULL)
20884d9c625SLionel Sambuc err(1, "malloc");
20984d9c625SLionel Sambuc memcpy(p->suff, s, len);
21084d9c625SLionel Sambuc p->suff[len] = '\0';
21184d9c625SLionel Sambuc p->len = len;
21284d9c625SLionel Sambuc p->next = *l;
21384d9c625SLionel Sambuc *l = p;
21484d9c625SLionel Sambuc }
21584d9c625SLionel Sambuc
21606617e7fSArun Thomas int
main(int argc,char ** argv)21706617e7fSArun Thomas main(int argc, char **argv)
21806617e7fSArun Thomas {
21984d9c625SLionel Sambuc int aflag, dflag, iflag, oflag, qflag;
22006617e7fSArun Thomas const char *filename;
22106617e7fSArun Thomas int dependfile;
22206617e7fSArun Thomas char *buf, *lim, *ptr, *line, *suf, *colon, *eol;
22306617e7fSArun Thomas int ok_ind, ch;
22406617e7fSArun Thomas size_t sz;
22506617e7fSArun Thomas int fd;
22606617e7fSArun Thomas size_t slen;
22706617e7fSArun Thomas const char *fname;
22884d9c625SLionel Sambuc const char *prefix = NULL;
22906617e7fSArun Thomas const char *suffixes = NULL, *s;
23006617e7fSArun Thomas suff_list_t *suff_list = NULL, *sl;
231*0a6a1f1dSLionel Sambuc #if !defined(__minix)
23206617e7fSArun Thomas size_t nr;
233*0a6a1f1dSLionel Sambuc #else
23420a91f77SLionel Sambuc /* triggers a 'may be used uninitialized', when compiled with gcc,
23520a91f77SLionel Sambuc * asserts off, and -Os. */
23620a91f77SLionel Sambuc slen = 0;
237*0a6a1f1dSLionel Sambuc #endif /* !defined(__minix) */
23806617e7fSArun Thomas
23906617e7fSArun Thomas suf = NULL; /* XXXGCC -Wuninitialized [sun2] */
24006617e7fSArun Thomas sl = NULL; /* XXXGCC -Wuninitialized [sun2] */
24106617e7fSArun Thomas
24206617e7fSArun Thomas setlocale(LC_ALL, "");
24306617e7fSArun Thomas setprogname(argv[0]);
24406617e7fSArun Thomas
24506617e7fSArun Thomas aflag = O_WRONLY | O_APPEND | O_CREAT | O_TRUNC;
24606617e7fSArun Thomas dflag = 0;
24784d9c625SLionel Sambuc iflag = 0;
24806617e7fSArun Thomas oflag = 0;
24906617e7fSArun Thomas qflag = 0;
25006617e7fSArun Thomas filename = DEFAULT_FILENAME;
25106617e7fSArun Thomas dependfile = -1;
25206617e7fSArun Thomas
25306617e7fSArun Thomas opterr = 0; /* stop getopt() bleating about errors. */
25406617e7fSArun Thomas for (;;) {
25506617e7fSArun Thomas ok_ind = optind;
25684d9c625SLionel Sambuc ch = getopt_long(argc, argv, "aDdf:ioP:pqRs:v", longopt, NULL);
25706617e7fSArun Thomas switch (ch) {
25806617e7fSArun Thomas case -1:
25906617e7fSArun Thomas ok_ind = optind;
26006617e7fSArun Thomas break;
26106617e7fSArun Thomas case 'a': /* Append to output file */
26206617e7fSArun Thomas aflag &= ~O_TRUNC;
26306617e7fSArun Thomas continue;
26406617e7fSArun Thomas case 'D': /* Process *.d files (don't run cc -M) */
26506617e7fSArun Thomas dflag = 2; /* Read names from stdin */
26606617e7fSArun Thomas opterr = 1;
26706617e7fSArun Thomas continue;
26806617e7fSArun Thomas case 'd': /* Process *.d files (don't run cc -M) */
26906617e7fSArun Thomas dflag = 1;
27006617e7fSArun Thomas opterr = 1;
27106617e7fSArun Thomas continue;
27206617e7fSArun Thomas case 'f': /* Name of output file */
27306617e7fSArun Thomas filename = optarg;
27406617e7fSArun Thomas continue;
27584d9c625SLionel Sambuc case 'i':
27684d9c625SLionel Sambuc iflag = 1;
27784d9c625SLionel Sambuc continue;
27884d9c625SLionel Sambuc case 'o': /* Mark dependent files .OPTIONAL */
27906617e7fSArun Thomas oflag = 1;
28006617e7fSArun Thomas continue;
28184d9c625SLionel Sambuc case 'P': /* Prefix for each target filename */
28284d9c625SLionel Sambuc prefix = optarg;
28384d9c625SLionel Sambuc continue;
28406617e7fSArun Thomas case 'p': /* Program mode (x.o: -> x:) */
28506617e7fSArun Thomas suffixes = "";
28606617e7fSArun Thomas continue;
28706617e7fSArun Thomas case 'q': /* Quiet */
28806617e7fSArun Thomas qflag = 1;
28906617e7fSArun Thomas continue;
29084d9c625SLionel Sambuc case 'R':
29184d9c625SLionel Sambuc /* sysroot = optarg */
29284d9c625SLionel Sambuc continue;
29306617e7fSArun Thomas case 's': /* Suffix list */
29406617e7fSArun Thomas suffixes = optarg;
29506617e7fSArun Thomas continue;
29684d9c625SLionel Sambuc case 'v':
29784d9c625SLionel Sambuc verbose = 1;
29884d9c625SLionel Sambuc continue;
29906617e7fSArun Thomas default:
30006617e7fSArun Thomas if (dflag)
30106617e7fSArun Thomas usage();
30206617e7fSArun Thomas /* Unknown arguments are passed to "${CC} -M" */
30306617e7fSArun Thomas break;
30406617e7fSArun Thomas }
30506617e7fSArun Thomas break;
30606617e7fSArun Thomas }
30706617e7fSArun Thomas
30806617e7fSArun Thomas argc -= ok_ind;
30906617e7fSArun Thomas argv += ok_ind;
31006617e7fSArun Thomas if ((argc == 0 && !dflag) || (argc != 0 && dflag == 2))
31106617e7fSArun Thomas usage();
31206617e7fSArun Thomas
31306617e7fSArun Thomas if (suffixes != NULL) {
31484d9c625SLionel Sambuc if (*suffixes) {
31584d9c625SLionel Sambuc for (s = suffixes; (sz = strcspn(s, ", ")) != 0;) {
31684d9c625SLionel Sambuc addsuff(&suff_list, s, sz);
31784d9c625SLionel Sambuc s += sz;
31884d9c625SLionel Sambuc while (*s && strchr(", ", *s))
31984d9c625SLionel Sambuc s++;
32006617e7fSArun Thomas }
32184d9c625SLionel Sambuc } else
32284d9c625SLionel Sambuc addsuff(&suff_list, "", 0);
32306617e7fSArun Thomas }
32406617e7fSArun Thomas
32506617e7fSArun Thomas dependfile = open(filename, aflag, 0666);
32606617e7fSArun Thomas if (dependfile == -1)
32784d9c625SLionel Sambuc goto wrerror;
32806617e7fSArun Thomas
32906617e7fSArun Thomas while (dflag == 2 || *argv != NULL) {
33006617e7fSArun Thomas if (dflag) {
33106617e7fSArun Thomas if (dflag == 2) {
33206617e7fSArun Thomas fname = read_fname();
33306617e7fSArun Thomas if (fname == NULL)
33406617e7fSArun Thomas break;
33506617e7fSArun Thomas } else
33606617e7fSArun Thomas fname = *argv++;
33784d9c625SLionel Sambuc if (iflag) {
33884d9c625SLionel Sambuc if (dprintf(dependfile, ".-include \"%s\"\n",
33984d9c625SLionel Sambuc fname) < 0)
34084d9c625SLionel Sambuc goto wrerror;
34184d9c625SLionel Sambuc continue;
34284d9c625SLionel Sambuc }
34306617e7fSArun Thomas fd = open(fname, O_RDONLY, 0);
34406617e7fSArun Thomas if (fd == -1) {
34506617e7fSArun Thomas if (!qflag)
34606617e7fSArun Thomas warn("ignoring %s", fname);
34706617e7fSArun Thomas continue;
34806617e7fSArun Thomas }
34906617e7fSArun Thomas } else {
35006617e7fSArun Thomas fd = run_cc(argc, argv, &fname);
35106617e7fSArun Thomas /* consume all args... */
35206617e7fSArun Thomas argv += argc;
35306617e7fSArun Thomas }
35406617e7fSArun Thomas
35506617e7fSArun Thomas sz = lseek(fd, 0, SEEK_END);
35606617e7fSArun Thomas if (sz == 0) {
35706617e7fSArun Thomas close(fd);
35806617e7fSArun Thomas continue;
35906617e7fSArun Thomas }
36006617e7fSArun Thomas buf = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
36106617e7fSArun Thomas close(fd);
36206617e7fSArun Thomas
36306617e7fSArun Thomas if (buf == MAP_FAILED)
36406617e7fSArun Thomas err(EXIT_FAILURE, "unable to mmap file %s", fname);
36506617e7fSArun Thomas lim = buf + sz - 1;
36606617e7fSArun Thomas
36706617e7fSArun Thomas /* Remove leading "./" from filenames */
36806617e7fSArun Thomas for (ptr = buf; ptr < lim; ptr++) {
36906617e7fSArun Thomas if (ptr[1] != '.' || ptr[2] != '/'
37006617e7fSArun Thomas || !isspace((unsigned char)ptr[0]))
37106617e7fSArun Thomas continue;
37206617e7fSArun Thomas ptr[1] = ' ';
37306617e7fSArun Thomas ptr[2] = ' ';
37406617e7fSArun Thomas }
37506617e7fSArun Thomas
37606617e7fSArun Thomas for (line = eol = buf; eol <= lim;) {
37706617e7fSArun Thomas while (eol <= lim && *eol++ != '\n')
37806617e7fSArun Thomas /* Find end of this line */
37906617e7fSArun Thomas continue;
38006617e7fSArun Thomas if (line == eol - 1) {
38106617e7fSArun Thomas /* empty line - ignore */
38206617e7fSArun Thomas line = eol;
38306617e7fSArun Thomas continue;
38406617e7fSArun Thomas }
38506617e7fSArun Thomas if (eol[-2] == '\\')
38606617e7fSArun Thomas /* Assemble continuation lines */
38706617e7fSArun Thomas continue;
38806617e7fSArun Thomas for (colon = line; *colon != ':'; colon++) {
38906617e7fSArun Thomas if (colon >= eol) {
39006617e7fSArun Thomas colon = NULL;
39106617e7fSArun Thomas break;
39206617e7fSArun Thomas }
39306617e7fSArun Thomas }
39406617e7fSArun Thomas if (isspace((unsigned char)*line) || colon == NULL) {
39506617e7fSArun Thomas /* No dependency - just transcribe line */
39684d9c625SLionel Sambuc if (write(dependfile, line, eol - line) < 0)
39784d9c625SLionel Sambuc goto wrerror;
39806617e7fSArun Thomas line = eol;
39906617e7fSArun Thomas continue;
40006617e7fSArun Thomas }
40106617e7fSArun Thomas if (suff_list != NULL) {
40206617e7fSArun Thomas /* Find the .o: */
40306617e7fSArun Thomas /* First allow for any whitespace */
40406617e7fSArun Thomas for (suf = colon; suf > buf; suf--) {
40506617e7fSArun Thomas if (!isspace((unsigned char)suf[-1]))
40606617e7fSArun Thomas break;
40706617e7fSArun Thomas }
40806617e7fSArun Thomas if (suf == buf)
40906617e7fSArun Thomas errx(EXIT_FAILURE,
41006617e7fSArun Thomas "Corrupted file `%s'", fname);
41106617e7fSArun Thomas /* Then look for any valid suffix */
41284d9c625SLionel Sambuc for (sl = suff_list; sl != NULL;
41384d9c625SLionel Sambuc sl = sl->next) {
41484d9c625SLionel Sambuc if (sl->len && buf <= suf - sl->len &&
41584d9c625SLionel Sambuc !memcmp(suf - sl->len, sl->suff,
41606617e7fSArun Thomas sl->len))
41706617e7fSArun Thomas break;
41806617e7fSArun Thomas }
41906617e7fSArun Thomas /*
42006617e7fSArun Thomas * Not found, check for .o, since the
42106617e7fSArun Thomas * original file will have it.
42206617e7fSArun Thomas */
42384d9c625SLionel Sambuc if (sl == NULL) {
42406617e7fSArun Thomas if (memcmp(suf - 2, ".o", 2) == 0)
42506617e7fSArun Thomas slen = 2;
42606617e7fSArun Thomas else
42706617e7fSArun Thomas slen = 0;
42806617e7fSArun Thomas } else
42906617e7fSArun Thomas slen = sl->len;
43006617e7fSArun Thomas }
43106617e7fSArun Thomas if (suff_list != NULL && slen != 0) {
43206617e7fSArun Thomas suf -= slen;
43384d9c625SLionel Sambuc for (sl = suff_list; sl != NULL; sl = sl->next)
43484d9c625SLionel Sambuc {
43506617e7fSArun Thomas if (sl != suff_list)
43684d9c625SLionel Sambuc if (write(dependfile, " ", 1)
43784d9c625SLionel Sambuc < 0)
43884d9c625SLionel Sambuc goto wrerror;
43984d9c625SLionel Sambuc if (prefix != NULL)
44084d9c625SLionel Sambuc if (write(dependfile, prefix,
44184d9c625SLionel Sambuc strlen(prefix)) < 0)
44284d9c625SLionel Sambuc goto wrerror;
44384d9c625SLionel Sambuc if (write(dependfile, line,
44484d9c625SLionel Sambuc suf - line) < 0)
44584d9c625SLionel Sambuc goto wrerror;
44684d9c625SLionel Sambuc if (write(dependfile, sl->suff,
44784d9c625SLionel Sambuc sl->len) < 0)
44884d9c625SLionel Sambuc goto wrerror;
44906617e7fSArun Thomas }
45084d9c625SLionel Sambuc if (write(dependfile, colon, eol - colon) < 0)
45184d9c625SLionel Sambuc goto wrerror;
45284d9c625SLionel Sambuc } else {
45384d9c625SLionel Sambuc if (prefix != NULL)
45484d9c625SLionel Sambuc if (write(dependfile, prefix,
45584d9c625SLionel Sambuc strlen(prefix)) < 0)
45684d9c625SLionel Sambuc goto wrerror;
45784d9c625SLionel Sambuc if (write(dependfile, line, eol - line) < 0)
45884d9c625SLionel Sambuc goto wrerror;
45984d9c625SLionel Sambuc }
46006617e7fSArun Thomas
46106617e7fSArun Thomas if (oflag)
46206617e7fSArun Thomas save_for_optional(colon + 1, eol);
46306617e7fSArun Thomas line = eol;
46406617e7fSArun Thomas }
46506617e7fSArun Thomas munmap(buf, sz);
46606617e7fSArun Thomas }
46706617e7fSArun Thomas
46806617e7fSArun Thomas if (oflag && opt != NULL) {
46984d9c625SLionel Sambuc if (write(dependfile, ".OPTIONAL:", 10) < 0)
47084d9c625SLionel Sambuc goto wrerror;
47106617e7fSArun Thomas width = 9;
47206617e7fSArun Thomas sz = write_optional(dependfile, opt, 0);
47384d9c625SLionel Sambuc if (sz == (size_t)-1)
47484d9c625SLionel Sambuc goto wrerror;
47506617e7fSArun Thomas /* 'depth' is about 39 for an i386 kernel */
47606617e7fSArun Thomas /* fprintf(stderr, "Recursion depth %d\n", sz); */
47706617e7fSArun Thomas }
47806617e7fSArun Thomas close(dependfile);
47906617e7fSArun Thomas
48006617e7fSArun Thomas exit(EXIT_SUCCESS);
48184d9c625SLionel Sambuc wrerror:
482*0a6a1f1dSLionel Sambuc err(EXIT_FAILURE, "unable to %s to file %s",
48384d9c625SLionel Sambuc aflag & O_TRUNC ? "write" : "append", filename);
48406617e7fSArun Thomas }
48506617e7fSArun Thomas
48606617e7fSArun Thomas
48706617e7fSArun Thomas /*
48806617e7fSArun Thomas * Only save each file once - the kernel .depend is 3MB and there is
48906617e7fSArun Thomas * no point doubling its size.
49006617e7fSArun Thomas * The data seems to be 'random enough' so the simple binary tree
49106617e7fSArun Thomas * only has a reasonable depth.
49206617e7fSArun Thomas */
49306617e7fSArun Thomas static void
save_for_optional(const char * start,const char * limit)49406617e7fSArun Thomas save_for_optional(const char *start, const char *limit)
49506617e7fSArun Thomas {
49606617e7fSArun Thomas opt_t **l, *n;
49706617e7fSArun Thomas const char *name, *end;
49806617e7fSArun Thomas int c;
49906617e7fSArun Thomas
50006617e7fSArun Thomas while (start < limit && strchr(" \t\n\\", *start))
50106617e7fSArun Thomas start++;
50206617e7fSArun Thomas for (name = start; ; name = end) {
50306617e7fSArun Thomas while (name < limit && strchr(" \t\n\\", *name))
50406617e7fSArun Thomas name++;
50506617e7fSArun Thomas for (end = name; end < limit && !strchr(" \t\n\\", *end);)
50606617e7fSArun Thomas end++;
50706617e7fSArun Thomas if (name >= limit)
50806617e7fSArun Thomas break;
50906617e7fSArun Thomas if (end[-1] == 'c' && end[-2] == '.' && name == start)
51006617e7fSArun Thomas /* ignore dependency on the files own .c */
51106617e7fSArun Thomas continue;
51206617e7fSArun Thomas for (l = &opt;;) {
51306617e7fSArun Thomas n = *l;
51406617e7fSArun Thomas if (n == NULL) {
51506617e7fSArun Thomas n = malloc(sizeof *n + (end - name));
51606617e7fSArun Thomas n->left = n->right = 0;
51706617e7fSArun Thomas n->len = end - name;
51806617e7fSArun Thomas n->count = 1;
51906617e7fSArun Thomas n->name[0] = ' ';
52006617e7fSArun Thomas memcpy(n->name + 1, name, end - name);
52106617e7fSArun Thomas *l = n;
52206617e7fSArun Thomas break;
52306617e7fSArun Thomas }
52406617e7fSArun Thomas c = (end - name) - n->len;
52506617e7fSArun Thomas if (c == 0)
52606617e7fSArun Thomas c = memcmp(n->name + 1, name, (end - name));
52706617e7fSArun Thomas if (c == 0) {
52806617e7fSArun Thomas /* Duplicate */
52906617e7fSArun Thomas n->count++;
53006617e7fSArun Thomas break;
53106617e7fSArun Thomas }
53206617e7fSArun Thomas if (c < 0)
53306617e7fSArun Thomas l = &n->left;
53406617e7fSArun Thomas else
53506617e7fSArun Thomas l = &n->right;
53606617e7fSArun Thomas }
53706617e7fSArun Thomas }
53806617e7fSArun Thomas }
53906617e7fSArun Thomas
54084d9c625SLionel Sambuc static size_t
write_optional(int fd,opt_t * node,size_t depth)54184d9c625SLionel Sambuc write_optional(int fd, opt_t *node, size_t depth)
54206617e7fSArun Thomas {
54384d9c625SLionel Sambuc size_t d1 = ++depth;
54406617e7fSArun Thomas
54506617e7fSArun Thomas if (node->left)
54606617e7fSArun Thomas d1 = write_optional(fd, node->left, d1);
54706617e7fSArun Thomas if (width > 76 - node->len) {
54884d9c625SLionel Sambuc if (write(fd, " \\\n ", 4) < 0)
54984d9c625SLionel Sambuc return (size_t)-1;
55006617e7fSArun Thomas width = 1;
55106617e7fSArun Thomas }
55206617e7fSArun Thomas width += 1 + node->len;
55384d9c625SLionel Sambuc if (write(fd, node->name, 1 + node->len) < 0)
55484d9c625SLionel Sambuc return (size_t)-1;
55506617e7fSArun Thomas if (node->right)
55606617e7fSArun Thomas depth = write_optional(fd, node->right, depth);
55706617e7fSArun Thomas return d1 > depth ? d1 : depth;
55806617e7fSArun Thomas }
559