xref: /freebsd/usr.sbin/crunch/crunchgen/crunchgen.c (revision 154fd6a9901bd37f6db53bca1f58ffb766af9e9d)
1de566360SJordan K. Hubbard /*
2de566360SJordan K. Hubbard  * Copyright (c) 1994 University of Maryland
3de566360SJordan K. Hubbard  * All Rights Reserved.
4de566360SJordan K. Hubbard  *
5de566360SJordan K. Hubbard  * Permission to use, copy, modify, distribute, and sell this software and its
6de566360SJordan K. Hubbard  * documentation for any purpose is hereby granted without fee, provided that
7de566360SJordan K. Hubbard  * the above copyright notice appear in all copies and that both that
8de566360SJordan K. Hubbard  * copyright notice and this permission notice appear in supporting
9de566360SJordan K. Hubbard  * documentation, and that the name of U.M. not be used in advertising or
10de566360SJordan K. Hubbard  * publicity pertaining to distribution of the software without specific,
11de566360SJordan K. Hubbard  * written prior permission.  U.M. makes no representations about the
12de566360SJordan K. Hubbard  * suitability of this software for any purpose.  It is provided "as is"
13de566360SJordan K. Hubbard  * without express or implied warranty.
14de566360SJordan K. Hubbard  *
15de566360SJordan K. Hubbard  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16de566360SJordan K. Hubbard  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
17de566360SJordan K. Hubbard  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18de566360SJordan K. Hubbard  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19de566360SJordan K. Hubbard  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20de566360SJordan K. Hubbard  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21de566360SJordan K. Hubbard  *
22de566360SJordan K. Hubbard  * Author: James da Silva, Systems Design and Analysis Group
23de566360SJordan K. Hubbard  *			   Computer Science Department
24de566360SJordan K. Hubbard  *			   University of Maryland at College Park
25de566360SJordan K. Hubbard  */
26de566360SJordan K. Hubbard /*
27de566360SJordan K. Hubbard  * ========================================================================
28de566360SJordan K. Hubbard  * crunchgen.c
29de566360SJordan K. Hubbard  *
30de566360SJordan K. Hubbard  * Generates a Makefile and main C file for a crunched executable,
31de566360SJordan K. Hubbard  * from specs given in a .conf file.
32de566360SJordan K. Hubbard  */
33de566360SJordan K. Hubbard #include <stdlib.h>
34de566360SJordan K. Hubbard #include <unistd.h>
35de566360SJordan K. Hubbard #include <stdio.h>
36de566360SJordan K. Hubbard #include <ctype.h>
37de566360SJordan K. Hubbard #include <string.h>
38de566360SJordan K. Hubbard 
39de566360SJordan K. Hubbard #include <sys/types.h>
40de566360SJordan K. Hubbard #include <sys/stat.h>
41de566360SJordan K. Hubbard #include <sys/param.h>
42de566360SJordan K. Hubbard 
43de566360SJordan K. Hubbard #define CRUNCH_VERSION	"0.2"
44de566360SJordan K. Hubbard 
45de566360SJordan K. Hubbard #define MAXLINELEN	16384
46de566360SJordan K. Hubbard #define MAXFIELDS 	 2048
47de566360SJordan K. Hubbard 
48de566360SJordan K. Hubbard 
49de566360SJordan K. Hubbard /* internal representation of conf file: */
50de566360SJordan K. Hubbard 
51de566360SJordan K. Hubbard /* simple lists of strings suffice for most parms */
52de566360SJordan K. Hubbard 
53de566360SJordan K. Hubbard typedef struct strlst {
54de566360SJordan K. Hubbard     struct strlst *next;
55de566360SJordan K. Hubbard     char *str;
56de566360SJordan K. Hubbard } strlst_t;
57de566360SJordan K. Hubbard 
58de566360SJordan K. Hubbard /* progs have structure, each field can be set with "special" or calculated */
59de566360SJordan K. Hubbard 
60de566360SJordan K. Hubbard typedef struct prog {
61de566360SJordan K. Hubbard     struct prog *next;
62de566360SJordan K. Hubbard     char *name, *ident;
63de566360SJordan K. Hubbard     char *srcdir, *objdir;
64de566360SJordan K. Hubbard     strlst_t *objs, *objpaths;
65de566360SJordan K. Hubbard     strlst_t *links;
66de566360SJordan K. Hubbard     int goterror;
67de566360SJordan K. Hubbard } prog_t;
68de566360SJordan K. Hubbard 
69de566360SJordan K. Hubbard 
70de566360SJordan K. Hubbard /* global state */
71de566360SJordan K. Hubbard 
72de566360SJordan K. Hubbard strlst_t *srcdirs = NULL;
73de566360SJordan K. Hubbard strlst_t *libs    = NULL;
74de566360SJordan K. Hubbard prog_t   *progs   = NULL;
75de566360SJordan K. Hubbard 
76de566360SJordan K. Hubbard char line[MAXLINELEN];
77de566360SJordan K. Hubbard 
78de566360SJordan K. Hubbard char confname[MAXPATHLEN], infilename[MAXPATHLEN];
79de566360SJordan K. Hubbard char outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN];
80de566360SJordan K. Hubbard char tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
81de566360SJordan K. Hubbard int linenum = -1;
82de566360SJordan K. Hubbard int goterror = 0;
83de566360SJordan K. Hubbard 
84de566360SJordan K. Hubbard char *pname = "crunchgen";
85de566360SJordan K. Hubbard 
86de566360SJordan K. Hubbard int verbose, readcache;	/* options */
87de566360SJordan K. Hubbard int reading_cache;
88de566360SJordan K. Hubbard 
89fb7f926eSPoul-Henning Kamp int list_mode;
90fb7f926eSPoul-Henning Kamp 
91de566360SJordan K. Hubbard /* general library routines */
92de566360SJordan K. Hubbard 
93de566360SJordan K. Hubbard void status(char *str);
94de566360SJordan K. Hubbard void out_of_memory(void);
95de566360SJordan K. Hubbard void add_string(strlst_t **listp, char *str);
96de566360SJordan K. Hubbard int is_dir(char *pathname);
97de566360SJordan K. Hubbard int is_nonempty_file(char *pathname);
98de566360SJordan K. Hubbard 
99de566360SJordan K. Hubbard /* helper routines for main() */
100de566360SJordan K. Hubbard 
101de566360SJordan K. Hubbard void usage(void);
102de566360SJordan K. Hubbard void parse_conf_file(void);
103de566360SJordan K. Hubbard void gen_outputs(void);
104de566360SJordan K. Hubbard 
105de566360SJordan K. Hubbard 
106de566360SJordan K. Hubbard int main(int argc, char **argv)
107de566360SJordan K. Hubbard {
108de566360SJordan K. Hubbard     char *p;
109de566360SJordan K. Hubbard     int optc;
110de566360SJordan K. Hubbard     extern int optind;
111de566360SJordan K. Hubbard     extern char *optarg;
112de566360SJordan K. Hubbard 
113de566360SJordan K. Hubbard     verbose = 1;
114de566360SJordan K. Hubbard     readcache = 1;
115de566360SJordan K. Hubbard     *outmkname = *outcfname = *execfname = '\0';
116de566360SJordan K. Hubbard 
117de566360SJordan K. Hubbard     if(argc > 0) pname = argv[0];
118de566360SJordan K. Hubbard 
119fb7f926eSPoul-Henning Kamp     while((optc = getopt(argc, argv, "lm:c:e:fq")) != -1) {
120de566360SJordan K. Hubbard 	switch(optc) {
121de566360SJordan K. Hubbard 	case 'f':	readcache = 0; break;
122de566360SJordan K. Hubbard 	case 'q':	verbose = 0; break;
123de566360SJordan K. Hubbard 
124de566360SJordan K. Hubbard 	case 'm':	strcpy(outmkname, optarg); break;
125de566360SJordan K. Hubbard 	case 'c':	strcpy(outcfname, optarg); break;
126de566360SJordan K. Hubbard 	case 'e':	strcpy(execfname, optarg); break;
127fb7f926eSPoul-Henning Kamp 	case 'l':	list_mode++; verbose = 0; break;
128de566360SJordan K. Hubbard 
129de566360SJordan K. Hubbard 	case '?':
130de566360SJordan K. Hubbard 	default:	usage();
131de566360SJordan K. Hubbard 	}
132de566360SJordan K. Hubbard     }
133de566360SJordan K. Hubbard 
134de566360SJordan K. Hubbard     argc -= optind;
135de566360SJordan K. Hubbard     argv += optind;
136de566360SJordan K. Hubbard 
137de566360SJordan K. Hubbard     if(argc != 1) usage();
138de566360SJordan K. Hubbard 
139de566360SJordan K. Hubbard     /*
140de566360SJordan K. Hubbard      * generate filenames
141de566360SJordan K. Hubbard      */
142de566360SJordan K. Hubbard 
143de566360SJordan K. Hubbard     strcpy(infilename, argv[0]);
144de566360SJordan K. Hubbard 
145de566360SJordan K. Hubbard     /* confname = `basename infilename .conf` */
146de566360SJordan K. Hubbard 
147de566360SJordan K. Hubbard     if((p=strrchr(infilename, '/')) != NULL) strcpy(confname, p+1);
148de566360SJordan K. Hubbard     else strcpy(confname, infilename);
149de566360SJordan K. Hubbard     if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0';
150de566360SJordan K. Hubbard 
151de566360SJordan K. Hubbard     if(!*outmkname) sprintf(outmkname, "%s.mk", confname);
152de566360SJordan K. Hubbard     if(!*outcfname) sprintf(outcfname, "%s.c", confname);
153de566360SJordan K. Hubbard     if(!*execfname) sprintf(execfname, "%s", confname);
154de566360SJordan K. Hubbard 
155de566360SJordan K. Hubbard     sprintf(cachename, "%s.cache", confname);
156de566360SJordan K. Hubbard     sprintf(tempfname, ".tmp_%sXXXXXX", confname);
157de566360SJordan K. Hubbard     if(mktemp(tempfname) == NULL) {
158de566360SJordan K. Hubbard 	perror(tempfname);
159de566360SJordan K. Hubbard 	exit(1);
160de566360SJordan K. Hubbard     }
161de566360SJordan K. Hubbard 
162de566360SJordan K. Hubbard     parse_conf_file();
163fb7f926eSPoul-Henning Kamp     if (list_mode)
164fb7f926eSPoul-Henning Kamp 	exit(goterror);
165fb7f926eSPoul-Henning Kamp 
166de566360SJordan K. Hubbard     gen_outputs();
167de566360SJordan K. Hubbard 
168de566360SJordan K. Hubbard     exit(goterror);
169de566360SJordan K. Hubbard }
170de566360SJordan K. Hubbard 
171de566360SJordan K. Hubbard 
172de566360SJordan K. Hubbard void usage(void)
173de566360SJordan K. Hubbard {
174de566360SJordan K. Hubbard     fprintf(stderr,
175de566360SJordan K. Hubbard 	"%s [-fq] [-m <makefile>] [-c <c file>] [-e <exec file>] <conffile>\n",
176de566360SJordan K. Hubbard 	    pname);
177de566360SJordan K. Hubbard     exit(1);
178de566360SJordan K. Hubbard }
179de566360SJordan K. Hubbard 
180de566360SJordan K. Hubbard 
181de566360SJordan K. Hubbard /*
182de566360SJordan K. Hubbard  * ========================================================================
183de566360SJordan K. Hubbard  * parse_conf_file subsystem
184de566360SJordan K. Hubbard  *
185de566360SJordan K. Hubbard  */
186de566360SJordan K. Hubbard 
187de566360SJordan K. Hubbard /* helper routines for parse_conf_file */
188de566360SJordan K. Hubbard 
189de566360SJordan K. Hubbard void parse_one_file(char *filename);
190de566360SJordan K. Hubbard void parse_line(char *line, int *fc, char **fv, int nf);
191de566360SJordan K. Hubbard void add_srcdirs(int argc, char **argv);
192de566360SJordan K. Hubbard void add_progs(int argc, char **argv);
193de566360SJordan K. Hubbard void add_link(int argc, char **argv);
194de566360SJordan K. Hubbard void add_libs(int argc, char **argv);
195de566360SJordan K. Hubbard void add_special(int argc, char **argv);
196de566360SJordan K. Hubbard 
197de566360SJordan K. Hubbard prog_t *find_prog(char *str);
198de566360SJordan K. Hubbard void add_prog(char *progname);
199de566360SJordan K. Hubbard 
200de566360SJordan K. Hubbard 
201de566360SJordan K. Hubbard void parse_conf_file(void)
202de566360SJordan K. Hubbard {
203de566360SJordan K. Hubbard     if(!is_nonempty_file(infilename)) {
204de566360SJordan K. Hubbard 	fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n",
205de566360SJordan K. Hubbard 		pname, infilename);
206de566360SJordan K. Hubbard 	exit(1);
207de566360SJordan K. Hubbard     }
208de566360SJordan K. Hubbard     parse_one_file(infilename);
209de566360SJordan K. Hubbard     if(readcache && is_nonempty_file(cachename)) {
210de566360SJordan K. Hubbard 	reading_cache = 1;
211de566360SJordan K. Hubbard 	parse_one_file(cachename);
212de566360SJordan K. Hubbard     }
213de566360SJordan K. Hubbard }
214de566360SJordan K. Hubbard 
215de566360SJordan K. Hubbard 
216de566360SJordan K. Hubbard void parse_one_file(char *filename)
217de566360SJordan K. Hubbard {
218de566360SJordan K. Hubbard     char *fieldv[MAXFIELDS];
219de566360SJordan K. Hubbard     int fieldc;
220de566360SJordan K. Hubbard     void (*f)(int c, char **v);
221de566360SJordan K. Hubbard     FILE *cf;
222de566360SJordan K. Hubbard 
223de566360SJordan K. Hubbard     sprintf(line, "reading %s", filename);
224de566360SJordan K. Hubbard     status(line);
225de566360SJordan K. Hubbard     strcpy(curfilename, filename);
226de566360SJordan K. Hubbard 
227de566360SJordan K. Hubbard     if((cf = fopen(curfilename, "r")) == NULL) {
228de566360SJordan K. Hubbard 	perror(curfilename);
229de566360SJordan K. Hubbard 	goterror = 1;
230de566360SJordan K. Hubbard 	return;
231de566360SJordan K. Hubbard     }
232de566360SJordan K. Hubbard 
233de566360SJordan K. Hubbard     linenum = 0;
234de566360SJordan K. Hubbard     while(fgets(line, MAXLINELEN, cf) != NULL) {
235de566360SJordan K. Hubbard 	linenum++;
236de566360SJordan K. Hubbard 	parse_line(line, &fieldc, fieldv, MAXFIELDS);
237de566360SJordan K. Hubbard 	if(fieldc < 1) continue;
238de566360SJordan K. Hubbard 	if(!strcmp(fieldv[0], "srcdirs"))	f = add_srcdirs;
239de566360SJordan K. Hubbard 	else if(!strcmp(fieldv[0], "progs"))    f = add_progs;
240de566360SJordan K. Hubbard 	else if(!strcmp(fieldv[0], "ln"))	f = add_link;
241de566360SJordan K. Hubbard 	else if(!strcmp(fieldv[0], "libs"))	f = add_libs;
242de566360SJordan K. Hubbard 	else if(!strcmp(fieldv[0], "special"))	f = add_special;
243de566360SJordan K. Hubbard 	else {
244de566360SJordan K. Hubbard 	    fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n",
245de566360SJordan K. Hubbard 		    curfilename, linenum, fieldv[0]);
246de566360SJordan K. Hubbard 	    goterror = 1;
247de566360SJordan K. Hubbard 	    continue;
248de566360SJordan K. Hubbard 	}
249de566360SJordan K. Hubbard 	if(fieldc < 2) {
250de566360SJordan K. Hubbard 	    fprintf(stderr,
251de566360SJordan K. Hubbard 		    "%s:%d: %s command needs at least 1 argument, skipping.\n",
252de566360SJordan K. Hubbard 		    curfilename, linenum, fieldv[0]);
253de566360SJordan K. Hubbard 	    goterror = 1;
254de566360SJordan K. Hubbard 	    continue;
255de566360SJordan K. Hubbard 	}
256de566360SJordan K. Hubbard 	f(fieldc, fieldv);
257de566360SJordan K. Hubbard     }
258de566360SJordan K. Hubbard 
259de566360SJordan K. Hubbard     if(ferror(cf)) {
260de566360SJordan K. Hubbard 	perror(curfilename);
261de566360SJordan K. Hubbard 	goterror = 1;
262de566360SJordan K. Hubbard     }
263de566360SJordan K. Hubbard     fclose(cf);
264de566360SJordan K. Hubbard }
265de566360SJordan K. Hubbard 
266de566360SJordan K. Hubbard 
267de566360SJordan K. Hubbard void parse_line(char *line, int *fc, char **fv, int nf)
268de566360SJordan K. Hubbard {
269de566360SJordan K. Hubbard     char *p;
270de566360SJordan K. Hubbard 
271de566360SJordan K. Hubbard     p = line;
272de566360SJordan K. Hubbard     *fc = 0;
273de566360SJordan K. Hubbard     while(1) {
274de566360SJordan K. Hubbard 	while(isspace(*p)) p++;
275de566360SJordan K. Hubbard 	if(*p == '\0' || *p == '#') break;
276de566360SJordan K. Hubbard 
277de566360SJordan K. Hubbard 	if(*fc < nf) fv[(*fc)++] = p;
278de566360SJordan K. Hubbard 	while(*p && !isspace(*p) && *p != '#') p++;
279de566360SJordan K. Hubbard 	if(*p == '\0' || *p == '#') break;
280de566360SJordan K. Hubbard 	*p++ = '\0';
281de566360SJordan K. Hubbard     }
282de566360SJordan K. Hubbard     if(*p) *p = '\0';		/* needed for '#' case */
283de566360SJordan K. Hubbard }
284de566360SJordan K. Hubbard 
285de566360SJordan K. Hubbard 
286de566360SJordan K. Hubbard void add_srcdirs(int argc, char **argv)
287de566360SJordan K. Hubbard {
288de566360SJordan K. Hubbard     int i;
289de566360SJordan K. Hubbard 
290de566360SJordan K. Hubbard     for(i=1;i<argc;i++) {
291de566360SJordan K. Hubbard 	if(is_dir(argv[i]))
292de566360SJordan K. Hubbard 	    add_string(&srcdirs, argv[i]);
293de566360SJordan K. Hubbard 	else {
294de566360SJordan K. Hubbard 	    fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
295de566360SJordan K. Hubbard 		    curfilename, linenum, argv[i]);
296de566360SJordan K. Hubbard 	    goterror = 1;
297de566360SJordan K. Hubbard 	}
298de566360SJordan K. Hubbard     }
299de566360SJordan K. Hubbard }
300de566360SJordan K. Hubbard 
301de566360SJordan K. Hubbard 
302de566360SJordan K. Hubbard void add_progs(int argc, char **argv)
303de566360SJordan K. Hubbard {
304de566360SJordan K. Hubbard     int i;
305de566360SJordan K. Hubbard 
306de566360SJordan K. Hubbard     for(i=1;i<argc;i++)
307de566360SJordan K. Hubbard 	add_prog(argv[i]);
308de566360SJordan K. Hubbard }
309de566360SJordan K. Hubbard 
310de566360SJordan K. Hubbard 
311de566360SJordan K. Hubbard void add_prog(char *progname)
312de566360SJordan K. Hubbard {
313de566360SJordan K. Hubbard     prog_t *p1, *p2;
314de566360SJordan K. Hubbard 
315de566360SJordan K. Hubbard     /* add to end, but be smart about dups */
316de566360SJordan K. Hubbard 
317de566360SJordan K. Hubbard     for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
318de566360SJordan K. Hubbard 	if(!strcmp(p2->name, progname)) return;
319de566360SJordan K. Hubbard 
320de566360SJordan K. Hubbard     p2 = malloc(sizeof(prog_t));
321de566360SJordan K. Hubbard     if(p2) p2->name = strdup(progname);
322de566360SJordan K. Hubbard     if(!p2 || !p2->name)
323de566360SJordan K. Hubbard 	out_of_memory();
324de566360SJordan K. Hubbard 
325de566360SJordan K. Hubbard     p2->next = NULL;
326de566360SJordan K. Hubbard     if(p1 == NULL) progs = p2;
327de566360SJordan K. Hubbard     else p1->next = p2;
328de566360SJordan K. Hubbard 
329de566360SJordan K. Hubbard     p2->ident = p2->srcdir = p2->objdir = NULL;
330de566360SJordan K. Hubbard     p2->links = p2->objs = NULL;
331de566360SJordan K. Hubbard     p2->goterror = 0;
332fb7f926eSPoul-Henning Kamp     if (list_mode)
333fb7f926eSPoul-Henning Kamp         printf("%s\n",progname);
334de566360SJordan K. Hubbard }
335de566360SJordan K. Hubbard 
336de566360SJordan K. Hubbard 
337de566360SJordan K. Hubbard void add_link(int argc, char **argv)
338de566360SJordan K. Hubbard {
339de566360SJordan K. Hubbard     int i;
340de566360SJordan K. Hubbard     prog_t *p = find_prog(argv[1]);
341de566360SJordan K. Hubbard 
342de566360SJordan K. Hubbard     if(p == NULL) {
343de566360SJordan K. Hubbard 	fprintf(stderr,
344de566360SJordan K. Hubbard 		"%s:%d: no prog %s previously declared, skipping link.\n",
345de566360SJordan K. Hubbard 		curfilename, linenum, argv[1]);
346de566360SJordan K. Hubbard 	goterror = 1;
347de566360SJordan K. Hubbard 	return;
348de566360SJordan K. Hubbard     }
349fb7f926eSPoul-Henning Kamp     for(i=2;i<argc;i++) {
350fb7f926eSPoul-Henning Kamp 	if (list_mode)
351fb7f926eSPoul-Henning Kamp 		printf("%s\n",argv[i]);
352de566360SJordan K. Hubbard 	add_string(&p->links, argv[i]);
353de566360SJordan K. Hubbard     }
354fb7f926eSPoul-Henning Kamp }
355de566360SJordan K. Hubbard 
356de566360SJordan K. Hubbard 
357de566360SJordan K. Hubbard void add_libs(int argc, char **argv)
358de566360SJordan K. Hubbard {
359de566360SJordan K. Hubbard     int i;
360de566360SJordan K. Hubbard 
361de566360SJordan K. Hubbard     for(i=1;i<argc;i++)
362de566360SJordan K. Hubbard 	add_string(&libs, argv[i]);
363de566360SJordan K. Hubbard }
364de566360SJordan K. Hubbard 
365de566360SJordan K. Hubbard 
366de566360SJordan K. Hubbard void add_special(int argc, char **argv)
367de566360SJordan K. Hubbard {
368de566360SJordan K. Hubbard     int i;
369de566360SJordan K. Hubbard     prog_t *p = find_prog(argv[1]);
370de566360SJordan K. Hubbard 
371de566360SJordan K. Hubbard     if(p == NULL) {
372de566360SJordan K. Hubbard 	if(reading_cache) return;
373de566360SJordan K. Hubbard 	fprintf(stderr,
374de566360SJordan K. Hubbard 		"%s:%d: no prog %s previously declared, skipping special.\n",
375de566360SJordan K. Hubbard 		curfilename, linenum, argv[1]);
376de566360SJordan K. Hubbard 	goterror = 1;
377de566360SJordan K. Hubbard 	return;
378de566360SJordan K. Hubbard     }
379de566360SJordan K. Hubbard 
380de566360SJordan K. Hubbard     if(!strcmp(argv[2], "ident")) {
381de566360SJordan K. Hubbard 	if(argc != 4) goto argcount;
382de566360SJordan K. Hubbard 	if((p->ident = strdup(argv[3])) == NULL)
383de566360SJordan K. Hubbard 	    out_of_memory();
384de566360SJordan K. Hubbard     }
385de566360SJordan K. Hubbard     else if(!strcmp(argv[2], "srcdir")) {
386de566360SJordan K. Hubbard 	if(argc != 4) goto argcount;
387de566360SJordan K. Hubbard 	if((p->srcdir = strdup(argv[3])) == NULL)
388de566360SJordan K. Hubbard 	    out_of_memory();
389de566360SJordan K. Hubbard     }
390de566360SJordan K. Hubbard     else if(!strcmp(argv[2], "objdir")) {
391de566360SJordan K. Hubbard 	if(argc != 4) goto argcount;
392de566360SJordan K. Hubbard 	if((p->objdir = strdup(argv[3])) == NULL)
393de566360SJordan K. Hubbard 	    out_of_memory();
394de566360SJordan K. Hubbard     }
395de566360SJordan K. Hubbard     else if(!strcmp(argv[2], "objs")) {
396de566360SJordan K. Hubbard 	p->objs = NULL;
397de566360SJordan K. Hubbard 	for(i=3;i<argc;i++)
398de566360SJordan K. Hubbard 	    add_string(&p->objs, argv[i]);
399de566360SJordan K. Hubbard     }
400de566360SJordan K. Hubbard     else if(!strcmp(argv[2], "objpaths")) {
401de566360SJordan K. Hubbard 	p->objpaths = NULL;
402de566360SJordan K. Hubbard 	for(i=3;i<argc;i++)
403de566360SJordan K. Hubbard 	    add_string(&p->objpaths, argv[i]);
404de566360SJordan K. Hubbard     }
405de566360SJordan K. Hubbard     else {
406de566360SJordan K. Hubbard 	fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n",
407de566360SJordan K. Hubbard 		curfilename, linenum, argv[2]);
408de566360SJordan K. Hubbard 	goterror = 1;
409de566360SJordan K. Hubbard     }
410de566360SJordan K. Hubbard     return;
411de566360SJordan K. Hubbard 
412de566360SJordan K. Hubbard 
413de566360SJordan K. Hubbard  argcount:
414de566360SJordan K. Hubbard     fprintf(stderr,
415de566360SJordan K. Hubbard 	    "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
416de566360SJordan K. Hubbard 	    curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]);
417de566360SJordan K. Hubbard     goterror = 1;
418de566360SJordan K. Hubbard }
419de566360SJordan K. Hubbard 
420de566360SJordan K. Hubbard 
421de566360SJordan K. Hubbard prog_t *find_prog(char *str)
422de566360SJordan K. Hubbard {
423de566360SJordan K. Hubbard     prog_t *p;
424de566360SJordan K. Hubbard 
425de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next)
426de566360SJordan K. Hubbard 	if(!strcmp(p->name, str)) return p;
427de566360SJordan K. Hubbard 
428de566360SJordan K. Hubbard     return NULL;
429de566360SJordan K. Hubbard }
430de566360SJordan K. Hubbard 
431de566360SJordan K. Hubbard 
432de566360SJordan K. Hubbard /*
433de566360SJordan K. Hubbard  * ========================================================================
434de566360SJordan K. Hubbard  * gen_outputs subsystem
435de566360SJordan K. Hubbard  *
436de566360SJordan K. Hubbard  */
437de566360SJordan K. Hubbard 
438de566360SJordan K. Hubbard /* helper subroutines */
439de566360SJordan K. Hubbard 
440de566360SJordan K. Hubbard void remove_error_progs(void);
441de566360SJordan K. Hubbard void fillin_program(prog_t *p);
442de566360SJordan K. Hubbard void gen_specials_cache(void);
443de566360SJordan K. Hubbard void gen_output_makefile(void);
444de566360SJordan K. Hubbard void gen_output_cfile(void);
445de566360SJordan K. Hubbard 
446de566360SJordan K. Hubbard void fillin_program_objs(prog_t *p, char *path);
447de566360SJordan K. Hubbard void top_makefile_rules(FILE *outmk);
448de566360SJordan K. Hubbard void prog_makefile_rules(FILE *outmk, prog_t *p);
449de566360SJordan K. Hubbard void output_strlst(FILE *outf, strlst_t *lst);
450de566360SJordan K. Hubbard char *genident(char *str);
451de566360SJordan K. Hubbard char *dir_search(char *progname);
452de566360SJordan K. Hubbard 
453de566360SJordan K. Hubbard 
454de566360SJordan K. Hubbard void gen_outputs(void)
455de566360SJordan K. Hubbard {
456de566360SJordan K. Hubbard     prog_t *p;
457de566360SJordan K. Hubbard 
458de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next)
459de566360SJordan K. Hubbard 	fillin_program(p);
460de566360SJordan K. Hubbard 
461de566360SJordan K. Hubbard     remove_error_progs();
462de566360SJordan K. Hubbard     gen_specials_cache();
463de566360SJordan K. Hubbard     gen_output_cfile();
464de566360SJordan K. Hubbard     gen_output_makefile();
465de566360SJordan K. Hubbard     status("");
466de566360SJordan K. Hubbard     fprintf(stderr,
467de566360SJordan K. Hubbard 	    "Run \"make -f %s objs exe\" to build crunched binary.\n",
468de566360SJordan K. Hubbard 	    outmkname);
469de566360SJordan K. Hubbard }
470de566360SJordan K. Hubbard 
471de566360SJordan K. Hubbard 
472de566360SJordan K. Hubbard void fillin_program(prog_t *p)
473de566360SJordan K. Hubbard {
474de566360SJordan K. Hubbard     char path[MAXPATHLEN];
475de566360SJordan K. Hubbard     char *srcparent;
476de566360SJordan K. Hubbard     strlst_t *s;
477de566360SJordan K. Hubbard 
478de566360SJordan K. Hubbard     sprintf(line, "filling in parms for %s", p->name);
479de566360SJordan K. Hubbard     status(line);
480de566360SJordan K. Hubbard 
481de566360SJordan K. Hubbard     if(!p->ident)
482de566360SJordan K. Hubbard 	p->ident = genident(p->name);
483de566360SJordan K. Hubbard     if(!p->srcdir) {
484de566360SJordan K. Hubbard 	srcparent = dir_search(p->name);
485de566360SJordan K. Hubbard 	if(srcparent)
486de566360SJordan K. Hubbard 	    sprintf(path, "%s/%s", srcparent, p->name);
487de566360SJordan K. Hubbard 	if(is_dir(path))
488de566360SJordan K. Hubbard 	    p->srcdir = strdup(path);
489de566360SJordan K. Hubbard     }
490de566360SJordan K. Hubbard     if(!p->objdir && p->srcdir) {
491154fd6a9SPoul-Henning Kamp 	FILE *f;
492154fd6a9SPoul-Henning Kamp 
493154fd6a9SPoul-Henning Kamp 	sprintf(path, "cd %s && echo -n /usr/obj/`pwd`", p->srcdir);
494154fd6a9SPoul-Henning Kamp         p->objdir = p->srcdir;
495154fd6a9SPoul-Henning Kamp 	f = popen(path,"r");
496154fd6a9SPoul-Henning Kamp 	if (f) {
497154fd6a9SPoul-Henning Kamp 	    fgets(path,sizeof path, f);
498154fd6a9SPoul-Henning Kamp 	    if (!pclose(f)) {
499de566360SJordan K. Hubbard 		if(is_dir(path))
500de566360SJordan K. Hubbard 		    p->objdir = strdup(path);
501154fd6a9SPoul-Henning Kamp 	    }
502154fd6a9SPoul-Henning Kamp 	}
503154fd6a9SPoul-Henning Kamp 
504154fd6a9SPoul-Henning Kamp 
505de566360SJordan K. Hubbard     }
506de566360SJordan K. Hubbard 
507de566360SJordan K. Hubbard     if(p->srcdir) sprintf(path, "%s/Makefile", p->srcdir);
508de566360SJordan K. Hubbard     if(!p->objs && p->srcdir && is_nonempty_file(path))
509de566360SJordan K. Hubbard 	fillin_program_objs(p, path);
510de566360SJordan K. Hubbard 
511de566360SJordan K. Hubbard     if(!p->objpaths && p->objdir && p->objs)
512de566360SJordan K. Hubbard 	for(s = p->objs; s != NULL; s = s->next) {
513de566360SJordan K. Hubbard 	    sprintf(line, "%s/%s", p->objdir, s->str);
514de566360SJordan K. Hubbard 	    add_string(&p->objpaths, line);
515de566360SJordan K. Hubbard 	}
516de566360SJordan K. Hubbard 
517de566360SJordan K. Hubbard     if(!p->srcdir && verbose)
518de566360SJordan K. Hubbard 	fprintf(stderr, "%s: %s: warning: could not find source directory.\n",
519de566360SJordan K. Hubbard 		infilename, p->name);
520de566360SJordan K. Hubbard     if(!p->objs && verbose)
521de566360SJordan K. Hubbard 	fprintf(stderr, "%s: %s: warning: could not find any .o files.\n",
522de566360SJordan K. Hubbard 		infilename, p->name);
523de566360SJordan K. Hubbard 
524de566360SJordan K. Hubbard     if(!p->objpaths) {
525de566360SJordan K. Hubbard 	fprintf(stderr,
526de566360SJordan K. Hubbard 		"%s: %s: error: no objpaths specified or calculated.\n",
527de566360SJordan K. Hubbard 		infilename, p->name);
528de566360SJordan K. Hubbard 	p->goterror = goterror = 1;
529de566360SJordan K. Hubbard     }
530de566360SJordan K. Hubbard }
531de566360SJordan K. Hubbard 
532de566360SJordan K. Hubbard void fillin_program_objs(prog_t *p, char *path)
533de566360SJordan K. Hubbard {
534de566360SJordan K. Hubbard     char *obj, *cp;
535de566360SJordan K. Hubbard     int rc;
536de566360SJordan K. Hubbard     FILE *f;
537de566360SJordan K. Hubbard 
538de566360SJordan K. Hubbard     /* discover the objs from the srcdir Makefile */
539de566360SJordan K. Hubbard 
540de566360SJordan K. Hubbard     if((f = fopen(tempfname, "w")) == NULL) {
541de566360SJordan K. Hubbard 	perror(tempfname);
542de566360SJordan K. Hubbard 	goterror = 1;
543de566360SJordan K. Hubbard 	return;
544de566360SJordan K. Hubbard     }
545de566360SJordan K. Hubbard 
546de566360SJordan K. Hubbard     fprintf(f, ".include \"%s\"\n", path);
547de566360SJordan K. Hubbard     fprintf(f, ".if defined(PROG) && !defined(OBJS)\n");
548de566360SJordan K. Hubbard     fprintf(f, "OBJS=${PROG}.o\n");
549de566360SJordan K. Hubbard     fprintf(f, ".endif\n");
550de566360SJordan K. Hubbard     fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
551de566360SJordan K. Hubbard     fclose(f);
552de566360SJordan K. Hubbard 
553de566360SJordan K. Hubbard     sprintf(line, "make -f %s crunchgen_objs 2>&1", tempfname);
554de566360SJordan K. Hubbard     if((f = popen(line, "r")) == NULL) {
555de566360SJordan K. Hubbard 	perror("submake pipe");
556de566360SJordan K. Hubbard 	goterror = 1;
557de566360SJordan K. Hubbard 	return;
558de566360SJordan K. Hubbard     }
559de566360SJordan K. Hubbard 
560de566360SJordan K. Hubbard     while(fgets(line, MAXLINELEN, f)) {
561de566360SJordan K. Hubbard 	if(strncmp(line, "OBJS= ", 6)) {
562de566360SJordan K. Hubbard 	    fprintf(stderr, "make error: %s", line);
563de566360SJordan K. Hubbard 	    goterror = 1;
564de566360SJordan K. Hubbard 	    continue;
565de566360SJordan K. Hubbard 	}
566de566360SJordan K. Hubbard 	cp = line + 6;
567de566360SJordan K. Hubbard 	while(isspace(*cp)) cp++;
568de566360SJordan K. Hubbard 	while(*cp) {
569de566360SJordan K. Hubbard 	    obj = cp;
570de566360SJordan K. Hubbard 	    while(*cp && !isspace(*cp)) cp++;
571de566360SJordan K. Hubbard 	    if(*cp) *cp++ = '\0';
572de566360SJordan K. Hubbard 	    add_string(&p->objs, obj);
573de566360SJordan K. Hubbard 	    while(isspace(*cp)) cp++;
574de566360SJordan K. Hubbard 	}
575de566360SJordan K. Hubbard     }
576de566360SJordan K. Hubbard     if((rc=pclose(f)) != 0) {
577de566360SJordan K. Hubbard 	fprintf(stderr, "make error: make returned %d\n", rc);
578de566360SJordan K. Hubbard 	goterror = 1;
579de566360SJordan K. Hubbard     }
580de566360SJordan K. Hubbard     unlink(tempfname);
581de566360SJordan K. Hubbard }
582de566360SJordan K. Hubbard 
583de566360SJordan K. Hubbard void remove_error_progs(void)
584de566360SJordan K. Hubbard {
585de566360SJordan K. Hubbard     prog_t *p1, *p2;
586de566360SJordan K. Hubbard 
587de566360SJordan K. Hubbard     p1 = NULL; p2 = progs;
588de566360SJordan K. Hubbard     while(p2 != NULL) {
589de566360SJordan K. Hubbard 	if(!p2->goterror)
590de566360SJordan K. Hubbard 	    p1 = p2, p2 = p2->next;
591de566360SJordan K. Hubbard 	else {
592de566360SJordan K. Hubbard 	    /* delete it from linked list */
593de566360SJordan K. Hubbard 	    fprintf(stderr, "%s: %s: ignoring program because of errors.\n",
594de566360SJordan K. Hubbard 		    infilename, p2->name);
595de566360SJordan K. Hubbard 	    if(p1) p1->next = p2->next;
596de566360SJordan K. Hubbard 	    else progs = p2->next;
597de566360SJordan K. Hubbard 	    p2 = p2->next;
598de566360SJordan K. Hubbard 	}
599de566360SJordan K. Hubbard     }
600de566360SJordan K. Hubbard }
601de566360SJordan K. Hubbard 
602de566360SJordan K. Hubbard void gen_specials_cache(void)
603de566360SJordan K. Hubbard {
604de566360SJordan K. Hubbard     FILE *cachef;
605de566360SJordan K. Hubbard     prog_t *p;
606de566360SJordan K. Hubbard 
607de566360SJordan K. Hubbard     sprintf(line, "generating %s", cachename);
608de566360SJordan K. Hubbard     status(line);
609de566360SJordan K. Hubbard 
610de566360SJordan K. Hubbard     if((cachef = fopen(cachename, "w")) == NULL) {
611de566360SJordan K. Hubbard 	perror(cachename);
612de566360SJordan K. Hubbard 	goterror = 1;
613de566360SJordan K. Hubbard 	return;
614de566360SJordan K. Hubbard     }
615de566360SJordan K. Hubbard 
616de566360SJordan K. Hubbard     fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n",
617de566360SJordan K. Hubbard 	    cachename, infilename, CRUNCH_VERSION);
618de566360SJordan K. Hubbard 
619de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next) {
620de566360SJordan K. Hubbard 	fprintf(cachef, "\n");
621de566360SJordan K. Hubbard 	if(p->srcdir)
622de566360SJordan K. Hubbard 	    fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir);
623de566360SJordan K. Hubbard 	if(p->objdir)
624de566360SJordan K. Hubbard 	    fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir);
625de566360SJordan K. Hubbard 	if(p->objs) {
626de566360SJordan K. Hubbard 	    fprintf(cachef, "special %s objs", p->name);
627de566360SJordan K. Hubbard 	    output_strlst(cachef, p->objs);
628de566360SJordan K. Hubbard 	}
629de566360SJordan K. Hubbard 	fprintf(cachef, "special %s objpaths", p->name);
630de566360SJordan K. Hubbard 	output_strlst(cachef, p->objpaths);
631de566360SJordan K. Hubbard     }
632de566360SJordan K. Hubbard     fclose(cachef);
633de566360SJordan K. Hubbard }
634de566360SJordan K. Hubbard 
635de566360SJordan K. Hubbard 
636de566360SJordan K. Hubbard void gen_output_makefile(void)
637de566360SJordan K. Hubbard {
638de566360SJordan K. Hubbard     prog_t *p;
639de566360SJordan K. Hubbard     FILE *outmk;
640de566360SJordan K. Hubbard 
641de566360SJordan K. Hubbard     sprintf(line, "generating %s", outmkname);
642de566360SJordan K. Hubbard     status(line);
643de566360SJordan K. Hubbard 
644de566360SJordan K. Hubbard     if((outmk = fopen(outmkname, "w")) == NULL) {
645de566360SJordan K. Hubbard 	perror(outmkname);
646de566360SJordan K. Hubbard 	goterror = 1;
647de566360SJordan K. Hubbard 	return;
648de566360SJordan K. Hubbard     }
649de566360SJordan K. Hubbard 
650de566360SJordan K. Hubbard     fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
651de566360SJordan K. Hubbard 	    outmkname, infilename, CRUNCH_VERSION);
652de566360SJordan K. Hubbard 
653de566360SJordan K. Hubbard     top_makefile_rules(outmk);
654de566360SJordan K. Hubbard 
655de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next)
656de566360SJordan K. Hubbard 	prog_makefile_rules(outmk, p);
657de566360SJordan K. Hubbard 
658de566360SJordan K. Hubbard     fprintf(outmk, "\n# ========\n");
659de566360SJordan K. Hubbard     fclose(outmk);
660de566360SJordan K. Hubbard }
661de566360SJordan K. Hubbard 
662de566360SJordan K. Hubbard 
663de566360SJordan K. Hubbard void gen_output_cfile(void)
664de566360SJordan K. Hubbard {
665de566360SJordan K. Hubbard     extern char *crunched_skel[];
666de566360SJordan K. Hubbard     char **cp;
667de566360SJordan K. Hubbard     FILE *outcf;
668de566360SJordan K. Hubbard     prog_t *p;
669de566360SJordan K. Hubbard     strlst_t *s;
670de566360SJordan K. Hubbard 
671de566360SJordan K. Hubbard     sprintf(line, "generating %s", outcfname);
672de566360SJordan K. Hubbard     status(line);
673de566360SJordan K. Hubbard 
674de566360SJordan K. Hubbard     if((outcf = fopen(outcfname, "w")) == NULL) {
675de566360SJordan K. Hubbard 	perror(outcfname);
676de566360SJordan K. Hubbard 	goterror = 1;
677de566360SJordan K. Hubbard 	return;
678de566360SJordan K. Hubbard     }
679de566360SJordan K. Hubbard 
680de566360SJordan K. Hubbard     fprintf(outcf,
681de566360SJordan K. Hubbard 	  "/* %s - generated from %s by crunchgen %s */\n",
682de566360SJordan K. Hubbard 	    outcfname, infilename, CRUNCH_VERSION);
683de566360SJordan K. Hubbard 
684de566360SJordan K. Hubbard     fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
685de566360SJordan K. Hubbard     for(cp = crunched_skel; *cp != NULL; cp++)
686de566360SJordan K. Hubbard 	fprintf(outcf, "%s\n", *cp);
687de566360SJordan K. Hubbard 
688de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next)
689de566360SJordan K. Hubbard 	fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
690de566360SJordan K. Hubbard 
691de566360SJordan K. Hubbard     fprintf(outcf, "\nstruct stub entry_points[] = {\n");
692de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next) {
693de566360SJordan K. Hubbard 	fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
694de566360SJordan K. Hubbard 		p->name, p->ident);
695de566360SJordan K. Hubbard 	for(s = p->links; s != NULL; s = s->next)
696de566360SJordan K. Hubbard 	    fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
697de566360SJordan K. Hubbard 		    s->str, p->ident);
698de566360SJordan K. Hubbard     }
699de566360SJordan K. Hubbard 
700de566360SJordan K. Hubbard     fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
701de566360SJordan K. Hubbard     fprintf(outcf, "\t{ NULL, NULL }\n};\n");
702de566360SJordan K. Hubbard     fclose(outcf);
703de566360SJordan K. Hubbard }
704de566360SJordan K. Hubbard 
705de566360SJordan K. Hubbard 
706de566360SJordan K. Hubbard char *genident(char *str)
707de566360SJordan K. Hubbard {
708de566360SJordan K. Hubbard     char *n,*s,*d;
709de566360SJordan K. Hubbard 
710de566360SJordan K. Hubbard     /*
711de566360SJordan K. Hubbard      * generates a Makefile/C identifier from a program name, mapping '-' to
712de566360SJordan K. Hubbard      * '_' and ignoring all other non-identifier characters.  This leads to
713de566360SJordan K. Hubbard      * programs named "foo.bar" and "foobar" to map to the same identifier.
714de566360SJordan K. Hubbard      */
715de566360SJordan K. Hubbard 
716de566360SJordan K. Hubbard     if((n = strdup(str)) == NULL)
717de566360SJordan K. Hubbard 	return NULL;
718de566360SJordan K. Hubbard     for(d = s = n; *s != '\0'; s++) {
719de566360SJordan K. Hubbard 	if(*s == '-') *d++ = '_';
720de566360SJordan K. Hubbard 	else if(*s == '_' || isalnum(*s)) *d++ = *s;
721de566360SJordan K. Hubbard     }
722de566360SJordan K. Hubbard     *d = '\0';
723de566360SJordan K. Hubbard     return n;
724de566360SJordan K. Hubbard }
725de566360SJordan K. Hubbard 
726de566360SJordan K. Hubbard 
727de566360SJordan K. Hubbard char *dir_search(char *progname)
728de566360SJordan K. Hubbard {
729de566360SJordan K. Hubbard     char path[MAXPATHLEN];
730de566360SJordan K. Hubbard     strlst_t *dir;
731de566360SJordan K. Hubbard 
732de566360SJordan K. Hubbard     for(dir=srcdirs; dir != NULL; dir=dir->next) {
733de566360SJordan K. Hubbard 	sprintf(path, "%s/%s", dir->str, progname);
734de566360SJordan K. Hubbard 	if(is_dir(path)) return dir->str;
735de566360SJordan K. Hubbard     }
736de566360SJordan K. Hubbard     return NULL;
737de566360SJordan K. Hubbard }
738de566360SJordan K. Hubbard 
739de566360SJordan K. Hubbard 
740de566360SJordan K. Hubbard void top_makefile_rules(FILE *outmk)
741de566360SJordan K. Hubbard {
742de566360SJordan K. Hubbard     prog_t *p;
743de566360SJordan K. Hubbard 
744de566360SJordan K. Hubbard     fprintf(outmk, "LIBS=");
745de566360SJordan K. Hubbard     output_strlst(outmk, libs);
746de566360SJordan K. Hubbard 
747de566360SJordan K. Hubbard     fprintf(outmk, "CRUNCHED_OBJS=");
748de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next)
749de566360SJordan K. Hubbard 	fprintf(outmk, " %s.lo", p->name);
750de566360SJordan K. Hubbard     fprintf(outmk, "\n");
751de566360SJordan K. Hubbard 
752de566360SJordan K. Hubbard     fprintf(outmk, "SUBMAKE_TARGETS=");
753de566360SJordan K. Hubbard     for(p = progs; p != NULL; p = p->next)
754de566360SJordan K. Hubbard 	fprintf(outmk, " %s_make", p->ident);
755de566360SJordan K. Hubbard     fprintf(outmk, "\n\n");
756de566360SJordan K. Hubbard 
757de566360SJordan K. Hubbard     fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n",
758de566360SJordan K. Hubbard 	    execfname, execfname);
759de566360SJordan K. Hubbard     fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
760de566360SJordan K. Hubbard 	    execfname, execfname);
761de566360SJordan K. Hubbard     fprintf(outmk, "\tstrip %s\n", execfname);
762de566360SJordan K. Hubbard     fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
763de566360SJordan K. Hubbard     fprintf(outmk, "exe: %s\n", execfname);
764de566360SJordan K. Hubbard     fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n",
765de566360SJordan K. Hubbard 	    execfname);
766de566360SJordan K. Hubbard }
767de566360SJordan K. Hubbard 
768de566360SJordan K. Hubbard 
769de566360SJordan K. Hubbard void prog_makefile_rules(FILE *outmk, prog_t *p)
770de566360SJordan K. Hubbard {
771de566360SJordan K. Hubbard     fprintf(outmk, "\n# -------- %s\n\n", p->name);
772de566360SJordan K. Hubbard 
773de566360SJordan K. Hubbard     if(p->srcdir && p->objs) {
774de566360SJordan K. Hubbard 	fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
775de566360SJordan K. Hubbard 	fprintf(outmk, "%s_OBJS=", p->ident);
776de566360SJordan K. Hubbard 	output_strlst(outmk, p->objs);
777de566360SJordan K. Hubbard 	fprintf(outmk, "%s_make:\n", p->ident);
778154fd6a9SPoul-Henning Kamp 	fprintf(outmk, "\t(cd $(%s_SRCDIR) && make depend && make $(%s_OBJS))\n\n",
779de566360SJordan K. Hubbard 		p->ident, p->ident);
780de566360SJordan K. Hubbard     }
781de566360SJordan K. Hubbard     else
782de566360SJordan K. Hubbard 	fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n",
783de566360SJordan K. Hubbard 		p->ident, p->name);
784de566360SJordan K. Hubbard 
785de566360SJordan K. Hubbard     fprintf(outmk,   "%s_OBJPATHS=", p->ident);
786de566360SJordan K. Hubbard     output_strlst(outmk, p->objpaths);
787de566360SJordan K. Hubbard 
788de566360SJordan K. Hubbard     fprintf(outmk, "%s_stub.c:\n", p->name);
789de566360SJordan K. Hubbard     fprintf(outmk, "\techo \""
790de566360SJordan K. Hubbard 	           "int _crunched_%s_stub(int argc, char **argv, char **envp)"
791de566360SJordan K. Hubbard 	           "{return main(argc,argv,envp);}\" >%s_stub.c\n",
792de566360SJordan K. Hubbard 	    p->ident, p->name);
793de566360SJordan K. Hubbard     fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
794de566360SJordan K. Hubbard 	    p->name, p->name, p->ident);
795de566360SJordan K. Hubbard     fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n",
796de566360SJordan K. Hubbard 	    p->name, p->name, p->ident);
797de566360SJordan K. Hubbard     fprintf(outmk, "\tcrunchide -k __crunched_%s_stub %s.lo\n",
798de566360SJordan K. Hubbard 	    p->ident, p->name);
799de566360SJordan K. Hubbard }
800de566360SJordan K. Hubbard 
801de566360SJordan K. Hubbard void output_strlst(FILE *outf, strlst_t *lst)
802de566360SJordan K. Hubbard {
803de566360SJordan K. Hubbard     for(; lst != NULL; lst = lst->next)
804de566360SJordan K. Hubbard 	fprintf(outf, " %s", lst->str);
805de566360SJordan K. Hubbard     fprintf(outf, "\n");
806de566360SJordan K. Hubbard }
807de566360SJordan K. Hubbard 
808de566360SJordan K. Hubbard 
809de566360SJordan K. Hubbard /*
810de566360SJordan K. Hubbard  * ========================================================================
811de566360SJordan K. Hubbard  * general library routines
812de566360SJordan K. Hubbard  *
813de566360SJordan K. Hubbard  */
814de566360SJordan K. Hubbard 
815de566360SJordan K. Hubbard void status(char *str)
816de566360SJordan K. Hubbard {
817de566360SJordan K. Hubbard     static int lastlen = 0;
818de566360SJordan K. Hubbard     int len, spaces;
819de566360SJordan K. Hubbard 
820de566360SJordan K. Hubbard     if(!verbose) return;
821de566360SJordan K. Hubbard 
822de566360SJordan K. Hubbard     len = strlen(str);
823de566360SJordan K. Hubbard     spaces = lastlen - len;
824de566360SJordan K. Hubbard     if(spaces < 1) spaces = 1;
825de566360SJordan K. Hubbard 
826de566360SJordan K. Hubbard     fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
827de566360SJordan K. Hubbard     fflush(stderr);
828de566360SJordan K. Hubbard     lastlen = len;
829de566360SJordan K. Hubbard }
830de566360SJordan K. Hubbard 
831de566360SJordan K. Hubbard 
832de566360SJordan K. Hubbard void out_of_memory(void)
833de566360SJordan K. Hubbard {
834de566360SJordan K. Hubbard     fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum);
835de566360SJordan K. Hubbard     exit(1);
836de566360SJordan K. Hubbard }
837de566360SJordan K. Hubbard 
838de566360SJordan K. Hubbard 
839de566360SJordan K. Hubbard void add_string(strlst_t **listp, char *str)
840de566360SJordan K. Hubbard {
841de566360SJordan K. Hubbard     strlst_t *p1, *p2;
842de566360SJordan K. Hubbard 
843de566360SJordan K. Hubbard     /* add to end, but be smart about dups */
844de566360SJordan K. Hubbard 
845de566360SJordan K. Hubbard     for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
846de566360SJordan K. Hubbard 	if(!strcmp(p2->str, str)) return;
847de566360SJordan K. Hubbard 
848de566360SJordan K. Hubbard     p2 = malloc(sizeof(strlst_t));
849de566360SJordan K. Hubbard     if(p2) p2->str = strdup(str);
850de566360SJordan K. Hubbard     if(!p2 || !p2->str)
851de566360SJordan K. Hubbard 	out_of_memory();
852de566360SJordan K. Hubbard 
853de566360SJordan K. Hubbard     p2->next = NULL;
854de566360SJordan K. Hubbard     if(p1 == NULL) *listp = p2;
855de566360SJordan K. Hubbard     else p1->next = p2;
856de566360SJordan K. Hubbard }
857de566360SJordan K. Hubbard 
858de566360SJordan K. Hubbard 
859de566360SJordan K. Hubbard int is_dir(char *pathname)
860de566360SJordan K. Hubbard {
861de566360SJordan K. Hubbard     struct stat buf;
862de566360SJordan K. Hubbard 
863de566360SJordan K. Hubbard     if(stat(pathname, &buf) == -1)
864de566360SJordan K. Hubbard 	return 0;
865de566360SJordan K. Hubbard     return S_ISDIR(buf.st_mode);
866de566360SJordan K. Hubbard }
867de566360SJordan K. Hubbard 
868de566360SJordan K. Hubbard int is_nonempty_file(char *pathname)
869de566360SJordan K. Hubbard {
870de566360SJordan K. Hubbard     struct stat buf;
871de566360SJordan K. Hubbard 
872de566360SJordan K. Hubbard     if(stat(pathname, &buf) == -1)
873de566360SJordan K. Hubbard 	return 0;
874de566360SJordan K. Hubbard 
875de566360SJordan K. Hubbard     return S_ISREG(buf.st_mode) && buf.st_size > 0;
876de566360SJordan K. Hubbard }
877