xref: /freebsd/usr.sbin/crunch/crunchgen/crunchgen.c (revision 87eb4a4220e9fe6f5edf4a3fc88a46b8bc678d58)
1de566360SJordan K. Hubbard /*
2de566360SJordan K. Hubbard  * Copyright (c) 1994 University of Maryland
3de566360SJordan K. Hubbard  * All Rights Reserved.
4de566360SJordan K. Hubbard  *
5de566360SJordan K. Hubbard  * Permission to use, copy, modify, distribute, and sell this software and its
6de566360SJordan K. Hubbard  * documentation for any purpose is hereby granted without fee, provided that
7de566360SJordan K. Hubbard  * the above copyright notice appear in all copies and that both that
8de566360SJordan K. Hubbard  * copyright notice and this permission notice appear in supporting
9de566360SJordan K. Hubbard  * documentation, and that the name of U.M. not be used in advertising or
10de566360SJordan K. Hubbard  * publicity pertaining to distribution of the software without specific,
11de566360SJordan K. Hubbard  * written prior permission.  U.M. makes no representations about the
12de566360SJordan K. Hubbard  * suitability of this software for any purpose.  It is provided "as is"
13de566360SJordan K. Hubbard  * without express or implied warranty.
14de566360SJordan K. Hubbard  *
15de566360SJordan K. Hubbard  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16de566360SJordan K. Hubbard  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
17de566360SJordan K. Hubbard  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18de566360SJordan K. Hubbard  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19de566360SJordan K. Hubbard  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20de566360SJordan K. Hubbard  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21de566360SJordan K. Hubbard  *
22de566360SJordan K. Hubbard  * Author: James da Silva, Systems Design and Analysis Group
23de566360SJordan K. Hubbard  *			   Computer Science Department
24de566360SJordan K. Hubbard  *			   University of Maryland at College Park
2508826cadSLuigi Rizzo  *
2608826cadSLuigi Rizzo  * $FreeBSD$
27de566360SJordan K. Hubbard  */
28de566360SJordan K. Hubbard /*
29de566360SJordan K. Hubbard  * ========================================================================
30de566360SJordan K. Hubbard  * crunchgen.c
31de566360SJordan K. Hubbard  *
32de566360SJordan K. Hubbard  * Generates a Makefile and main C file for a crunched executable,
33de566360SJordan K. Hubbard  * from specs given in a .conf file.
34de566360SJordan K. Hubbard  */
3587eb4a42SJosef Karthauser #include <sys/types.h>
3687eb4a42SJosef Karthauser #include <sys/stat.h>
3787eb4a42SJosef Karthauser #include <sys/param.h>
3887eb4a42SJosef Karthauser 
39de566360SJordan K. Hubbard #include <ctype.h>
40b17e90a9SPhilippe Charnier #include <err.h>
4161ffadb1SJosef Karthauser #include <paths.h>
42b17e90a9SPhilippe Charnier #include <stdio.h>
43b17e90a9SPhilippe Charnier #include <stdlib.h>
44de566360SJordan K. Hubbard #include <string.h>
45b17e90a9SPhilippe Charnier #include <unistd.h>
46de566360SJordan K. Hubbard 
47de566360SJordan K. Hubbard #define CRUNCH_VERSION	"0.2"
48de566360SJordan K. Hubbard 
49de566360SJordan K. Hubbard #define MAXLINELEN	16384
50de566360SJordan K. Hubbard #define MAXFIELDS 	 2048
51de566360SJordan K. Hubbard 
52de566360SJordan K. Hubbard 
53de566360SJordan K. Hubbard /* internal representation of conf file: */
54de566360SJordan K. Hubbard 
55de566360SJordan K. Hubbard /* simple lists of strings suffice for most parms */
56de566360SJordan K. Hubbard 
57de566360SJordan K. Hubbard typedef struct strlst {
58de566360SJordan K. Hubbard 	struct strlst *next;
59de566360SJordan K. Hubbard 	char *str;
60de566360SJordan K. Hubbard } strlst_t;
61de566360SJordan K. Hubbard 
62de566360SJordan K. Hubbard /* progs have structure, each field can be set with "special" or calculated */
63de566360SJordan K. Hubbard 
64de566360SJordan K. Hubbard typedef struct prog {
6508826cadSLuigi Rizzo 	struct prog *next;	/* link field */
6608826cadSLuigi Rizzo 	char *name;		/* program name */
6708826cadSLuigi Rizzo 	char *ident;		/* C identifier for the program name */
6808826cadSLuigi Rizzo 	char *srcdir;
69843d8d51SJosef Karthauser 	char *realsrcdir;
7008826cadSLuigi Rizzo 	char *objdir;
7108826cadSLuigi Rizzo 	char *objvar;		/* Makefile variable to replace OBJS */
72de566360SJordan K. Hubbard 	strlst_t *objs, *objpaths;
7334944d48SJosef Karthauser 	strlst_t *buildopts;
7442ac3bf1SJoerg Wunsch 	strlst_t *keeplist;
75de566360SJordan K. Hubbard 	strlst_t *links;
76de566360SJordan K. Hubbard 	int goterror;
77de566360SJordan K. Hubbard } prog_t;
78de566360SJordan K. Hubbard 
79de566360SJordan K. Hubbard 
80de566360SJordan K. Hubbard /* global state */
81de566360SJordan K. Hubbard 
8208a15190SJosef Karthauser strlst_t *buildopts = NULL;
83de566360SJordan K. Hubbard strlst_t *srcdirs   = NULL;
84de566360SJordan K. Hubbard strlst_t *libs      = NULL;
85de566360SJordan K. Hubbard prog_t   *progs     = NULL;
86de566360SJordan K. Hubbard 
87de566360SJordan K. Hubbard char confname[MAXPATHLEN], infilename[MAXPATHLEN];
88de566360SJordan K. Hubbard char outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN];
89de566360SJordan K. Hubbard char tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
9008826cadSLuigi Rizzo char outhdrname[MAXPATHLEN] ;	/* user-supplied header for *.mk */
91019d04d1SLuigi Rizzo char *objprefix;		/* where are the objects ? */
92de566360SJordan K. Hubbard int linenum = -1;
93de566360SJordan K. Hubbard int goterror = 0;
94de566360SJordan K. Hubbard 
95de566360SJordan K. Hubbard int verbose, readcache;		/* options */
96de566360SJordan K. Hubbard int reading_cache;
97ba2250ddSJosef Karthauser int makeobj = 0;		/* add 'make obj' rules to the makefile */
98de566360SJordan K. Hubbard 
99fb7f926eSPoul-Henning Kamp int list_mode;
100fb7f926eSPoul-Henning Kamp 
101de566360SJordan K. Hubbard /* general library routines */
102de566360SJordan K. Hubbard 
103de566360SJordan K. Hubbard void status(char *str);
104de566360SJordan K. Hubbard void out_of_memory(void);
105de566360SJordan K. Hubbard void add_string(strlst_t **listp, char *str);
106de566360SJordan K. Hubbard int is_dir(char *pathname);
107de566360SJordan K. Hubbard int is_nonempty_file(char *pathname);
108de566360SJordan K. Hubbard 
109de566360SJordan K. Hubbard /* helper routines for main() */
110de566360SJordan K. Hubbard 
111de566360SJordan K. Hubbard void usage(void);
112de566360SJordan K. Hubbard void parse_conf_file(void);
113de566360SJordan K. Hubbard void gen_outputs(void);
114de566360SJordan K. Hubbard 
115de566360SJordan K. Hubbard 
116de566360SJordan K. Hubbard int main(int argc, char **argv)
117de566360SJordan K. Hubbard {
118de566360SJordan K. Hubbard 	char *p;
119de566360SJordan K. Hubbard 	int optc;
120de566360SJordan K. Hubbard 
121de566360SJordan K. Hubbard 	verbose = 1;
122de566360SJordan K. Hubbard 	readcache = 1;
123de566360SJordan K. Hubbard 	*outmkname = *outcfname = *execfname = '\0';
124de566360SJordan K. Hubbard 
125019d04d1SLuigi Rizzo 	p = getenv("MAKEOBJDIRPREFIX");
126019d04d1SLuigi Rizzo 	if (p == NULL || *p == '\0')
127019d04d1SLuigi Rizzo 		objprefix = "/usr/obj"; /* default */
128019d04d1SLuigi Rizzo 	else
129f3c47f54SJosef Karthauser 		if ((objprefix = strdup(p)) == NULL)
130f3c47f54SJosef Karthauser 			out_of_memory();
131019d04d1SLuigi Rizzo 
132019d04d1SLuigi Rizzo 	while((optc = getopt(argc, argv, "lh:m:c:e:p:foq")) != -1) {
133de566360SJordan K. Hubbard 		switch(optc) {
13487eb4a42SJosef Karthauser 		case 'f':
13587eb4a42SJosef Karthauser 			readcache = 0;
13687eb4a42SJosef Karthauser 			break;
13787eb4a42SJosef Karthauser 		case 'o':
13887eb4a42SJosef Karthauser 			makeobj = 1;
13987eb4a42SJosef Karthauser 			break;
14087eb4a42SJosef Karthauser 		case 'q':
14187eb4a42SJosef Karthauser 			verbose = 0;
14287eb4a42SJosef Karthauser 			break;
143de566360SJordan K. Hubbard 
14487eb4a42SJosef Karthauser 		case 'm':
14587eb4a42SJosef Karthauser 			strlcpy(outmkname, optarg, sizeof(outmkname));
14687eb4a42SJosef Karthauser 			break;
14787eb4a42SJosef Karthauser 		case 'p':
14887eb4a42SJosef Karthauser 			if ((objprefix = strdup(optarg)) == NULL)
149f3c47f54SJosef Karthauser 				out_of_memory();
150f3c47f54SJosef Karthauser 			break;
15187eb4a42SJosef Karthauser 
15287eb4a42SJosef Karthauser 		case 'h':
15387eb4a42SJosef Karthauser 			strlcpy(outhdrname, optarg, sizeof(outhdrname));
15487eb4a42SJosef Karthauser 			break;
15587eb4a42SJosef Karthauser 		case 'c':
15687eb4a42SJosef Karthauser 			strlcpy(outcfname, optarg, sizeof(outcfname));
15787eb4a42SJosef Karthauser 			break;
15887eb4a42SJosef Karthauser 		case 'e':
15987eb4a42SJosef Karthauser 			strlcpy(execfname, optarg, sizeof(execfname));
16087eb4a42SJosef Karthauser 			break;
16187eb4a42SJosef Karthauser 
16287eb4a42SJosef Karthauser 		case 'l':
16387eb4a42SJosef Karthauser 			list_mode++;
16487eb4a42SJosef Karthauser 			verbose = 0;
16587eb4a42SJosef Karthauser 			break;
166de566360SJordan K. Hubbard 
167de566360SJordan K. Hubbard 		case '?':
16887eb4a42SJosef Karthauser 		default:
16987eb4a42SJosef Karthauser 			usage();
170de566360SJordan K. Hubbard 		}
171de566360SJordan K. Hubbard 	}
172de566360SJordan K. Hubbard 
173de566360SJordan K. Hubbard 	argc -= optind;
174de566360SJordan K. Hubbard 	argv += optind;
175de566360SJordan K. Hubbard 
17687eb4a42SJosef Karthauser 	if (argc != 1)
17787eb4a42SJosef Karthauser 		usage();
178de566360SJordan K. Hubbard 
179de566360SJordan K. Hubbard 	/*
180de566360SJordan K. Hubbard 	 * generate filenames
181de566360SJordan K. Hubbard 	 */
182de566360SJordan K. Hubbard 
183f3c47f54SJosef Karthauser 	strlcpy(infilename, argv[0], sizeof(infilename));
184de566360SJordan K. Hubbard 
185de566360SJordan K. Hubbard 	/* confname = `basename infilename .conf` */
186de566360SJordan K. Hubbard 
187f3c47f54SJosef Karthauser 	if ((p=strrchr(infilename, '/')) != NULL)
188f3c47f54SJosef Karthauser 		strlcpy(confname, p + 1, sizeof(confname));
189f3c47f54SJosef Karthauser 	else
190f3c47f54SJosef Karthauser 		strlcpy(confname, infilename, sizeof(confname));
191de566360SJordan K. Hubbard 
19287eb4a42SJosef Karthauser 	if ((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
19387eb4a42SJosef Karthauser 		*p = '\0';
19487eb4a42SJosef Karthauser 
19587eb4a42SJosef Karthauser 	if (!*outmkname)
19687eb4a42SJosef Karthauser 		snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
19787eb4a42SJosef Karthauser 	if (!*outcfname)
19887eb4a42SJosef Karthauser 		snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
19987eb4a42SJosef Karthauser 	if (!*execfname)
20087eb4a42SJosef Karthauser 		snprintf(execfname, sizeof(execfname), "%s", confname);
201de566360SJordan K. Hubbard 
202019d04d1SLuigi Rizzo 	snprintf(cachename, sizeof(cachename), "%s.cache", confname);
20361ffadb1SJosef Karthauser 	snprintf(tempfname, sizeof(tempfname), "%s/crunchgen_%sXXXXXX",
20461ffadb1SJosef Karthauser 	getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, confname);
205de566360SJordan K. Hubbard 
206de566360SJordan K. Hubbard 	parse_conf_file();
207fb7f926eSPoul-Henning Kamp 	if (list_mode)
208fb7f926eSPoul-Henning Kamp 		exit(goterror);
209fb7f926eSPoul-Henning Kamp 
210de566360SJordan K. Hubbard 	gen_outputs();
211de566360SJordan K. Hubbard 
212de566360SJordan K. Hubbard 	exit(goterror);
213de566360SJordan K. Hubbard }
214de566360SJordan K. Hubbard 
215de566360SJordan K. Hubbard 
216de566360SJordan K. Hubbard void usage(void)
217de566360SJordan K. Hubbard {
21887eb4a42SJosef Karthauser 	fprintf(stderr, "%s%s\n\t%s%s\n", "usage: crunchgen [-foq] ",
21987eb4a42SJosef Karthauser 	    "[-h <makefile-header-name>] [-m <makefile>]",
22087eb4a42SJosef Karthauser 	    "[-p <obj-prefix>] [-c <c-file-name>] [-e <exec-file>] ",
22187eb4a42SJosef Karthauser 	    "<conffile>");
222de566360SJordan K. Hubbard 	exit(1);
223de566360SJordan K. Hubbard }
224de566360SJordan K. Hubbard 
225de566360SJordan K. Hubbard 
226de566360SJordan K. Hubbard /*
227de566360SJordan K. Hubbard  * ========================================================================
228de566360SJordan K. Hubbard  * parse_conf_file subsystem
229de566360SJordan K. Hubbard  *
230de566360SJordan K. Hubbard  */
231de566360SJordan K. Hubbard 
232de566360SJordan K. Hubbard /* helper routines for parse_conf_file */
233de566360SJordan K. Hubbard 
234de566360SJordan K. Hubbard void parse_one_file(char *filename);
235de566360SJordan K. Hubbard void parse_line(char *line, int *fc, char **fv, int nf);
236de566360SJordan K. Hubbard void add_srcdirs(int argc, char **argv);
237de566360SJordan K. Hubbard void add_progs(int argc, char **argv);
238de566360SJordan K. Hubbard void add_link(int argc, char **argv);
239de566360SJordan K. Hubbard void add_libs(int argc, char **argv);
24008a15190SJosef Karthauser void add_buildopts(int argc, char **argv);
241de566360SJordan K. Hubbard void add_special(int argc, char **argv);
242de566360SJordan K. Hubbard 
243de566360SJordan K. Hubbard prog_t *find_prog(char *str);
244de566360SJordan K. Hubbard void add_prog(char *progname);
245de566360SJordan K. Hubbard 
246de566360SJordan K. Hubbard 
247de566360SJordan K. Hubbard void parse_conf_file(void)
248de566360SJordan K. Hubbard {
249b17e90a9SPhilippe Charnier 	if (!is_nonempty_file(infilename))
250b17e90a9SPhilippe Charnier 		errx(1, "fatal: input file \"%s\" not found", infilename);
25187eb4a42SJosef Karthauser 
252de566360SJordan K. Hubbard 	parse_one_file(infilename);
253de566360SJordan K. Hubbard 	if (readcache && is_nonempty_file(cachename)) {
254de566360SJordan K. Hubbard 		reading_cache = 1;
255de566360SJordan K. Hubbard 		parse_one_file(cachename);
256de566360SJordan K. Hubbard 	}
257de566360SJordan K. Hubbard }
258de566360SJordan K. Hubbard 
259de566360SJordan K. Hubbard 
260de566360SJordan K. Hubbard void parse_one_file(char *filename)
261de566360SJordan K. Hubbard {
262de566360SJordan K. Hubbard 	char *fieldv[MAXFIELDS];
263de566360SJordan K. Hubbard 	int fieldc;
264de566360SJordan K. Hubbard 	void (*f)(int c, char **v);
265de566360SJordan K. Hubbard 	FILE *cf;
266019d04d1SLuigi Rizzo 	char line[MAXLINELEN];
267de566360SJordan K. Hubbard 
268f3c47f54SJosef Karthauser 	snprintf(line, sizeof(line), "reading %s", filename);
269de566360SJordan K. Hubbard 	status(line);
270f3c47f54SJosef Karthauser 	strlcpy(curfilename, filename, sizeof(curfilename));
271de566360SJordan K. Hubbard 
272de566360SJordan K. Hubbard 	if ((cf = fopen(curfilename, "r")) == NULL) {
273b17e90a9SPhilippe Charnier 		warn("%s", curfilename);
274de566360SJordan K. Hubbard 		goterror = 1;
275de566360SJordan K. Hubbard 		return;
276de566360SJordan K. Hubbard 	}
277de566360SJordan K. Hubbard 
278de566360SJordan K. Hubbard 	linenum = 0;
279de566360SJordan K. Hubbard 	while (fgets(line, MAXLINELEN, cf) != NULL) {
280de566360SJordan K. Hubbard 		linenum++;
281de566360SJordan K. Hubbard 		parse_line(line, &fieldc, fieldv, MAXFIELDS);
28287eb4a42SJosef Karthauser 
28387eb4a42SJosef Karthauser 		if (fieldc < 1)
28487eb4a42SJosef Karthauser 			continue;
28587eb4a42SJosef Karthauser 
28687eb4a42SJosef Karthauser 		if (!strcmp(fieldv[0], "srcdirs"))
28787eb4a42SJosef Karthauser 			f = add_srcdirs;
28887eb4a42SJosef Karthauser 		else if(!strcmp(fieldv[0], "progs"))
28987eb4a42SJosef Karthauser 			f = add_progs;
29087eb4a42SJosef Karthauser 		else if(!strcmp(fieldv[0], "ln"))
29187eb4a42SJosef Karthauser 			f = add_link;
29287eb4a42SJosef Karthauser 		else if(!strcmp(fieldv[0], "libs"))
29387eb4a42SJosef Karthauser 			f = add_libs;
29487eb4a42SJosef Karthauser 		else if(!strcmp(fieldv[0], "buildopts"))
29587eb4a42SJosef Karthauser 			f = add_buildopts;
29687eb4a42SJosef Karthauser 		else if(!strcmp(fieldv[0], "special"))
29787eb4a42SJosef Karthauser 			f = add_special;
298de566360SJordan K. Hubbard 		else {
299b17e90a9SPhilippe Charnier 			warnx("%s:%d: skipping unknown command `%s'",
300de566360SJordan K. Hubbard 			    curfilename, linenum, fieldv[0]);
301de566360SJordan K. Hubbard 			goterror = 1;
302de566360SJordan K. Hubbard 			continue;
303de566360SJordan K. Hubbard 		}
30487eb4a42SJosef Karthauser 
305de566360SJordan K. Hubbard 		if (fieldc < 2) {
30687eb4a42SJosef Karthauser 			warnx("%s:%d: %s %s",
30787eb4a42SJosef Karthauser 			    curfilename, linenum, fieldv[0],
30887eb4a42SJosef Karthauser 			    "command needs at least 1 argument, skipping");
309de566360SJordan K. Hubbard 			goterror = 1;
310de566360SJordan K. Hubbard 			continue;
311de566360SJordan K. Hubbard 		}
31287eb4a42SJosef Karthauser 
313de566360SJordan K. Hubbard 		f(fieldc, fieldv);
314de566360SJordan K. Hubbard 	}
315de566360SJordan K. Hubbard 
316de566360SJordan K. Hubbard 	if (ferror(cf)) {
317b17e90a9SPhilippe Charnier 		warn("%s", curfilename);
318de566360SJordan K. Hubbard 		goterror = 1;
319de566360SJordan K. Hubbard 	}
320de566360SJordan K. Hubbard 	fclose(cf);
321de566360SJordan K. Hubbard }
322de566360SJordan K. Hubbard 
323de566360SJordan K. Hubbard 
324de566360SJordan K. Hubbard void parse_line(char *line, int *fc, char **fv, int nf)
325de566360SJordan K. Hubbard {
326de566360SJordan K. Hubbard 	char *p;
327de566360SJordan K. Hubbard 
328de566360SJordan K. Hubbard 	p = line;
329de566360SJordan K. Hubbard 	*fc = 0;
330de566360SJordan K. Hubbard 
33187eb4a42SJosef Karthauser 	while (1) {
33287eb4a42SJosef Karthauser 		while (isspace(*p))
33387eb4a42SJosef Karthauser 			p++;
33487eb4a42SJosef Karthauser 
33587eb4a42SJosef Karthauser 		if (*p == '\0' || *p == '#')
33687eb4a42SJosef Karthauser 			break;
33787eb4a42SJosef Karthauser 
33887eb4a42SJosef Karthauser 		if (*fc < nf)
33987eb4a42SJosef Karthauser 			fv[(*fc)++] = p;
34087eb4a42SJosef Karthauser 
34187eb4a42SJosef Karthauser 		while (*p && !isspace(*p) && *p != '#')
34287eb4a42SJosef Karthauser 			p++;
34387eb4a42SJosef Karthauser 
34487eb4a42SJosef Karthauser 		if (*p == '\0' || *p == '#')
34587eb4a42SJosef Karthauser 			break;
34687eb4a42SJosef Karthauser 
347de566360SJordan K. Hubbard 		*p++ = '\0';
348de566360SJordan K. Hubbard 	}
34987eb4a42SJosef Karthauser 
35087eb4a42SJosef Karthauser 	if (*p)
35187eb4a42SJosef Karthauser 		*p = '\0';		/* needed for '#' case */
352de566360SJordan K. Hubbard }
353de566360SJordan K. Hubbard 
354de566360SJordan K. Hubbard 
355de566360SJordan K. Hubbard void add_srcdirs(int argc, char **argv)
356de566360SJordan K. Hubbard {
357de566360SJordan K. Hubbard 	int i;
358de566360SJordan K. Hubbard 
359de566360SJordan K. Hubbard 	for (i = 1; i < argc; i++) {
360de566360SJordan K. Hubbard 		if (is_dir(argv[i]))
361de566360SJordan K. Hubbard 			add_string(&srcdirs, argv[i]);
362de566360SJordan K. Hubbard 		else {
363b17e90a9SPhilippe Charnier 			warnx("%s:%d: `%s' is not a directory, skipping it",
364de566360SJordan K. Hubbard 			    curfilename, linenum, argv[i]);
365de566360SJordan K. Hubbard 			goterror = 1;
366de566360SJordan K. Hubbard 		}
367de566360SJordan K. Hubbard 	}
368de566360SJordan K. Hubbard }
369de566360SJordan K. Hubbard 
370de566360SJordan K. Hubbard 
371de566360SJordan K. Hubbard void add_progs(int argc, char **argv)
372de566360SJordan K. Hubbard {
373de566360SJordan K. Hubbard 	int i;
374de566360SJordan K. Hubbard 
375de566360SJordan K. Hubbard 	for (i = 1; i < argc; i++)
376de566360SJordan K. Hubbard 		add_prog(argv[i]);
377de566360SJordan K. Hubbard }
378de566360SJordan K. Hubbard 
379de566360SJordan K. Hubbard 
380de566360SJordan K. Hubbard void add_prog(char *progname)
381de566360SJordan K. Hubbard {
382de566360SJordan K. Hubbard 	prog_t *p1, *p2;
383de566360SJordan K. Hubbard 
384de566360SJordan K. Hubbard 	/* add to end, but be smart about dups */
385de566360SJordan K. Hubbard 
386de566360SJordan K. Hubbard 	for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
38787eb4a42SJosef Karthauser 		if (!strcmp(p2->name, progname))
38887eb4a42SJosef Karthauser 			return;
389de566360SJordan K. Hubbard 
390de566360SJordan K. Hubbard 	p2 = malloc(sizeof(prog_t));
391eb148815SJoerg Wunsch 	if(p2) {
392eb148815SJoerg Wunsch 		memset(p2, 0, sizeof(prog_t));
393eb148815SJoerg Wunsch 		p2->name = strdup(progname);
394eb148815SJoerg Wunsch 	}
395de566360SJordan K. Hubbard 	if (!p2 || !p2->name)
396de566360SJordan K. Hubbard 		out_of_memory();
397de566360SJordan K. Hubbard 
398de566360SJordan K. Hubbard 	p2->next = NULL;
39987eb4a42SJosef Karthauser 	if (p1 == NULL)
40087eb4a42SJosef Karthauser 		progs = p2;
40187eb4a42SJosef Karthauser 	else
40287eb4a42SJosef Karthauser 		p1->next = p2;
403de566360SJordan K. Hubbard 
40487eb4a42SJosef Karthauser 	p2->ident = NULL;
40587eb4a42SJosef Karthauser 	p2->srcdir = NULL;
40687eb4a42SJosef Karthauser 	p2->realsrcdir = NULL;
40787eb4a42SJosef Karthauser 	p2->objdir = NULL;
40887eb4a42SJosef Karthauser 	p2->links = NULL;
40987eb4a42SJosef Karthauser 	p2->objs = NULL;
41087eb4a42SJosef Karthauser 	p2->keeplist = NULL;
41134944d48SJosef Karthauser 	p2->buildopts = NULL;
412de566360SJordan K. Hubbard 	p2->goterror = 0;
41387eb4a42SJosef Karthauser 
414fb7f926eSPoul-Henning Kamp 	if (list_mode)
415fb7f926eSPoul-Henning Kamp 		printf("%s\n",progname);
416de566360SJordan K. Hubbard }
417de566360SJordan K. Hubbard 
418de566360SJordan K. Hubbard 
419de566360SJordan K. Hubbard void add_link(int argc, char **argv)
420de566360SJordan K. Hubbard {
421de566360SJordan K. Hubbard 	int i;
422de566360SJordan K. Hubbard 	prog_t *p = find_prog(argv[1]);
423de566360SJordan K. Hubbard 
424de566360SJordan K. Hubbard 	if (p == NULL) {
425b17e90a9SPhilippe Charnier 		warnx("%s:%d: no prog %s previously declared, skipping link",
426de566360SJordan K. Hubbard 		    curfilename, linenum, argv[1]);
427de566360SJordan K. Hubbard 		goterror = 1;
428de566360SJordan K. Hubbard 		return;
429de566360SJordan K. Hubbard 	}
43087eb4a42SJosef Karthauser 
431fb7f926eSPoul-Henning Kamp 	for (i = 2; i < argc; i++) {
432fb7f926eSPoul-Henning Kamp 		if (list_mode)
433fb7f926eSPoul-Henning Kamp 			printf("%s\n",argv[i]);
43487eb4a42SJosef Karthauser 
435de566360SJordan K. Hubbard 		add_string(&p->links, argv[i]);
436de566360SJordan K. Hubbard 	}
437fb7f926eSPoul-Henning Kamp }
438de566360SJordan K. Hubbard 
439de566360SJordan K. Hubbard 
440de566360SJordan K. Hubbard void add_libs(int argc, char **argv)
441de566360SJordan K. Hubbard {
442de566360SJordan K. Hubbard 	int i;
443de566360SJordan K. Hubbard 
444de566360SJordan K. Hubbard 	for(i = 1; i < argc; i++)
445de566360SJordan K. Hubbard 		add_string(&libs, argv[i]);
446de566360SJordan K. Hubbard }
447de566360SJordan K. Hubbard 
448de566360SJordan K. Hubbard 
44908a15190SJosef Karthauser void add_buildopts(int argc, char **argv)
45008a15190SJosef Karthauser {
45108a15190SJosef Karthauser 	int i;
45208a15190SJosef Karthauser 
45308a15190SJosef Karthauser 	for (i = 1; i < argc; i++)
45408a15190SJosef Karthauser 		add_string(&buildopts, argv[i]);
45508a15190SJosef Karthauser }
45608a15190SJosef Karthauser 
45708a15190SJosef Karthauser 
458de566360SJordan K. Hubbard void add_special(int argc, char **argv)
459de566360SJordan K. Hubbard {
460de566360SJordan K. Hubbard 	int i;
461de566360SJordan K. Hubbard 	prog_t *p = find_prog(argv[1]);
462de566360SJordan K. Hubbard 
463de566360SJordan K. Hubbard 	if (p == NULL) {
46487eb4a42SJosef Karthauser 		if (reading_cache)
46587eb4a42SJosef Karthauser 			return;
46687eb4a42SJosef Karthauser 
467b17e90a9SPhilippe Charnier 		warnx("%s:%d: no prog %s previously declared, skipping special",
468de566360SJordan K. Hubbard 		    curfilename, linenum, argv[1]);
469de566360SJordan K. Hubbard 		goterror = 1;
470de566360SJordan K. Hubbard 		return;
471de566360SJordan K. Hubbard 	}
472de566360SJordan K. Hubbard 
473de566360SJordan K. Hubbard 	if (!strcmp(argv[2], "ident")) {
47487eb4a42SJosef Karthauser 		if (argc != 4)
47587eb4a42SJosef Karthauser 			goto argcount;
476de566360SJordan K. Hubbard 		if ((p->ident = strdup(argv[3])) == NULL)
477de566360SJordan K. Hubbard 			out_of_memory();
47887eb4a42SJosef Karthauser 	} else if (!strcmp(argv[2], "srcdir")) {
47987eb4a42SJosef Karthauser 		if (argc != 4)
48087eb4a42SJosef Karthauser 			goto argcount;
481de566360SJordan K. Hubbard 		if ((p->srcdir = strdup(argv[3])) == NULL)
482de566360SJordan K. Hubbard 			out_of_memory();
48387eb4a42SJosef Karthauser 	} else if (!strcmp(argv[2], "objdir")) {
48487eb4a42SJosef Karthauser 		if(argc != 4)
48587eb4a42SJosef Karthauser 			goto argcount;
486de566360SJordan K. Hubbard 		if((p->objdir = strdup(argv[3])) == NULL)
487de566360SJordan K. Hubbard 			out_of_memory();
48887eb4a42SJosef Karthauser 	} else if (!strcmp(argv[2], "objs")) {
489de566360SJordan K. Hubbard 		p->objs = NULL;
490de566360SJordan K. Hubbard 		for (i = 3; i < argc; i++)
491de566360SJordan K. Hubbard 			add_string(&p->objs, argv[i]);
49287eb4a42SJosef Karthauser 	} else if (!strcmp(argv[2], "objpaths")) {
493de566360SJordan K. Hubbard 		p->objpaths = NULL;
494de566360SJordan K. Hubbard 		for (i = 3; i < argc; i++)
495de566360SJordan K. Hubbard 			add_string(&p->objpaths, argv[i]);
49687eb4a42SJosef Karthauser 	} else if (!strcmp(argv[2], "keep")) {
49742ac3bf1SJoerg Wunsch 		p->keeplist = NULL;
49842ac3bf1SJoerg Wunsch 		for(i = 3; i < argc; i++)
49942ac3bf1SJoerg Wunsch 			add_string(&p->keeplist, argv[i]);
50087eb4a42SJosef Karthauser 	} else if (!strcmp(argv[2], "objvar")) {
50108826cadSLuigi Rizzo 		if(argc != 4)
50208826cadSLuigi Rizzo 			goto argcount;
50308826cadSLuigi Rizzo 		if ((p->objvar = strdup(argv[3])) == NULL)
50408826cadSLuigi Rizzo 			out_of_memory();
50587eb4a42SJosef Karthauser 	} else if (!strcmp(argv[2], "buildopts")) {
50634944d48SJosef Karthauser 		p->buildopts = NULL;
50734944d48SJosef Karthauser 		for (i = 3; i < argc; i++)
50834944d48SJosef Karthauser 			add_string(&p->buildopts, argv[i]);
50987eb4a42SJosef Karthauser 	} else {
510b17e90a9SPhilippe Charnier 		warnx("%s:%d: bad parameter name `%s', skipping line",
511de566360SJordan K. Hubbard 		    curfilename, linenum, argv[2]);
512de566360SJordan K. Hubbard 		goterror = 1;
513de566360SJordan K. Hubbard 	}
514de566360SJordan K. Hubbard 	return;
515de566360SJordan K. Hubbard 
516de566360SJordan K. Hubbard  argcount:
517b17e90a9SPhilippe Charnier 	warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"",
518de566360SJordan K. Hubbard 	    curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]);
519de566360SJordan K. Hubbard 	goterror = 1;
520de566360SJordan K. Hubbard }
521de566360SJordan K. Hubbard 
522de566360SJordan K. Hubbard 
523de566360SJordan K. Hubbard prog_t *find_prog(char *str)
524de566360SJordan K. Hubbard {
525de566360SJordan K. Hubbard 	prog_t *p;
526de566360SJordan K. Hubbard 
527de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next)
52887eb4a42SJosef Karthauser 		if (!strcmp(p->name, str))
52987eb4a42SJosef Karthauser 			return p;
530de566360SJordan K. Hubbard 
531de566360SJordan K. Hubbard 	return NULL;
532de566360SJordan K. Hubbard }
533de566360SJordan K. Hubbard 
534de566360SJordan K. Hubbard 
535de566360SJordan K. Hubbard /*
536de566360SJordan K. Hubbard  * ========================================================================
537de566360SJordan K. Hubbard  * gen_outputs subsystem
538de566360SJordan K. Hubbard  *
539de566360SJordan K. Hubbard  */
540de566360SJordan K. Hubbard 
541de566360SJordan K. Hubbard /* helper subroutines */
542de566360SJordan K. Hubbard 
543de566360SJordan K. Hubbard void remove_error_progs(void);
544de566360SJordan K. Hubbard void fillin_program(prog_t *p);
545de566360SJordan K. Hubbard void gen_specials_cache(void);
546de566360SJordan K. Hubbard void gen_output_makefile(void);
547de566360SJordan K. Hubbard void gen_output_cfile(void);
548de566360SJordan K. Hubbard 
549de566360SJordan K. Hubbard void fillin_program_objs(prog_t *p, char *path);
550de566360SJordan K. Hubbard void top_makefile_rules(FILE *outmk);
551de566360SJordan K. Hubbard void prog_makefile_rules(FILE *outmk, prog_t *p);
552de566360SJordan K. Hubbard void output_strlst(FILE *outf, strlst_t *lst);
553de566360SJordan K. Hubbard char *genident(char *str);
554de566360SJordan K. Hubbard char *dir_search(char *progname);
555de566360SJordan K. Hubbard 
556de566360SJordan K. Hubbard 
557de566360SJordan K. Hubbard void gen_outputs(void)
558de566360SJordan K. Hubbard {
559de566360SJordan K. Hubbard 	prog_t *p;
560de566360SJordan K. Hubbard 
561de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next)
562de566360SJordan K. Hubbard 		fillin_program(p);
563de566360SJordan K. Hubbard 
564de566360SJordan K. Hubbard 	remove_error_progs();
565de566360SJordan K. Hubbard 	gen_specials_cache();
566de566360SJordan K. Hubbard 	gen_output_cfile();
567de566360SJordan K. Hubbard 	gen_output_makefile();
568de566360SJordan K. Hubbard 	status("");
569de566360SJordan K. Hubbard 	fprintf(stderr,
570843d8d51SJosef Karthauser 	    "Run \"make -f %s\" to build crunched binary.\n", outmkname);
571de566360SJordan K. Hubbard }
572de566360SJordan K. Hubbard 
57308826cadSLuigi Rizzo /*
57408826cadSLuigi Rizzo  * run the makefile for the program to find which objects are necessary
57508826cadSLuigi Rizzo  */
576de566360SJordan K. Hubbard void fillin_program(prog_t *p)
577de566360SJordan K. Hubbard {
578de566360SJordan K. Hubbard 	char path[MAXPATHLEN];
579019d04d1SLuigi Rizzo 	char line[MAXLINELEN];
580843d8d51SJosef Karthauser 	FILE *f;
581de566360SJordan K. Hubbard 
582019d04d1SLuigi Rizzo 	snprintf(line, MAXLINELEN, "filling in parms for %s", p->name);
583de566360SJordan K. Hubbard 	status(line);
584de566360SJordan K. Hubbard 
585de566360SJordan K. Hubbard 	if (!p->ident)
586de566360SJordan K. Hubbard 		p->ident = genident(p->name);
587e3b7d178SJosef Karthauser 
588e3b7d178SJosef Karthauser 	/* look for the source directory if one wasn't specified by a special */
589de566360SJordan K. Hubbard 	if (!p->srcdir) {
590e3b7d178SJosef Karthauser 		p->srcdir = dir_search(p->name);
591de566360SJordan K. Hubbard 	}
592843d8d51SJosef Karthauser 
593843d8d51SJosef Karthauser 	/* Determine the actual srcdir (maybe symlinked). */
594e3b7d178SJosef Karthauser 	if (p->srcdir) {
59587eb4a42SJosef Karthauser 		snprintf(line, MAXLINELEN, "cd %s && echo -n `/bin/pwd`",
59687eb4a42SJosef Karthauser 		    p->srcdir);
597019d04d1SLuigi Rizzo 		f = popen(line,"r");
598e3b7d178SJosef Karthauser 		if (!f)
599e3b7d178SJosef Karthauser 			errx(1, "Can't execute: %s\n", line);
600e3b7d178SJosef Karthauser 
601019d04d1SLuigi Rizzo 		path[0] = '\0';
602154fd6a9SPoul-Henning Kamp 		fgets(path, sizeof path, f);
603e3b7d178SJosef Karthauser 		if (pclose(f))
604e3b7d178SJosef Karthauser 			errx(1, "Can't execute: %s\n", line);
605e3b7d178SJosef Karthauser 
606e3b7d178SJosef Karthauser 		if (!*path)
607e3b7d178SJosef Karthauser 			errx(1, "Can't perform pwd on: %s\n", p->srcdir);
608e3b7d178SJosef Karthauser 
609843d8d51SJosef Karthauser 		p->realsrcdir = strdup(path);
610154fd6a9SPoul-Henning Kamp 	}
611843d8d51SJosef Karthauser 
612843d8d51SJosef Karthauser 	/* Unless the option to make object files was specified the
613843d8d51SJosef Karthauser 	* the objects will be built in the source directory unless
614843d8d51SJosef Karthauser 	* an object directory already exists.
615843d8d51SJosef Karthauser 	*/
616843d8d51SJosef Karthauser 	if (!makeobj && !p->objdir && p->srcdir) {
617843d8d51SJosef Karthauser 		snprintf(line, sizeof line, "%s/%s", objprefix, p->realsrcdir);
6185e5f3826SJosef Karthauser 		if (is_dir(line)) {
619f3c47f54SJosef Karthauser 			if ((p->objdir = strdup(line)) == NULL)
620f3c47f54SJosef Karthauser 			out_of_memory();
6215e5f3826SJosef Karthauser 		} else
622843d8d51SJosef Karthauser 			p->objdir = p->realsrcdir;
623de566360SJordan K. Hubbard 	}
62487eb4a42SJosef Karthauser 
62508826cadSLuigi Rizzo 	/*
62608826cadSLuigi Rizzo 	* XXX look for a Makefile.{name} in local directory first.
62708826cadSLuigi Rizzo 	* This lets us override the original Makefile.
62808826cadSLuigi Rizzo 	*/
629019d04d1SLuigi Rizzo 	snprintf(path, sizeof(path), "Makefile.%s", p->name);
63008826cadSLuigi Rizzo 	if (is_nonempty_file(path)) {
631019d04d1SLuigi Rizzo 		snprintf(line, MAXLINELEN, "Using %s for %s", path, p->name);
63208826cadSLuigi Rizzo 		status(line);
63308826cadSLuigi Rizzo 	} else
63487eb4a42SJosef Karthauser 		if (p->srcdir)
63587eb4a42SJosef Karthauser 			snprintf(path, sizeof(path), "%s/Makefile", p->srcdir);
636de566360SJordan K. Hubbard 	if (!p->objs && p->srcdir && is_nonempty_file(path))
637de566360SJordan K. Hubbard 		fillin_program_objs(p, path);
638de566360SJordan K. Hubbard 
639de566360SJordan K. Hubbard 	if (!p->srcdir && verbose)
64087eb4a42SJosef Karthauser 		warnx("%s: %s: %s",
64187eb4a42SJosef Karthauser 		    "warning: could not find source directory",
642de566360SJordan K. Hubbard 		    infilename, p->name);
643de566360SJordan K. Hubbard 	if (!p->objs && verbose)
644b17e90a9SPhilippe Charnier 		warnx("%s: %s: warning: could not find any .o files",
645de566360SJordan K. Hubbard 		    infilename, p->name);
646617b8180SJosef Karthauser 
647617b8180SJosef Karthauser 	if (!p->srcdir || !p->objs)
648617b8180SJosef Karthauser 		p->goterror = 1;
649de566360SJordan K. Hubbard }
650de566360SJordan K. Hubbard 
651de566360SJordan K. Hubbard void fillin_program_objs(prog_t *p, char *path)
652de566360SJordan K. Hubbard {
653de566360SJordan K. Hubbard 	char *obj, *cp;
654f3c47f54SJosef Karthauser 	int fd, rc;
655de566360SJordan K. Hubbard 	FILE *f;
65608826cadSLuigi Rizzo 	char *objvar="OBJS";
65734944d48SJosef Karthauser 	strlst_t *s;
658019d04d1SLuigi Rizzo 	char line[MAXLINELEN];
659de566360SJordan K. Hubbard 
660de566360SJordan K. Hubbard 	/* discover the objs from the srcdir Makefile */
661de566360SJordan K. Hubbard 
662f3c47f54SJosef Karthauser 	if ((fd = mkstemp(tempfname)) == -1) {
663f3c47f54SJosef Karthauser 		perror(tempfname);
664f3c47f54SJosef Karthauser 		exit(1);
665f3c47f54SJosef Karthauser 	}
666f3c47f54SJosef Karthauser 	if ((f = fdopen(fd, "w")) == NULL) {
667b17e90a9SPhilippe Charnier 		warn("%s", tempfname);
668de566360SJordan K. Hubbard 		goterror = 1;
669de566360SJordan K. Hubbard 		return;
670de566360SJordan K. Hubbard 	}
67108826cadSLuigi Rizzo 	if (p->objvar)
67208826cadSLuigi Rizzo 		objvar = p->objvar;
673de566360SJordan K. Hubbard 
67408826cadSLuigi Rizzo 	/*
67508826cadSLuigi Rizzo 	* XXX include outhdrname (e.g. to contain Make variables)
67608826cadSLuigi Rizzo 	*/
67708826cadSLuigi Rizzo 	if (outhdrname[0] != '\0')
67808826cadSLuigi Rizzo 		fprintf(f, ".include \"%s\"\n", outhdrname);
679de566360SJordan K. Hubbard 	fprintf(f, ".include \"%s\"\n", path);
68008a15190SJosef Karthauser 	if (buildopts) {
68108a15190SJosef Karthauser 		fprintf(f, "BUILDOPTS+=");
68208a15190SJosef Karthauser 		output_strlst(f, buildopts);
68308a15190SJosef Karthauser 	}
68408826cadSLuigi Rizzo 	fprintf(f, ".if defined(PROG) && !defined(%s)\n", objvar);
68508826cadSLuigi Rizzo 	fprintf(f, "%s=${PROG}.o\n", objvar);
686de566360SJordan K. Hubbard 	fprintf(f, ".endif\n");
68765cb078fSJosef Karthauser 	fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar);
68834944d48SJosef Karthauser 
68908a15190SJosef Karthauser 	fprintf(f, "crunchgen_objs:\n\t@make -f %s $(BUILDOPTS) $(%s_OPTS)",
69065cb078fSJosef Karthauser 	    tempfname, p->ident);
69134944d48SJosef Karthauser 	for (s = p->buildopts; s != NULL; s = s->next)
69234944d48SJosef Karthauser 		fprintf(f, " %s", s->str);
69334944d48SJosef Karthauser 	fprintf(f, " loop\n");
69434944d48SJosef Karthauser 
695de566360SJordan K. Hubbard 	fclose(f);
696de566360SJordan K. Hubbard 
697019d04d1SLuigi Rizzo 	snprintf(line, MAXLINELEN, "make -f %s crunchgen_objs 2>&1", tempfname);
698de566360SJordan K. Hubbard 	if ((f = popen(line, "r")) == NULL) {
699b17e90a9SPhilippe Charnier 		warn("submake pipe");
700de566360SJordan K. Hubbard 		goterror = 1;
701de566360SJordan K. Hubbard 		return;
702de566360SJordan K. Hubbard 	}
703de566360SJordan K. Hubbard 
704de566360SJordan K. Hubbard 	while(fgets(line, MAXLINELEN, f)) {
705de566360SJordan K. Hubbard 		if (strncmp(line, "OBJS= ", 6)) {
706b17e90a9SPhilippe Charnier 			warnx("make error: %s", line);
707de566360SJordan K. Hubbard 			goterror = 1;
708de566360SJordan K. Hubbard 			continue;
709de566360SJordan K. Hubbard 		}
71087eb4a42SJosef Karthauser 
711de566360SJordan K. Hubbard 		cp = line + 6;
71287eb4a42SJosef Karthauser 		while (isspace(*cp))
71387eb4a42SJosef Karthauser 			cp++;
71487eb4a42SJosef Karthauser 
715de566360SJordan K. Hubbard 		while(*cp) {
716de566360SJordan K. Hubbard 			obj = cp;
71787eb4a42SJosef Karthauser 			while (*cp && !isspace(*cp))
71887eb4a42SJosef Karthauser 				cp++;
71987eb4a42SJosef Karthauser 			if (*cp)
72087eb4a42SJosef Karthauser 				*cp++ = '\0';
721de566360SJordan K. Hubbard 			add_string(&p->objs, obj);
72287eb4a42SJosef Karthauser 			while (isspace(*cp))
72387eb4a42SJosef Karthauser 				cp++;
724de566360SJordan K. Hubbard 		}
725de566360SJordan K. Hubbard 	}
72687eb4a42SJosef Karthauser 
727de566360SJordan K. Hubbard 	if ((rc=pclose(f)) != 0) {
728b17e90a9SPhilippe Charnier 		warnx("make error: make returned %d", rc);
729de566360SJordan K. Hubbard 		goterror = 1;
730de566360SJordan K. Hubbard 	}
73187eb4a42SJosef Karthauser 
732de566360SJordan K. Hubbard 	unlink(tempfname);
733de566360SJordan K. Hubbard }
734de566360SJordan K. Hubbard 
735de566360SJordan K. Hubbard void remove_error_progs(void)
736de566360SJordan K. Hubbard {
737de566360SJordan K. Hubbard 	prog_t *p1, *p2;
738de566360SJordan K. Hubbard 
739de566360SJordan K. Hubbard 	p1 = NULL; p2 = progs;
740de566360SJordan K. Hubbard 	while (p2 != NULL) {
741de566360SJordan K. Hubbard 		if (!p2->goterror)
742de566360SJordan K. Hubbard 			p1 = p2, p2 = p2->next;
743de566360SJordan K. Hubbard 		else {
744de566360SJordan K. Hubbard 			/* delete it from linked list */
745b17e90a9SPhilippe Charnier 			warnx("%s: %s: ignoring program because of errors",
746de566360SJordan K. Hubbard 			    infilename, p2->name);
74787eb4a42SJosef Karthauser 			if (p1)
74887eb4a42SJosef Karthauser 				p1->next = p2->next;
74987eb4a42SJosef Karthauser 			else
75087eb4a42SJosef Karthauser 				progs = p2->next;
751de566360SJordan K. Hubbard 			p2 = p2->next;
752de566360SJordan K. Hubbard 		}
753de566360SJordan K. Hubbard 	}
754de566360SJordan K. Hubbard }
755de566360SJordan K. Hubbard 
756de566360SJordan K. Hubbard void gen_specials_cache(void)
757de566360SJordan K. Hubbard {
758de566360SJordan K. Hubbard 	FILE *cachef;
759de566360SJordan K. Hubbard 	prog_t *p;
760019d04d1SLuigi Rizzo 	char line[MAXLINELEN];
761de566360SJordan K. Hubbard 
762019d04d1SLuigi Rizzo 	snprintf(line, MAXLINELEN, "generating %s", cachename);
763de566360SJordan K. Hubbard 	status(line);
764de566360SJordan K. Hubbard 
765de566360SJordan K. Hubbard 	if ((cachef = fopen(cachename, "w")) == NULL) {
766b17e90a9SPhilippe Charnier 		warn("%s", cachename);
767de566360SJordan K. Hubbard 		goterror = 1;
768de566360SJordan K. Hubbard 		return;
769de566360SJordan K. Hubbard 	}
770de566360SJordan K. Hubbard 
77187eb4a42SJosef Karthauser 	fprintf(cachef, "# %s - parm cache generated from %s by crunchgen "
77287eb4a42SJosef Karthauser 	    " %s\n\n",
773de566360SJordan K. Hubbard 	    cachename, infilename, CRUNCH_VERSION);
774de566360SJordan K. Hubbard 
775de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next) {
776de566360SJordan K. Hubbard 		fprintf(cachef, "\n");
777de566360SJordan K. Hubbard 		if (p->srcdir)
77887eb4a42SJosef Karthauser 			fprintf(cachef, "special %s srcdir %s\n",
77987eb4a42SJosef Karthauser 			    p->name, p->srcdir);
780de566360SJordan K. Hubbard 		if (p->objdir)
78187eb4a42SJosef Karthauser 			fprintf(cachef, "special %s objdir %s\n",
78287eb4a42SJosef Karthauser 			    p->name, p->objdir);
783de566360SJordan K. Hubbard 		if (p->objs) {
784de566360SJordan K. Hubbard 			fprintf(cachef, "special %s objs", p->name);
785de566360SJordan K. Hubbard 			output_strlst(cachef, p->objs);
786de566360SJordan K. Hubbard 		}
787843d8d51SJosef Karthauser 		if (p->objpaths) {
788de566360SJordan K. Hubbard 			fprintf(cachef, "special %s objpaths", p->name);
789de566360SJordan K. Hubbard 			output_strlst(cachef, p->objpaths);
790de566360SJordan K. Hubbard 		}
791843d8d51SJosef Karthauser 	}
792de566360SJordan K. Hubbard 	fclose(cachef);
793de566360SJordan K. Hubbard }
794de566360SJordan K. Hubbard 
795de566360SJordan K. Hubbard 
796de566360SJordan K. Hubbard void gen_output_makefile(void)
797de566360SJordan K. Hubbard {
798de566360SJordan K. Hubbard 	prog_t *p;
799de566360SJordan K. Hubbard 	FILE *outmk;
800019d04d1SLuigi Rizzo 	char line[MAXLINELEN];
801de566360SJordan K. Hubbard 
802019d04d1SLuigi Rizzo 	snprintf(line, MAXLINELEN, "generating %s", outmkname);
803de566360SJordan K. Hubbard 	status(line);
804de566360SJordan K. Hubbard 
805de566360SJordan K. Hubbard 	if ((outmk = fopen(outmkname, "w")) == NULL) {
806b17e90a9SPhilippe Charnier 		warn("%s", outmkname);
807de566360SJordan K. Hubbard 		goterror = 1;
808de566360SJordan K. Hubbard 		return;
809de566360SJordan K. Hubbard 	}
810de566360SJordan K. Hubbard 
811de566360SJordan K. Hubbard 	fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
812de566360SJordan K. Hubbard 	    outmkname, infilename, CRUNCH_VERSION);
81387eb4a42SJosef Karthauser 
81408826cadSLuigi Rizzo 	if (outhdrname[0] != '\0')
81508826cadSLuigi Rizzo 		fprintf(outmk, ".include \"%s\"\n", outhdrname);
816de566360SJordan K. Hubbard 
817de566360SJordan K. Hubbard 	top_makefile_rules(outmk);
818de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next)
819de566360SJordan K. Hubbard 		prog_makefile_rules(outmk, p);
820de566360SJordan K. Hubbard 
821de566360SJordan K. Hubbard 	fprintf(outmk, "\n# ========\n");
822de566360SJordan K. Hubbard 	fclose(outmk);
823de566360SJordan K. Hubbard }
824de566360SJordan K. Hubbard 
825de566360SJordan K. Hubbard 
826de566360SJordan K. Hubbard void gen_output_cfile(void)
827de566360SJordan K. Hubbard {
828de566360SJordan K. Hubbard 	extern char *crunched_skel[];
829de566360SJordan K. Hubbard 	char **cp;
830de566360SJordan K. Hubbard 	FILE *outcf;
831de566360SJordan K. Hubbard 	prog_t *p;
832de566360SJordan K. Hubbard 	strlst_t *s;
833019d04d1SLuigi Rizzo 	char line[MAXLINELEN];
834de566360SJordan K. Hubbard 
835019d04d1SLuigi Rizzo 	snprintf(line, MAXLINELEN, "generating %s", outcfname);
836de566360SJordan K. Hubbard 	status(line);
837de566360SJordan K. Hubbard 
838de566360SJordan K. Hubbard 	if((outcf = fopen(outcfname, "w")) == NULL) {
839b17e90a9SPhilippe Charnier 		warn("%s", outcfname);
840de566360SJordan K. Hubbard 		goterror = 1;
841de566360SJordan K. Hubbard 		return;
842de566360SJordan K. Hubbard 	}
843de566360SJordan K. Hubbard 
844de566360SJordan K. Hubbard 	fprintf(outcf,
845de566360SJordan K. Hubbard 	    "/* %s - generated from %s by crunchgen %s */\n",
846de566360SJordan K. Hubbard 	    outcfname, infilename, CRUNCH_VERSION);
847de566360SJordan K. Hubbard 
848de566360SJordan K. Hubbard 	fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
849de566360SJordan K. Hubbard 	for (cp = crunched_skel; *cp != NULL; cp++)
850de566360SJordan K. Hubbard 		fprintf(outcf, "%s\n", *cp);
851de566360SJordan K. Hubbard 
852de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next)
853de566360SJordan K. Hubbard 		fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
854de566360SJordan K. Hubbard 
855de566360SJordan K. Hubbard 	fprintf(outcf, "\nstruct stub entry_points[] = {\n");
856de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next) {
857de566360SJordan K. Hubbard 		fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
858de566360SJordan K. Hubbard 		    p->name, p->ident);
859de566360SJordan K. Hubbard 		for (s = p->links; s != NULL; s = s->next)
860de566360SJordan K. Hubbard 			fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
861de566360SJordan K. Hubbard 			    s->str, p->ident);
862de566360SJordan K. Hubbard 	}
863de566360SJordan K. Hubbard 
864de566360SJordan K. Hubbard 	fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
865de566360SJordan K. Hubbard 	fprintf(outcf, "\t{ NULL, NULL }\n};\n");
866de566360SJordan K. Hubbard 	fclose(outcf);
867de566360SJordan K. Hubbard }
868de566360SJordan K. Hubbard 
869de566360SJordan K. Hubbard 
870de566360SJordan K. Hubbard char *genident(char *str)
871de566360SJordan K. Hubbard {
872de566360SJordan K. Hubbard 	char *n, *s, *d;
873de566360SJordan K. Hubbard 
874de566360SJordan K. Hubbard 	/*
87587eb4a42SJosef Karthauser 	 * generates a Makefile/C identifier from a program name,
87687eb4a42SJosef Karthauser 	 * mapping '-' to '_' and ignoring all other non-identifier
87787eb4a42SJosef Karthauser 	 * characters.  This leads to programs named "foo.bar" and
87887eb4a42SJosef Karthauser 	 * "foobar" to map to the same identifier.
879de566360SJordan K. Hubbard 	 */
880de566360SJordan K. Hubbard 
881de566360SJordan K. Hubbard 	if ((n = strdup(str)) == NULL)
882de566360SJordan K. Hubbard 		return NULL;
883de566360SJordan K. Hubbard 	for (d = s = n; *s != '\0'; s++) {
88487eb4a42SJosef Karthauser 		if (*s == '-')
88587eb4a42SJosef Karthauser 			*d++ = '_';
88687eb4a42SJosef Karthauser 		else if (*s == '_' || isalnum(*s))
88787eb4a42SJosef Karthauser 			*d++ = *s;
888de566360SJordan K. Hubbard 	}
889de566360SJordan K. Hubbard 	*d = '\0';
890de566360SJordan K. Hubbard 	return n;
891de566360SJordan K. Hubbard }
892de566360SJordan K. Hubbard 
893de566360SJordan K. Hubbard 
894de566360SJordan K. Hubbard char *dir_search(char *progname)
895de566360SJordan K. Hubbard {
896de566360SJordan K. Hubbard 	char path[MAXPATHLEN];
897de566360SJordan K. Hubbard 	strlst_t *dir;
898e3b7d178SJosef Karthauser 	char *srcdir;
899de566360SJordan K. Hubbard 
900de566360SJordan K. Hubbard 	for (dir = srcdirs; dir != NULL; dir = dir->next) {
901019d04d1SLuigi Rizzo 		snprintf(path, MAXPATHLEN, "%s/%s", dir->str, progname);
90287eb4a42SJosef Karthauser 		if (!is_dir(path))
903e3b7d178SJosef Karthauser 			continue;
904e3b7d178SJosef Karthauser 
905e3b7d178SJosef Karthauser 		if ((srcdir = strdup(path)) == NULL)
906e3b7d178SJosef Karthauser 			out_of_memory();
90787eb4a42SJosef Karthauser 
908e3b7d178SJosef Karthauser 		return srcdir;
909de566360SJordan K. Hubbard 	}
910de566360SJordan K. Hubbard 	return NULL;
911de566360SJordan K. Hubbard }
912de566360SJordan K. Hubbard 
913de566360SJordan K. Hubbard 
914de566360SJordan K. Hubbard void top_makefile_rules(FILE *outmk)
915de566360SJordan K. Hubbard {
916de566360SJordan K. Hubbard 	prog_t *p;
917de566360SJordan K. Hubbard 
918de566360SJordan K. Hubbard 	fprintf(outmk, "LIBS=");
919de566360SJordan K. Hubbard 	output_strlst(outmk, libs);
920de566360SJordan K. Hubbard 
921843d8d51SJosef Karthauser 	if (makeobj) {
922843d8d51SJosef Karthauser 		fprintf(outmk, "MAKEOBJDIRPREFIX?=%s\n", objprefix);
92387eb4a42SJosef Karthauser 		fprintf(outmk, "MAKE=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX) "
92487eb4a42SJosef Karthauser 		    "make\n");
925843d8d51SJosef Karthauser 	} else {
926843d8d51SJosef Karthauser 		fprintf(outmk, "MAKE=make\n");
927843d8d51SJosef Karthauser 	}
928843d8d51SJosef Karthauser 
92908a15190SJosef Karthauser 	if (buildopts) {
93008a15190SJosef Karthauser 		fprintf(outmk, "BUILDOPTS+=");
93108a15190SJosef Karthauser 		output_strlst(outmk, buildopts);
93208a15190SJosef Karthauser 	}
93308a15190SJosef Karthauser 
934de566360SJordan K. Hubbard 	fprintf(outmk, "CRUNCHED_OBJS=");
935de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next)
936de566360SJordan K. Hubbard 		fprintf(outmk, " %s.lo", p->name);
937de566360SJordan K. Hubbard 	fprintf(outmk, "\n");
938de566360SJordan K. Hubbard 
939de566360SJordan K. Hubbard 	fprintf(outmk, "SUBMAKE_TARGETS=");
940de566360SJordan K. Hubbard 	for (p = progs; p != NULL; p = p->next)
941de566360SJordan K. Hubbard 		fprintf(outmk, " %s_make", p->ident);
942ced716c3SBrian Somers 	fprintf(outmk, "\nSUBCLEAN_TARGETS=");
943ced716c3SBrian Somers 	for (p = progs; p != NULL; p = p->next)
944ced716c3SBrian Somers 		fprintf(outmk, " %s_clean", p->ident);
945de566360SJordan K. Hubbard 	fprintf(outmk, "\n\n");
946de566360SJordan K. Hubbard 
947843d8d51SJosef Karthauser 	fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
948843d8d51SJosef Karthauser 	fprintf(outmk, "exe: %s\n", execfname);
94987eb4a42SJosef Karthauser 	fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n", execfname, execfname);
950de566360SJordan K. Hubbard 	fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
951de566360SJordan K. Hubbard 	    execfname, execfname);
952de566360SJordan K. Hubbard 	fprintf(outmk, "\tstrip %s\n", execfname);
953ced716c3SBrian Somers 	fprintf(outmk, "realclean: clean subclean\n");
95487eb4a42SJosef Karthauser 	fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", execfname);
955ced716c3SBrian Somers 	fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n");
956de566360SJordan K. Hubbard }
957de566360SJordan K. Hubbard 
958de566360SJordan K. Hubbard 
959de566360SJordan K. Hubbard void prog_makefile_rules(FILE *outmk, prog_t *p)
960de566360SJordan K. Hubbard {
96142ac3bf1SJoerg Wunsch 	strlst_t *lst;
96242ac3bf1SJoerg Wunsch 
963de566360SJordan K. Hubbard 	fprintf(outmk, "\n# -------- %s\n\n", p->name);
964de566360SJordan K. Hubbard 
965de566360SJordan K. Hubbard 	if (p->srcdir && p->objs) {
966de566360SJordan K. Hubbard 		fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
967843d8d51SJosef Karthauser 		fprintf(outmk, "%s_REALSRCDIR=%s\n", p->ident, p->realsrcdir);
968843d8d51SJosef Karthauser 
969843d8d51SJosef Karthauser 		fprintf(outmk, "%s_OBJDIR=", p->ident);
970843d8d51SJosef Karthauser 		if (p->objdir)
971843d8d51SJosef Karthauser 			fprintf(outmk, "%s", p->objdir);
972843d8d51SJosef Karthauser 		else
973843d8d51SJosef Karthauser 			fprintf(outmk, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n",
974843d8d51SJosef Karthauser 			    p->ident);
975843d8d51SJosef Karthauser 		fprintf(outmk, "\n");
976843d8d51SJosef Karthauser 
977de566360SJordan K. Hubbard 		fprintf(outmk, "%s_OBJS=", p->ident);
978de566360SJordan K. Hubbard 		output_strlst(outmk, p->objs);
97934944d48SJosef Karthauser 		if (p->buildopts != NULL) {
98034944d48SJosef Karthauser 			fprintf(outmk, "%s_OPTS+=", p->ident);
98134944d48SJosef Karthauser 			output_strlst(outmk, p->buildopts);
98234944d48SJosef Karthauser 		}
983de566360SJordan K. Hubbard 		fprintf(outmk, "%s_make:\n", p->ident);
984ba2250ddSJosef Karthauser 		fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident);
985ba2250ddSJosef Karthauser 		if (makeobj)
986843d8d51SJosef Karthauser 			fprintf(outmk, "$(MAKE) obj && ");
987ba2250ddSJosef Karthauser 		fprintf(outmk, "\\\n");
98887eb4a42SJosef Karthauser 		fprintf(outmk, "\t\t$(MAKE) $(BUILDOPTS) $(%s_OPTS) depend &&",
98987eb4a42SJosef Karthauser 		    p->ident);
99087eb4a42SJosef Karthauser 		fprintf(outmk, "\\\n");
99187eb4a42SJosef Karthauser 		fprintf(outmk, "\t\t$(MAKE) $(BUILDOPTS) $(%s_OPTS) "
99287eb4a42SJosef Karthauser 		    "$(%s_OBJS))",
99387eb4a42SJosef Karthauser 		    p->ident, p->ident);
99487eb4a42SJosef Karthauser 		fprintf(outmk, "\n");
995ced716c3SBrian Somers 		fprintf(outmk, "%s_clean:\n", p->ident);
99687eb4a42SJosef Karthauser 		fprintf(outmk, "\t(cd $(%s_SRCDIR) && $(MAKE) clean)\n\n",
99787eb4a42SJosef Karthauser 		    p->ident);
99887eb4a42SJosef Karthauser 	} else {
99987eb4a42SJosef Karthauser 		fprintf(outmk, "%s_make:\n", p->ident);
100087eb4a42SJosef Karthauser 		fprintf(outmk, "\t@echo \"** cannot make objs for %s\"\n\n",
1001de566360SJordan K. Hubbard 		    p->ident, p->name);
100287eb4a42SJosef Karthauser 	}
1003de566360SJordan K. Hubbard 
1004de566360SJordan K. Hubbard 	fprintf(outmk, "%s_OBJPATHS=", p->ident);
1005843d8d51SJosef Karthauser 	if (p->objpaths)
1006de566360SJordan K. Hubbard 		output_strlst(outmk, p->objpaths);
1007843d8d51SJosef Karthauser 	else {
1008843d8d51SJosef Karthauser 		for (lst = p->objs; lst != NULL; lst = lst->next) {
1009843d8d51SJosef Karthauser 			fprintf(outmk, " $(%s_OBJDIR)/%s", p->ident, lst->str);
1010843d8d51SJosef Karthauser 		}
1011843d8d51SJosef Karthauser 		fprintf(outmk, "\n");
1012843d8d51SJosef Karthauser 	}
1013de566360SJordan K. Hubbard 
1014de566360SJordan K. Hubbard 	fprintf(outmk, "%s_stub.c:\n", p->name);
1015de566360SJordan K. Hubbard 	fprintf(outmk, "\techo \""
1016de566360SJordan K. Hubbard 	    "int _crunched_%s_stub(int argc, char **argv, char **envp)"
1017de566360SJordan K. Hubbard 	    "{return main(argc,argv,envp);}\" >%s_stub.c\n",
1018de566360SJordan K. Hubbard 	    p->ident, p->name);
1019de566360SJordan K. Hubbard 	fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
1020de566360SJordan K. Hubbard 	    p->name, p->name, p->ident);
1021de566360SJordan K. Hubbard 	fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n",
1022de566360SJordan K. Hubbard 	    p->name, p->name, p->ident);
10236cd35234SJordan K. Hubbard 	fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident);
102442ac3bf1SJoerg Wunsch 	for (lst = p->keeplist; lst != NULL; lst = lst->next)
102542ac3bf1SJoerg Wunsch 		fprintf(outmk, "-k _%s ", lst->str);
102642ac3bf1SJoerg Wunsch 	fprintf(outmk, "%s.lo\n", p->name);
1027de566360SJordan K. Hubbard }
1028de566360SJordan K. Hubbard 
1029de566360SJordan K. Hubbard void output_strlst(FILE *outf, strlst_t *lst)
1030de566360SJordan K. Hubbard {
1031de566360SJordan K. Hubbard 	for (; lst != NULL; lst = lst->next)
1032de566360SJordan K. Hubbard 		fprintf(outf, " %s", lst->str);
1033de566360SJordan K. Hubbard 	fprintf(outf, "\n");
1034de566360SJordan K. Hubbard }
1035de566360SJordan K. Hubbard 
1036de566360SJordan K. Hubbard 
1037de566360SJordan K. Hubbard /*
1038de566360SJordan K. Hubbard  * ========================================================================
1039de566360SJordan K. Hubbard  * general library routines
1040de566360SJordan K. Hubbard  *
1041de566360SJordan K. Hubbard  */
1042de566360SJordan K. Hubbard 
1043de566360SJordan K. Hubbard void status(char *str)
1044de566360SJordan K. Hubbard {
1045de566360SJordan K. Hubbard 	static int lastlen = 0;
1046de566360SJordan K. Hubbard 	int len, spaces;
1047de566360SJordan K. Hubbard 
104887eb4a42SJosef Karthauser 	if (!verbose)
104987eb4a42SJosef Karthauser 		return;
1050de566360SJordan K. Hubbard 
1051de566360SJordan K. Hubbard 	len = strlen(str);
1052de566360SJordan K. Hubbard 	spaces = lastlen - len;
105387eb4a42SJosef Karthauser 	if (spaces < 1)
105487eb4a42SJosef Karthauser 		spaces = 1;
1055de566360SJordan K. Hubbard 
1056de566360SJordan K. Hubbard 	fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
1057de566360SJordan K. Hubbard 	fflush(stderr);
1058de566360SJordan K. Hubbard 	lastlen = len;
1059de566360SJordan K. Hubbard }
1060de566360SJordan K. Hubbard 
1061de566360SJordan K. Hubbard 
1062de566360SJordan K. Hubbard void out_of_memory(void)
1063de566360SJordan K. Hubbard {
1064f3c47f54SJosef Karthauser 	err(1, "%s: %d: out of memory, stopping", infilename, linenum);
1065de566360SJordan K. Hubbard }
1066de566360SJordan K. Hubbard 
1067de566360SJordan K. Hubbard 
1068de566360SJordan K. Hubbard void add_string(strlst_t **listp, char *str)
1069de566360SJordan K. Hubbard {
1070de566360SJordan K. Hubbard 	strlst_t *p1, *p2;
1071de566360SJordan K. Hubbard 
1072de566360SJordan K. Hubbard 	/* add to end, but be smart about dups */
1073de566360SJordan K. Hubbard 
1074de566360SJordan K. Hubbard 	for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
107587eb4a42SJosef Karthauser 		if (!strcmp(p2->str, str))
107687eb4a42SJosef Karthauser 			return;
1077de566360SJordan K. Hubbard 
1078de566360SJordan K. Hubbard 	p2 = malloc(sizeof(strlst_t));
1079eb148815SJoerg Wunsch 	if (p2) {
1080019d04d1SLuigi Rizzo 		p2->next = NULL;
1081eb148815SJoerg Wunsch 		p2->str = strdup(str);
1082eb148815SJoerg Wunsch     	}
1083de566360SJordan K. Hubbard 	if (!p2 || !p2->str)
1084de566360SJordan K. Hubbard 		out_of_memory();
1085de566360SJordan K. Hubbard 
108687eb4a42SJosef Karthauser 	if (p1 == NULL)
108787eb4a42SJosef Karthauser 		*listp = p2;
108887eb4a42SJosef Karthauser 	else
108987eb4a42SJosef Karthauser 		p1->next = p2;
1090de566360SJordan K. Hubbard }
1091de566360SJordan K. Hubbard 
1092de566360SJordan K. Hubbard 
1093de566360SJordan K. Hubbard int is_dir(char *pathname)
1094de566360SJordan K. Hubbard {
1095de566360SJordan K. Hubbard 	struct stat buf;
1096de566360SJordan K. Hubbard 
1097de566360SJordan K. Hubbard 	if (stat(pathname, &buf) == -1)
1098de566360SJordan K. Hubbard 		return 0;
109987eb4a42SJosef Karthauser 
1100de566360SJordan K. Hubbard 	return S_ISDIR(buf.st_mode);
1101de566360SJordan K. Hubbard }
1102de566360SJordan K. Hubbard 
1103de566360SJordan K. Hubbard int is_nonempty_file(char *pathname)
1104de566360SJordan K. Hubbard {
1105de566360SJordan K. Hubbard 	struct stat buf;
1106de566360SJordan K. Hubbard 
1107de566360SJordan K. Hubbard 	if (stat(pathname, &buf) == -1)
1108de566360SJordan K. Hubbard 		return 0;
1109de566360SJordan K. Hubbard 
1110de566360SJordan K. Hubbard 	return S_ISREG(buf.st_mode) && buf.st_size > 0;
1111de566360SJordan K. Hubbard }
1112