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 */
33246576Spfg
34246576Spfg#include <sys/cdefs.h>
35246576Spfg__FBSDID("$FreeBSD$");
36246576Spfg
37246576Spfg#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 ? */
96246576Spfgchar *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
108246576Spfgvoid status(const char *str);
1091722Sjkhvoid out_of_memory(void);
1101722Sjkhvoid add_string(strlst_t **listp, char *str);
111246576Spfgint is_dir(const char *pathname);
112246576Spfgint is_nonempty_file(const char *pathname);
113153687Sceriint subtract_strlst(strlst_t **lista, strlst_t **listb);
114153687Sceriint in_list(strlst_t **listp, char *str);
1151722Sjkh
1161722Sjkh
117246576Spfgextern char *crunched_skel[];
118246576Spfg
1198857Srgrimesvoid usage(void);
1201722Sjkhvoid parse_conf_file(void);
1211722Sjkhvoid gen_outputs(void);
1221722Sjkh
1231722Sjkh
124246576Spfgint
125246576Spfgmain(int argc, char **argv)
1261722Sjkh{
12770884Sjoe	char *p;
12870884Sjoe	int optc;
1291722Sjkh
13070884Sjoe	verbose = 1;
13170884Sjoe	readcache = 1;
13270884Sjoe	*outmkname = *outcfname = *execfname = '\0';
1338857Srgrimes
134246576Spfg	path_make = getenv("MAKE");
135246576Spfg	if (path_make == NULL || *path_make == '\0')
136246576Spfg		path_make = "make";
137246576Spfg
13870884Sjoe	p = getenv("MAKEOBJDIRPREFIX");
13970884Sjoe	if (p == NULL || *p == '\0')
14070884Sjoe		objprefix = "/usr/obj"; /* default */
14170884Sjoe	else
14270884Sjoe		if ((objprefix = strdup(p)) == NULL)
14370884Sjoe			out_of_memory();
14469413Sluigi
14570884Sjoe	while((optc = getopt(argc, argv, "lh:m:c:e:p:foq")) != -1) {
14670884Sjoe		switch(optc) {
14770884Sjoe		case 'f':
14870884Sjoe			readcache = 0;
14970884Sjoe			break;
15070884Sjoe		case 'o':
15170884Sjoe			makeobj = 1;
15270884Sjoe			break;
15370884Sjoe		case 'q':
15470884Sjoe			verbose = 0;
15570884Sjoe			break;
1561722Sjkh
15770884Sjoe		case 'm':
15870884Sjoe			strlcpy(outmkname, optarg, sizeof(outmkname));
15970884Sjoe			break;
16070884Sjoe		case 'p':
16170884Sjoe			if ((objprefix = strdup(optarg)) == NULL)
16270113Sjoe				out_of_memory();
16370113Sjoe			break;
1641722Sjkh
16570884Sjoe		case 'h':
16670884Sjoe			strlcpy(outhdrname, optarg, sizeof(outhdrname));
16770884Sjoe			break;
16870884Sjoe		case 'c':
16970884Sjoe			strlcpy(outcfname, optarg, sizeof(outcfname));
17070884Sjoe			break;
17170884Sjoe		case 'e':
17270884Sjoe			strlcpy(execfname, optarg, sizeof(execfname));
17370884Sjoe			break;
17470884Sjoe
17570884Sjoe		case 'l':
17670884Sjoe			list_mode++;
17770884Sjoe			verbose = 0;
17870884Sjoe			break;
17970884Sjoe
18070884Sjoe		case '?':
18170884Sjoe		default:
18270884Sjoe			usage();
18370884Sjoe		}
1841722Sjkh	}
1851722Sjkh
18670884Sjoe	argc -= optind;
18770884Sjoe	argv += optind;
1881722Sjkh
18970884Sjoe	if (argc != 1)
19070884Sjoe		usage();
1911722Sjkh
19270884Sjoe	/*
19370884Sjoe	 * generate filenames
19470884Sjoe	 */
1951722Sjkh
19670884Sjoe	strlcpy(infilename, argv[0], sizeof(infilename));
1971722Sjkh
19870884Sjoe	/* confname = `basename infilename .conf` */
1991722Sjkh
20070884Sjoe	if ((p=strrchr(infilename, '/')) != NULL)
20170884Sjoe		strlcpy(confname, p + 1, sizeof(confname));
20270884Sjoe	else
20370884Sjoe		strlcpy(confname, infilename, sizeof(confname));
2041722Sjkh
20570884Sjoe	if ((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
20670884Sjoe		*p = '\0';
2071722Sjkh
20870884Sjoe	if (!*outmkname)
20970884Sjoe		snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
21070884Sjoe	if (!*outcfname)
21170884Sjoe		snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
21270884Sjoe	if (!*execfname)
21370884Sjoe		snprintf(execfname, sizeof(execfname), "%s", confname);
21470884Sjoe
21570884Sjoe	snprintf(cachename, sizeof(cachename), "%s.cache", confname);
21670884Sjoe	snprintf(tempfname, sizeof(tempfname), "%s/crunchgen_%sXXXXXX",
21770124Sjoe	getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, confname);
2181722Sjkh
21970884Sjoe	parse_conf_file();
22070884Sjoe	if (list_mode)
22170884Sjoe		exit(goterror);
2226696Sphk
22370884Sjoe	gen_outputs();
2241722Sjkh
22570884Sjoe	exit(goterror);
2261722Sjkh}
2271722Sjkh
2281722Sjkh
229246576Spfgvoid
230246576Spfgusage(void)
2311722Sjkh{
23270884Sjoe	fprintf(stderr, "%s%s\n\t%s%s\n", "usage: crunchgen [-foq] ",
23370884Sjoe	    "[-h <makefile-header-name>] [-m <makefile>]",
23470884Sjoe	    "[-p <obj-prefix>] [-c <c-file-name>] [-e <exec-file>] ",
23570884Sjoe	    "<conffile>");
23670884Sjoe	exit(1);
2371722Sjkh}
2381722Sjkh
2391722Sjkh
2401722Sjkh/*
2411722Sjkh * ========================================================================
2421722Sjkh * parse_conf_file subsystem
2431722Sjkh *
2441722Sjkh */
2451722Sjkh
2461722Sjkh/* helper routines for parse_conf_file */
2471722Sjkh
2481722Sjkhvoid parse_one_file(char *filename);
249246576Spfgvoid parse_line(char *pline, int *fc, char **fv, int nf);
2501722Sjkhvoid add_srcdirs(int argc, char **argv);
2511722Sjkhvoid add_progs(int argc, char **argv);
2521722Sjkhvoid add_link(int argc, char **argv);
2531722Sjkhvoid add_libs(int argc, char **argv);
254153687Scerivoid add_libs_so(int argc, char **argv);
25568750Sjoevoid add_buildopts(int argc, char **argv);
2561722Sjkhvoid add_special(int argc, char **argv);
2571722Sjkh
2581722Sjkhprog_t *find_prog(char *str);
2591722Sjkhvoid add_prog(char *progname);
2601722Sjkh
2611722Sjkh
262246576Spfgvoid
263246576Spfgparse_conf_file(void)
2641722Sjkh{
26570884Sjoe	if (!is_nonempty_file(infilename))
26629453Scharnier		errx(1, "fatal: input file \"%s\" not found", infilename);
26770884Sjoe
26870884Sjoe	parse_one_file(infilename);
26970884Sjoe	if (readcache && is_nonempty_file(cachename)) {
27070884Sjoe		reading_cache = 1;
27170884Sjoe		parse_one_file(cachename);
27270884Sjoe	}
2731722Sjkh}
2741722Sjkh
2751722Sjkh
276246576Spfgvoid
277246576Spfgparse_one_file(char *filename)
2781722Sjkh{
27970884Sjoe	char *fieldv[MAXFIELDS];
28070884Sjoe	int fieldc;
28170884Sjoe	void (*f)(int c, char **v);
28270884Sjoe	FILE *cf;
28370884Sjoe	char line[MAXLINELEN];
2841722Sjkh
28570884Sjoe	snprintf(line, sizeof(line), "reading %s", filename);
28670884Sjoe	status(line);
28770884Sjoe	strlcpy(curfilename, filename, sizeof(curfilename));
2881722Sjkh
28970884Sjoe	if ((cf = fopen(curfilename, "r")) == NULL) {
29070884Sjoe		warn("%s", curfilename);
29170884Sjoe		goterror = 1;
29270884Sjoe		return;
29370884Sjoe	}
2941722Sjkh
29570884Sjoe	linenum = 0;
29670884Sjoe	while (fgets(line, MAXLINELEN, cf) != NULL) {
29770884Sjoe		linenum++;
29870884Sjoe		parse_line(line, &fieldc, fieldv, MAXFIELDS);
29970884Sjoe
30070884Sjoe		if (fieldc < 1)
30170884Sjoe			continue;
30270884Sjoe
30370884Sjoe		if (!strcmp(fieldv[0], "srcdirs"))
30470884Sjoe			f = add_srcdirs;
30570884Sjoe		else if(!strcmp(fieldv[0], "progs"))
30670884Sjoe			f = add_progs;
30770884Sjoe		else if(!strcmp(fieldv[0], "ln"))
30870884Sjoe			f = add_link;
30970884Sjoe		else if(!strcmp(fieldv[0], "libs"))
31070884Sjoe			f = add_libs;
311153687Sceri		else if(!strcmp(fieldv[0], "libs_so"))
312153687Sceri			f = add_libs_so;
31370884Sjoe		else if(!strcmp(fieldv[0], "buildopts"))
31470884Sjoe			f = add_buildopts;
31570884Sjoe		else if(!strcmp(fieldv[0], "special"))
31670884Sjoe			f = add_special;
31770884Sjoe		else {
31870884Sjoe			warnx("%s:%d: skipping unknown command `%s'",
31970884Sjoe			    curfilename, linenum, fieldv[0]);
32070884Sjoe			goterror = 1;
32170884Sjoe			continue;
32270884Sjoe		}
32370884Sjoe
32470884Sjoe		if (fieldc < 2) {
32570884Sjoe			warnx("%s:%d: %s %s",
32670884Sjoe			    curfilename, linenum, fieldv[0],
32770884Sjoe			    "command needs at least 1 argument, skipping");
32870884Sjoe			goterror = 1;
32970884Sjoe			continue;
33070884Sjoe		}
33170884Sjoe
33270884Sjoe		f(fieldc, fieldv);
3331722Sjkh	}
33470884Sjoe
33570884Sjoe	if (ferror(cf)) {
33670884Sjoe		warn("%s", curfilename);
33770884Sjoe		goterror = 1;
3381722Sjkh	}
33970884Sjoe	fclose(cf);
3401722Sjkh}
3411722Sjkh
3421722Sjkh
343246576Spfgvoid
344246576Spfgparse_line(char *pline, int *fc, char **fv, int nf)
3451722Sjkh{
34670884Sjoe	char *p;
3471722Sjkh
348246576Spfg	p = pline;
34970884Sjoe	*fc = 0;
3501722Sjkh
35170884Sjoe	while (1) {
352246576Spfg		while (isspace((unsigned char)*p))
35370884Sjoe			p++;
35470884Sjoe
35570884Sjoe		if (*p == '\0' || *p == '#')
35670884Sjoe			break;
35770884Sjoe
35870884Sjoe		if (*fc < nf)
35970884Sjoe			fv[(*fc)++] = p;
36070884Sjoe
361246576Spfg		while (*p && !isspace((unsigned char)*p) && *p != '#')
36270884Sjoe			p++;
36370884Sjoe
36470884Sjoe		if (*p == '\0' || *p == '#')
36570884Sjoe			break;
36670884Sjoe
36770884Sjoe		*p++ = '\0';
36870884Sjoe	}
36970884Sjoe
37070884Sjoe	if (*p)
37170884Sjoe		*p = '\0';		/* needed for '#' case */
3721722Sjkh}
3731722Sjkh
3741722Sjkh
375246576Spfgvoid
376246576Spfgadd_srcdirs(int argc, char **argv)
3771722Sjkh{
37870884Sjoe	int i;
3791722Sjkh
38070884Sjoe	for (i = 1; i < argc; i++) {
38170884Sjoe		if (is_dir(argv[i]))
38270884Sjoe			add_string(&srcdirs, argv[i]);
38370884Sjoe		else {
38470884Sjoe			warnx("%s:%d: `%s' is not a directory, skipping it",
38570884Sjoe			    curfilename, linenum, argv[i]);
38670884Sjoe			goterror = 1;
38770884Sjoe		}
3881722Sjkh	}
3891722Sjkh}
3901722Sjkh
3911722Sjkh
392246576Spfgvoid
393246576Spfgadd_progs(int argc, char **argv)
3941722Sjkh{
39570884Sjoe	int i;
3961722Sjkh
39770884Sjoe	for (i = 1; i < argc; i++)
39870884Sjoe		add_prog(argv[i]);
3991722Sjkh}
4001722Sjkh
4011722Sjkh
402246576Spfgvoid
403246576Spfgadd_prog(char *progname)
4041722Sjkh{
40570884Sjoe	prog_t *p1, *p2;
4061722Sjkh
40770884Sjoe	/* add to end, but be smart about dups */
4081722Sjkh
40970884Sjoe	for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
41070884Sjoe		if (!strcmp(p2->name, progname))
41170884Sjoe			return;
4121722Sjkh
41370884Sjoe	p2 = malloc(sizeof(prog_t));
41470884Sjoe	if(p2) {
41570884Sjoe		memset(p2, 0, sizeof(prog_t));
41670884Sjoe		p2->name = strdup(progname);
41770884Sjoe	}
41870884Sjoe	if (!p2 || !p2->name)
41970884Sjoe		out_of_memory();
4201722Sjkh
42170884Sjoe	p2->next = NULL;
42270884Sjoe	if (p1 == NULL)
42370884Sjoe		progs = p2;
42470884Sjoe	else
42570884Sjoe		p1->next = p2;
4261722Sjkh
42770884Sjoe	p2->ident = NULL;
42870884Sjoe	p2->srcdir = NULL;
42970884Sjoe	p2->realsrcdir = NULL;
43070884Sjoe	p2->objdir = NULL;
43170884Sjoe	p2->links = NULL;
43293435Sluigi	p2->libs = NULL;
433153687Sceri	p2->libs_so = NULL;
43470884Sjoe	p2->objs = NULL;
43570884Sjoe	p2->keeplist = NULL;
43670884Sjoe	p2->buildopts = NULL;
43770884Sjoe	p2->goterror = 0;
43870884Sjoe
43970884Sjoe	if (list_mode)
44070884Sjoe		printf("%s\n",progname);
4411722Sjkh}
4421722Sjkh
4431722Sjkh
444246576Spfgvoid
445246576Spfgadd_link(int argc, char **argv)
4461722Sjkh{
44770884Sjoe	int i;
44870884Sjoe	prog_t *p = find_prog(argv[1]);
4491722Sjkh
45070884Sjoe	if (p == NULL) {
45170884Sjoe		warnx("%s:%d: no prog %s previously declared, skipping link",
45270884Sjoe		    curfilename, linenum, argv[1]);
45370884Sjoe		goterror = 1;
45470884Sjoe		return;
45570884Sjoe	}
45670884Sjoe
45770884Sjoe	for (i = 2; i < argc; i++) {
45870884Sjoe		if (list_mode)
45970884Sjoe			printf("%s\n",argv[i]);
46070884Sjoe
46170884Sjoe		add_string(&p->links, argv[i]);
46270884Sjoe	}
4631722Sjkh}
4641722Sjkh
4651722Sjkh
466246576Spfgvoid
467246576Spfgadd_libs(int argc, char **argv)
4681722Sjkh{
46970884Sjoe	int i;
4701722Sjkh
471153687Sceri	for(i = 1; i < argc; i++) {
47270884Sjoe		add_string(&libs, argv[i]);
473153687Sceri		if ( in_list(&libs_so, argv[i]) )
474153687Sceri			warnx("%s:%d: "
475153687Sceri				"library `%s' specified as dynamic earlier",
476153687Sceri				curfilename, linenum, argv[i]);
477153687Sceri	}
4781722Sjkh}
4791722Sjkh
4801722Sjkh
481246576Spfgvoid
482246576Spfgadd_libs_so(int argc, char **argv)
483153687Sceri{
484153687Sceri	int i;
485153687Sceri
486153687Sceri	for(i = 1; i < argc; i++) {
487153687Sceri		add_string(&libs_so, argv[i]);
488153687Sceri		if ( in_list(&libs, argv[i]) )
489153687Sceri			warnx("%s:%d: "
490153687Sceri				"library `%s' specified as static earlier",
491153687Sceri				curfilename, linenum, argv[i]);
492153687Sceri	}
493153687Sceri}
494153687Sceri
495153687Sceri
496246576Spfgvoid
497246576Spfgadd_buildopts(int argc, char **argv)
49868750Sjoe{
49970884Sjoe	int i;
50068750Sjoe
50170884Sjoe	for (i = 1; i < argc; i++)
50270884Sjoe		add_string(&buildopts, argv[i]);
50368750Sjoe}
50468750Sjoe
50568750Sjoe
506246576Spfgvoid
507246576Spfgadd_special(int argc, char **argv)
5081722Sjkh{
50970884Sjoe	int i;
51070884Sjoe	prog_t *p = find_prog(argv[1]);
5111722Sjkh
51270884Sjoe	if (p == NULL) {
51370884Sjoe		if (reading_cache)
51470884Sjoe			return;
5151722Sjkh
51670884Sjoe		warnx("%s:%d: no prog %s previously declared, skipping special",
51770884Sjoe		    curfilename, linenum, argv[1]);
51870884Sjoe		goterror = 1;
51970884Sjoe		return;
52070884Sjoe	}
5211722Sjkh
52270884Sjoe	if (!strcmp(argv[2], "ident")) {
52370884Sjoe		if (argc != 4)
52470884Sjoe			goto argcount;
52570884Sjoe		if ((p->ident = strdup(argv[3])) == NULL)
52670884Sjoe			out_of_memory();
52770884Sjoe	} else if (!strcmp(argv[2], "srcdir")) {
52870884Sjoe		if (argc != 4)
52970884Sjoe			goto argcount;
53070884Sjoe		if ((p->srcdir = strdup(argv[3])) == NULL)
53170884Sjoe			out_of_memory();
53270884Sjoe	} else if (!strcmp(argv[2], "objdir")) {
53370884Sjoe		if(argc != 4)
53470884Sjoe			goto argcount;
53570884Sjoe		if((p->objdir = strdup(argv[3])) == NULL)
53670884Sjoe			out_of_memory();
53770884Sjoe	} else if (!strcmp(argv[2], "objs")) {
53870884Sjoe		p->objs = NULL;
53970884Sjoe		for (i = 3; i < argc; i++)
54070884Sjoe			add_string(&p->objs, argv[i]);
54170884Sjoe	} else if (!strcmp(argv[2], "objpaths")) {
54270884Sjoe		p->objpaths = NULL;
54370884Sjoe		for (i = 3; i < argc; i++)
54470884Sjoe			add_string(&p->objpaths, argv[i]);
54570884Sjoe	} else if (!strcmp(argv[2], "keep")) {
54670884Sjoe		p->keeplist = NULL;
54770884Sjoe		for(i = 3; i < argc; i++)
54870884Sjoe			add_string(&p->keeplist, argv[i]);
54970884Sjoe	} else if (!strcmp(argv[2], "objvar")) {
55070884Sjoe		if(argc != 4)
55170884Sjoe			goto argcount;
55270884Sjoe		if ((p->objvar = strdup(argv[3])) == NULL)
55370884Sjoe			out_of_memory();
55470884Sjoe	} else if (!strcmp(argv[2], "buildopts")) {
55570884Sjoe		p->buildopts = NULL;
55670884Sjoe		for (i = 3; i < argc; i++)
55770884Sjoe			add_string(&p->buildopts, argv[i]);
55893435Sluigi	} else if (!strcmp(argv[2], "lib")) {
55993435Sluigi		for (i = 3; i < argc; i++)
56093435Sluigi			add_string(&p->libs, argv[i]);
56170884Sjoe	} else {
56270884Sjoe		warnx("%s:%d: bad parameter name `%s', skipping line",
56370884Sjoe		    curfilename, linenum, argv[2]);
56470884Sjoe		goterror = 1;
56570884Sjoe	}
56670884Sjoe	return;
5671722Sjkh
5681722Sjkh argcount:
56970884Sjoe	warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"",
5701722Sjkh	    curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]);
57170884Sjoe	goterror = 1;
5721722Sjkh}
5731722Sjkh
5741722Sjkh
5751722Sjkhprog_t *find_prog(char *str)
5761722Sjkh{
57770884Sjoe	prog_t *p;
5781722Sjkh
57970884Sjoe	for (p = progs; p != NULL; p = p->next)
58070884Sjoe		if (!strcmp(p->name, str))
58170884Sjoe			return p;
5821722Sjkh
58370884Sjoe	return NULL;
5841722Sjkh}
5851722Sjkh
5861722Sjkh
5871722Sjkh/*
5881722Sjkh * ========================================================================
5891722Sjkh * gen_outputs subsystem
5901722Sjkh *
5911722Sjkh */
5921722Sjkh
5931722Sjkh/* helper subroutines */
5941722Sjkh
5951722Sjkhvoid remove_error_progs(void);
5961722Sjkhvoid fillin_program(prog_t *p);
5971722Sjkhvoid gen_specials_cache(void);
5981722Sjkhvoid gen_output_makefile(void);
5991722Sjkhvoid gen_output_cfile(void);
6001722Sjkh
6011722Sjkhvoid fillin_program_objs(prog_t *p, char *path);
6021722Sjkhvoid top_makefile_rules(FILE *outmk);
6031722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p);
6041722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst);
6051722Sjkhchar *genident(char *str);
6061722Sjkhchar *dir_search(char *progname);
6071722Sjkh
6081722Sjkh
609246576Spfgvoid
610246576Spfggen_outputs(void)
6111722Sjkh{
61270884Sjoe	prog_t *p;
6131722Sjkh
61470884Sjoe	for (p = progs; p != NULL; p = p->next)
61570884Sjoe		fillin_program(p);
6161722Sjkh
61770884Sjoe	remove_error_progs();
61870884Sjoe	gen_specials_cache();
61970884Sjoe	gen_output_cfile();
62070884Sjoe	gen_output_makefile();
62170884Sjoe	status("");
62270884Sjoe	fprintf(stderr,
623246576Spfg	    "Run \"%s -f %s\" to build crunched binary.\n",
624246576Spfg	    path_make, outmkname);
6251722Sjkh}
6261722Sjkh
62756995Sluigi/*
62856995Sluigi * run the makefile for the program to find which objects are necessary
62956995Sluigi */
630246576Spfgvoid
631246576Spfgfillin_program(prog_t *p)
6321722Sjkh{
63370884Sjoe	char path[MAXPATHLEN];
63470884Sjoe	char line[MAXLINELEN];
63570884Sjoe	FILE *f;
6361722Sjkh
63770884Sjoe	snprintf(line, MAXLINELEN, "filling in parms for %s", p->name);
63870884Sjoe	status(line);
6391722Sjkh
64070884Sjoe	if (!p->ident)
64170884Sjoe		p->ident = genident(p->name);
64270331Sjoe
64370884Sjoe	/* look for the source directory if one wasn't specified by a special */
64470884Sjoe	if (!p->srcdir) {
64570884Sjoe		p->srcdir = dir_search(p->name);
64670884Sjoe	}
64770112Sjoe
64870884Sjoe	/* Determine the actual srcdir (maybe symlinked). */
64970884Sjoe	if (p->srcdir) {
65070884Sjoe		snprintf(line, MAXLINELEN, "cd %s && echo -n `/bin/pwd`",
65170884Sjoe		    p->srcdir);
65270884Sjoe		f = popen(line,"r");
65370884Sjoe		if (!f)
65470884Sjoe			errx(1, "Can't execute: %s\n", line);
65570331Sjoe
65670884Sjoe		path[0] = '\0';
65770884Sjoe		fgets(path, sizeof path, f);
65870884Sjoe		if (pclose(f))
65970884Sjoe			errx(1, "Can't execute: %s\n", line);
66070331Sjoe
66170884Sjoe		if (!*path)
66270884Sjoe			errx(1, "Can't perform pwd on: %s\n", p->srcdir);
66370331Sjoe
66470884Sjoe		p->realsrcdir = strdup(path);
66570884Sjoe	}
66670112Sjoe
66770884Sjoe	/* Unless the option to make object files was specified the
66870884Sjoe	* the objects will be built in the source directory unless
66970884Sjoe	* an object directory already exists.
67070884Sjoe	*/
67170884Sjoe	if (!makeobj && !p->objdir && p->srcdir) {
67270884Sjoe		snprintf(line, sizeof line, "%s/%s", objprefix, p->realsrcdir);
67370884Sjoe		if (is_dir(line)) {
67470884Sjoe			if ((p->objdir = strdup(line)) == NULL)
67570884Sjoe			out_of_memory();
67670884Sjoe		} else
67770884Sjoe			p->objdir = p->realsrcdir;
67870884Sjoe	}
67970884Sjoe
68070884Sjoe	/*
68170884Sjoe	* XXX look for a Makefile.{name} in local directory first.
68270884Sjoe	* This lets us override the original Makefile.
68370884Sjoe	*/
68470884Sjoe	snprintf(path, sizeof(path), "Makefile.%s", p->name);
68570884Sjoe	if (is_nonempty_file(path)) {
68670884Sjoe		snprintf(line, MAXLINELEN, "Using %s for %s", path, p->name);
68770884Sjoe		status(line);
68870114Sjoe	} else
68970884Sjoe		if (p->srcdir)
69070884Sjoe			snprintf(path, sizeof(path), "%s/Makefile", p->srcdir);
69170884Sjoe	if (!p->objs && p->srcdir && is_nonempty_file(path))
69270884Sjoe		fillin_program_objs(p, path);
6931722Sjkh
69481700Sjoe	if (!p->srcdir && !p->objdir && verbose)
69570884Sjoe		warnx("%s: %s: %s",
69670884Sjoe		    "warning: could not find source directory",
69770884Sjoe		    infilename, p->name);
69870884Sjoe	if (!p->objs && verbose)
69970884Sjoe		warnx("%s: %s: warning: could not find any .o files",
70070884Sjoe		    infilename, p->name);
70170880Sjoe
70281823Sjoe	if ((!p->srcdir || !p->objdir) && !p->objs)
70370884Sjoe		p->goterror = 1;
7041722Sjkh}
7051722Sjkh
706246576Spfgvoid
707246576Spfgfillin_program_objs(prog_t *p, char *path)
7081722Sjkh{
70970884Sjoe	char *obj, *cp;
71070884Sjoe	int fd, rc;
71170884Sjoe	FILE *f;
71270884Sjoe	char *objvar="OBJS";
71370884Sjoe	strlst_t *s;
71470884Sjoe	char line[MAXLINELEN];
7151722Sjkh
71670884Sjoe	/* discover the objs from the srcdir Makefile */
7171722Sjkh
71870884Sjoe	if ((fd = mkstemp(tempfname)) == -1) {
71970884Sjoe		perror(tempfname);
72070884Sjoe		exit(1);
72170884Sjoe	}
72270884Sjoe	if ((f = fdopen(fd, "w")) == NULL) {
72370884Sjoe		warn("%s", tempfname);
72470884Sjoe		goterror = 1;
72570884Sjoe		return;
72670884Sjoe	}
72770884Sjoe	if (p->objvar)
72870884Sjoe		objvar = p->objvar;
7298857Srgrimes
73070884Sjoe	/*
73170884Sjoe	* XXX include outhdrname (e.g. to contain Make variables)
73270884Sjoe	*/
73370884Sjoe	if (outhdrname[0] != '\0')
73470884Sjoe		fprintf(f, ".include \"%s\"\n", outhdrname);
73570884Sjoe	fprintf(f, ".include \"%s\"\n", path);
736187943Sobrien	fprintf(f, ".POSIX:\n");
73770884Sjoe	if (buildopts) {
73870884Sjoe		fprintf(f, "BUILDOPTS+=");
73970884Sjoe		output_strlst(f, buildopts);
74070884Sjoe	}
741187131Sobrien	fprintf(f, ".if defined(PROG)\n");
742187131Sobrien	fprintf(f, "%s?=${PROG}.o\n", objvar);
74370884Sjoe	fprintf(f, ".endif\n");
74470884Sjoe	fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar);
74568569Sjoe
746113886Sru	fprintf(f, "crunchgen_objs:\n"
747246576Spfg	    "\t@cd %s && %s -f %s $(BUILDOPTS) $(%s_OPTS)",
748246576Spfg	    p->srcdir, path_make, tempfname, p->ident);
74970884Sjoe	for (s = p->buildopts; s != NULL; s = s->next)
75070884Sjoe		fprintf(f, " %s", s->str);
75170884Sjoe	fprintf(f, " loop\n");
75268569Sjoe
75370884Sjoe	fclose(f);
7541722Sjkh
755246576Spfg	snprintf(line, MAXLINELEN, "cd %s && %s -f %s -B crunchgen_objs",
756246576Spfg	     p->srcdir, path_make, tempfname);
75770884Sjoe	if ((f = popen(line, "r")) == NULL) {
75870884Sjoe		warn("submake pipe");
75970884Sjoe		goterror = 1;
76070884Sjoe		return;
76170884Sjoe	}
7621722Sjkh
76370884Sjoe	while(fgets(line, MAXLINELEN, f)) {
76470884Sjoe		if (strncmp(line, "OBJS= ", 6)) {
76570884Sjoe			warnx("make error: %s", line);
76670884Sjoe			goterror = 1;
76770884Sjoe			continue;
76870884Sjoe		}
76970884Sjoe
77070884Sjoe		cp = line + 6;
771246576Spfg		while (isspace((unsigned char)*cp))
77270884Sjoe			cp++;
77370884Sjoe
77470884Sjoe		while(*cp) {
77570884Sjoe			obj = cp;
776246576Spfg			while (*cp && !isspace((unsigned char)*cp))
77770884Sjoe				cp++;
77870884Sjoe			if (*cp)
77970884Sjoe				*cp++ = '\0';
78070884Sjoe			add_string(&p->objs, obj);
781246576Spfg			while (isspace((unsigned char)*cp))
78270884Sjoe				cp++;
78370884Sjoe		}
7841722Sjkh	}
78570884Sjoe
78670884Sjoe	if ((rc=pclose(f)) != 0) {
78770884Sjoe		warnx("make error: make returned %d", rc);
78870884Sjoe		goterror = 1;
7891722Sjkh	}
79070884Sjoe
79170884Sjoe	unlink(tempfname);
7921722Sjkh}
7931722Sjkh
794246576Spfgvoid
795246576Spfgremove_error_progs(void)
7961722Sjkh{
79770884Sjoe	prog_t *p1, *p2;
7981722Sjkh
79970884Sjoe	p1 = NULL; p2 = progs;
80070884Sjoe	while (p2 != NULL) {
80170884Sjoe		if (!p2->goterror)
80270884Sjoe			p1 = p2, p2 = p2->next;
80370884Sjoe		else {
80470884Sjoe			/* delete it from linked list */
80570884Sjoe			warnx("%s: %s: ignoring program because of errors",
80670884Sjoe			    infilename, p2->name);
80770884Sjoe			if (p1)
80870884Sjoe				p1->next = p2->next;
80970884Sjoe			else
81070884Sjoe				progs = p2->next;
81170884Sjoe			p2 = p2->next;
81270884Sjoe		}
8131722Sjkh	}
8141722Sjkh}
8151722Sjkh
816246576Spfgvoid
817246576Spfggen_specials_cache(void)
8181722Sjkh{
81970884Sjoe	FILE *cachef;
82070884Sjoe	prog_t *p;
82170884Sjoe	char line[MAXLINELEN];
8221722Sjkh
82370884Sjoe	snprintf(line, MAXLINELEN, "generating %s", cachename);
82470884Sjoe	status(line);
8251722Sjkh
82670884Sjoe	if ((cachef = fopen(cachename, "w")) == NULL) {
82770884Sjoe		warn("%s", cachename);
82870884Sjoe		goterror = 1;
82970884Sjoe		return;
83070884Sjoe	}
8311722Sjkh
83270884Sjoe	fprintf(cachef, "# %s - parm cache generated from %s by crunchgen "
83370884Sjoe	    " %s\n\n",
8341722Sjkh	    cachename, infilename, CRUNCH_VERSION);
8351722Sjkh
83670884Sjoe	for (p = progs; p != NULL; p = p->next) {
83770884Sjoe		fprintf(cachef, "\n");
83870884Sjoe		if (p->srcdir)
83970884Sjoe			fprintf(cachef, "special %s srcdir %s\n",
84070884Sjoe			    p->name, p->srcdir);
84170884Sjoe		if (p->objdir)
84270884Sjoe			fprintf(cachef, "special %s objdir %s\n",
84370884Sjoe			    p->name, p->objdir);
84470884Sjoe		if (p->objs) {
84570884Sjoe			fprintf(cachef, "special %s objs", p->name);
84670884Sjoe			output_strlst(cachef, p->objs);
84770884Sjoe		}
84870884Sjoe		if (p->objpaths) {
84970884Sjoe			fprintf(cachef, "special %s objpaths", p->name);
85070884Sjoe			output_strlst(cachef, p->objpaths);
85170884Sjoe		}
8521722Sjkh	}
85370884Sjoe	fclose(cachef);
8541722Sjkh}
8551722Sjkh
8561722Sjkh
857246576Spfgvoid
858246576Spfggen_output_makefile(void)
8591722Sjkh{
86070884Sjoe	prog_t *p;
86170884Sjoe	FILE *outmk;
86270884Sjoe	char line[MAXLINELEN];
8631722Sjkh
86470884Sjoe	snprintf(line, MAXLINELEN, "generating %s", outmkname);
86570884Sjoe	status(line);
8661722Sjkh
86770884Sjoe	if ((outmk = fopen(outmkname, "w")) == NULL) {
86870884Sjoe		warn("%s", outmkname);
86970884Sjoe		goterror = 1;
87070884Sjoe		return;
87170884Sjoe	}
8721722Sjkh
87370884Sjoe	fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
8741722Sjkh	    outmkname, infilename, CRUNCH_VERSION);
8751722Sjkh
87670884Sjoe	if (outhdrname[0] != '\0')
87770884Sjoe		fprintf(outmk, ".include \"%s\"\n", outhdrname);
8781722Sjkh
87970884Sjoe	top_makefile_rules(outmk);
88070884Sjoe	for (p = progs; p != NULL; p = p->next)
88170884Sjoe		prog_makefile_rules(outmk, p);
88270884Sjoe
88370884Sjoe	fprintf(outmk, "\n# ========\n");
88470884Sjoe	fclose(outmk);
8851722Sjkh}
8861722Sjkh
8871722Sjkh
888246576Spfgvoid
889246576Spfggen_output_cfile(void)
8901722Sjkh{
89170884Sjoe	char **cp;
89270884Sjoe	FILE *outcf;
89370884Sjoe	prog_t *p;
89470884Sjoe	strlst_t *s;
89570884Sjoe	char line[MAXLINELEN];
8961722Sjkh
89770884Sjoe	snprintf(line, MAXLINELEN, "generating %s", outcfname);
89870884Sjoe	status(line);
8991722Sjkh
90070884Sjoe	if((outcf = fopen(outcfname, "w")) == NULL) {
90170884Sjoe		warn("%s", outcfname);
90270884Sjoe		goterror = 1;
90370884Sjoe		return;
90470884Sjoe	}
9051722Sjkh
90670884Sjoe	fprintf(outcf,
90770884Sjoe	    "/* %s - generated from %s by crunchgen %s */\n",
9081722Sjkh	    outcfname, infilename, CRUNCH_VERSION);
9091722Sjkh
91070884Sjoe	fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
91170884Sjoe	for (cp = crunched_skel; *cp != NULL; cp++)
91270884Sjoe		fprintf(outcf, "%s\n", *cp);
9131722Sjkh
91470884Sjoe	for (p = progs; p != NULL; p = p->next)
91570884Sjoe		fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
9161722Sjkh
91770884Sjoe	fprintf(outcf, "\nstruct stub entry_points[] = {\n");
91870884Sjoe	for (p = progs; p != NULL; p = p->next) {
91970884Sjoe		fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
92070884Sjoe		    p->name, p->ident);
92170884Sjoe		for (s = p->links; s != NULL; s = s->next)
92270884Sjoe			fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
92370884Sjoe			    s->str, p->ident);
92470884Sjoe	}
9258857Srgrimes
92670884Sjoe	fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
92770884Sjoe	fprintf(outcf, "\t{ NULL, NULL }\n};\n");
92870884Sjoe	fclose(outcf);
9291722Sjkh}
9301722Sjkh
9311722Sjkh
9321722Sjkhchar *genident(char *str)
9331722Sjkh{
93470884Sjoe	char *n, *s, *d;
9351722Sjkh
93670884Sjoe	/*
93770884Sjoe	 * generates a Makefile/C identifier from a program name,
93870884Sjoe	 * mapping '-' to '_' and ignoring all other non-identifier
93970884Sjoe	 * characters.  This leads to programs named "foo.bar" and
94070884Sjoe	 * "foobar" to map to the same identifier.
94170884Sjoe	 */
9421722Sjkh
94370884Sjoe	if ((n = strdup(str)) == NULL)
94470884Sjoe		return NULL;
94570884Sjoe	for (d = s = n; *s != '\0'; s++) {
94670884Sjoe		if (*s == '-')
94770884Sjoe			*d++ = '_';
948246576Spfg		else if (*s == '_' || isalnum((unsigned char)*s))
94970884Sjoe			*d++ = *s;
95070884Sjoe	}
95170884Sjoe	*d = '\0';
95270884Sjoe	return n;
9531722Sjkh}
9541722Sjkh
9551722Sjkh
9561722Sjkhchar *dir_search(char *progname)
9571722Sjkh{
95870884Sjoe	char path[MAXPATHLEN];
95970884Sjoe	strlst_t *dir;
96070884Sjoe	char *srcdir;
9611722Sjkh
96270884Sjoe	for (dir = srcdirs; dir != NULL; dir = dir->next) {
96370884Sjoe		snprintf(path, MAXPATHLEN, "%s/%s", dir->str, progname);
96470884Sjoe		if (!is_dir(path))
96570884Sjoe			continue;
96670884Sjoe
96770884Sjoe		if ((srcdir = strdup(path)) == NULL)
96870884Sjoe			out_of_memory();
96970884Sjoe
97070884Sjoe		return srcdir;
97170331Sjoe	}
97270884Sjoe	return NULL;
9731722Sjkh}
9741722Sjkh
9751722Sjkh
976246576Spfgvoid
977246576Spfgtop_makefile_rules(FILE *outmk)
9781722Sjkh{
97970884Sjoe	prog_t *p;
9801722Sjkh
981246895Spfg	fprintf(outmk, "LD?= ld\n");
982153687Sceri	if ( subtract_strlst(&libs, &libs_so) )
983153687Sceri		fprintf(outmk, "# NOTE: Some LIBS declarations below overridden by LIBS_SO\n");
984153687Sceri
98578520Sjoe	fprintf(outmk, "LIBS+=");
98670884Sjoe	output_strlst(outmk, libs);
9871722Sjkh
988153687Sceri	fprintf(outmk, "LIBS_SO+=");
989153687Sceri	output_strlst(outmk, libs_so);
990153687Sceri
99170884Sjoe	if (makeobj) {
99270884Sjoe		fprintf(outmk, "MAKEOBJDIRPREFIX?=%s\n", objprefix);
993133399Sharti		fprintf(outmk, "MAKEENV=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX)\n");
994133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKEENV) $(MAKE)\n");
99570884Sjoe	} else {
996133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKE)\n");
99770884Sjoe	}
99870112Sjoe
99970884Sjoe	if (buildopts) {
100070884Sjoe		fprintf(outmk, "BUILDOPTS+=");
100170884Sjoe		output_strlst(outmk, buildopts);
100270884Sjoe	}
100368750Sjoe
100470884Sjoe	fprintf(outmk, "CRUNCHED_OBJS=");
100570884Sjoe	for (p = progs; p != NULL; p = p->next)
100670884Sjoe		fprintf(outmk, " %s.lo", p->name);
100770884Sjoe	fprintf(outmk, "\n");
10081722Sjkh
100970884Sjoe	fprintf(outmk, "SUBMAKE_TARGETS=");
101070884Sjoe	for (p = progs; p != NULL; p = p->next)
101170884Sjoe		fprintf(outmk, " %s_make", p->ident);
101270884Sjoe	fprintf(outmk, "\nSUBCLEAN_TARGETS=");
101370884Sjoe	for (p = progs; p != NULL; p = p->next)
101470884Sjoe		fprintf(outmk, " %s_clean", p->ident);
101570884Sjoe	fprintf(outmk, "\n\n");
10161722Sjkh
101770884Sjoe	fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
101870884Sjoe	fprintf(outmk, "exe: %s\n", execfname);
1019164504Sjb	fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS) $(SUBMAKE_TARGETS)\n", execfname, execfname);
1020153687Sceri	fprintf(outmk, ".if defined(LIBS_SO) && !empty(LIBS_SO)\n");
1021153687Sceri	fprintf(outmk, "\t$(CC) -o %s %s.o $(CRUNCHED_OBJS) \\\n",
1022153687Sceri	    execfname, execfname);
1023153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bstatic $(LIBS) \\\n");
1024153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bdynamic $(LIBS_SO)\n");
1025153687Sceri	fprintf(outmk, ".else\n");
102670884Sjoe	fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
10271722Sjkh	    execfname, execfname);
1028153687Sceri	fprintf(outmk, ".endif\n");
102970884Sjoe	fprintf(outmk, "\tstrip %s\n", execfname);
103070884Sjoe	fprintf(outmk, "realclean: clean subclean\n");
103170884Sjoe	fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", execfname);
103270884Sjoe	fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n");
10331722Sjkh}
10341722Sjkh
10351722Sjkh
1036246576Spfgvoid
1037246576Spfgprog_makefile_rules(FILE *outmk, prog_t *p)
10381722Sjkh{
103970884Sjoe	strlst_t *lst;
104030120Sjoerg
104170884Sjoe	fprintf(outmk, "\n# -------- %s\n\n", p->name);
10421722Sjkh
104381700Sjoe	fprintf(outmk, "%s_OBJDIR=", p->ident);
104481700Sjoe	if (p->objdir)
104581700Sjoe		fprintf(outmk, "%s", p->objdir);
104681700Sjoe	else
104781700Sjoe		fprintf(outmk, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n",
104881700Sjoe		    p->ident);
104981700Sjoe	fprintf(outmk, "\n");
105081700Sjoe
1051164571Sjb	fprintf(outmk, "%s_OBJPATHS=", p->ident);
1052164571Sjb	if (p->objpaths)
1053164571Sjb		output_strlst(outmk, p->objpaths);
1054164571Sjb	else {
1055164571Sjb		for (lst = p->objs; lst != NULL; lst = lst->next) {
1056164571Sjb			fprintf(outmk, " $(%s_OBJDIR)/%s", p->ident, lst->str);
1057164571Sjb		}
1058164571Sjb		fprintf(outmk, "\n");
1059164571Sjb	}
1060164571Sjb
106170884Sjoe	if (p->srcdir && p->objs) {
106270884Sjoe		fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
106370884Sjoe		fprintf(outmk, "%s_REALSRCDIR=%s\n", p->ident, p->realsrcdir);
106470112Sjoe
106570884Sjoe		fprintf(outmk, "%s_OBJS=", p->ident);
106670884Sjoe		output_strlst(outmk, p->objs);
106770884Sjoe		if (p->buildopts != NULL) {
106870884Sjoe			fprintf(outmk, "%s_OPTS+=", p->ident);
106970884Sjoe			output_strlst(outmk, p->buildopts);
107070884Sjoe		}
1071164654Sjb#if 0
1072164571Sjb		fprintf(outmk, "$(%s_OBJPATHS): %s_make\n\n", p->ident, p->ident);
1073164654Sjb#endif
107470884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
107570884Sjoe		fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident);
107670884Sjoe		if (makeobj)
1077133399Sharti			fprintf(outmk, "$(CRUNCHMAKE) obj && ");
107870884Sjoe		fprintf(outmk, "\\\n");
1079133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) depend &&",
108070112Sjoe		    p->ident);
108170884Sjoe		fprintf(outmk, "\\\n");
1082133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) "
108370884Sjoe		    "$(%s_OBJS))",
108470884Sjoe		    p->ident, p->ident);
108570884Sjoe		fprintf(outmk, "\n");
108670884Sjoe		fprintf(outmk, "%s_clean:\n", p->ident);
1087133399Sharti		fprintf(outmk, "\t(cd $(%s_SRCDIR) && $(CRUNCHMAKE) $(BUILDOPTS) clean cleandepend)\n\n",
108870884Sjoe		    p->ident);
108970884Sjoe	} else {
109070884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
109170884Sjoe		fprintf(outmk, "\t@echo \"** cannot make objs for %s\"\n\n",
109275152Sru		    p->name);
109368569Sjoe	}
10941722Sjkh
109593435Sluigi	if (p->libs) {
109693435Sluigi		fprintf(outmk, "%s_LIBS=", p->ident);
109793435Sluigi		output_strlst(outmk, p->libs);
109893435Sluigi	}
10991722Sjkh
110070884Sjoe	fprintf(outmk, "%s_stub.c:\n", p->name);
110170884Sjoe	fprintf(outmk, "\techo \""
110270884Sjoe	    "int _crunched_%s_stub(int argc, char **argv, char **envp)"
110370884Sjoe	    "{return main(argc,argv,envp);}\" >%s_stub.c\n",
11041722Sjkh	    p->ident, p->name);
110593435Sluigi	fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)",
11061722Sjkh	    p->name, p->name, p->ident);
110793435Sluigi	if (p->libs)
110893435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
1109153687Sceri
111093435Sluigi	fprintf(outmk, "\n");
1111246895Spfg	fprintf(outmk, "\t$(LD) -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)",
11121722Sjkh	    p->name, p->name, p->ident);
111393435Sluigi	if (p->libs)
111493435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
111593435Sluigi	fprintf(outmk, "\n");
111670884Sjoe	fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident);
111770884Sjoe	for (lst = p->keeplist; lst != NULL; lst = lst->next)
111870884Sjoe		fprintf(outmk, "-k _%s ", lst->str);
111970884Sjoe	fprintf(outmk, "%s.lo\n", p->name);
11201722Sjkh}
11211722Sjkh
1122246576Spfgvoid
1123246576Spfgoutput_strlst(FILE *outf, strlst_t *lst)
11241722Sjkh{
112570884Sjoe	for (; lst != NULL; lst = lst->next)
1126153687Sceri		if ( strlen(lst->str) )
1127153687Sceri			fprintf(outf, " %s", lst->str);
112870884Sjoe	fprintf(outf, "\n");
11291722Sjkh}
11301722Sjkh
11311722Sjkh
11321722Sjkh/*
11331722Sjkh * ========================================================================
11341722Sjkh * general library routines
11351722Sjkh *
11361722Sjkh */
11371722Sjkh
1138246576Spfgvoid
1139246576Spfgstatus(const char *str)
11401722Sjkh{
114170884Sjoe	static int lastlen = 0;
114270884Sjoe	int len, spaces;
11431722Sjkh
114470884Sjoe	if (!verbose)
114570884Sjoe		return;
11461722Sjkh
114770884Sjoe	len = strlen(str);
114870884Sjoe	spaces = lastlen - len;
114970884Sjoe	if (spaces < 1)
115070884Sjoe		spaces = 1;
11511722Sjkh
115270884Sjoe	fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
115370884Sjoe	fflush(stderr);
115470884Sjoe	lastlen = len;
11551722Sjkh}
11561722Sjkh
11571722Sjkh
1158246576Spfgvoid
1159246576Spfgout_of_memory(void)
11601722Sjkh{
116170884Sjoe	err(1, "%s: %d: out of memory, stopping", infilename, linenum);
11621722Sjkh}
11631722Sjkh
11641722Sjkh
1165246576Spfgvoid
1166246576Spfgadd_string(strlst_t **listp, char *str)
11671722Sjkh{
116870884Sjoe	strlst_t *p1, *p2;
11691722Sjkh
117070884Sjoe	/* add to end, but be smart about dups */
11711722Sjkh
117270884Sjoe	for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
117370884Sjoe		if (!strcmp(p2->str, str))
117470884Sjoe			return;
11751722Sjkh
117670884Sjoe	p2 = malloc(sizeof(strlst_t));
117770884Sjoe	if (p2) {
117870884Sjoe		p2->next = NULL;
117970884Sjoe		p2->str = strdup(str);
118070884Sjoe    	}
118170884Sjoe	if (!p2 || !p2->str)
118270884Sjoe		out_of_memory();
11831722Sjkh
118470884Sjoe	if (p1 == NULL)
118570884Sjoe		*listp = p2;
118670884Sjoe	else
118770884Sjoe		p1->next = p2;
11881722Sjkh}
11891722Sjkh
1190246576Spfgint
1191246576Spfgsubtract_strlst(strlst_t **lista, strlst_t **listb)
1192153687Sceri{
1193153687Sceri	int subtract_count = 0;
1194153687Sceri	strlst_t *p1;
1195153687Sceri	for (p1 = *listb; p1 != NULL; p1 = p1->next)
1196153687Sceri		if ( in_list(lista, p1->str) ) {
1197153687Sceri			warnx("Will compile library `%s' dynamically", p1->str);
1198153687Sceri			strcat(p1->str, "");
1199153687Sceri			subtract_count++;
1200153687Sceri		}
1201153687Sceri	return subtract_count;
1202153687Sceri}
12031722Sjkh
1204246576Spfgint
1205246576Spfgin_list(strlst_t **listp, char *str)
1206153687Sceri{
1207153687Sceri	strlst_t *p1;
1208153687Sceri	for (p1 = *listp; p1 != NULL; p1 = p1->next)
1209153687Sceri		if (!strcmp(p1->str, str))
1210153687Sceri			return 1;
1211153687Sceri	return 0;
1212153687Sceri}
1213153687Sceri
1214246576Spfgint
1215246576Spfgis_dir(const char *pathname)
12161722Sjkh{
121770884Sjoe	struct stat buf;
12181722Sjkh
121970884Sjoe	if (stat(pathname, &buf) == -1)
122070884Sjoe		return 0;
122170884Sjoe
122270884Sjoe	return S_ISDIR(buf.st_mode);
12231722Sjkh}
12241722Sjkh
1225246576Spfgint
1226246576Spfgis_nonempty_file(const char *pathname)
12271722Sjkh{
122870884Sjoe	struct stat buf;
12291722Sjkh
123070884Sjoe	if (stat(pathname, &buf) == -1)
123170884Sjoe		return 0;
12321722Sjkh
123370884Sjoe	return S_ISREG(buf.st_mode) && buf.st_size > 0;
12341722Sjkh}
1235