crunchgen.c revision 237625
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: head/usr.sbin/crunch/crunchgen/crunchgen.c 237625 2012-06-27 04:39:30Z obrien $");
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
1081722Sjkhvoid status(char *str);
1091722Sjkhvoid out_of_memory(void);
1101722Sjkhvoid add_string(strlst_t **listp, char *str);
1111722Sjkhint is_dir(char *pathname);
1121722Sjkhint is_nonempty_file(char *pathname);
113153687Sceriint subtract_strlst(strlst_t **lista, strlst_t **listb);
114153687Sceriint in_list(strlst_t **listp, char *str);
1151722Sjkh
1161722Sjkh/* helper routines for main() */
1171722Sjkh
1188857Srgrimesvoid usage(void);
1191722Sjkhvoid parse_conf_file(void);
1201722Sjkhvoid gen_outputs(void);
1211722Sjkh
1221722Sjkh
123237625Sobrienint
124237625Sobrienmain(int argc, char **argv)
1251722Sjkh{
12670884Sjoe	char *p;
12770884Sjoe	int optc;
1281722Sjkh
12970884Sjoe	verbose = 1;
13070884Sjoe	readcache = 1;
13170884Sjoe	*outmkname = *outcfname = *execfname = '\0';
1328857Srgrimes
133237574Sobrien	path_make = getenv("MAKE");
134237574Sobrien	if (path_make == NULL || *path_make == '\0')
135237574Sobrien		path_make = "make";
136237574Sobrien
13770884Sjoe	p = getenv("MAKEOBJDIRPREFIX");
13870884Sjoe	if (p == NULL || *p == '\0')
13970884Sjoe		objprefix = "/usr/obj"; /* default */
14070884Sjoe	else
14170884Sjoe		if ((objprefix = strdup(p)) == NULL)
14270884Sjoe			out_of_memory();
14369413Sluigi
14470884Sjoe	while((optc = getopt(argc, argv, "lh:m:c:e:p:foq")) != -1) {
14570884Sjoe		switch(optc) {
14670884Sjoe		case 'f':
14770884Sjoe			readcache = 0;
14870884Sjoe			break;
14970884Sjoe		case 'o':
15070884Sjoe			makeobj = 1;
15170884Sjoe			break;
15270884Sjoe		case 'q':
15370884Sjoe			verbose = 0;
15470884Sjoe			break;
1551722Sjkh
15670884Sjoe		case 'm':
15770884Sjoe			strlcpy(outmkname, optarg, sizeof(outmkname));
15870884Sjoe			break;
15970884Sjoe		case 'p':
16070884Sjoe			if ((objprefix = strdup(optarg)) == NULL)
16170113Sjoe				out_of_memory();
16270113Sjoe			break;
1631722Sjkh
16470884Sjoe		case 'h':
16570884Sjoe			strlcpy(outhdrname, optarg, sizeof(outhdrname));
16670884Sjoe			break;
16770884Sjoe		case 'c':
16870884Sjoe			strlcpy(outcfname, optarg, sizeof(outcfname));
16970884Sjoe			break;
17070884Sjoe		case 'e':
17170884Sjoe			strlcpy(execfname, optarg, sizeof(execfname));
17270884Sjoe			break;
17370884Sjoe
17470884Sjoe		case 'l':
17570884Sjoe			list_mode++;
17670884Sjoe			verbose = 0;
17770884Sjoe			break;
17870884Sjoe
17970884Sjoe		case '?':
18070884Sjoe		default:
18170884Sjoe			usage();
18270884Sjoe		}
1831722Sjkh	}
1841722Sjkh
18570884Sjoe	argc -= optind;
18670884Sjoe	argv += optind;
1871722Sjkh
18870884Sjoe	if (argc != 1)
18970884Sjoe		usage();
1901722Sjkh
19170884Sjoe	/*
19270884Sjoe	 * generate filenames
19370884Sjoe	 */
1941722Sjkh
19570884Sjoe	strlcpy(infilename, argv[0], sizeof(infilename));
1961722Sjkh
19770884Sjoe	/* confname = `basename infilename .conf` */
1981722Sjkh
19970884Sjoe	if ((p=strrchr(infilename, '/')) != NULL)
20070884Sjoe		strlcpy(confname, p + 1, sizeof(confname));
20170884Sjoe	else
20270884Sjoe		strlcpy(confname, infilename, sizeof(confname));
2031722Sjkh
20470884Sjoe	if ((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
20570884Sjoe		*p = '\0';
2061722Sjkh
20770884Sjoe	if (!*outmkname)
20870884Sjoe		snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
20970884Sjoe	if (!*outcfname)
21070884Sjoe		snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
21170884Sjoe	if (!*execfname)
21270884Sjoe		snprintf(execfname, sizeof(execfname), "%s", confname);
21370884Sjoe
21470884Sjoe	snprintf(cachename, sizeof(cachename), "%s.cache", confname);
21570884Sjoe	snprintf(tempfname, sizeof(tempfname), "%s/crunchgen_%sXXXXXX",
21670124Sjoe	getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, confname);
2171722Sjkh
21870884Sjoe	parse_conf_file();
21970884Sjoe	if (list_mode)
22070884Sjoe		exit(goterror);
2216696Sphk
22270884Sjoe	gen_outputs();
2231722Sjkh
22470884Sjoe	exit(goterror);
2251722Sjkh}
2261722Sjkh
2271722Sjkh
228237625Sobrienvoid
229237625Sobrienusage(void)
2301722Sjkh{
23170884Sjoe	fprintf(stderr, "%s%s\n\t%s%s\n", "usage: crunchgen [-foq] ",
23270884Sjoe	    "[-h <makefile-header-name>] [-m <makefile>]",
23370884Sjoe	    "[-p <obj-prefix>] [-c <c-file-name>] [-e <exec-file>] ",
23470884Sjoe	    "<conffile>");
23570884Sjoe	exit(1);
2361722Sjkh}
2371722Sjkh
2381722Sjkh
2391722Sjkh/*
2401722Sjkh * ========================================================================
2411722Sjkh * parse_conf_file subsystem
2421722Sjkh *
2431722Sjkh */
2441722Sjkh
2451722Sjkh/* helper routines for parse_conf_file */
2461722Sjkh
2471722Sjkhvoid parse_one_file(char *filename);
2488857Srgrimesvoid parse_line(char *line, int *fc, char **fv, int nf);
2491722Sjkhvoid add_srcdirs(int argc, char **argv);
2501722Sjkhvoid add_progs(int argc, char **argv);
2511722Sjkhvoid add_link(int argc, char **argv);
2521722Sjkhvoid add_libs(int argc, char **argv);
253153687Scerivoid add_libs_so(int argc, char **argv);
25468750Sjoevoid add_buildopts(int argc, char **argv);
2551722Sjkhvoid add_special(int argc, char **argv);
2561722Sjkh
2571722Sjkhprog_t *find_prog(char *str);
2581722Sjkhvoid add_prog(char *progname);
2591722Sjkh
2601722Sjkh
261237625Sobrienvoid
262237625Sobrienparse_conf_file(void)
2631722Sjkh{
26470884Sjoe	if (!is_nonempty_file(infilename))
26529453Scharnier		errx(1, "fatal: input file \"%s\" not found", infilename);
26670884Sjoe
26770884Sjoe	parse_one_file(infilename);
26870884Sjoe	if (readcache && is_nonempty_file(cachename)) {
26970884Sjoe		reading_cache = 1;
27070884Sjoe		parse_one_file(cachename);
27170884Sjoe	}
2721722Sjkh}
2731722Sjkh
2741722Sjkh
275237625Sobrienvoid
276237625Sobrienparse_one_file(char *filename)
2771722Sjkh{
27870884Sjoe	char *fieldv[MAXFIELDS];
27970884Sjoe	int fieldc;
28070884Sjoe	void (*f)(int c, char **v);
28170884Sjoe	FILE *cf;
28270884Sjoe	char line[MAXLINELEN];
2831722Sjkh
28470884Sjoe	snprintf(line, sizeof(line), "reading %s", filename);
28570884Sjoe	status(line);
28670884Sjoe	strlcpy(curfilename, filename, sizeof(curfilename));
2871722Sjkh
28870884Sjoe	if ((cf = fopen(curfilename, "r")) == NULL) {
28970884Sjoe		warn("%s", curfilename);
29070884Sjoe		goterror = 1;
29170884Sjoe		return;
29270884Sjoe	}
2931722Sjkh
29470884Sjoe	linenum = 0;
29570884Sjoe	while (fgets(line, MAXLINELEN, cf) != NULL) {
29670884Sjoe		linenum++;
29770884Sjoe		parse_line(line, &fieldc, fieldv, MAXFIELDS);
29870884Sjoe
29970884Sjoe		if (fieldc < 1)
30070884Sjoe			continue;
30170884Sjoe
30270884Sjoe		if (!strcmp(fieldv[0], "srcdirs"))
30370884Sjoe			f = add_srcdirs;
30470884Sjoe		else if(!strcmp(fieldv[0], "progs"))
30570884Sjoe			f = add_progs;
30670884Sjoe		else if(!strcmp(fieldv[0], "ln"))
30770884Sjoe			f = add_link;
30870884Sjoe		else if(!strcmp(fieldv[0], "libs"))
30970884Sjoe			f = add_libs;
310153687Sceri		else if(!strcmp(fieldv[0], "libs_so"))
311153687Sceri			f = add_libs_so;
31270884Sjoe		else if(!strcmp(fieldv[0], "buildopts"))
31370884Sjoe			f = add_buildopts;
31470884Sjoe		else if(!strcmp(fieldv[0], "special"))
31570884Sjoe			f = add_special;
31670884Sjoe		else {
31770884Sjoe			warnx("%s:%d: skipping unknown command `%s'",
31870884Sjoe			    curfilename, linenum, fieldv[0]);
31970884Sjoe			goterror = 1;
32070884Sjoe			continue;
32170884Sjoe		}
32270884Sjoe
32370884Sjoe		if (fieldc < 2) {
32470884Sjoe			warnx("%s:%d: %s %s",
32570884Sjoe			    curfilename, linenum, fieldv[0],
32670884Sjoe			    "command needs at least 1 argument, skipping");
32770884Sjoe			goterror = 1;
32870884Sjoe			continue;
32970884Sjoe		}
33070884Sjoe
33170884Sjoe		f(fieldc, fieldv);
3321722Sjkh	}
33370884Sjoe
33470884Sjoe	if (ferror(cf)) {
33570884Sjoe		warn("%s", curfilename);
33670884Sjoe		goterror = 1;
3371722Sjkh	}
33870884Sjoe	fclose(cf);
3391722Sjkh}
3401722Sjkh
3411722Sjkh
342237625Sobrienvoid
343237625Sobrienparse_line(char *line, int *fc, char **fv, int nf)
3441722Sjkh{
34570884Sjoe	char *p;
3461722Sjkh
34770884Sjoe	p = line;
34870884Sjoe	*fc = 0;
3491722Sjkh
35070884Sjoe	while (1) {
35170884Sjoe		while (isspace(*p))
35270884Sjoe			p++;
35370884Sjoe
35470884Sjoe		if (*p == '\0' || *p == '#')
35570884Sjoe			break;
35670884Sjoe
35770884Sjoe		if (*fc < nf)
35870884Sjoe			fv[(*fc)++] = p;
35970884Sjoe
36070884Sjoe		while (*p && !isspace(*p) && *p != '#')
36170884Sjoe			p++;
36270884Sjoe
36370884Sjoe		if (*p == '\0' || *p == '#')
36470884Sjoe			break;
36570884Sjoe
36670884Sjoe		*p++ = '\0';
36770884Sjoe	}
36870884Sjoe
36970884Sjoe	if (*p)
37070884Sjoe		*p = '\0';		/* needed for '#' case */
3711722Sjkh}
3721722Sjkh
3731722Sjkh
374237625Sobrienvoid
375237625Sobrienadd_srcdirs(int argc, char **argv)
3761722Sjkh{
37770884Sjoe	int i;
3781722Sjkh
37970884Sjoe	for (i = 1; i < argc; i++) {
38070884Sjoe		if (is_dir(argv[i]))
38170884Sjoe			add_string(&srcdirs, argv[i]);
38270884Sjoe		else {
38370884Sjoe			warnx("%s:%d: `%s' is not a directory, skipping it",
38470884Sjoe			    curfilename, linenum, argv[i]);
38570884Sjoe			goterror = 1;
38670884Sjoe		}
3871722Sjkh	}
3881722Sjkh}
3891722Sjkh
3901722Sjkh
391237625Sobrienvoid
392237625Sobrienadd_progs(int argc, char **argv)
3931722Sjkh{
39470884Sjoe	int i;
3951722Sjkh
39670884Sjoe	for (i = 1; i < argc; i++)
39770884Sjoe		add_prog(argv[i]);
3981722Sjkh}
3991722Sjkh
4001722Sjkh
401237625Sobrienvoid
402237625Sobrienadd_prog(char *progname)
4031722Sjkh{
40470884Sjoe	prog_t *p1, *p2;
4051722Sjkh
40670884Sjoe	/* add to end, but be smart about dups */
4071722Sjkh
40870884Sjoe	for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
40970884Sjoe		if (!strcmp(p2->name, progname))
41070884Sjoe			return;
4111722Sjkh
41270884Sjoe	p2 = malloc(sizeof(prog_t));
41370884Sjoe	if(p2) {
41470884Sjoe		memset(p2, 0, sizeof(prog_t));
41570884Sjoe		p2->name = strdup(progname);
41670884Sjoe	}
41770884Sjoe	if (!p2 || !p2->name)
41870884Sjoe		out_of_memory();
4191722Sjkh
42070884Sjoe	p2->next = NULL;
42170884Sjoe	if (p1 == NULL)
42270884Sjoe		progs = p2;
42370884Sjoe	else
42470884Sjoe		p1->next = p2;
4251722Sjkh
42670884Sjoe	p2->ident = NULL;
42770884Sjoe	p2->srcdir = NULL;
42870884Sjoe	p2->realsrcdir = NULL;
42970884Sjoe	p2->objdir = NULL;
43070884Sjoe	p2->links = NULL;
43193435Sluigi	p2->libs = NULL;
432153687Sceri	p2->libs_so = NULL;
43370884Sjoe	p2->objs = NULL;
43470884Sjoe	p2->keeplist = NULL;
43570884Sjoe	p2->buildopts = NULL;
43670884Sjoe	p2->goterror = 0;
43770884Sjoe
43870884Sjoe	if (list_mode)
43970884Sjoe		printf("%s\n",progname);
4401722Sjkh}
4411722Sjkh
4421722Sjkh
443237625Sobrienvoid
444237625Sobrienadd_link(int argc, char **argv)
4451722Sjkh{
44670884Sjoe	int i;
44770884Sjoe	prog_t *p = find_prog(argv[1]);
4481722Sjkh
44970884Sjoe	if (p == NULL) {
45070884Sjoe		warnx("%s:%d: no prog %s previously declared, skipping link",
45170884Sjoe		    curfilename, linenum, argv[1]);
45270884Sjoe		goterror = 1;
45370884Sjoe		return;
45470884Sjoe	}
45570884Sjoe
45670884Sjoe	for (i = 2; i < argc; i++) {
45770884Sjoe		if (list_mode)
45870884Sjoe			printf("%s\n",argv[i]);
45970884Sjoe
46070884Sjoe		add_string(&p->links, argv[i]);
46170884Sjoe	}
4621722Sjkh}
4631722Sjkh
4641722Sjkh
465237625Sobrienvoid
466237625Sobrienadd_libs(int argc, char **argv)
4671722Sjkh{
46870884Sjoe	int i;
4691722Sjkh
470153687Sceri	for(i = 1; i < argc; i++) {
47170884Sjoe		add_string(&libs, argv[i]);
472153687Sceri		if ( in_list(&libs_so, argv[i]) )
473153687Sceri			warnx("%s:%d: "
474153687Sceri				"library `%s' specified as dynamic earlier",
475153687Sceri				curfilename, linenum, argv[i]);
476153687Sceri	}
4771722Sjkh}
4781722Sjkh
4791722Sjkh
480237625Sobrienvoid
481237625Sobrienadd_libs_so(int argc, char **argv)
482153687Sceri{
483153687Sceri	int i;
484153687Sceri
485153687Sceri	for(i = 1; i < argc; i++) {
486153687Sceri		add_string(&libs_so, argv[i]);
487153687Sceri		if ( in_list(&libs, argv[i]) )
488153687Sceri			warnx("%s:%d: "
489153687Sceri				"library `%s' specified as static earlier",
490153687Sceri				curfilename, linenum, argv[i]);
491153687Sceri	}
492153687Sceri}
493153687Sceri
494153687Sceri
495237625Sobrienvoid
496237625Sobrienadd_buildopts(int argc, char **argv)
49768750Sjoe{
49870884Sjoe	int i;
49968750Sjoe
50070884Sjoe	for (i = 1; i < argc; i++)
50170884Sjoe		add_string(&buildopts, argv[i]);
50268750Sjoe}
50368750Sjoe
50468750Sjoe
505237625Sobrienvoid
506237625Sobrienadd_special(int argc, char **argv)
5071722Sjkh{
50870884Sjoe	int i;
50970884Sjoe	prog_t *p = find_prog(argv[1]);
5101722Sjkh
51170884Sjoe	if (p == NULL) {
51270884Sjoe		if (reading_cache)
51370884Sjoe			return;
5141722Sjkh
51570884Sjoe		warnx("%s:%d: no prog %s previously declared, skipping special",
51670884Sjoe		    curfilename, linenum, argv[1]);
51770884Sjoe		goterror = 1;
51870884Sjoe		return;
51970884Sjoe	}
5201722Sjkh
52170884Sjoe	if (!strcmp(argv[2], "ident")) {
52270884Sjoe		if (argc != 4)
52370884Sjoe			goto argcount;
52470884Sjoe		if ((p->ident = strdup(argv[3])) == NULL)
52570884Sjoe			out_of_memory();
52670884Sjoe	} else if (!strcmp(argv[2], "srcdir")) {
52770884Sjoe		if (argc != 4)
52870884Sjoe			goto argcount;
52970884Sjoe		if ((p->srcdir = strdup(argv[3])) == NULL)
53070884Sjoe			out_of_memory();
53170884Sjoe	} else if (!strcmp(argv[2], "objdir")) {
53270884Sjoe		if(argc != 4)
53370884Sjoe			goto argcount;
53470884Sjoe		if((p->objdir = strdup(argv[3])) == NULL)
53570884Sjoe			out_of_memory();
53670884Sjoe	} else if (!strcmp(argv[2], "objs")) {
53770884Sjoe		p->objs = NULL;
53870884Sjoe		for (i = 3; i < argc; i++)
53970884Sjoe			add_string(&p->objs, argv[i]);
54070884Sjoe	} else if (!strcmp(argv[2], "objpaths")) {
54170884Sjoe		p->objpaths = NULL;
54270884Sjoe		for (i = 3; i < argc; i++)
54370884Sjoe			add_string(&p->objpaths, argv[i]);
54470884Sjoe	} else if (!strcmp(argv[2], "keep")) {
54570884Sjoe		p->keeplist = NULL;
54670884Sjoe		for(i = 3; i < argc; i++)
54770884Sjoe			add_string(&p->keeplist, argv[i]);
54870884Sjoe	} else if (!strcmp(argv[2], "objvar")) {
54970884Sjoe		if(argc != 4)
55070884Sjoe			goto argcount;
55170884Sjoe		if ((p->objvar = strdup(argv[3])) == NULL)
55270884Sjoe			out_of_memory();
55370884Sjoe	} else if (!strcmp(argv[2], "buildopts")) {
55470884Sjoe		p->buildopts = NULL;
55570884Sjoe		for (i = 3; i < argc; i++)
55670884Sjoe			add_string(&p->buildopts, argv[i]);
55793435Sluigi	} else if (!strcmp(argv[2], "lib")) {
55893435Sluigi		for (i = 3; i < argc; i++)
55993435Sluigi			add_string(&p->libs, argv[i]);
56070884Sjoe	} else {
56170884Sjoe		warnx("%s:%d: bad parameter name `%s', skipping line",
56270884Sjoe		    curfilename, linenum, argv[2]);
56370884Sjoe		goterror = 1;
56470884Sjoe	}
56570884Sjoe	return;
5661722Sjkh
5671722Sjkh argcount:
56870884Sjoe	warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"",
5691722Sjkh	    curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]);
57070884Sjoe	goterror = 1;
5711722Sjkh}
5721722Sjkh
5731722Sjkh
5741722Sjkhprog_t *find_prog(char *str)
5751722Sjkh{
57670884Sjoe	prog_t *p;
5771722Sjkh
57870884Sjoe	for (p = progs; p != NULL; p = p->next)
57970884Sjoe		if (!strcmp(p->name, str))
58070884Sjoe			return p;
5811722Sjkh
58270884Sjoe	return NULL;
5831722Sjkh}
5841722Sjkh
5851722Sjkh
5861722Sjkh/*
5871722Sjkh * ========================================================================
5881722Sjkh * gen_outputs subsystem
5891722Sjkh *
5901722Sjkh */
5911722Sjkh
5921722Sjkh/* helper subroutines */
5931722Sjkh
5941722Sjkhvoid remove_error_progs(void);
5951722Sjkhvoid fillin_program(prog_t *p);
5961722Sjkhvoid gen_specials_cache(void);
5971722Sjkhvoid gen_output_makefile(void);
5981722Sjkhvoid gen_output_cfile(void);
5991722Sjkh
6001722Sjkhvoid fillin_program_objs(prog_t *p, char *path);
6011722Sjkhvoid top_makefile_rules(FILE *outmk);
6021722Sjkhvoid prog_makefile_rules(FILE *outmk, prog_t *p);
6031722Sjkhvoid output_strlst(FILE *outf, strlst_t *lst);
6041722Sjkhchar *genident(char *str);
6051722Sjkhchar *dir_search(char *progname);
6061722Sjkh
6071722Sjkh
608237625Sobrienvoid
609237625Sobriengen_outputs(void)
6101722Sjkh{
61170884Sjoe	prog_t *p;
6121722Sjkh
61370884Sjoe	for (p = progs; p != NULL; p = p->next)
61470884Sjoe		fillin_program(p);
6151722Sjkh
61670884Sjoe	remove_error_progs();
61770884Sjoe	gen_specials_cache();
61870884Sjoe	gen_output_cfile();
61970884Sjoe	gen_output_makefile();
62070884Sjoe	status("");
62170884Sjoe	fprintf(stderr,
622237574Sobrien	    "Run \"%s -f %s\" to build crunched binary.\n",
623237574Sobrien	    path_make, outmkname);
6241722Sjkh}
6251722Sjkh
62656995Sluigi/*
62756995Sluigi * run the makefile for the program to find which objects are necessary
62856995Sluigi */
629237625Sobrienvoid
630237625Sobrienfillin_program(prog_t *p)
6311722Sjkh{
63270884Sjoe	char path[MAXPATHLEN];
63370884Sjoe	char line[MAXLINELEN];
63470884Sjoe	FILE *f;
6351722Sjkh
63670884Sjoe	snprintf(line, MAXLINELEN, "filling in parms for %s", p->name);
63770884Sjoe	status(line);
6381722Sjkh
63970884Sjoe	if (!p->ident)
64070884Sjoe		p->ident = genident(p->name);
64170331Sjoe
64270884Sjoe	/* look for the source directory if one wasn't specified by a special */
64370884Sjoe	if (!p->srcdir) {
64470884Sjoe		p->srcdir = dir_search(p->name);
64570884Sjoe	}
64670112Sjoe
64770884Sjoe	/* Determine the actual srcdir (maybe symlinked). */
64870884Sjoe	if (p->srcdir) {
64970884Sjoe		snprintf(line, MAXLINELEN, "cd %s && echo -n `/bin/pwd`",
65070884Sjoe		    p->srcdir);
65170884Sjoe		f = popen(line,"r");
65270884Sjoe		if (!f)
65370884Sjoe			errx(1, "Can't execute: %s\n", line);
65470331Sjoe
65570884Sjoe		path[0] = '\0';
65670884Sjoe		fgets(path, sizeof path, f);
65770884Sjoe		if (pclose(f))
65870884Sjoe			errx(1, "Can't execute: %s\n", line);
65970331Sjoe
66070884Sjoe		if (!*path)
66170884Sjoe			errx(1, "Can't perform pwd on: %s\n", p->srcdir);
66270331Sjoe
66370884Sjoe		p->realsrcdir = strdup(path);
66470884Sjoe	}
66570112Sjoe
66670884Sjoe	/* Unless the option to make object files was specified the
66770884Sjoe	* the objects will be built in the source directory unless
66870884Sjoe	* an object directory already exists.
66970884Sjoe	*/
67070884Sjoe	if (!makeobj && !p->objdir && p->srcdir) {
67170884Sjoe		snprintf(line, sizeof line, "%s/%s", objprefix, p->realsrcdir);
67270884Sjoe		if (is_dir(line)) {
67370884Sjoe			if ((p->objdir = strdup(line)) == NULL)
67470884Sjoe			out_of_memory();
67570884Sjoe		} else
67670884Sjoe			p->objdir = p->realsrcdir;
67770884Sjoe	}
67870884Sjoe
67970884Sjoe	/*
68070884Sjoe	* XXX look for a Makefile.{name} in local directory first.
68170884Sjoe	* This lets us override the original Makefile.
68270884Sjoe	*/
68370884Sjoe	snprintf(path, sizeof(path), "Makefile.%s", p->name);
68470884Sjoe	if (is_nonempty_file(path)) {
68570884Sjoe		snprintf(line, MAXLINELEN, "Using %s for %s", path, p->name);
68670884Sjoe		status(line);
68770114Sjoe	} else
68870884Sjoe		if (p->srcdir)
68970884Sjoe			snprintf(path, sizeof(path), "%s/Makefile", p->srcdir);
69070884Sjoe	if (!p->objs && p->srcdir && is_nonempty_file(path))
69170884Sjoe		fillin_program_objs(p, path);
6921722Sjkh
69381700Sjoe	if (!p->srcdir && !p->objdir && verbose)
69470884Sjoe		warnx("%s: %s: %s",
69570884Sjoe		    "warning: could not find source directory",
69670884Sjoe		    infilename, p->name);
69770884Sjoe	if (!p->objs && verbose)
69870884Sjoe		warnx("%s: %s: warning: could not find any .o files",
69970884Sjoe		    infilename, p->name);
70070880Sjoe
70181823Sjoe	if ((!p->srcdir || !p->objdir) && !p->objs)
70270884Sjoe		p->goterror = 1;
7031722Sjkh}
7041722Sjkh
705237625Sobrienvoid
706237625Sobrienfillin_program_objs(prog_t *p, char *path)
7071722Sjkh{
70870884Sjoe	char *obj, *cp;
70970884Sjoe	int fd, rc;
71070884Sjoe	FILE *f;
71170884Sjoe	char *objvar="OBJS";
71270884Sjoe	strlst_t *s;
71370884Sjoe	char line[MAXLINELEN];
7141722Sjkh
71570884Sjoe	/* discover the objs from the srcdir Makefile */
7161722Sjkh
71770884Sjoe	if ((fd = mkstemp(tempfname)) == -1) {
71870884Sjoe		perror(tempfname);
71970884Sjoe		exit(1);
72070884Sjoe	}
72170884Sjoe	if ((f = fdopen(fd, "w")) == NULL) {
72270884Sjoe		warn("%s", tempfname);
72370884Sjoe		goterror = 1;
72470884Sjoe		return;
72570884Sjoe	}
72670884Sjoe	if (p->objvar)
72770884Sjoe		objvar = p->objvar;
7288857Srgrimes
72970884Sjoe	/*
73070884Sjoe	* XXX include outhdrname (e.g. to contain Make variables)
73170884Sjoe	*/
73270884Sjoe	if (outhdrname[0] != '\0')
73370884Sjoe		fprintf(f, ".include \"%s\"\n", outhdrname);
73470884Sjoe	fprintf(f, ".include \"%s\"\n", path);
735187943Sobrien	fprintf(f, ".POSIX:\n");
73670884Sjoe	if (buildopts) {
73770884Sjoe		fprintf(f, "BUILDOPTS+=");
73870884Sjoe		output_strlst(f, buildopts);
73970884Sjoe	}
740187131Sobrien	fprintf(f, ".if defined(PROG)\n");
741187131Sobrien	fprintf(f, "%s?=${PROG}.o\n", objvar);
74270884Sjoe	fprintf(f, ".endif\n");
74370884Sjoe	fprintf(f, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar);
74468569Sjoe
745113886Sru	fprintf(f, "crunchgen_objs:\n"
746237574Sobrien	    "\t@cd %s && %s -f %s $(BUILDOPTS) $(%s_OPTS)",
747237574Sobrien	    p->srcdir, path_make, tempfname, p->ident);
74870884Sjoe	for (s = p->buildopts; s != NULL; s = s->next)
74970884Sjoe		fprintf(f, " %s", s->str);
75070884Sjoe	fprintf(f, " loop\n");
75168569Sjoe
75270884Sjoe	fclose(f);
7531722Sjkh
754237574Sobrien	snprintf(line, MAXLINELEN, "cd %s && %s -f %s -B crunchgen_objs",
755237574Sobrien	     p->srcdir, path_make, tempfname);
75670884Sjoe	if ((f = popen(line, "r")) == NULL) {
75770884Sjoe		warn("submake pipe");
75870884Sjoe		goterror = 1;
75970884Sjoe		return;
76070884Sjoe	}
7611722Sjkh
76270884Sjoe	while(fgets(line, MAXLINELEN, f)) {
76370884Sjoe		if (strncmp(line, "OBJS= ", 6)) {
76470884Sjoe			warnx("make error: %s", line);
76570884Sjoe			goterror = 1;
76670884Sjoe			continue;
76770884Sjoe		}
76870884Sjoe
76970884Sjoe		cp = line + 6;
77070884Sjoe		while (isspace(*cp))
77170884Sjoe			cp++;
77270884Sjoe
77370884Sjoe		while(*cp) {
77470884Sjoe			obj = cp;
77570884Sjoe			while (*cp && !isspace(*cp))
77670884Sjoe				cp++;
77770884Sjoe			if (*cp)
77870884Sjoe				*cp++ = '\0';
77970884Sjoe			add_string(&p->objs, obj);
78070884Sjoe			while (isspace(*cp))
78170884Sjoe				cp++;
78270884Sjoe		}
7831722Sjkh	}
78470884Sjoe
78570884Sjoe	if ((rc=pclose(f)) != 0) {
78670884Sjoe		warnx("make error: make returned %d", rc);
78770884Sjoe		goterror = 1;
7881722Sjkh	}
78970884Sjoe
79070884Sjoe	unlink(tempfname);
7911722Sjkh}
7921722Sjkh
793237625Sobrienvoid
794237625Sobrienremove_error_progs(void)
7951722Sjkh{
79670884Sjoe	prog_t *p1, *p2;
7971722Sjkh
79870884Sjoe	p1 = NULL; p2 = progs;
79970884Sjoe	while (p2 != NULL) {
80070884Sjoe		if (!p2->goterror)
80170884Sjoe			p1 = p2, p2 = p2->next;
80270884Sjoe		else {
80370884Sjoe			/* delete it from linked list */
80470884Sjoe			warnx("%s: %s: ignoring program because of errors",
80570884Sjoe			    infilename, p2->name);
80670884Sjoe			if (p1)
80770884Sjoe				p1->next = p2->next;
80870884Sjoe			else
80970884Sjoe				progs = p2->next;
81070884Sjoe			p2 = p2->next;
81170884Sjoe		}
8121722Sjkh	}
8131722Sjkh}
8141722Sjkh
815237625Sobrienvoid
816237625Sobriengen_specials_cache(void)
8171722Sjkh{
81870884Sjoe	FILE *cachef;
81970884Sjoe	prog_t *p;
82070884Sjoe	char line[MAXLINELEN];
8211722Sjkh
82270884Sjoe	snprintf(line, MAXLINELEN, "generating %s", cachename);
82370884Sjoe	status(line);
8241722Sjkh
82570884Sjoe	if ((cachef = fopen(cachename, "w")) == NULL) {
82670884Sjoe		warn("%s", cachename);
82770884Sjoe		goterror = 1;
82870884Sjoe		return;
82970884Sjoe	}
8301722Sjkh
83170884Sjoe	fprintf(cachef, "# %s - parm cache generated from %s by crunchgen "
83270884Sjoe	    " %s\n\n",
8331722Sjkh	    cachename, infilename, CRUNCH_VERSION);
8341722Sjkh
83570884Sjoe	for (p = progs; p != NULL; p = p->next) {
83670884Sjoe		fprintf(cachef, "\n");
83770884Sjoe		if (p->srcdir)
83870884Sjoe			fprintf(cachef, "special %s srcdir %s\n",
83970884Sjoe			    p->name, p->srcdir);
84070884Sjoe		if (p->objdir)
84170884Sjoe			fprintf(cachef, "special %s objdir %s\n",
84270884Sjoe			    p->name, p->objdir);
84370884Sjoe		if (p->objs) {
84470884Sjoe			fprintf(cachef, "special %s objs", p->name);
84570884Sjoe			output_strlst(cachef, p->objs);
84670884Sjoe		}
84770884Sjoe		if (p->objpaths) {
84870884Sjoe			fprintf(cachef, "special %s objpaths", p->name);
84970884Sjoe			output_strlst(cachef, p->objpaths);
85070884Sjoe		}
8511722Sjkh	}
85270884Sjoe	fclose(cachef);
8531722Sjkh}
8541722Sjkh
8551722Sjkh
856237625Sobrienvoid
857237625Sobriengen_output_makefile(void)
8581722Sjkh{
85970884Sjoe	prog_t *p;
86070884Sjoe	FILE *outmk;
86170884Sjoe	char line[MAXLINELEN];
8621722Sjkh
86370884Sjoe	snprintf(line, MAXLINELEN, "generating %s", outmkname);
86470884Sjoe	status(line);
8651722Sjkh
86670884Sjoe	if ((outmk = fopen(outmkname, "w")) == NULL) {
86770884Sjoe		warn("%s", outmkname);
86870884Sjoe		goterror = 1;
86970884Sjoe		return;
87070884Sjoe	}
8711722Sjkh
87270884Sjoe	fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
8731722Sjkh	    outmkname, infilename, CRUNCH_VERSION);
8741722Sjkh
87570884Sjoe	if (outhdrname[0] != '\0')
87670884Sjoe		fprintf(outmk, ".include \"%s\"\n", outhdrname);
8771722Sjkh
87870884Sjoe	top_makefile_rules(outmk);
87970884Sjoe	for (p = progs; p != NULL; p = p->next)
88070884Sjoe		prog_makefile_rules(outmk, p);
88170884Sjoe
88270884Sjoe	fprintf(outmk, "\n# ========\n");
88370884Sjoe	fclose(outmk);
8841722Sjkh}
8851722Sjkh
8861722Sjkh
887237625Sobrienvoid
888237625Sobriengen_output_cfile(void)
8891722Sjkh{
89070884Sjoe	extern char *crunched_skel[];
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++ = '_';
94870884Sjoe		else if (*s == '_' || isalnum(*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
976237625Sobrienvoid
977237625Sobrientop_makefile_rules(FILE *outmk)
9781722Sjkh{
97970884Sjoe	prog_t *p;
9801722Sjkh
981153687Sceri	if ( subtract_strlst(&libs, &libs_so) )
982153687Sceri		fprintf(outmk, "# NOTE: Some LIBS declarations below overridden by LIBS_SO\n");
983153687Sceri
98478520Sjoe	fprintf(outmk, "LIBS+=");
98570884Sjoe	output_strlst(outmk, libs);
9861722Sjkh
987153687Sceri	fprintf(outmk, "LIBS_SO+=");
988153687Sceri	output_strlst(outmk, libs_so);
989153687Sceri
99070884Sjoe	if (makeobj) {
99170884Sjoe		fprintf(outmk, "MAKEOBJDIRPREFIX?=%s\n", objprefix);
992133399Sharti		fprintf(outmk, "MAKEENV=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX)\n");
993133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKEENV) $(MAKE)\n");
99470884Sjoe	} else {
995133399Sharti		fprintf(outmk, "CRUNCHMAKE=$(MAKE)\n");
99670884Sjoe	}
99770112Sjoe
99870884Sjoe	if (buildopts) {
99970884Sjoe		fprintf(outmk, "BUILDOPTS+=");
100070884Sjoe		output_strlst(outmk, buildopts);
100170884Sjoe	}
100268750Sjoe
100370884Sjoe	fprintf(outmk, "CRUNCHED_OBJS=");
100470884Sjoe	for (p = progs; p != NULL; p = p->next)
100570884Sjoe		fprintf(outmk, " %s.lo", p->name);
100670884Sjoe	fprintf(outmk, "\n");
10071722Sjkh
100870884Sjoe	fprintf(outmk, "SUBMAKE_TARGETS=");
100970884Sjoe	for (p = progs; p != NULL; p = p->next)
101070884Sjoe		fprintf(outmk, " %s_make", p->ident);
101170884Sjoe	fprintf(outmk, "\nSUBCLEAN_TARGETS=");
101270884Sjoe	for (p = progs; p != NULL; p = p->next)
101370884Sjoe		fprintf(outmk, " %s_clean", p->ident);
101470884Sjoe	fprintf(outmk, "\n\n");
10151722Sjkh
101670884Sjoe	fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
101770884Sjoe	fprintf(outmk, "exe: %s\n", execfname);
1018164504Sjb	fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS) $(SUBMAKE_TARGETS)\n", execfname, execfname);
1019153687Sceri	fprintf(outmk, ".if defined(LIBS_SO) && !empty(LIBS_SO)\n");
1020153687Sceri	fprintf(outmk, "\t$(CC) -o %s %s.o $(CRUNCHED_OBJS) \\\n",
1021153687Sceri	    execfname, execfname);
1022153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bstatic $(LIBS) \\\n");
1023153687Sceri	fprintf(outmk, "\t\t-Xlinker -Bdynamic $(LIBS_SO)\n");
1024153687Sceri	fprintf(outmk, ".else\n");
102570884Sjoe	fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
10261722Sjkh	    execfname, execfname);
1027153687Sceri	fprintf(outmk, ".endif\n");
102870884Sjoe	fprintf(outmk, "\tstrip %s\n", execfname);
102970884Sjoe	fprintf(outmk, "realclean: clean subclean\n");
103070884Sjoe	fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", execfname);
103170884Sjoe	fprintf(outmk, "subclean: $(SUBCLEAN_TARGETS)\n");
10321722Sjkh}
10331722Sjkh
10341722Sjkh
1035237625Sobrienvoid
1036237625Sobrienprog_makefile_rules(FILE *outmk, prog_t *p)
10371722Sjkh{
103870884Sjoe	strlst_t *lst;
103930120Sjoerg
104070884Sjoe	fprintf(outmk, "\n# -------- %s\n\n", p->name);
10411722Sjkh
104281700Sjoe	fprintf(outmk, "%s_OBJDIR=", p->ident);
104381700Sjoe	if (p->objdir)
104481700Sjoe		fprintf(outmk, "%s", p->objdir);
104581700Sjoe	else
104681700Sjoe		fprintf(outmk, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n",
104781700Sjoe		    p->ident);
104881700Sjoe	fprintf(outmk, "\n");
104981700Sjoe
1050164571Sjb	fprintf(outmk, "%s_OBJPATHS=", p->ident);
1051164571Sjb	if (p->objpaths)
1052164571Sjb		output_strlst(outmk, p->objpaths);
1053164571Sjb	else {
1054164571Sjb		for (lst = p->objs; lst != NULL; lst = lst->next) {
1055164571Sjb			fprintf(outmk, " $(%s_OBJDIR)/%s", p->ident, lst->str);
1056164571Sjb		}
1057164571Sjb		fprintf(outmk, "\n");
1058164571Sjb	}
1059164571Sjb
106070884Sjoe	if (p->srcdir && p->objs) {
106170884Sjoe		fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
106270884Sjoe		fprintf(outmk, "%s_REALSRCDIR=%s\n", p->ident, p->realsrcdir);
106370112Sjoe
106470884Sjoe		fprintf(outmk, "%s_OBJS=", p->ident);
106570884Sjoe		output_strlst(outmk, p->objs);
106670884Sjoe		if (p->buildopts != NULL) {
106770884Sjoe			fprintf(outmk, "%s_OPTS+=", p->ident);
106870884Sjoe			output_strlst(outmk, p->buildopts);
106970884Sjoe		}
1070164654Sjb#if 0
1071164571Sjb		fprintf(outmk, "$(%s_OBJPATHS): %s_make\n\n", p->ident, p->ident);
1072164654Sjb#endif
107370884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
107470884Sjoe		fprintf(outmk, "\t(cd $(%s_SRCDIR) && ", p->ident);
107570884Sjoe		if (makeobj)
1076133399Sharti			fprintf(outmk, "$(CRUNCHMAKE) obj && ");
107770884Sjoe		fprintf(outmk, "\\\n");
1078133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) depend &&",
107970112Sjoe		    p->ident);
108070884Sjoe		fprintf(outmk, "\\\n");
1081133399Sharti		fprintf(outmk, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) "
108270884Sjoe		    "$(%s_OBJS))",
108370884Sjoe		    p->ident, p->ident);
108470884Sjoe		fprintf(outmk, "\n");
108570884Sjoe		fprintf(outmk, "%s_clean:\n", p->ident);
1086133399Sharti		fprintf(outmk, "\t(cd $(%s_SRCDIR) && $(CRUNCHMAKE) $(BUILDOPTS) clean cleandepend)\n\n",
108770884Sjoe		    p->ident);
108870884Sjoe	} else {
108970884Sjoe		fprintf(outmk, "%s_make:\n", p->ident);
109070884Sjoe		fprintf(outmk, "\t@echo \"** cannot make objs for %s\"\n\n",
109175152Sru		    p->name);
109268569Sjoe	}
10931722Sjkh
109493435Sluigi	if (p->libs) {
109593435Sluigi		fprintf(outmk, "%s_LIBS=", p->ident);
109693435Sluigi		output_strlst(outmk, p->libs);
109793435Sluigi	}
10981722Sjkh
109970884Sjoe	fprintf(outmk, "%s_stub.c:\n", p->name);
110070884Sjoe	fprintf(outmk, "\techo \""
110170884Sjoe	    "int _crunched_%s_stub(int argc, char **argv, char **envp)"
110270884Sjoe	    "{return main(argc,argv,envp);}\" >%s_stub.c\n",
11031722Sjkh	    p->ident, p->name);
110493435Sluigi	fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)",
11051722Sjkh	    p->name, p->name, p->ident);
110693435Sluigi	if (p->libs)
110793435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
1108153687Sceri
110993435Sluigi	fprintf(outmk, "\n");
111093435Sluigi	fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)",
11111722Sjkh	    p->name, p->name, p->ident);
111293435Sluigi	if (p->libs)
111393435Sluigi		fprintf(outmk, " $(%s_LIBS)", p->ident);
111493435Sluigi	fprintf(outmk, "\n");
111570884Sjoe	fprintf(outmk, "\tcrunchide -k _crunched_%s_stub ", p->ident);
111670884Sjoe	for (lst = p->keeplist; lst != NULL; lst = lst->next)
111770884Sjoe		fprintf(outmk, "-k _%s ", lst->str);
111870884Sjoe	fprintf(outmk, "%s.lo\n", p->name);
11191722Sjkh}
11201722Sjkh
1121237625Sobrienvoid
1122237625Sobrienoutput_strlst(FILE *outf, strlst_t *lst)
11231722Sjkh{
112470884Sjoe	for (; lst != NULL; lst = lst->next)
1125153687Sceri		if ( strlen(lst->str) )
1126153687Sceri			fprintf(outf, " %s", lst->str);
112770884Sjoe	fprintf(outf, "\n");
11281722Sjkh}
11291722Sjkh
11301722Sjkh
11311722Sjkh/*
11321722Sjkh * ========================================================================
11331722Sjkh * general library routines
11341722Sjkh *
11351722Sjkh */
11361722Sjkh
1137237625Sobrienvoid
1138237625Sobrienstatus(char *str)
11391722Sjkh{
114070884Sjoe	static int lastlen = 0;
114170884Sjoe	int len, spaces;
11421722Sjkh
114370884Sjoe	if (!verbose)
114470884Sjoe		return;
11451722Sjkh
114670884Sjoe	len = strlen(str);
114770884Sjoe	spaces = lastlen - len;
114870884Sjoe	if (spaces < 1)
114970884Sjoe		spaces = 1;
11501722Sjkh
115170884Sjoe	fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
115270884Sjoe	fflush(stderr);
115370884Sjoe	lastlen = len;
11541722Sjkh}
11551722Sjkh
11561722Sjkh
1157237625Sobrienvoid
1158237625Sobrienout_of_memory(void)
11591722Sjkh{
116070884Sjoe	err(1, "%s: %d: out of memory, stopping", infilename, linenum);
11611722Sjkh}
11621722Sjkh
11631722Sjkh
1164237625Sobrienvoid
1165237625Sobrienadd_string(strlst_t **listp, char *str)
11661722Sjkh{
116770884Sjoe	strlst_t *p1, *p2;
11681722Sjkh
116970884Sjoe	/* add to end, but be smart about dups */
11701722Sjkh
117170884Sjoe	for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
117270884Sjoe		if (!strcmp(p2->str, str))
117370884Sjoe			return;
11741722Sjkh
117570884Sjoe	p2 = malloc(sizeof(strlst_t));
117670884Sjoe	if (p2) {
117770884Sjoe		p2->next = NULL;
117870884Sjoe		p2->str = strdup(str);
117970884Sjoe    	}
118070884Sjoe	if (!p2 || !p2->str)
118170884Sjoe		out_of_memory();
11821722Sjkh
118370884Sjoe	if (p1 == NULL)
118470884Sjoe		*listp = p2;
118570884Sjoe	else
118670884Sjoe		p1->next = p2;
11871722Sjkh}
11881722Sjkh
1189237625Sobrienint
1190237625Sobriensubtract_strlst(strlst_t **lista, strlst_t **listb)
1191153687Sceri{
1192153687Sceri	int subtract_count = 0;
1193153687Sceri	strlst_t *p1;
1194153687Sceri	for (p1 = *listb; p1 != NULL; p1 = p1->next)
1195153687Sceri		if ( in_list(lista, p1->str) ) {
1196153687Sceri			warnx("Will compile library `%s' dynamically", p1->str);
1197153687Sceri			strcat(p1->str, "");
1198153687Sceri			subtract_count++;
1199153687Sceri		}
1200153687Sceri	return subtract_count;
1201153687Sceri}
12021722Sjkh
1203237625Sobrienint
1204237625Sobrienin_list(strlst_t **listp, char *str)
1205153687Sceri{
1206153687Sceri	strlst_t *p1;
1207153687Sceri	for (p1 = *listp; p1 != NULL; p1 = p1->next)
1208153687Sceri		if (!strcmp(p1->str, str))
1209153687Sceri			return 1;
1210153687Sceri	return 0;
1211153687Sceri}
1212153687Sceri
1213237625Sobrienint
1214237625Sobrienis_dir(char *pathname)
12151722Sjkh{
121670884Sjoe	struct stat buf;
12171722Sjkh
121870884Sjoe	if (stat(pathname, &buf) == -1)
121970884Sjoe		return 0;
122070884Sjoe
122170884Sjoe	return S_ISDIR(buf.st_mode);
12221722Sjkh}
12231722Sjkh
1224237625Sobrienint
1225237625Sobrienis_nonempty_file(char *pathname)
12261722Sjkh{
122770884Sjoe	struct stat buf;
12281722Sjkh
122970884Sjoe	if (stat(pathname, &buf) == -1)
123070884Sjoe		return 0;
12311722Sjkh
123270884Sjoe	return S_ISREG(buf.st_mode) && buf.st_size > 0;
12331722Sjkh}
1234