11722Sjkh/*
21722Sjkh * Copyright (c) 1994 University of Maryland
31722Sjkh * All Rights Reserved.
41722Sjkh *
51722Sjkh * Permission to use, copy, modify, distribute, and sell this software and its
61722Sjkh * documentation for any purpose is hereby granted without fee, provided that
71722Sjkh * the above copyright notice appear in all copies and that both that
81722Sjkh * copyright notice and this permission notice appear in supporting
91722Sjkh * documentation, and that the name of U.M. not be used in advertising or
101722Sjkh * publicity pertaining to distribution of the software without specific,
111722Sjkh * written prior permission.  U.M. makes no representations about the
121722Sjkh * suitability of this software for any purpose.  It is provided "as is"
131722Sjkh * without express or implied warranty.
141722Sjkh *
151722Sjkh * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
161722Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
171722Sjkh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
181722Sjkh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
191722Sjkh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
201722Sjkh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
211722Sjkh *
221722Sjkh * Author: James da Silva, Systems Design and Analysis Group
231722Sjkh *			   Computer Science Department
241722Sjkh *			   University of Maryland at College Park
251722Sjkh */
261722Sjkh/*
271722Sjkh * ========================================================================
281722Sjkh * crunchgen.c
291722Sjkh *
301722Sjkh * Generates a Makefile and main C file for a crunched executable,
318857Srgrimes * from specs given in a .conf file.
321722Sjkh */
33237625Sobrien
34237625Sobrien#include <sys/cdefs.h>
35237625Sobrien__FBSDID("$FreeBSD: releng/10.3/usr.sbin/crunch/crunchgen/crunchgen.c 246346 2013-02-05 02:57:59Z pfg $");
36237625Sobrien
37237625Sobrien#include <sys/param.h>
3870884Sjoe#include <sys/stat.h>
3970884Sjoe
4029453Scharnier#include <ctype.h>
4129453Scharnier#include <err.h>
4270124Sjoe#include <paths.h>
4329453Scharnier#include <stdio.h>
441722Sjkh#include <stdlib.h>
4529453Scharnier#include <string.h>
461722Sjkh#include <unistd.h>
471722Sjkh
481722Sjkh#define CRUNCH_VERSION	"0.2"
491722Sjkh
501722Sjkh#define MAXLINELEN	16384
511722Sjkh#define MAXFIELDS 	 2048
521722Sjkh
531722Sjkh
541722Sjkh/* internal representation of conf file: */
551722Sjkh
561722Sjkh/* simple lists of strings suffice for most parms */
571722Sjkh
581722Sjkhtypedef struct strlst {
5970884Sjoe	struct strlst *next;
6070884Sjoe	char *str;
611722Sjkh} strlst_t;
621722Sjkh
631722Sjkh/* progs have structure, each field can be set with "special" or calculated */
641722Sjkh
651722Sjkhtypedef struct prog {
6670884Sjoe	struct prog *next;	/* link field */
6770884Sjoe	char *name;		/* program name */
6870884Sjoe	char *ident;		/* C identifier for the program name */
6970884Sjoe	char *srcdir;
7070884Sjoe	char *realsrcdir;
7170884Sjoe	char *objdir;
7270884Sjoe	char *objvar;		/* Makefile variable to replace OBJS */
7370884Sjoe	strlst_t *objs, *objpaths;
7470884Sjoe	strlst_t *buildopts;
7570884Sjoe	strlst_t *keeplist;
7670884Sjoe	strlst_t *links;
7793435Sluigi	strlst_t *libs;
78153687Sceri	strlst_t *libs_so;
7970884Sjoe	int goterror;
801722Sjkh} prog_t;
811722Sjkh
821722Sjkh
831722Sjkh/* global state */
841722Sjkh
8568750Sjoestrlst_t *buildopts = NULL;
8670884Sjoestrlst_t *srcdirs   = NULL;
8770884Sjoestrlst_t *libs      = NULL;
88153687Sceristrlst_t *libs_so   = NULL;
8970884Sjoeprog_t   *progs     = NULL;
901722Sjkh
911722Sjkhchar confname[MAXPATHLEN], infilename[MAXPATHLEN];
921722Sjkhchar outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN];
931722Sjkhchar tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
9470884Sjoechar outhdrname[MAXPATHLEN] ;	/* user-supplied header for *.mk */
9570884Sjoechar *objprefix;		/* where are the objects ? */
96237574Sobrienchar *path_make;
971722Sjkhint linenum = -1;
981722Sjkhint goterror = 0;
991722Sjkh
10070884Sjoeint verbose, readcache;		/* options */
1011722Sjkhint reading_cache;
10270884Sjoeint makeobj = 0;		/* add 'make obj' rules to the makefile */
1031722Sjkh
1046696Sphkint list_mode;
1056696Sphk
1061722Sjkh/* general library routines */
1071722Sjkh
108246256Spfgvoid status(const char *str);
1091722Sjkhvoid out_of_memory(void);
1101722Sjkhvoid add_string(strlst_t **listp, char *str);
111246256Spfgint is_dir(const char *pathname);
112246256Spfgint is_nonempty_file(const char *pathname);
113153687Sceriint subtract_strlst(strlst_t **lista, strlst_t **listb);
114153687Sceriint in_list(strlst_t **listp, char *str);
1151722Sjkh
116246261Spfg/* helper routines for main() */
1171722Sjkh
1188857Srgrimesvoid usage(void);
1191722Sjkhvoid parse_conf_file(void);
1201722Sjkhvoid gen_outputs(void);
1211722Sjkh
122246261Spfgextern char *crunched_skel[];
1231722Sjkh
124246261Spfg
125237625Sobrienint
126237625Sobrienmain(int argc, char **argv)
1271722Sjkh{
12870884Sjoe	char *p;
12970884Sjoe	int optc;
1301722Sjkh
13170884Sjoe	verbose = 1;
13270884Sjoe	readcache = 1;
13370884Sjoe	*outmkname = *outcfname = *execfname = '\0';
1348857Srgrimes
135237574Sobrien	path_make = getenv("MAKE");
136237574Sobrien	if (path_make == NULL || *path_make == '\0')
137237574Sobrien		path_make = "make";
138237574Sobrien
13970884Sjoe	p = getenv("MAKEOBJDIRPREFIX");
14070884Sjoe	if (p == NULL || *p == '\0')
14170884Sjoe		objprefix = "/usr/obj"; /* default */
14270884Sjoe	else
14370884Sjoe		if ((objprefix = strdup(p)) == NULL)
14470884Sjoe			out_of_memory();
14569413Sluigi
14670884Sjoe	while((optc = getopt(argc, argv, "lh:m:c:e:p:foq")) != -1) {
14770884Sjoe		switch(optc) {
14870884Sjoe		case 'f':
14970884Sjoe			readcache = 0;
15070884Sjoe			break;
15170884Sjoe		case 'o':
15270884Sjoe			makeobj = 1;
15370884Sjoe			break;
15470884Sjoe		case 'q':
15570884Sjoe			verbose = 0;
15670884Sjoe			break;
1571722Sjkh
15870884Sjoe		case 'm':
15970884Sjoe			strlcpy(outmkname, optarg, sizeof(outmkname));
16070884Sjoe			break;
16170884Sjoe		case 'p':
16270884Sjoe			if ((objprefix = strdup(optarg)) == NULL)
16370113Sjoe				out_of_memory();
16470113Sjoe			break;
1651722Sjkh
16670884Sjoe		case 'h':
16770884Sjoe			strlcpy(outhdrname, optarg, sizeof(outhdrname));
16870884Sjoe			break;
16970884Sjoe		case 'c':
17070884Sjoe			strlcpy(outcfname, optarg, sizeof(outcfname));
17170884Sjoe			break;
17270884Sjoe		case 'e':
17370884Sjoe			strlcpy(execfname, optarg, sizeof(execfname));
17470884Sjoe			break;
17570884Sjoe
17670884Sjoe		case 'l':
17770884Sjoe			list_mode++;
17870884Sjoe			verbose = 0;
17970884Sjoe			break;
18070884Sjoe
18170884Sjoe		case '?':
18270884Sjoe		default:
18370884Sjoe			usage();
18470884Sjoe		}
1851722Sjkh	}
1861722Sjkh
18770884Sjoe	argc -= optind;
18870884Sjoe	argv += optind;
1891722Sjkh
19070884Sjoe	if (argc != 1)
19170884Sjoe		usage();
1921722Sjkh
19370884Sjoe	/*
19470884Sjoe	 * generate filenames
19570884Sjoe	 */
1961722Sjkh
19770884Sjoe	strlcpy(infilename, argv[0], sizeof(infilename));
1981722Sjkh
19970884Sjoe	/* confname = `basename infilename .conf` */
2001722Sjkh
20170884Sjoe	if ((p=strrchr(infilename, '/')) != NULL)
20270884Sjoe		strlcpy(confname, p + 1, sizeof(confname));
20370884Sjoe	else
20470884Sjoe		strlcpy(confname, infilename, sizeof(confname));
2051722Sjkh
20670884Sjoe	if ((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
20770884Sjoe		*p = '\0';
2081722Sjkh
20970884Sjoe	if (!*outmkname)
21070884Sjoe		snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
21170884Sjoe	if (!*outcfname)
21270884Sjoe		snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
21370884Sjoe	if (!*execfname)
21470884Sjoe		snprintf(execfname, sizeof(execfname), "%s", confname);
21570884Sjoe
21670884Sjoe	snprintf(cachename, sizeof(cachename), "%s.cache", confname);
21770884Sjoe	snprintf(tempfname, sizeof(tempfname), "%s/crunchgen_%sXXXXXX",
21870124Sjoe	getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, confname);
2191722Sjkh
22070884Sjoe	parse_conf_file();
22170884Sjoe	if (list_mode)
22270884Sjoe		exit(goterror);
2236696Sphk
22470884Sjoe	gen_outputs();
2251722Sjkh
22670884Sjoe	exit(goterror);
2271722Sjkh}
2281722Sjkh
2291722Sjkh
230237625Sobrienvoid
231237625Sobrienusage(void)
2321722Sjkh{
23370884Sjoe	fprintf(stderr, "%s%s\n\t%s%s\n", "usage: crunchgen [-foq] ",
23470884Sjoe	    "[-h <makefile-header-name>] [-m <makefile>]",
23570884Sjoe	    "[-p <obj-prefix>] [-c <c-file-name>] [-e <exec-file>] ",
23670884Sjoe	    "<conffile>");
23770884Sjoe	exit(1);
2381722Sjkh}
2391722Sjkh
2401722Sjkh
2411722Sjkh/*
2421722Sjkh * ========================================================================
2431722Sjkh * parse_conf_file subsystem
2441722Sjkh *
2451722Sjkh */
2461722Sjkh
2471722Sjkh/* helper routines for parse_conf_file */
2481722Sjkh
2491722Sjkhvoid parse_one_file(char *filename);
250246256Spfgvoid parse_line(char *pline, int *fc, char **fv, int nf);
2511722Sjkhvoid add_srcdirs(int argc, char **argv);
2521722Sjkhvoid add_progs(int argc, char **argv);
2531722Sjkhvoid add_link(int argc, char **argv);
2541722Sjkhvoid add_libs(int argc, char **argv);
255153687Scerivoid add_libs_so(int argc, char **argv);
25668750Sjoevoid add_buildopts(int argc, char **argv);
2571722Sjkhvoid add_special(int argc, char **argv);
2581722Sjkh
2591722Sjkhprog_t *find_prog(char *str);
2601722Sjkhvoid add_prog(char *progname);
2611722Sjkh
2621722Sjkh
263237625Sobrienvoid
264237625Sobrienparse_conf_file(void)
2651722Sjkh{
26670884Sjoe	if (!is_nonempty_file(infilename))
26729453Scharnier		errx(1, "fatal: input file \"%s\" not found", infilename);
26870884Sjoe
26970884Sjoe	parse_one_file(infilename);
27070884Sjoe	if (readcache && is_nonempty_file(cachename)) {
27170884Sjoe		reading_cache = 1;
27270884Sjoe		parse_one_file(cachename);
27370884Sjoe	}
2741722Sjkh}
2751722Sjkh
2761722Sjkh
277237625Sobrienvoid
278237625Sobrienparse_one_file(char *filename)
2791722Sjkh{
28070884Sjoe	char *fieldv[MAXFIELDS];
28170884Sjoe	int fieldc;
28270884Sjoe	void (*f)(int c, char **v);
28370884Sjoe	FILE *cf;
28470884Sjoe	char line[MAXLINELEN];
2851722Sjkh
28670884Sjoe	snprintf(line, sizeof(line), "reading %s", filename);
28770884Sjoe	status(line);
28870884Sjoe	strlcpy(curfilename, filename, sizeof(curfilename));
2891722Sjkh
29070884Sjoe	if ((cf = fopen(curfilename, "r")) == NULL) {
29170884Sjoe		warn("%s", curfilename);
29270884Sjoe		goterror = 1;
29370884Sjoe		return;
29470884Sjoe	}
2951722Sjkh
29670884Sjoe	linenum = 0;
29770884Sjoe	while (fgets(line, MAXLINELEN, cf) != NULL) {
29870884Sjoe		linenum++;
29970884Sjoe		parse_line(line, &fieldc, fieldv, MAXFIELDS);
30070884Sjoe
30170884Sjoe		if (fieldc < 1)
30270884Sjoe			continue;
30370884Sjoe
30470884Sjoe		if (!strcmp(fieldv[0], "srcdirs"))
30570884Sjoe			f = add_srcdirs;
30670884Sjoe		else if(!strcmp(fieldv[0], "progs"))
30770884Sjoe			f = add_progs;
30870884Sjoe		else if(!strcmp(fieldv[0], "ln"))
30970884Sjoe			f = add_link;
31070884Sjoe		else if(!strcmp(fieldv[0], "libs"))
31170884Sjoe			f = add_libs;
312153687Sceri		else if(!strcmp(fieldv[0], "libs_so"))
313153687Sceri			f = add_libs_so;
31470884Sjoe		else if(!strcmp(fieldv[0], "buildopts"))
31570884Sjoe			f = add_buildopts;
31670884Sjoe		else if(!strcmp(fieldv[0], "special"))
31770884Sjoe			f = add_special;
31870884Sjoe		else {
31970884Sjoe			warnx("%s:%d: skipping unknown command `%s'",
32070884Sjoe			    curfilename, linenum, fieldv[0]);
32170884Sjoe			goterror = 1;
32270884Sjoe			continue;
32370884Sjoe		}
32470884Sjoe
32570884Sjoe		if (fieldc < 2) {
32670884Sjoe			warnx("%s:%d: %s %s",
32770884Sjoe			    curfilename, linenum, fieldv[0],
32870884Sjoe			    "command needs at least 1 argument, skipping");
32970884Sjoe			goterror = 1;
33070884Sjoe			continue;
33170884Sjoe		}
33270884Sjoe
33370884Sjoe		f(fieldc, fieldv);
3341722Sjkh	}
33570884Sjoe
33670884Sjoe	if (ferror(cf)) {
33770884Sjoe		warn("%s", curfilename);
33870884Sjoe		goterror = 1;
3391722Sjkh	}
34070884Sjoe	fclose(cf);
3411722Sjkh}
3421722Sjkh
3431722Sjkh
344237625Sobrienvoid
345246256Spfgparse_line(char *pline, int *fc, char **fv, int nf)
3461722Sjkh{
34770884Sjoe	char *p;
3481722Sjkh
349246256Spfg	p = pline;
35070884Sjoe	*fc = 0;
3511722Sjkh
35270884Sjoe	while (1) {
353246256Spfg		while (isspace((unsigned char)*p))
35470884Sjoe			p++;
35570884Sjoe
35670884Sjoe		if (*p == '\0' || *p == '#')
35770884Sjoe			break;
35870884Sjoe
35970884Sjoe		if (*fc < nf)
36070884Sjoe			fv[(*fc)++] = p;
36170884Sjoe
362246256Spfg		while (*p && !isspace((unsigned char)*p) && *p != '#')
36370884Sjoe			p++;
36470884Sjoe
36570884Sjoe		if (*p == '\0' || *p == '#')
36670884Sjoe			break;
36770884Sjoe
36870884Sjoe		*p++ = '\0';
36970884Sjoe	}
37070884Sjoe
37170884Sjoe	if (*p)
37270884Sjoe		*p = '\0';		/* needed for '#' case */
3731722Sjkh}
3741722Sjkh
3751722Sjkh
376237625Sobrienvoid
377237625Sobrienadd_srcdirs(int argc, char **argv)
3781722Sjkh{
37970884Sjoe	int i;
3801722Sjkh
38170884Sjoe	for (i = 1; i < argc; i++) {
38270884Sjoe		if (is_dir(argv[i]))
38370884Sjoe			add_string(&srcdirs, argv[i]);
38470884Sjoe		else {
38570884Sjoe			warnx("%s:%d: `%s' is not a directory, skipping it",
38670884Sjoe			    curfilename, linenum, argv[i]);
38770884Sjoe			goterror = 1;
38870884Sjoe		}
3891722Sjkh	}
3901722Sjkh}
3911722Sjkh
3921722Sjkh
393237625Sobrienvoid
394237625Sobrienadd_progs(int argc, char **argv)
3951722Sjkh{
39670884Sjoe	int i;
3971722Sjkh
39870884Sjoe	for (i = 1; i < argc; i++)
39970884Sjoe		add_prog(argv[i]);
4001722Sjkh}
4011722Sjkh
4021722Sjkh
403237625Sobrienvoid
404237625Sobrienadd_prog(char *progname)
4051722Sjkh{
40670884Sjoe	prog_t *p1, *p2;
4071722Sjkh
40870884Sjoe	/* add to end, but be smart about dups */
4091722Sjkh
41070884Sjoe	for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
41170884Sjoe		if (!strcmp(p2->name, progname))
41270884Sjoe			return;
4131722Sjkh
41470884Sjoe	p2 = malloc(sizeof(prog_t));
41570884Sjoe	if(p2) {
41670884Sjoe		memset(p2, 0, sizeof(prog_t));
41770884Sjoe		p2->name = strdup(progname);
41870884Sjoe	}
41970884Sjoe	if (!p2 || !p2->name)
42070884Sjoe		out_of_memory();
4211722Sjkh
42270884Sjoe	p2->next = NULL;
42370884Sjoe	if (p1 == NULL)
42470884Sjoe		progs = p2;
42570884Sjoe	else
42670884Sjoe		p1->next = p2;
4271722Sjkh
42870884Sjoe	p2->ident = NULL;
42970884Sjoe	p2->srcdir = NULL;
43070884Sjoe	p2->realsrcdir = NULL;
43170884Sjoe	p2->objdir = NULL;
43270884Sjoe	p2->links = NULL;
43393435Sluigi	p2->libs = NULL;
434153687Sceri	p2->libs_so = NULL;
43570884Sjoe	p2->objs = NULL;
43670884Sjoe	p2->keeplist = NULL;
43770884Sjoe	p2->buildopts = NULL;
43870884Sjoe	p2->goterror = 0;
43970884Sjoe
44070884Sjoe	if (list_mode)
44170884Sjoe		printf("%s\n",progname);
4421722Sjkh}
4431722Sjkh
4441722Sjkh
445237625Sobrienvoid
446237625Sobrienadd_link(int argc, char **argv)
4471722Sjkh{
44870884Sjoe	int i;
44970884Sjoe	prog_t *p = find_prog(argv[1]);
4501722Sjkh
45170884Sjoe	if (p == NULL) {
45270884Sjoe		warnx("%s:%d: no prog %s previously declared, skipping link",
45370884Sjoe		    curfilename, linenum, argv[1]);
45470884Sjoe		goterror = 1;
45570884Sjoe		return;
45670884Sjoe	}
45770884Sjoe
45870884Sjoe	for (i = 2; i < argc; i++) {
45970884Sjoe		if (list_mode)
46070884Sjoe			printf("%s\n",argv[i]);
46170884Sjoe
46270884Sjoe		add_string(&p->links, argv[i]);
46370884Sjoe	}
4641722Sjkh}
4651722Sjkh
4661722Sjkh
467237625Sobrienvoid
468237625Sobrienadd_libs(int argc, char **argv)
4691722Sjkh{
47070884Sjoe	int i;
4711722Sjkh
472153687Sceri	for(i = 1; i < argc; i++) {
47370884Sjoe		add_string(&libs, argv[i]);
474153687Sceri		if ( in_list(&libs_so, argv[i]) )
475153687Sceri			warnx("%s:%d: "
476153687Sceri				"library `%s' specified as dynamic earlier",
477153687Sceri				curfilename, linenum, argv[i]);
478153687Sceri	}
4791722Sjkh}
4801722Sjkh
4811722Sjkh
482237625Sobrienvoid
483237625Sobrienadd_libs_so(int argc, char **argv)
484153687Sceri{
485153687Sceri	int i;
486153687Sceri
487153687Sceri	for(i = 1; i < argc; i++) {
488153687Sceri		add_string(&libs_so, argv[i]);
489153687Sceri		if ( in_list(&libs, argv[i]) )
490153687Sceri			warnx("%s:%d: "
491153687Sceri				"library `%s' specified as static earlier",
492153687Sceri				curfilename, linenum, argv[i]);
493153687Sceri	}
494153687Sceri}
495153687Sceri
496153687Sceri
497237625Sobrienvoid
498237625Sobrienadd_buildopts(int argc, char **argv)
49968750Sjoe{
50070884Sjoe	int i;
50168750Sjoe
50270884Sjoe	for (i = 1; i < argc; i++)
50370884Sjoe		add_string(&buildopts, argv[i]);
50468750Sjoe}
50568750Sjoe
50668750Sjoe
507237625Sobrienvoid
508237625Sobrienadd_special(int argc, char **argv)
5091722Sjkh{
51070884Sjoe	int i;
51170884Sjoe	prog_t *p = find_prog(argv[1]);
5121722Sjkh
51370884Sjoe	if (p == NULL) {
51470884Sjoe		if (reading_cache)
51570884Sjoe			return;
5161722Sjkh
51770884Sjoe		warnx("%s:%d: no prog %s previously declared, skipping special",
51870884Sjoe		    curfilename, linenum, argv[1]);
51970884Sjoe		goterror = 1;
52070884Sjoe		return;
52170884Sjoe	}
5221722Sjkh
52370884Sjoe	if (!strcmp(argv[2], "ident")) {
52470884Sjoe		if (argc != 4)
52570884Sjoe			goto argcount;
52670884Sjoe		if ((p->ident = strdup(argv[3])) == NULL)
52770884Sjoe			out_of_memory();
52870884Sjoe	} else if (!strcmp(argv[2], "srcdir")) {
52970884Sjoe		if (argc != 4)
53070884Sjoe			goto argcount;
53170884Sjoe		if ((p->srcdir = strdup(argv[3])) == NULL)
53270884Sjoe			out_of_memory();
53370884Sjoe	} else if (!strcmp(argv[2], "objdir")) {
53470884Sjoe		if(argc != 4)
53570884Sjoe			goto argcount;
53670884Sjoe		if((p->objdir = strdup(argv[3])) == NULL)
53770884Sjoe			out_of_memory();
53870884Sjoe	} else if (!strcmp(argv[2], "objs")) {
53970884Sjoe		p->objs = NULL;
54070884Sjoe		for (i = 3; i < argc; i++)
54170884Sjoe			add_string(&p->objs, argv[i]);
54270884Sjoe	} else if (!strcmp(argv[2], "objpaths")) {
54370884Sjoe		p->objpaths = NULL;
54470884Sjoe		for (i = 3; i < argc; i++)
54570884Sjoe			add_string(&p->objpaths, argv[i]);
54670884Sjoe	} else if (!strcmp(argv[2], "keep")) {
54770884Sjoe		p->keeplist = NULL;
54870884Sjoe		for(i = 3; i < argc; i++)
54970884Sjoe			add_string(&p->keeplist, argv[i]);
55070884Sjoe	} else if (!strcmp(argv[2], "objvar")) {
55170884Sjoe		if(argc != 4)
55270884Sjoe			goto argcount;
55370884Sjoe		if ((p->objvar = strdup(argv[3])) == NULL)
55470884Sjoe			out_of_memory();
55570884Sjoe	} else if (!strcmp(argv[2], "buildopts")) {
55670884Sjoe		p->buildopts = NULL;
55770884Sjoe		for (i = 3; i < argc; i++)
55870884Sjoe			add_string(&p->buildopts, argv[i]);
55993435Sluigi	} else if (!strcmp(argv[2], "lib")) {
56093435Sluigi		for (i = 3; i < argc; i++)
56193435Sluigi			add_string(&p->libs, argv[i]);
56270884Sjoe	} else {
56370884Sjoe		warnx("%s:%d: bad parameter name `%s', skipping line",
56470884Sjoe		    curfilename, linenum, argv[2]);
56570884Sjoe		goterror = 1;
56670884Sjoe	}
56770884Sjoe	return;
5681722Sjkh
5691722Sjkh argcount:
57070884Sjoe	warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"",
5711722Sjkh	    curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]);
57270884Sjoe	goterror = 1;
5731722Sjkh}
5741722Sjkh
5751722Sjkh
5761722Sjkhprog_t *find_prog(char *str)
5771722Sjkh{
57870884Sjoe	prog_t *p;
5791722Sjkh
58070884Sjoe	for (p = progs; p != NULL; p = p->next)
58170884Sjoe		if (!strcmp(p->name, str))
58270884Sjoe			return p;
5831722Sjkh
58470884Sjoe	return NULL;
5851722Sjkh}
5861722Sjkh
5871722Sjkh
5881722Sjkh/*
5891722Sjkh * ========================================================================
5901722Sjkh * gen_outputs subsystem
5911722Sjkh *
5921722Sjkh */
5931722Sjkh
5941722Sjkh/* helper subroutines */
5951722Sjkh
5961722Sjkhvoid remove_error_progs(void);
5971722Sjkhvoid fillin_program(prog_t *p);
5981722Sjkhvoid gen_specials_cache(void);
5991722Sjkhvoid gen_output_makefile(void);
6001722Sjkhvoid gen_output_cfile(void);
6011722Sjkh
6021722Sjkhvoid fillin_program_objs(prog_t *p, char *path);
6031722Sjkhvoid top_makefile_rules(FILE *outmk);
6041722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p);
6051722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst);
6061722Sjkhchar *genident(char *str);
6071722Sjkhchar *dir_search(char *progname);
6081722Sjkh
6091722Sjkh
610237625Sobrienvoid
611237625Sobriengen_outputs(void)
6121722Sjkh{
61370884Sjoe	prog_t *p;
6141722Sjkh
61570884Sjoe	for (p = progs; p != NULL; p = p->next)
61670884Sjoe		fillin_program(p);
6171722Sjkh
61870884Sjoe	remove_error_progs();
61970884Sjoe	gen_specials_cache();
62070884Sjoe	gen_output_cfile();
62170884Sjoe	gen_output_makefile();
62270884Sjoe	status("");
62370884Sjoe	fprintf(stderr,
624237574Sobrien	    "Run \"%s -f %s\" to build crunched binary.\n",
625237574Sobrien	    path_make, outmkname);
6261722Sjkh}
6271722Sjkh
62856995Sluigi/*
62956995Sluigi * run the makefile for the program to find which objects are necessary
63056995Sluigi */
631237625Sobrienvoid
632237625Sobrienfillin_program(prog_t *p)
6331722Sjkh{
63470884Sjoe	char path[MAXPATHLEN];
63570884Sjoe	char line[MAXLINELEN];
63670884Sjoe	FILE *f;
6371722Sjkh
63870884Sjoe	snprintf(line, MAXLINELEN, "filling in parms for %s", p->name);
63970884Sjoe	status(line);
6401722Sjkh
64170884Sjoe	if (!p->ident)
64270884Sjoe		p->ident = genident(p->name);
64370331Sjoe
64470884Sjoe	/* look for the source directory if one wasn't specified by a special */
64570884Sjoe	if (!p->srcdir) {
64670884Sjoe		p->srcdir = dir_search(p->name);
64770884Sjoe	}
64870112Sjoe
64970884Sjoe	/* Determine the actual srcdir (maybe symlinked). */
65070884Sjoe	if (p->srcdir) {
65170884Sjoe		snprintf(line, MAXLINELEN, "cd %s && echo -n `/bin/pwd`",
65270884Sjoe		    p->srcdir);
65370884Sjoe		f = popen(line,"r");
65470884Sjoe		if (!f)
65570884Sjoe			errx(1, "Can't execute: %s\n", line);
65670331Sjoe
65770884Sjoe		path[0] = '\0';
65870884Sjoe		fgets(path, sizeof path, f);
65970884Sjoe		if (pclose(f))
66070884Sjoe			errx(1, "Can't execute: %s\n", line);
66170331Sjoe
66270884Sjoe		if (!*path)
66370884Sjoe			errx(1, "Can't perform pwd on: %s\n", p->srcdir);
66470331Sjoe
66570884Sjoe		p->realsrcdir = strdup(path);
66670884Sjoe	}
66770112Sjoe
66870884Sjoe	/* Unless the option to make object files was specified the
66970884Sjoe	* the objects will be built in the source directory unless
67070884Sjoe	* an object directory already exists.
67170884Sjoe	*/
67270884Sjoe	if (!makeobj && !p->objdir && p->srcdir) {
67370884Sjoe		snprintf(line, sizeof line, "%s/%s", objprefix, p->realsrcdir);
67470884Sjoe		if (is_dir(line)) {
67570884Sjoe			if ((p->objdir = strdup(line)) == NULL)
67670884Sjoe			out_of_memory();
67770884Sjoe		} else
67870884Sjoe			p->objdir = p->realsrcdir;
67970884Sjoe	}
68070884Sjoe
68170884Sjoe	/*
68270884Sjoe	* XXX look for a Makefile.{name} in local directory first.
68370884Sjoe	* This lets us override the original Makefile.
68470884Sjoe	*/
68570884Sjoe	snprintf(path, sizeof(path), "Makefile.%s", p->name);
68670884Sjoe	if (is_nonempty_file(path)) {
68770884Sjoe		snprintf(line, MAXLINELEN, "Using %s for %s", path, p->name);
68870884Sjoe		status(line);
68970114Sjoe	} else
69070884Sjoe		if (p->srcdir)
69170884Sjoe			snprintf(path, sizeof(path), "%s/Makefile", p->srcdir);
69270884Sjoe	if (!p->objs && p->srcdir && is_nonempty_file(path))
69370884Sjoe		fillin_program_objs(p, path);
6941722Sjkh
69581700Sjoe	if (!p->srcdir && !p->objdir && verbose)
69670884Sjoe		warnx("%s: %s: %s",
69770884Sjoe		    "warning: could not find source directory",
69870884Sjoe		    infilename, p->name);
69970884Sjoe	if (!p->objs && verbose)
70070884Sjoe		warnx("%s: %s: warning: could not find any .o files",
70170884Sjoe		    infilename, p->name);
70270880Sjoe
70381823Sjoe	if ((!p->srcdir || !p->objdir) && !p->objs)
70470884Sjoe		p->goterror = 1;
7051722Sjkh}
7061722Sjkh
707237625Sobrienvoid
708237625Sobrienfillin_program_objs(prog_t *p, char *path)
7091722Sjkh{
71070884Sjoe	char *obj, *cp;
71170884Sjoe	int fd, rc;
71270884Sjoe	FILE *f;
71370884Sjoe	char *objvar="OBJS";
71470884Sjoe	strlst_t *s;
71570884Sjoe	char line[MAXLINELEN];
7161722Sjkh
71770884Sjoe	/* discover the objs from the srcdir Makefile */
7181722Sjkh
71970884Sjoe	if ((fd = mkstemp(tempfname)) == -1) {
72070884Sjoe		perror(tempfname);
72170884Sjoe		exit(1);
72270884Sjoe	}
72370884Sjoe	if ((f = fdopen(fd, "w")) == NULL) {
72470884Sjoe		warn("%s", tempfname);
72570884Sjoe		goterror = 1;
72670884Sjoe		return;
72770884Sjoe	}
72870884Sjoe	if (p->objvar)
72970884Sjoe		objvar = p->objvar;
7308857Srgrimes
73170884Sjoe	/*
73270884Sjoe	* XXX include outhdrname (e.g. to contain Make variables)
73370884Sjoe	*/
73470884Sjoe	if (outhdrname[0] != '\0')
73570884Sjoe		fprintf(f, ".include \"%s\"\n", outhdrname);
73670884Sjoe	fprintf(f, ".include \"%s\"\n", path);
737187943Sobrien	fprintf(f, ".POSIX:\n");
73870884Sjoe	if (buildopts) {
73970884Sjoe		fprintf(f, "BUILDOPTS+=");
74070884Sjoe		output_strlst(f, buildopts);
74170884Sjoe	}
742187131Sobrien	fprintf(f, ".if defined(PROG)\n");
743187131Sobrien	fprintf(f, "%s?=${PROG}.o\n", objvar);
74470884Sjoe	fprintf(f, ".endif\n");
74570884Sjoe	fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar);
74668569Sjoe
747113886Sru	fprintf(f, "crunchgen_objs:\n"
748237574Sobrien	    "\t@cd %s && %s -f %s $(BUILDOPTS) $(%s_OPTS)",
749237574Sobrien	    p->srcdir, path_make, tempfname, p->ident);
75070884Sjoe	for (s = p->buildopts; s != NULL; s = s->next)
75170884Sjoe		fprintf(f, " %s", s->str);
75270884Sjoe	fprintf(f, " loop\n");
75368569Sjoe
75470884Sjoe	fclose(f);
7551722Sjkh
756237574Sobrien	snprintf(line, MAXLINELEN, "cd %s && %s -f %s -B crunchgen_objs",
757237574Sobrien	     p->srcdir, path_make, tempfname);
75870884Sjoe	if ((f = popen(line, "r")) == NULL) {
75970884Sjoe		warn("submake pipe");
76070884Sjoe		goterror = 1;
76170884Sjoe		return;
76270884Sjoe	}
7631722Sjkh
76470884Sjoe	while(fgets(line, MAXLINELEN, f)) {
76570884Sjoe		if (strncmp(line, "OBJS= ", 6)) {
76670884Sjoe			warnx("make error: %s", line);
76770884Sjoe			goterror = 1;
76870884Sjoe			continue;
76970884Sjoe		}
77070884Sjoe
77170884Sjoe		cp = line + 6;
772246256Spfg		while (isspace((unsigned char)*cp))
77370884Sjoe			cp++;
77470884Sjoe
77570884Sjoe		while(*cp) {
77670884Sjoe			obj = cp;
777246256Spfg			while (*cp && !isspace((unsigned char)*cp))
77870884Sjoe				cp++;
77970884Sjoe			if (*cp)
78070884Sjoe				*cp++ = '\0';
78170884Sjoe			add_string(&p->objs, obj);
782246256Spfg			while (isspace((unsigned char)*cp))
78370884Sjoe				cp++;
78470884Sjoe		}
7851722Sjkh	}
78670884Sjoe
78770884Sjoe	if ((rc=pclose(f)) != 0) {
78870884Sjoe		warnx("make error: make returned %d", rc);
78970884Sjoe		goterror = 1;
7901722Sjkh	}
79170884Sjoe
79270884Sjoe	unlink(tempfname);
7931722Sjkh}
7941722Sjkh
795237625Sobrienvoid
796237625Sobrienremove_error_progs(void)
7971722Sjkh{
79870884Sjoe	prog_t *p1, *p2;
7991722Sjkh
80070884Sjoe	p1 = NULL; p2 = progs;
80170884Sjoe	while (p2 != NULL) {
80270884Sjoe		if (!p2->goterror)
80370884Sjoe			p1 = p2, p2 = p2->next;
80470884Sjoe		else {
80570884Sjoe			/* delete it from linked list */
80670884Sjoe			warnx("%s: %s: ignoring program because of errors",
80770884Sjoe			    infilename, p2->name);
80870884Sjoe			if (p1)
80970884Sjoe				p1->next = p2->next;
81070884Sjoe			else
81170884Sjoe				progs = p2->next;
81270884Sjoe			p2 = p2->next;
81370884Sjoe		}
8141722Sjkh	}
8151722Sjkh}
8161722Sjkh
817237625Sobrienvoid
818237625Sobriengen_specials_cache(void)
8191722Sjkh{
82070884Sjoe	FILE *cachef;
82170884Sjoe	prog_t *p;
82270884Sjoe	char line[MAXLINELEN];
8231722Sjkh
82470884Sjoe	snprintf(line, MAXLINELEN, "generating %s", cachename);
82570884Sjoe	status(line);
8261722Sjkh
82770884Sjoe	if ((cachef = fopen(cachename, "w")) == NULL) {
82870884Sjoe		warn("%s", cachename);
82970884Sjoe		goterror = 1;
83070884Sjoe		return;
83170884Sjoe	}
8321722Sjkh
83370884Sjoe	fprintf(cachef, "# %s - parm cache generated from %s by crunchgen "
83470884Sjoe	    " %s\n\n",
8351722Sjkh	    cachename, infilename, CRUNCH_VERSION);
8361722Sjkh
83770884Sjoe	for (p = progs; p != NULL; p = p->next) {
83870884Sjoe		fprintf(cachef, "\n");
83970884Sjoe		if (p->srcdir)
84070884Sjoe			fprintf(cachef, "special %s srcdir %s\n",
84170884Sjoe			    p->name, p->srcdir);
84270884Sjoe		if (p->objdir)
84370884Sjoe			fprintf(cachef, "special %s objdir %s\n",
84470884Sjoe			    p->name, p->objdir);
84570884Sjoe		if (p->objs) {
84670884Sjoe			fprintf(cachef, "special %s objs", p->name);
84770884Sjoe			output_strlst(cachef, p->objs);
84870884Sjoe		}
84970884Sjoe		if (p->objpaths) {
85070884Sjoe			fprintf(cachef, "special %s objpaths", p->name);
85170884Sjoe			output_strlst(cachef, p->objpaths);
85270884Sjoe		}
8531722Sjkh	}
85470884Sjoe	fclose(cachef);
8551722Sjkh}
8561722Sjkh
8571722Sjkh
858237625Sobrienvoid
859237625Sobriengen_output_makefile(void)
8601722Sjkh{
86170884Sjoe	prog_t *p;
86270884Sjoe	FILE *outmk;
86370884Sjoe	char line[MAXLINELEN];
8641722Sjkh
86570884Sjoe	snprintf(line, MAXLINELEN, "generating %s", outmkname);
86670884Sjoe	status(line);
8671722Sjkh
86870884Sjoe	if ((outmk = fopen(outmkname, "w")) == NULL) {
86970884Sjoe		warn("%s", outmkname);
87070884Sjoe		goterror = 1;
87170884Sjoe		return;
87270884Sjoe	}
8731722Sjkh
87470884Sjoe	fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
8751722Sjkh	    outmkname, infilename, CRUNCH_VERSION);
8761722Sjkh
87770884Sjoe	if (outhdrname[0] != '\0')
87870884Sjoe		fprintf(outmk, ".include \"%s\"\n", outhdrname);
8791722Sjkh
88070884Sjoe	top_makefile_rules(outmk);
88170884Sjoe	for (p = progs; p != NULL; p = p->next)
88270884Sjoe		prog_makefile_rules(outmk, p);
88370884Sjoe
88470884Sjoe	fprintf(outmk, "\n# ========\n");
88570884Sjoe	fclose(outmk);
8861722Sjkh}
8871722Sjkh
8881722Sjkh
889237625Sobrienvoid
890237625Sobriengen_output_cfile(void)
8911722Sjkh{
89270884Sjoe	char **cp;
89370884Sjoe	FILE *outcf;
89470884Sjoe	prog_t *p;
89570884Sjoe	strlst_t *s;
89670884Sjoe	char line[MAXLINELEN];
8971722Sjkh
89870884Sjoe	snprintf(line, MAXLINELEN, "generating %s", outcfname);
89970884Sjoe	status(line);
9001722Sjkh
90170884Sjoe	if((outcf = fopen(outcfname, "w")) == NULL) {
90270884Sjoe		warn("%s", outcfname);
90370884Sjoe		goterror = 1;
90470884Sjoe		return;
90570884Sjoe	}
9061722Sjkh
90770884Sjoe	fprintf(outcf,
90870884Sjoe	    "/* %s - generated from %s by crunchgen %s */\n",
9091722Sjkh	    outcfname, infilename, CRUNCH_VERSION);
9101722Sjkh
91170884Sjoe	fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
91270884Sjoe	for (cp = crunched_skel; *cp != NULL; cp++)
91370884Sjoe		fprintf(outcf, "%s\n", *cp);
9141722Sjkh
91570884Sjoe	for (p = progs; p != NULL; p = p->next)
91670884Sjoe		fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
9171722Sjkh
91870884Sjoe	fprintf(outcf, "\nstruct stub entry_points[] = {\n");
91970884Sjoe	for (p = progs; p != NULL; p = p->next) {
92070884Sjoe		fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
92170884Sjoe		    p->name, p->ident);
92270884Sjoe		for (s = p->links; s != NULL; s = s->next)
92370884Sjoe			fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
92470884Sjoe			    s->str, p->ident);
92570884Sjoe	}
9268857Srgrimes
92770884Sjoe	fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
92870884Sjoe	fprintf(outcf, "\t{ NULL, NULL }\n};\n");
92970884Sjoe	fclose(outcf);
9301722Sjkh}
9311722Sjkh
9321722Sjkh
9331722Sjkhchar *genident(char *str)
9341722Sjkh{
93570884Sjoe	char *n, *s, *d;
9361722Sjkh
93770884Sjoe	/*
93870884Sjoe	 * generates a Makefile/C identifier from a program name,
93970884Sjoe	 * mapping '-' to '_' and ignoring all other non-identifier
94070884Sjoe	 * characters.  This leads to programs named "foo.bar" and
94170884Sjoe	 * "foobar" to map to the same identifier.
94270884Sjoe	 */
9431722Sjkh
94470884Sjoe	if ((n = strdup(str)) == NULL)
94570884Sjoe		return NULL;
94670884Sjoe	for (d = s = n; *s != '\0'; s++) {
94770884Sjoe		if (*s == '-')
94870884Sjoe			*d++ = '_';
949246256Spfg		else if (*s == '_' || isalnum((unsigned char)*s))
95070884Sjoe			*d++ = *s;
95170884Sjoe	}
95270884Sjoe	*d = '\0';
95370884Sjoe	return n;
9541722Sjkh}
9551722Sjkh
9561722Sjkh
9571722Sjkhchar *dir_search(char *progname)
9581722Sjkh{
95970884Sjoe	char path[MAXPATHLEN];
96070884Sjoe	strlst_t *dir;
96170884Sjoe	char *srcdir;
9621722Sjkh
96370884Sjoe	for (dir = srcdirs; dir != NULL; dir = dir->next) {
96470884Sjoe		snprintf(path, MAXPATHLEN, "%s/%s", dir->str, progname);
96570884Sjoe		if (!is_dir(path))
96670884Sjoe			continue;
96770884Sjoe
96870884Sjoe		if ((srcdir = strdup(path)) == NULL)
96970884Sjoe			out_of_memory();
97070884Sjoe
97170884Sjoe		return srcdir;
97270331Sjoe	}
97370884Sjoe	return NULL;
9741722Sjkh}
9751722Sjkh
9761722Sjkh
977237625Sobrienvoid
978237625Sobrientop_makefile_rules(FILE *outmk)
9791722Sjkh{
98070884Sjoe	prog_t *p;
9811722Sjkh
982246346Spfg	fprintf(outmk, "LD?= ld\n");
983153687Sceri	if ( subtract_strlst(&libs, &libs_so) )
984153687Sceri		fprintf(outmk, "# NOTE: Some LIBS declarations below overridden by LIBS_SO\n");
985153687Sceri
98678520Sjoe	fprintf(outmk, "LIBS+=");
98770884Sjoe	output_strlst(outmk, libs);
9881722Sjkh
989153687Sceri	fprintf(outmk, "LIBS_SO+=");
990153687Sceri	output_strlst(outmk, libs_so);
991153687Sceri
99270884Sjoe	if (makeobj) {
99370884Sjoe		fprintf(outmk, "MAKEOBJDIRPREFIX?=%s\n", objprefix);
994133399Sharti		fprintf(outmk, "MAKEENV=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX)\n");
995133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKEENV) $(MAKE)\n");
99670884Sjoe	} else {
997133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKE)\n");
99870884Sjoe	}
99970112Sjoe
100070884Sjoe	if (buildopts) {
100170884Sjoe		fprintf(outmk, "BUILDOPTS+=");
100270884Sjoe		output_strlst(outmk, buildopts);
100370884Sjoe	}
100468750Sjoe
100570884Sjoe	fprintf(outmk, "CRUNCHED_OBJS=");
100670884Sjoe	for (p = progs; p != NULL; p = p->next)
100770884Sjoe		fprintf(outmk, " %s.lo", p->name);
100870884Sjoe	fprintf(outmk, "\n");
10091722Sjkh
101070884Sjoe	fprintf(outmk, "SUBMAKE_TARGETS=");
101170884Sjoe	for (p = progs; p != NULL; p = p->next)
101270884Sjoe		fprintf(outmk, " %s_make", p->ident);
101370884Sjoe	fprintf(outmk, "\nSUBCLEAN_TARGETS=");
101470884Sjoe	for (p = progs; p != NULL; p = p->next)
101570884Sjoe		fprintf(outmk, " %s_clean", p->ident);
101670884Sjoe	fprintf(outmk, "\n\n");
10171722Sjkh
101870884Sjoe	fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
101970884Sjoe	fprintf(outmk, "exe: %s\n", execfname);
1020164504Sjb	fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS) $(SUBMAKE_TARGETS)\n", execfname, execfname);
1021153687Sceri	fprintf(outmk, ".if defined(LIBS_SO) && !empty(LIBS_SO)\n");
1022153687Sceri	fprintf(outmk, "\t$(CC) -o %s %s.o $(CRUNCHED_OBJS) \\\n",
1023153687Sceri	    execfname, execfname);
1024153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bstatic $(LIBS) \\\n");
1025153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bdynamic $(LIBS_SO)\n");
1026153687Sceri	fprintf(outmk, ".else\n");
102770884Sjoe	fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
10281722Sjkh	    execfname, execfname);
1029153687Sceri	fprintf(outmk, ".endif\n");
103070884Sjoe	fprintf(outmk, "\tstrip %s\n", execfname);
103170884Sjoe	fprintf(outmk, "realclean: clean subclean\n");
103270884Sjoe	fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", execfname);
103370884Sjoe	fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n");
10341722Sjkh}
10351722Sjkh
10361722Sjkh
1037237625Sobrienvoid
1038237625Sobrienprog_makefile_rules(FILE *outmk, prog_t *p)
10391722Sjkh{
104070884Sjoe	strlst_t *lst;
104130120Sjoerg
104270884Sjoe	fprintf(outmk, "\n# -------- %s\n\n", p->name);
10431722Sjkh
104481700Sjoe	fprintf(outmk, "%s_OBJDIR=", p->ident);
104581700Sjoe	if (p->objdir)
104681700Sjoe		fprintf(outmk, "%s", p->objdir);
104781700Sjoe	else
104881700Sjoe		fprintf(outmk, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n",
104981700Sjoe		    p->ident);
105081700Sjoe	fprintf(outmk, "\n");
105181700Sjoe
1052164571Sjb	fprintf(outmk, "%s_OBJPATHS=", p->ident);
1053164571Sjb	if (p->objpaths)
1054164571Sjb		output_strlst(outmk, p->objpaths);
1055164571Sjb	else {
1056164571Sjb		for (lst = p->objs; lst != NULL; lst = lst->next) {
1057164571Sjb			fprintf(outmk, " $(%s_OBJDIR)/%s", p->ident, lst->str);
1058164571Sjb		}
1059164571Sjb		fprintf(outmk, "\n");
1060164571Sjb	}
1061164571Sjb
106270884Sjoe	if (p->srcdir && p->objs) {
106370884Sjoe		fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
106470884Sjoe		fprintf(outmk, "%s_REALSRCDIR=%s\n", p->ident, p->realsrcdir);
106570112Sjoe
106670884Sjoe		fprintf(outmk, "%s_OBJS=", p->ident);
106770884Sjoe		output_strlst(outmk, p->objs);
106870884Sjoe		if (p->buildopts != NULL) {
106970884Sjoe			fprintf(outmk, "%s_OPTS+=", p->ident);
107070884Sjoe			output_strlst(outmk, p->buildopts);
107170884Sjoe		}
1072164654Sjb#if 0
1073164571Sjb		fprintf(outmk, "$(%s_OBJPATHS): %s_make\n\n", p->ident, p->ident);
1074164654Sjb#endif
107570884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
107670884Sjoe		fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident);
107770884Sjoe		if (makeobj)
1078133399Sharti			fprintf(outmk, "$(CRUNCHMAKE) obj && ");
107970884Sjoe		fprintf(outmk, "\\\n");
1080133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) depend &&",
108170112Sjoe		    p->ident);
108270884Sjoe		fprintf(outmk, "\\\n");
1083133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) "
108470884Sjoe		    "$(%s_OBJS))",
108570884Sjoe		    p->ident, p->ident);
108670884Sjoe		fprintf(outmk, "\n");
108770884Sjoe		fprintf(outmk, "%s_clean:\n", p->ident);
1088133399Sharti		fprintf(outmk, "\t(cd $(%s_SRCDIR) && $(CRUNCHMAKE) $(BUILDOPTS) clean cleandepend)\n\n",
108970884Sjoe		    p->ident);
109070884Sjoe	} else {
109170884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
109270884Sjoe		fprintf(outmk, "\t@echo \"** cannot make objs for %s\"\n\n",
109375152Sru		    p->name);
109468569Sjoe	}
10951722Sjkh
109693435Sluigi	if (p->libs) {
109793435Sluigi		fprintf(outmk, "%s_LIBS=", p->ident);
109893435Sluigi		output_strlst(outmk, p->libs);
109993435Sluigi	}
11001722Sjkh
110170884Sjoe	fprintf(outmk, "%s_stub.c:\n", p->name);
110270884Sjoe	fprintf(outmk, "\techo \""
110370884Sjoe	    "int _crunched_%s_stub(int argc, char **argv, char **envp)"
110470884Sjoe	    "{return main(argc,argv,envp);}\" >%s_stub.c\n",
11051722Sjkh	    p->ident, p->name);
110693435Sluigi	fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)",
11071722Sjkh	    p->name, p->name, p->ident);
110893435Sluigi	if (p->libs)
110993435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
1110153687Sceri
111193435Sluigi	fprintf(outmk, "\n");
1112246346Spfg	fprintf(outmk, "\t$(LD) -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)",
11131722Sjkh	    p->name, p->name, p->ident);
111493435Sluigi	if (p->libs)
111593435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
111693435Sluigi	fprintf(outmk, "\n");
111770884Sjoe	fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident);
111870884Sjoe	for (lst = p->keeplist; lst != NULL; lst = lst->next)
111970884Sjoe		fprintf(outmk, "-k _%s ", lst->str);
112070884Sjoe	fprintf(outmk, "%s.lo\n", p->name);
11211722Sjkh}
11221722Sjkh
1123237625Sobrienvoid
1124237625Sobrienoutput_strlst(FILE *outf, strlst_t *lst)
11251722Sjkh{
112670884Sjoe	for (; lst != NULL; lst = lst->next)
1127153687Sceri		if ( strlen(lst->str) )
1128153687Sceri			fprintf(outf, " %s", lst->str);
112970884Sjoe	fprintf(outf, "\n");
11301722Sjkh}
11311722Sjkh
11321722Sjkh
11331722Sjkh/*
11341722Sjkh * ========================================================================
11351722Sjkh * general library routines
11361722Sjkh *
11371722Sjkh */
11381722Sjkh
1139237625Sobrienvoid
1140246256Spfgstatus(const char *str)
11411722Sjkh{
114270884Sjoe	static int lastlen = 0;
114370884Sjoe	int len, spaces;
11441722Sjkh
114570884Sjoe	if (!verbose)
114670884Sjoe		return;
11471722Sjkh
114870884Sjoe	len = strlen(str);
114970884Sjoe	spaces = lastlen - len;
115070884Sjoe	if (spaces < 1)
115170884Sjoe		spaces = 1;
11521722Sjkh
115370884Sjoe	fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
115470884Sjoe	fflush(stderr);
115570884Sjoe	lastlen = len;
11561722Sjkh}
11571722Sjkh
11581722Sjkh
1159237625Sobrienvoid
1160237625Sobrienout_of_memory(void)
11611722Sjkh{
116270884Sjoe	err(1, "%s: %d: out of memory, stopping", infilename, linenum);
11631722Sjkh}
11641722Sjkh
11651722Sjkh
1166237625Sobrienvoid
1167237625Sobrienadd_string(strlst_t **listp, char *str)
11681722Sjkh{
116970884Sjoe	strlst_t *p1, *p2;
11701722Sjkh
117170884Sjoe	/* add to end, but be smart about dups */
11721722Sjkh
117370884Sjoe	for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
117470884Sjoe		if (!strcmp(p2->str, str))
117570884Sjoe			return;
11761722Sjkh
117770884Sjoe	p2 = malloc(sizeof(strlst_t));
117870884Sjoe	if (p2) {
117970884Sjoe		p2->next = NULL;
118070884Sjoe		p2->str = strdup(str);
118170884Sjoe    	}
118270884Sjoe	if (!p2 || !p2->str)
118370884Sjoe		out_of_memory();
11841722Sjkh
118570884Sjoe	if (p1 == NULL)
118670884Sjoe		*listp = p2;
118770884Sjoe	else
118870884Sjoe		p1->next = p2;
11891722Sjkh}
11901722Sjkh
1191237625Sobrienint
1192237625Sobriensubtract_strlst(strlst_t **lista, strlst_t **listb)
1193153687Sceri{
1194153687Sceri	int subtract_count = 0;
1195153687Sceri	strlst_t *p1;
1196153687Sceri	for (p1 = *listb; p1 != NULL; p1 = p1->next)
1197153687Sceri		if ( in_list(lista, p1->str) ) {
1198153687Sceri			warnx("Will compile library `%s' dynamically", p1->str);
1199153687Sceri			strcat(p1->str, "");
1200153687Sceri			subtract_count++;
1201153687Sceri		}
1202153687Sceri	return subtract_count;
1203153687Sceri}
12041722Sjkh
1205237625Sobrienint
1206237625Sobrienin_list(strlst_t **listp, char *str)
1207153687Sceri{
1208153687Sceri	strlst_t *p1;
1209153687Sceri	for (p1 = *listp; p1 != NULL; p1 = p1->next)
1210153687Sceri		if (!strcmp(p1->str, str))
1211153687Sceri			return 1;
1212153687Sceri	return 0;
1213153687Sceri}
1214153687Sceri
1215237625Sobrienint
1216246256Spfgis_dir(const char *pathname)
12171722Sjkh{
121870884Sjoe	struct stat buf;
12191722Sjkh
122070884Sjoe	if (stat(pathname, &buf) == -1)
122170884Sjoe		return 0;
122270884Sjoe
122370884Sjoe	return S_ISDIR(buf.st_mode);
12241722Sjkh}
12251722Sjkh
1226237625Sobrienint
1227246256Spfgis_nonempty_file(const char *pathname)
12281722Sjkh{
122970884Sjoe	struct stat buf;
12301722Sjkh
123170884Sjoe	if (stat(pathname, &buf) == -1)
123270884Sjoe		return 0;
12331722Sjkh
123470884Sjoe	return S_ISREG(buf.st_mode) && buf.st_size > 0;
12351722Sjkh}
1236