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: stable/11/usr.sbin/crunch/crunchgen/crunchgen.c 311185 2017-01-03 22:55:10Z bdrewery $");
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) {
673300806Sbdrewery		char *auto_obj;
674300806Sbdrewery
675300806Sbdrewery		auto_obj = NULL;
67670884Sjoe		snprintf(line, sizeof line, "%s/%s", objprefix, p->realsrcdir);
677300806Sbdrewery		if (is_dir(line) ||
678300806Sbdrewery		    ((auto_obj = getenv("MK_AUTO_OBJ")) != NULL &&
679300806Sbdrewery		    strcmp(auto_obj, "yes") == 0)) {
68070884Sjoe			if ((p->objdir = strdup(line)) == NULL)
68170884Sjoe			out_of_memory();
68270884Sjoe		} else
68370884Sjoe			p->objdir = p->realsrcdir;
68470884Sjoe	}
68570884Sjoe
68670884Sjoe	/*
68770884Sjoe	* XXX look for a Makefile.{name} in local directory first.
68870884Sjoe	* This lets us override the original Makefile.
68970884Sjoe	*/
69070884Sjoe	snprintf(path, sizeof(path), "Makefile.%s", p->name);
69170884Sjoe	if (is_nonempty_file(path)) {
69270884Sjoe		snprintf(line, MAXLINELEN, "Using %s for %s", path, p->name);
69370884Sjoe		status(line);
69470114Sjoe	} else
69570884Sjoe		if (p->srcdir)
69670884Sjoe			snprintf(path, sizeof(path), "%s/Makefile", p->srcdir);
69770884Sjoe	if (!p->objs && p->srcdir && is_nonempty_file(path))
69870884Sjoe		fillin_program_objs(p, path);
6991722Sjkh
70081700Sjoe	if (!p->srcdir && !p->objdir && verbose)
70170884Sjoe		warnx("%s: %s: %s",
70270884Sjoe		    "warning: could not find source directory",
70370884Sjoe		    infilename, p->name);
70470884Sjoe	if (!p->objs && verbose)
70570884Sjoe		warnx("%s: %s: warning: could not find any .o files",
70670884Sjoe		    infilename, p->name);
70770880Sjoe
70881823Sjoe	if ((!p->srcdir || !p->objdir) && !p->objs)
70970884Sjoe		p->goterror = 1;
7101722Sjkh}
7111722Sjkh
712237625Sobrienvoid
713237625Sobrienfillin_program_objs(prog_t *p, char *path)
7141722Sjkh{
71570884Sjoe	char *obj, *cp;
71670884Sjoe	int fd, rc;
71770884Sjoe	FILE *f;
71870884Sjoe	char *objvar="OBJS";
71970884Sjoe	strlst_t *s;
72070884Sjoe	char line[MAXLINELEN];
7211722Sjkh
72270884Sjoe	/* discover the objs from the srcdir Makefile */
7231722Sjkh
72470884Sjoe	if ((fd = mkstemp(tempfname)) == -1) {
72570884Sjoe		perror(tempfname);
72670884Sjoe		exit(1);
72770884Sjoe	}
72870884Sjoe	if ((f = fdopen(fd, "w")) == NULL) {
72970884Sjoe		warn("%s", tempfname);
73070884Sjoe		goterror = 1;
73170884Sjoe		return;
73270884Sjoe	}
73370884Sjoe	if (p->objvar)
73470884Sjoe		objvar = p->objvar;
7358857Srgrimes
73670884Sjoe	/*
73770884Sjoe	* XXX include outhdrname (e.g. to contain Make variables)
73870884Sjoe	*/
73970884Sjoe	if (outhdrname[0] != '\0')
74070884Sjoe		fprintf(f, ".include \"%s\"\n", outhdrname);
74170884Sjoe	fprintf(f, ".include \"%s\"\n", path);
742187943Sobrien	fprintf(f, ".POSIX:\n");
74370884Sjoe	if (buildopts) {
74470884Sjoe		fprintf(f, "BUILDOPTS+=");
74570884Sjoe		output_strlst(f, buildopts);
74670884Sjoe	}
747187131Sobrien	fprintf(f, ".if defined(PROG)\n");
748187131Sobrien	fprintf(f, "%s?=${PROG}.o\n", objvar);
74970884Sjoe	fprintf(f, ".endif\n");
75070884Sjoe	fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar);
75168569Sjoe
752113886Sru	fprintf(f, "crunchgen_objs:\n"
753237574Sobrien	    "\t@cd %s && %s -f %s $(BUILDOPTS) $(%s_OPTS)",
754237574Sobrien	    p->srcdir, path_make, tempfname, p->ident);
75570884Sjoe	for (s = p->buildopts; s != NULL; s = s->next)
75670884Sjoe		fprintf(f, " %s", s->str);
75770884Sjoe	fprintf(f, " loop\n");
75868569Sjoe
75970884Sjoe	fclose(f);
7601722Sjkh
761237574Sobrien	snprintf(line, MAXLINELEN, "cd %s && %s -f %s -B crunchgen_objs",
762237574Sobrien	     p->srcdir, path_make, tempfname);
76370884Sjoe	if ((f = popen(line, "r")) == NULL) {
76470884Sjoe		warn("submake pipe");
76570884Sjoe		goterror = 1;
76670884Sjoe		return;
76770884Sjoe	}
7681722Sjkh
76970884Sjoe	while(fgets(line, MAXLINELEN, f)) {
77070884Sjoe		if (strncmp(line, "OBJS= ", 6)) {
77170884Sjoe			warnx("make error: %s", line);
77270884Sjoe			goterror = 1;
77370884Sjoe			continue;
77470884Sjoe		}
77570884Sjoe
77670884Sjoe		cp = line + 6;
777246256Spfg		while (isspace((unsigned char)*cp))
77870884Sjoe			cp++;
77970884Sjoe
78070884Sjoe		while(*cp) {
78170884Sjoe			obj = cp;
782246256Spfg			while (*cp && !isspace((unsigned char)*cp))
78370884Sjoe				cp++;
78470884Sjoe			if (*cp)
78570884Sjoe				*cp++ = '\0';
78670884Sjoe			add_string(&p->objs, obj);
787246256Spfg			while (isspace((unsigned char)*cp))
78870884Sjoe				cp++;
78970884Sjoe		}
7901722Sjkh	}
79170884Sjoe
79270884Sjoe	if ((rc=pclose(f)) != 0) {
79370884Sjoe		warnx("make error: make returned %d", rc);
79470884Sjoe		goterror = 1;
7951722Sjkh	}
79670884Sjoe
79770884Sjoe	unlink(tempfname);
7981722Sjkh}
7991722Sjkh
800237625Sobrienvoid
801237625Sobrienremove_error_progs(void)
8021722Sjkh{
80370884Sjoe	prog_t *p1, *p2;
8041722Sjkh
80570884Sjoe	p1 = NULL; p2 = progs;
80670884Sjoe	while (p2 != NULL) {
80770884Sjoe		if (!p2->goterror)
80870884Sjoe			p1 = p2, p2 = p2->next;
80970884Sjoe		else {
81070884Sjoe			/* delete it from linked list */
81170884Sjoe			warnx("%s: %s: ignoring program because of errors",
81270884Sjoe			    infilename, p2->name);
81370884Sjoe			if (p1)
81470884Sjoe				p1->next = p2->next;
81570884Sjoe			else
81670884Sjoe				progs = p2->next;
81770884Sjoe			p2 = p2->next;
81870884Sjoe		}
8191722Sjkh	}
8201722Sjkh}
8211722Sjkh
822237625Sobrienvoid
823237625Sobriengen_specials_cache(void)
8241722Sjkh{
82570884Sjoe	FILE *cachef;
82670884Sjoe	prog_t *p;
82770884Sjoe	char line[MAXLINELEN];
8281722Sjkh
82970884Sjoe	snprintf(line, MAXLINELEN, "generating %s", cachename);
83070884Sjoe	status(line);
8311722Sjkh
83270884Sjoe	if ((cachef = fopen(cachename, "w")) == NULL) {
83370884Sjoe		warn("%s", cachename);
83470884Sjoe		goterror = 1;
83570884Sjoe		return;
83670884Sjoe	}
8371722Sjkh
83870884Sjoe	fprintf(cachef, "# %s - parm cache generated from %s by crunchgen "
83970884Sjoe	    " %s\n\n",
8401722Sjkh	    cachename, infilename, CRUNCH_VERSION);
8411722Sjkh
84270884Sjoe	for (p = progs; p != NULL; p = p->next) {
84370884Sjoe		fprintf(cachef, "\n");
84470884Sjoe		if (p->srcdir)
84570884Sjoe			fprintf(cachef, "special %s srcdir %s\n",
84670884Sjoe			    p->name, p->srcdir);
84770884Sjoe		if (p->objdir)
84870884Sjoe			fprintf(cachef, "special %s objdir %s\n",
84970884Sjoe			    p->name, p->objdir);
85070884Sjoe		if (p->objs) {
85170884Sjoe			fprintf(cachef, "special %s objs", p->name);
85270884Sjoe			output_strlst(cachef, p->objs);
85370884Sjoe		}
85470884Sjoe		if (p->objpaths) {
85570884Sjoe			fprintf(cachef, "special %s objpaths", p->name);
85670884Sjoe			output_strlst(cachef, p->objpaths);
85770884Sjoe		}
8581722Sjkh	}
85970884Sjoe	fclose(cachef);
8601722Sjkh}
8611722Sjkh
8621722Sjkh
863237625Sobrienvoid
864237625Sobriengen_output_makefile(void)
8651722Sjkh{
86670884Sjoe	prog_t *p;
86770884Sjoe	FILE *outmk;
86870884Sjoe	char line[MAXLINELEN];
8691722Sjkh
87070884Sjoe	snprintf(line, MAXLINELEN, "generating %s", outmkname);
87170884Sjoe	status(line);
8721722Sjkh
87370884Sjoe	if ((outmk = fopen(outmkname, "w")) == NULL) {
87470884Sjoe		warn("%s", outmkname);
87570884Sjoe		goterror = 1;
87670884Sjoe		return;
87770884Sjoe	}
8781722Sjkh
87970884Sjoe	fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
8801722Sjkh	    outmkname, infilename, CRUNCH_VERSION);
8811722Sjkh
88270884Sjoe	if (outhdrname[0] != '\0')
88370884Sjoe		fprintf(outmk, ".include \"%s\"\n", outhdrname);
8841722Sjkh
88570884Sjoe	top_makefile_rules(outmk);
88670884Sjoe	for (p = progs; p != NULL; p = p->next)
88770884Sjoe		prog_makefile_rules(outmk, p);
88870884Sjoe
88970884Sjoe	fprintf(outmk, "\n# ========\n");
89070884Sjoe	fclose(outmk);
8911722Sjkh}
8921722Sjkh
8931722Sjkh
894237625Sobrienvoid
895237625Sobriengen_output_cfile(void)
8961722Sjkh{
89770884Sjoe	char **cp;
89870884Sjoe	FILE *outcf;
89970884Sjoe	prog_t *p;
90070884Sjoe	strlst_t *s;
90170884Sjoe	char line[MAXLINELEN];
9021722Sjkh
90370884Sjoe	snprintf(line, MAXLINELEN, "generating %s", outcfname);
90470884Sjoe	status(line);
9051722Sjkh
90670884Sjoe	if((outcf = fopen(outcfname, "w")) == NULL) {
90770884Sjoe		warn("%s", outcfname);
90870884Sjoe		goterror = 1;
90970884Sjoe		return;
91070884Sjoe	}
9111722Sjkh
91270884Sjoe	fprintf(outcf,
91370884Sjoe	    "/* %s - generated from %s by crunchgen %s */\n",
9141722Sjkh	    outcfname, infilename, CRUNCH_VERSION);
9151722Sjkh
91670884Sjoe	fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
91770884Sjoe	for (cp = crunched_skel; *cp != NULL; cp++)
91870884Sjoe		fprintf(outcf, "%s\n", *cp);
9191722Sjkh
92070884Sjoe	for (p = progs; p != NULL; p = p->next)
92170884Sjoe		fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
9221722Sjkh
92370884Sjoe	fprintf(outcf, "\nstruct stub entry_points[] = {\n");
92470884Sjoe	for (p = progs; p != NULL; p = p->next) {
92570884Sjoe		fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
92670884Sjoe		    p->name, p->ident);
92770884Sjoe		for (s = p->links; s != NULL; s = s->next)
92870884Sjoe			fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
92970884Sjoe			    s->str, p->ident);
93070884Sjoe	}
9318857Srgrimes
93270884Sjoe	fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
93370884Sjoe	fprintf(outcf, "\t{ NULL, NULL }\n};\n");
93470884Sjoe	fclose(outcf);
9351722Sjkh}
9361722Sjkh
9371722Sjkh
9381722Sjkhchar *genident(char *str)
9391722Sjkh{
94070884Sjoe	char *n, *s, *d;
9411722Sjkh
94270884Sjoe	/*
94370884Sjoe	 * generates a Makefile/C identifier from a program name,
94470884Sjoe	 * mapping '-' to '_' and ignoring all other non-identifier
94570884Sjoe	 * characters.  This leads to programs named "foo.bar" and
94670884Sjoe	 * "foobar" to map to the same identifier.
94770884Sjoe	 */
9481722Sjkh
94970884Sjoe	if ((n = strdup(str)) == NULL)
95070884Sjoe		return NULL;
95170884Sjoe	for (d = s = n; *s != '\0'; s++) {
95270884Sjoe		if (*s == '-')
95370884Sjoe			*d++ = '_';
954246256Spfg		else if (*s == '_' || isalnum((unsigned char)*s))
95570884Sjoe			*d++ = *s;
95670884Sjoe	}
95770884Sjoe	*d = '\0';
95870884Sjoe	return n;
9591722Sjkh}
9601722Sjkh
9611722Sjkh
9621722Sjkhchar *dir_search(char *progname)
9631722Sjkh{
96470884Sjoe	char path[MAXPATHLEN];
96570884Sjoe	strlst_t *dir;
96670884Sjoe	char *srcdir;
9671722Sjkh
96870884Sjoe	for (dir = srcdirs; dir != NULL; dir = dir->next) {
96970884Sjoe		snprintf(path, MAXPATHLEN, "%s/%s", dir->str, progname);
97070884Sjoe		if (!is_dir(path))
97170884Sjoe			continue;
97270884Sjoe
97370884Sjoe		if ((srcdir = strdup(path)) == NULL)
97470884Sjoe			out_of_memory();
97570884Sjoe
97670884Sjoe		return srcdir;
97770331Sjoe	}
97870884Sjoe	return NULL;
9791722Sjkh}
9801722Sjkh
9811722Sjkh
982237625Sobrienvoid
983237625Sobrientop_makefile_rules(FILE *outmk)
9841722Sjkh{
98570884Sjoe	prog_t *p;
9861722Sjkh
987246346Spfg	fprintf(outmk, "LD?= ld\n");
988285986Sbdrewery	fprintf(outmk, "STRIPBIN?= strip\n");
989153687Sceri	if ( subtract_strlst(&libs, &libs_so) )
990153687Sceri		fprintf(outmk, "# NOTE: Some LIBS declarations below overridden by LIBS_SO\n");
991153687Sceri
99278520Sjoe	fprintf(outmk, "LIBS+=");
99370884Sjoe	output_strlst(outmk, libs);
9941722Sjkh
995153687Sceri	fprintf(outmk, "LIBS_SO+=");
996153687Sceri	output_strlst(outmk, libs_so);
997153687Sceri
99870884Sjoe	if (makeobj) {
99970884Sjoe		fprintf(outmk, "MAKEOBJDIRPREFIX?=%s\n", objprefix);
1000133399Sharti		fprintf(outmk, "MAKEENV=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX)\n");
1001133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKEENV) $(MAKE)\n");
100270884Sjoe	} else {
1003133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKE)\n");
100470884Sjoe	}
100570112Sjoe
100670884Sjoe	if (buildopts) {
100770884Sjoe		fprintf(outmk, "BUILDOPTS+=");
100870884Sjoe		output_strlst(outmk, buildopts);
100970884Sjoe	}
101068750Sjoe
101170884Sjoe	fprintf(outmk, "CRUNCHED_OBJS=");
101270884Sjoe	for (p = progs; p != NULL; p = p->next)
101370884Sjoe		fprintf(outmk, " %s.lo", p->name);
101470884Sjoe	fprintf(outmk, "\n");
10151722Sjkh
101670884Sjoe	fprintf(outmk, "SUBMAKE_TARGETS=");
101770884Sjoe	for (p = progs; p != NULL; p = p->next)
101870884Sjoe		fprintf(outmk, " %s_make", p->ident);
101970884Sjoe	fprintf(outmk, "\nSUBCLEAN_TARGETS=");
102070884Sjoe	for (p = progs; p != NULL; p = p->next)
102170884Sjoe		fprintf(outmk, " %s_clean", p->ident);
102270884Sjoe	fprintf(outmk, "\n\n");
10231722Sjkh
102470884Sjoe	fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
102570884Sjoe	fprintf(outmk, "exe: %s\n", execfname);
1026164504Sjb	fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS) $(SUBMAKE_TARGETS)\n", execfname, execfname);
1027153687Sceri	fprintf(outmk, ".if defined(LIBS_SO) && !empty(LIBS_SO)\n");
1028153687Sceri	fprintf(outmk, "\t$(CC) -o %s %s.o $(CRUNCHED_OBJS) \\\n",
1029153687Sceri	    execfname, execfname);
1030153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bstatic $(LIBS) \\\n");
1031153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bdynamic $(LIBS_SO)\n");
1032153687Sceri	fprintf(outmk, ".else\n");
103370884Sjoe	fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
10341722Sjkh	    execfname, execfname);
1035153687Sceri	fprintf(outmk, ".endif\n");
1036285986Sbdrewery	fprintf(outmk, "\t$(STRIPBIN) %s\n", execfname);
103770884Sjoe	fprintf(outmk, "realclean: clean subclean\n");
103870884Sjoe	fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", execfname);
103970884Sjoe	fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n");
10401722Sjkh}
10411722Sjkh
10421722Sjkh
1043237625Sobrienvoid
1044237625Sobrienprog_makefile_rules(FILE *outmk, prog_t *p)
10451722Sjkh{
104670884Sjoe	strlst_t *lst;
104730120Sjoerg
104870884Sjoe	fprintf(outmk, "\n# -------- %s\n\n", p->name);
10491722Sjkh
105081700Sjoe	fprintf(outmk, "%s_OBJDIR=", p->ident);
105181700Sjoe	if (p->objdir)
105281700Sjoe		fprintf(outmk, "%s", p->objdir);
105381700Sjoe	else
105481700Sjoe		fprintf(outmk, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n",
105581700Sjoe		    p->ident);
105681700Sjoe	fprintf(outmk, "\n");
105781700Sjoe
1058164571Sjb	fprintf(outmk, "%s_OBJPATHS=", p->ident);
1059164571Sjb	if (p->objpaths)
1060164571Sjb		output_strlst(outmk, p->objpaths);
1061164571Sjb	else {
1062164571Sjb		for (lst = p->objs; lst != NULL; lst = lst->next) {
1063164571Sjb			fprintf(outmk, " $(%s_OBJDIR)/%s", p->ident, lst->str);
1064164571Sjb		}
1065164571Sjb		fprintf(outmk, "\n");
1066164571Sjb	}
1067311185Sbdrewery	fprintf(outmk, "$(%s_OBJPATHS): .NOMETA\n", p->ident);
1068164571Sjb
106970884Sjoe	if (p->srcdir && p->objs) {
107070884Sjoe		fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
107170884Sjoe		fprintf(outmk, "%s_REALSRCDIR=%s\n", p->ident, p->realsrcdir);
107270112Sjoe
107370884Sjoe		fprintf(outmk, "%s_OBJS=", p->ident);
107470884Sjoe		output_strlst(outmk, p->objs);
107570884Sjoe		if (p->buildopts != NULL) {
107670884Sjoe			fprintf(outmk, "%s_OPTS+=", p->ident);
107770884Sjoe			output_strlst(outmk, p->buildopts);
107870884Sjoe		}
1079164654Sjb#if 0
1080164571Sjb		fprintf(outmk, "$(%s_OBJPATHS): %s_make\n\n", p->ident, p->ident);
1081164654Sjb#endif
108270884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
108370884Sjoe		fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident);
108470884Sjoe		if (makeobj)
1085133399Sharti			fprintf(outmk, "$(CRUNCHMAKE) obj && ");
108670884Sjoe		fprintf(outmk, "\\\n");
1087133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) depend &&",
108870112Sjoe		    p->ident);
108970884Sjoe		fprintf(outmk, "\\\n");
1090133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) "
109170884Sjoe		    "$(%s_OBJS))",
109270884Sjoe		    p->ident, p->ident);
109370884Sjoe		fprintf(outmk, "\n");
109470884Sjoe		fprintf(outmk, "%s_clean:\n", p->ident);
1095133399Sharti		fprintf(outmk, "\t(cd $(%s_SRCDIR) && $(CRUNCHMAKE) $(BUILDOPTS) clean cleandepend)\n\n",
109670884Sjoe		    p->ident);
109770884Sjoe	} else {
109870884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
109970884Sjoe		fprintf(outmk, "\t@echo \"** cannot make objs for %s\"\n\n",
110075152Sru		    p->name);
110168569Sjoe	}
11021722Sjkh
110393435Sluigi	if (p->libs) {
110493435Sluigi		fprintf(outmk, "%s_LIBS=", p->ident);
110593435Sluigi		output_strlst(outmk, p->libs);
110693435Sluigi	}
11071722Sjkh
110870884Sjoe	fprintf(outmk, "%s_stub.c:\n", p->name);
110970884Sjoe	fprintf(outmk, "\techo \""
111070884Sjoe	    "int _crunched_%s_stub(int argc, char **argv, char **envp)"
111170884Sjoe	    "{return main(argc,argv,envp);}\" >%s_stub.c\n",
11121722Sjkh	    p->ident, p->name);
111393435Sluigi	fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)",
11141722Sjkh	    p->name, p->name, p->ident);
111593435Sluigi	if (p->libs)
111693435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
1117153687Sceri
111893435Sluigi	fprintf(outmk, "\n");
1119284422Stijl	fprintf(outmk, "\t$(CC) -nostdlib -Wl,-dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)",
11201722Sjkh	    p->name, p->name, p->ident);
112193435Sluigi	if (p->libs)
112293435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
112393435Sluigi	fprintf(outmk, "\n");
112470884Sjoe	fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident);
112570884Sjoe	for (lst = p->keeplist; lst != NULL; lst = lst->next)
112670884Sjoe		fprintf(outmk, "-k _%s ", lst->str);
112770884Sjoe	fprintf(outmk, "%s.lo\n", p->name);
11281722Sjkh}
11291722Sjkh
1130237625Sobrienvoid
1131237625Sobrienoutput_strlst(FILE *outf, strlst_t *lst)
11321722Sjkh{
113370884Sjoe	for (; lst != NULL; lst = lst->next)
1134153687Sceri		if ( strlen(lst->str) )
1135153687Sceri			fprintf(outf, " %s", lst->str);
113670884Sjoe	fprintf(outf, "\n");
11371722Sjkh}
11381722Sjkh
11391722Sjkh
11401722Sjkh/*
11411722Sjkh * ========================================================================
11421722Sjkh * general library routines
11431722Sjkh *
11441722Sjkh */
11451722Sjkh
1146237625Sobrienvoid
1147246256Spfgstatus(const char *str)
11481722Sjkh{
114970884Sjoe	static int lastlen = 0;
115070884Sjoe	int len, spaces;
11511722Sjkh
115270884Sjoe	if (!verbose)
115370884Sjoe		return;
11541722Sjkh
115570884Sjoe	len = strlen(str);
115670884Sjoe	spaces = lastlen - len;
115770884Sjoe	if (spaces < 1)
115870884Sjoe		spaces = 1;
11591722Sjkh
116070884Sjoe	fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
116170884Sjoe	fflush(stderr);
116270884Sjoe	lastlen = len;
11631722Sjkh}
11641722Sjkh
11651722Sjkh
1166237625Sobrienvoid
1167237625Sobrienout_of_memory(void)
11681722Sjkh{
116970884Sjoe	err(1, "%s: %d: out of memory, stopping", infilename, linenum);
11701722Sjkh}
11711722Sjkh
11721722Sjkh
1173237625Sobrienvoid
1174237625Sobrienadd_string(strlst_t **listp, char *str)
11751722Sjkh{
117670884Sjoe	strlst_t *p1, *p2;
11771722Sjkh
117870884Sjoe	/* add to end, but be smart about dups */
11791722Sjkh
118070884Sjoe	for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
118170884Sjoe		if (!strcmp(p2->str, str))
118270884Sjoe			return;
11831722Sjkh
118470884Sjoe	p2 = malloc(sizeof(strlst_t));
118570884Sjoe	if (p2) {
118670884Sjoe		p2->next = NULL;
118770884Sjoe		p2->str = strdup(str);
118870884Sjoe    	}
118970884Sjoe	if (!p2 || !p2->str)
119070884Sjoe		out_of_memory();
11911722Sjkh
119270884Sjoe	if (p1 == NULL)
119370884Sjoe		*listp = p2;
119470884Sjoe	else
119570884Sjoe		p1->next = p2;
11961722Sjkh}
11971722Sjkh
1198237625Sobrienint
1199237625Sobriensubtract_strlst(strlst_t **lista, strlst_t **listb)
1200153687Sceri{
1201153687Sceri	int subtract_count = 0;
1202153687Sceri	strlst_t *p1;
1203153687Sceri	for (p1 = *listb; p1 != NULL; p1 = p1->next)
1204153687Sceri		if ( in_list(lista, p1->str) ) {
1205153687Sceri			warnx("Will compile library `%s' dynamically", p1->str);
1206153687Sceri			strcat(p1->str, "");
1207153687Sceri			subtract_count++;
1208153687Sceri		}
1209153687Sceri	return subtract_count;
1210153687Sceri}
12111722Sjkh
1212237625Sobrienint
1213237625Sobrienin_list(strlst_t **listp, char *str)
1214153687Sceri{
1215153687Sceri	strlst_t *p1;
1216153687Sceri	for (p1 = *listp; p1 != NULL; p1 = p1->next)
1217153687Sceri		if (!strcmp(p1->str, str))
1218153687Sceri			return 1;
1219153687Sceri	return 0;
1220153687Sceri}
1221153687Sceri
1222237625Sobrienint
1223246256Spfgis_dir(const char *pathname)
12241722Sjkh{
122570884Sjoe	struct stat buf;
12261722Sjkh
122770884Sjoe	if (stat(pathname, &buf) == -1)
122870884Sjoe		return 0;
122970884Sjoe
123070884Sjoe	return S_ISDIR(buf.st_mode);
12311722Sjkh}
12321722Sjkh
1233237625Sobrienint
1234246256Spfgis_nonempty_file(const char *pathname)
12351722Sjkh{
123670884Sjoe	struct stat buf;
12371722Sjkh
123870884Sjoe	if (stat(pathname, &buf) == -1)
123970884Sjoe		return 0;
12401722Sjkh
124170884Sjoe	return S_ISREG(buf.st_mode) && buf.st_size > 0;
12421722Sjkh}
1243