xref: /freebsd-13.1/usr.sbin/config/mkmakefile.c (revision 5dda1d0b)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 #if 0
34 static char sccsid[] = "@(#)mkmakefile.c	8.1 (Berkeley) 6/6/93";
35 #endif
36 static const char rcsid[] =
37   "$FreeBSD$";
38 #endif /* not lint */
39 
40 /*
41  * Build the makefile for the system, from
42  * the information in the files files and the
43  * additional files for the machine being compiled to.
44  */
45 
46 #include <ctype.h>
47 #include <err.h>
48 #include <stdarg.h>
49 #include <stdbool.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <sys/cnv.h>
53 #include <sys/nv.h>
54 #include <sys/param.h>
55 #include "y.tab.h"
56 #include "config.h"
57 #include "configvers.h"
58 
59 static char *tail(char *);
60 static void do_clean(FILE *);
61 static void do_rules(FILE *);
62 static void do_xxfiles(char *, FILE *);
63 static void do_objs(FILE *);
64 static void do_before_depend(FILE *);
65 static void read_files(void);
66 static void sanitize_envline(char *result, const char *src);
67 static bool preprocess(char *line, char *result);
68 static void process_into_file(char *line, FILE *ofp);
69 static void process_into_nvlist(char *line, nvlist_t *nvl);
70 static void dump_nvlist(nvlist_t *nvl, FILE *ofp);
71 
errout(const char * fmt,...)72 static void errout(const char *fmt, ...)
73 {
74 	va_list ap;
75 
76 	va_start(ap, fmt);
77 	vfprintf(stderr, fmt, ap);
78 	va_end(ap);
79 	exit(1);
80 }
81 
82 /*
83  * Lookup a file, by name.
84  */
85 static struct file_list *
fl_lookup(char * file)86 fl_lookup(char *file)
87 {
88 	struct file_list *fp;
89 
90 	STAILQ_FOREACH(fp, &ftab, f_next) {
91 		if (eq(fp->f_fn, file))
92 			return (fp);
93 	}
94 	return (0);
95 }
96 
97 /*
98  * Make a new file list entry
99  */
100 static struct file_list *
new_fent(void)101 new_fent(void)
102 {
103 	struct file_list *fp;
104 
105 	fp = (struct file_list *) calloc(1, sizeof *fp);
106 	if (fp == NULL)
107 		err(EXIT_FAILURE, "calloc");
108 	STAILQ_INSERT_TAIL(&ftab, fp, f_next);
109 	return (fp);
110 }
111 
112 /*
113  * Open the correct Makefile and return it, or error out.
114  */
115 FILE *
open_makefile_template(void)116 open_makefile_template(void)
117 {
118 	FILE *ifp;
119 	char line[BUFSIZ];
120 
121 	snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename);
122 	ifp = fopen(line, "r");
123 	if (ifp == NULL) {
124 		snprintf(line, sizeof(line), "Makefile.%s", machinename);
125 		ifp = fopen(line, "r");
126 	}
127 	if (ifp == NULL)
128 		err(1, "%s", line);
129 	return (ifp);
130 }
131 
132 /*
133  * Build the makefile from the skeleton
134  */
135 void
makefile(void)136 makefile(void)
137 {
138 	FILE *ifp, *ofp;
139 	char line[BUFSIZ];
140 	struct opt *op, *t;
141 
142 	read_files();
143 	ifp = open_makefile_template();
144 	ofp = fopen(path("Makefile.new"), "w");
145 	if (ofp == NULL)
146 		err(1, "%s", path("Makefile.new"));
147 	fprintf(ofp, "KERN_IDENT=%s\n", ident);
148 	fprintf(ofp, "MACHINE=%s\n", machinename);
149 	fprintf(ofp, "MACHINE_ARCH=%s\n", machinearch);
150 	SLIST_FOREACH_SAFE(op, &mkopt, op_next, t) {
151 		fprintf(ofp, "%s=%s", op->op_name, op->op_value);
152 		while ((op = SLIST_NEXT(op, op_append)) != NULL)
153 			fprintf(ofp, " %s", op->op_value);
154 		fprintf(ofp, "\n");
155 	}
156 	if (debugging)
157 		fprintf(ofp, "DEBUG=-g\n");
158 	if (profiling)
159 		fprintf(ofp, "PROFLEVEL=%d\n", profiling);
160 	if (*srcdir != '\0')
161 		fprintf(ofp,"S=%s\n", srcdir);
162 	while (fgets(line, BUFSIZ, ifp) != NULL) {
163 		if (*line != '%') {
164 			fprintf(ofp, "%s", line);
165 			continue;
166 		}
167 		if (eq(line, "%BEFORE_DEPEND\n"))
168 			do_before_depend(ofp);
169 		else if (eq(line, "%OBJS\n"))
170 			do_objs(ofp);
171 		else if (strncmp(line, "%FILES.", 7) == 0)
172 			do_xxfiles(line, ofp);
173 		else if (eq(line, "%RULES\n"))
174 			do_rules(ofp);
175 		else if (eq(line, "%CLEAN\n"))
176 			do_clean(ofp);
177 		else if (strncmp(line, "%VERSREQ=", 9) == 0)
178 			line[0] = '\0'; /* handled elsewhere */
179 		else
180 			fprintf(stderr,
181 			    "Unknown %% construct in generic makefile: %s",
182 			    line);
183 	}
184 	(void) fclose(ifp);
185 	(void) fclose(ofp);
186 	moveifchanged(path("Makefile.new"), path("Makefile"));
187 }
188 
189 static void
sanitize_envline(char * result,const char * src)190 sanitize_envline(char *result, const char *src)
191 {
192 	const char *eq;
193 	char c, *dst;
194 	bool leading;
195 
196 	/* If there is no '=' it's not a well-formed name=value line. */
197 	if ((eq = strchr(src, '=')) == NULL) {
198 		*result = 0;
199 		return;
200 	}
201 	dst = result;
202 
203 	/* Copy chars before the '=', skipping any leading spaces/quotes. */
204 	leading = true;
205 	while (src < eq) {
206 		c = *src++;
207 		if (leading && (isspace(c) || c == '"'))
208 			continue;
209 		*dst++ = c;
210 		leading = false;
211 	}
212 
213 	/* If it was all leading space, we don't have a well-formed line. */
214 	if (leading) {
215 		*result = 0;
216 		return;
217 	}
218 
219 	/* Trim spaces/quotes immediately before the '=', then copy the '='. */
220 	while (isspace(dst[-1]) || dst[-1] == '"')
221 		--dst;
222 	*dst++ = *src++;
223 
224 	/* Copy chars after the '=', skipping any leading whitespace. */
225 	leading = true;
226 	while ((c = *src++) != 0) {
227 		if (leading && (isspace(c) || c == '"'))
228 			continue;
229 		*dst++ = c;
230 		leading = false;
231 	}
232 
233 	/* If it was all leading space, it's a valid 'var=' (nil value). */
234 	if (leading) {
235 		*dst = 0;
236 		return;
237 	}
238 
239 	/* Trim trailing whitespace and quotes. */
240 	while (isspace(dst[-1]) || dst[-1] == '"')
241 		--dst;
242 
243 	*dst = 0;
244 }
245 
246 /*
247  * Returns true if the caller may use the string.
248  */
249 static bool
preprocess(char * line,char * result)250 preprocess(char *line, char *result)
251 {
252 	char *s;
253 
254 	/* Strip any comments */
255 	if ((s = strchr(line, '#')) != NULL)
256 		*s = '\0';
257 	sanitize_envline(result, line);
258 	/* Return true if it's non-empty */
259 	return (*result != '\0');
260 }
261 
262 static void
process_into_file(char * line,FILE * ofp)263 process_into_file(char *line, FILE *ofp)
264 {
265 	char result[BUFSIZ];
266 
267 	if (preprocess(line, result))
268 		fprintf(ofp, "\"%s\\0\"\n", result);
269 }
270 
271 static void
process_into_nvlist(char * line,nvlist_t * nvl)272 process_into_nvlist(char *line, nvlist_t *nvl)
273 {
274 	char result[BUFSIZ], *s;
275 
276 	if (preprocess(line, result)) {
277 		s = strchr(result, '=');
278 		*s = '\0';
279 		if (nvlist_exists(nvl, result))
280 			nvlist_free(nvl, result);
281 		nvlist_add_string(nvl, result, s + 1);
282 	}
283 }
284 
285 static void
dump_nvlist(nvlist_t * nvl,FILE * ofp)286 dump_nvlist(nvlist_t *nvl, FILE *ofp)
287 {
288 	const char *name;
289 	void *cookie;
290 
291 	if (nvl == NULL)
292 		return;
293 
294 	while (!nvlist_empty(nvl)) {
295 		cookie = NULL;
296 		name = nvlist_next(nvl, NULL, &cookie);
297 		fprintf(ofp, "\"%s=%s\\0\"\n", name,
298 		     cnvlist_get_string(cookie));
299 
300 		cnvlist_free_string(cookie);
301 	}
302 }
303 
304 /*
305  * Build hints.c from the skeleton
306  */
307 void
makehints(void)308 makehints(void)
309 {
310 	FILE *ifp, *ofp;
311 	nvlist_t *nvl;
312 	char line[BUFSIZ];
313 	struct hint *hint;
314 
315 	ofp = fopen(path("hints.c.new"), "w");
316 	if (ofp == NULL)
317 		err(1, "%s", path("hints.c.new"));
318 	fprintf(ofp, "#include <sys/types.h>\n");
319 	fprintf(ofp, "#include <sys/systm.h>\n");
320 	fprintf(ofp, "\n");
321 	/*
322 	 * Write out hintmode for older kernels. Remove when config(8) major
323 	 * version rolls over.
324 	 */
325 	if (versreq <= CONFIGVERS_ENVMODE_REQ)
326 		fprintf(ofp, "int hintmode = %d;\n",
327 			!STAILQ_EMPTY(&hints) ? 1 : 0);
328 	fprintf(ofp, "char static_hints[] = {\n");
329 	nvl = nvlist_create(0);
330 	STAILQ_FOREACH(hint, &hints, hint_next) {
331 		ifp = fopen(hint->hint_name, "r");
332 		if (ifp == NULL)
333 			err(1, "%s", hint->hint_name);
334 		while (fgets(line, BUFSIZ, ifp) != NULL)
335 			process_into_nvlist(line, nvl);
336 		dump_nvlist(nvl, ofp);
337 		fclose(ifp);
338 	}
339 	nvlist_destroy(nvl);
340 	fprintf(ofp, "\"\\0\"\n};\n");
341 	fclose(ofp);
342 	moveifchanged(path("hints.c.new"), path("hints.c"));
343 }
344 
345 /*
346  * Build env.c from the skeleton
347  */
348 void
makeenv(void)349 makeenv(void)
350 {
351 	FILE *ifp, *ofp;
352 	nvlist_t *nvl;
353 	char line[BUFSIZ];
354 	struct envvar *envvar;
355 
356 	ofp = fopen(path("env.c.new"), "w");
357 	if (ofp == NULL)
358 		err(1, "%s", path("env.c.new"));
359 	fprintf(ofp, "#include <sys/types.h>\n");
360 	fprintf(ofp, "#include <sys/systm.h>\n");
361 	fprintf(ofp, "\n");
362 	/*
363 	 * Write out envmode for older kernels. Remove when config(8) major
364 	 * version rolls over.
365 	 */
366 	if (versreq <= CONFIGVERS_ENVMODE_REQ)
367 		fprintf(ofp, "int envmode = %d;\n",
368 			!STAILQ_EMPTY(&envvars) ? 1 : 0);
369 	fprintf(ofp, "char static_env[] = {\n");
370 	nvl = nvlist_create(0);
371 	STAILQ_FOREACH(envvar, &envvars, envvar_next) {
372 		if (envvar->env_is_file) {
373 			ifp = fopen(envvar->env_str, "r");
374 			if (ifp == NULL)
375 				err(1, "%s", envvar->env_str);
376 			while (fgets(line, BUFSIZ, ifp) != NULL)
377 				process_into_nvlist(line, nvl);
378 			dump_nvlist(nvl, ofp);
379 			fclose(ifp);
380 		} else
381 			process_into_file(envvar->env_str, ofp);
382 	}
383 	nvlist_destroy(nvl);
384 	fprintf(ofp, "\"\\0\"\n};\n");
385 	fclose(ofp);
386 	moveifchanged(path("env.c.new"), path("env.c"));
387 }
388 
389 static void
read_file(char * fname)390 read_file(char *fname)
391 {
392 	char ifname[MAXPATHLEN];
393 	FILE *fp;
394 	struct file_list *tp;
395 	struct device *dp;
396 	struct opt *op;
397 	char *wd, *this, *compilewith, *depends, *clean, *warning;
398 	const char *objprefix;
399 	int compile, match, nreqs, std, filetype, not,
400 	    imp_rule, no_ctfconvert, no_obj, before_depend, nowerror;
401 
402 	fp = fopen(fname, "r");
403 	if (fp == NULL)
404 		err(1, "%s", fname);
405 next:
406 	/*
407 	 * include "filename"
408 	 * filename    [ standard | optional ]
409 	 *	[ dev* [ | dev* ... ] | profiling-routine ] [ no-obj ]
410 	 *	[ compile-with "compile rule" [no-implicit-rule] ]
411 	 *      [ dependency "dependency-list"] [ before-depend ]
412 	 *	[ clean "file-list"] [ warning "text warning" ]
413 	 *	[ obj-prefix "file prefix"]
414 	 *	[ nowerror ] [ local ]
415 	 */
416 	wd = get_word(fp);
417 	if (wd == (char *)EOF) {
418 		(void) fclose(fp);
419 		return;
420 	}
421 	if (wd == NULL)
422 		goto next;
423 	if (wd[0] == '#')
424 	{
425 		while (((wd = get_word(fp)) != (char *)EOF) && wd)
426 			;
427 		goto next;
428 	}
429 	if (eq(wd, "include")) {
430 		wd = get_quoted_word(fp);
431 		if (wd == (char *)EOF || wd == NULL)
432 			errout("%s: missing include filename.\n", fname);
433 		(void) snprintf(ifname, sizeof(ifname), "../../%s", wd);
434 		read_file(ifname);
435 		while (((wd = get_word(fp)) != (char *)EOF) && wd)
436 			;
437 		goto next;
438 	}
439 	this = ns(wd);
440 	wd = get_word(fp);
441 	if (wd == (char *)EOF)
442 		return;
443 	if (wd == NULL)
444 		errout("%s: No type for %s.\n", fname, this);
445 	tp = fl_lookup(this);
446 	compile = 0;
447 	match = 1;
448 	nreqs = 0;
449 	compilewith = 0;
450 	depends = 0;
451 	clean = 0;
452 	warning = 0;
453 	std = 0;
454 	imp_rule = 0;
455 	no_ctfconvert = 0;
456 	no_obj = 0;
457 	before_depend = 0;
458 	nowerror = 0;
459 	not = 0;
460 	filetype = NORMAL;
461 	objprefix = "";
462 	if (eq(wd, "standard"))
463 		std = 1;
464 	else if (!eq(wd, "optional"))
465 		errout("%s: \"%s\" %s must be optional or standard\n",
466 		    fname, wd, this);
467 	for (wd = get_word(fp); wd; wd = get_word(fp)) {
468 		if (wd == (char *)EOF)
469 			return;
470 		if (eq(wd, "!")) {
471 			not = 1;
472 			continue;
473 		}
474 		if (eq(wd, "|")) {
475 			if (nreqs == 0)
476 				errout("%s: syntax error describing %s\n",
477 				       fname, this);
478 			compile += match;
479 			match = 1;
480 			nreqs = 0;
481 			continue;
482 		}
483 		if (eq(wd, "no-ctfconvert")) {
484 			no_ctfconvert++;
485 			continue;
486 		}
487 		if (eq(wd, "no-obj")) {
488 			no_obj++;
489 			continue;
490 		}
491 		if (eq(wd, "no-implicit-rule")) {
492 			if (compilewith == NULL)
493 				errout("%s: alternate rule required when "
494 				       "\"no-implicit-rule\" is specified for"
495 				       " %s.\n",
496 				       fname, this);
497 			imp_rule++;
498 			continue;
499 		}
500 		if (eq(wd, "before-depend")) {
501 			before_depend++;
502 			continue;
503 		}
504 		if (eq(wd, "dependency")) {
505 			wd = get_quoted_word(fp);
506 			if (wd == (char *)EOF || wd == NULL)
507 				errout("%s: %s missing dependency string.\n",
508 				       fname, this);
509 			depends = ns(wd);
510 			continue;
511 		}
512 		if (eq(wd, "clean")) {
513 			wd = get_quoted_word(fp);
514 			if (wd == (char *)EOF || wd == NULL)
515 				errout("%s: %s missing clean file list.\n",
516 				       fname, this);
517 			clean = ns(wd);
518 			continue;
519 		}
520 		if (eq(wd, "compile-with")) {
521 			wd = get_quoted_word(fp);
522 			if (wd == (char *)EOF || wd == NULL)
523 				errout("%s: %s missing compile command string.\n",
524 				       fname, this);
525 			compilewith = ns(wd);
526 			continue;
527 		}
528 		if (eq(wd, "warning")) {
529 			wd = get_quoted_word(fp);
530 			if (wd == (char *)EOF || wd == NULL)
531 				errout("%s: %s missing warning text string.\n",
532 				       fname, this);
533 			warning = ns(wd);
534 			continue;
535 		}
536 		if (eq(wd, "obj-prefix")) {
537 			wd = get_quoted_word(fp);
538 			if (wd == (char *)EOF || wd == NULL)
539 				errout("%s: %s missing object prefix string.\n",
540 				       fname, this);
541 			objprefix = ns(wd);
542 			continue;
543 		}
544 		if (eq(wd, "nowerror")) {
545 			nowerror = 1;
546 			continue;
547 		}
548 		if (eq(wd, "local")) {
549 			filetype = LOCAL;
550 			continue;
551 		}
552 		if (eq(wd, "no-depend")) {
553 			filetype = NODEPEND;
554 			continue;
555 		}
556 		nreqs++;
557 		if (eq(wd, "profiling-routine")) {
558 			filetype = PROFILING;
559 			continue;
560 		}
561 		if (std)
562 			errout("standard entry %s has optional inclusion specifier %s!\n",
563 			       this, wd);
564 		STAILQ_FOREACH(dp, &dtab, d_next)
565 			if (eq(dp->d_name, wd)) {
566 				if (not)
567 					match = 0;
568 				else
569 					dp->d_done |= DEVDONE;
570 				goto nextparam;
571 			}
572 		SLIST_FOREACH(op, &opt, op_next)
573 			if (op->op_value == 0 &&
574 			    strcasecmp(op->op_name, wd) == 0) {
575 				if (not)
576 					match = 0;
577 				goto nextparam;
578 			}
579 		match &= not;
580 nextparam:;
581 		not = 0;
582 	}
583 	compile += match;
584 	if (compile && tp == NULL) {
585 		if (std == 0 && nreqs == 0)
586 			errout("%s: what is %s optional on?\n",
587 			       fname, this);
588 		if (filetype == PROFILING && profiling == 0)
589 			goto next;
590 		tp = new_fent();
591 		tp->f_fn = this;
592 		tp->f_type = filetype;
593 		if (filetype == LOCAL)
594 			tp->f_srcprefix = "";
595 		else
596 			tp->f_srcprefix = "$S/";
597 		if (imp_rule)
598 			tp->f_flags |= NO_IMPLCT_RULE;
599 		if (no_ctfconvert)
600 			tp->f_flags |= NO_CTFCONVERT;
601 		if (no_obj)
602 			tp->f_flags |= NO_OBJ | NO_CTFCONVERT;
603 		if (before_depend)
604 			tp->f_flags |= BEFORE_DEPEND;
605 		if (nowerror)
606 			tp->f_flags |= NOWERROR;
607 		tp->f_compilewith = compilewith;
608 		tp->f_depends = depends;
609 		tp->f_clean = clean;
610 		tp->f_warn = warning;
611 		tp->f_objprefix = objprefix;
612 	}
613 	goto next;
614 }
615 
616 /*
617  * Read in the information about files used in making the system.
618  * Store it in the ftab linked list.
619  */
620 static void
read_files(void)621 read_files(void)
622 {
623 	char fname[MAXPATHLEN];
624 	struct files_name *nl, *tnl;
625 
626 	(void) snprintf(fname, sizeof(fname), "../../conf/files");
627 	read_file(fname);
628 	(void) snprintf(fname, sizeof(fname),
629 		       	"../../conf/files.%s", machinename);
630 	read_file(fname);
631 	for (nl = STAILQ_FIRST(&fntab); nl != NULL; nl = tnl) {
632 		read_file(nl->f_name);
633 		tnl = STAILQ_NEXT(nl, f_next);
634 		free(nl->f_name);
635 		free(nl);
636 	}
637 }
638 
639 static void
do_before_depend(FILE * fp)640 do_before_depend(FILE *fp)
641 {
642 	struct file_list *tp;
643 	int lpos, len;
644 
645 	fputs("BEFORE_DEPEND=", fp);
646 	lpos = 15;
647 	STAILQ_FOREACH(tp, &ftab, f_next)
648 		if (tp->f_flags & BEFORE_DEPEND) {
649 			len = strlen(tp->f_fn) + strlen(tp->f_srcprefix);
650 			if (len + lpos > 72) {
651 				lpos = 8;
652 				fputs("\\\n\t", fp);
653 			}
654 			if (tp->f_flags & NO_IMPLCT_RULE)
655 				lpos += fprintf(fp, "%s ", tp->f_fn);
656 			else
657 				lpos += fprintf(fp, "%s%s ", tp->f_srcprefix,
658 				    tp->f_fn);
659 		}
660 	if (lpos != 8)
661 		putc('\n', fp);
662 }
663 
664 static void
do_objs(FILE * fp)665 do_objs(FILE *fp)
666 {
667 	struct file_list *tp;
668 	int lpos, len;
669 	char *cp, och, *sp;
670 
671 	fprintf(fp, "OBJS=");
672 	lpos = 6;
673 	STAILQ_FOREACH(tp, &ftab, f_next) {
674 		if (tp->f_flags & NO_OBJ)
675 			continue;
676 		sp = tail(tp->f_fn);
677 		cp = sp + (len = strlen(sp)) - 1;
678 		och = *cp;
679 		*cp = 'o';
680 		len += strlen(tp->f_objprefix);
681 		if (len + lpos > 72) {
682 			lpos = 8;
683 			fprintf(fp, "\\\n\t");
684 		}
685 		fprintf(fp, "%s%s ", tp->f_objprefix, sp);
686 		lpos += len + 1;
687 		*cp = och;
688 	}
689 	if (lpos != 8)
690 		putc('\n', fp);
691 }
692 
693 static void
do_xxfiles(char * tag,FILE * fp)694 do_xxfiles(char *tag, FILE *fp)
695 {
696 	struct file_list *tp;
697 	int lpos, len, slen;
698 	char *suff, *SUFF;
699 
700 	if (tag[strlen(tag) - 1] == '\n')
701 		tag[strlen(tag) - 1] = '\0';
702 
703 	suff = ns(tag + 7);
704 	SUFF = ns(suff);
705 	raisestr(SUFF);
706 	slen = strlen(suff);
707 
708 	fprintf(fp, "%sFILES=", SUFF);
709 	free(SUFF);
710 	lpos = 8;
711 	STAILQ_FOREACH(tp, &ftab, f_next)
712 		if (tp->f_type != NODEPEND) {
713 			len = strlen(tp->f_fn);
714 			if (tp->f_fn[len - slen - 1] != '.')
715 				continue;
716 			if (strcasecmp(&tp->f_fn[len - slen], suff) != 0)
717 				continue;
718 			if (len + strlen(tp->f_srcprefix) + lpos > 72) {
719 				lpos = 8;
720 				fputs("\\\n\t", fp);
721 			}
722 			lpos += fprintf(fp, "%s%s ", tp->f_srcprefix, tp->f_fn);
723 		}
724 	free(suff);
725 	if (lpos != 8)
726 		putc('\n', fp);
727 }
728 
729 static char *
tail(char * fn)730 tail(char *fn)
731 {
732 	char *cp;
733 
734 	cp = strrchr(fn, '/');
735 	if (cp == NULL)
736 		return (fn);
737 	return (cp+1);
738 }
739 
740 /*
741  * Create the makerules for each file
742  * which is part of the system.
743  */
744 static void
do_rules(FILE * f)745 do_rules(FILE *f)
746 {
747 	char *cp, *np, och;
748 	struct file_list *ftp;
749 	char *compilewith;
750 	char cmd[128];
751 
752 	STAILQ_FOREACH(ftp, &ftab, f_next) {
753 		if (ftp->f_warn)
754 			fprintf(stderr, "WARNING: %s\n", ftp->f_warn);
755 		cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
756 		och = *cp;
757 		if (ftp->f_flags & NO_IMPLCT_RULE) {
758 			if (ftp->f_depends)
759 				fprintf(f, "%s%s: %s\n",
760 					ftp->f_objprefix, np, ftp->f_depends);
761 			else
762 				fprintf(f, "%s%s: \n", ftp->f_objprefix, np);
763 		}
764 		else {
765 			*cp = '\0';
766 			if (och == 'o') {
767 				fprintf(f, "%s%so:\n\t-cp %s%so .\n\n",
768 					ftp->f_objprefix, tail(np),
769 					ftp->f_srcprefix, np);
770 				continue;
771 			}
772 			if (ftp->f_depends) {
773 				fprintf(f, "%s%so: %s%s%c %s\n",
774 					ftp->f_objprefix, tail(np),
775 					ftp->f_srcprefix, np, och,
776 					ftp->f_depends);
777 			}
778 			else {
779 				fprintf(f, "%s%so: %s%s%c\n",
780 					ftp->f_objprefix, tail(np),
781 					ftp->f_srcprefix, np, och);
782 			}
783 		}
784 		compilewith = ftp->f_compilewith;
785 		if (compilewith == NULL) {
786 			const char *ftype = NULL;
787 
788 			switch (ftp->f_type) {
789 			case NORMAL:
790 				ftype = "NORMAL";
791 				break;
792 			case PROFILING:
793 				if (!profiling)
794 					continue;
795 				ftype = "PROFILE";
796 				break;
797 			default:
798 				fprintf(stderr,
799 				    "config: don't know rules for %s\n", np);
800 				break;
801 			}
802 			snprintf(cmd, sizeof(cmd),
803 			    "${%s_%c%s}", ftype,
804 			    toupper(och),
805 			    ftp->f_flags & NOWERROR ? "_NOWERROR" : "");
806 			compilewith = cmd;
807 		}
808 		*cp = och;
809 		if (strlen(ftp->f_objprefix))
810 			fprintf(f, "\t%s %s%s\n", compilewith,
811 			    ftp->f_srcprefix, np);
812 		else
813 			fprintf(f, "\t%s\n", compilewith);
814 
815 		if (!(ftp->f_flags & NO_CTFCONVERT))
816 			fprintf(f, "\t${NORMAL_CTFCONVERT}\n\n");
817 		else
818 			fprintf(f, "\n");
819 	}
820 }
821 
822 static void
do_clean(FILE * fp)823 do_clean(FILE *fp)
824 {
825 	struct file_list *tp;
826 	int lpos, len;
827 
828 	fputs("CLEAN=", fp);
829 	lpos = 7;
830 	STAILQ_FOREACH(tp, &ftab, f_next)
831 		if (tp->f_clean) {
832 			len = strlen(tp->f_clean);
833 			if (len + lpos > 72) {
834 				lpos = 8;
835 				fputs("\\\n\t", fp);
836 			}
837 			fprintf(fp, "%s ", tp->f_clean);
838 			lpos += len + 1;
839 		}
840 	if (lpos != 8)
841 		putc('\n', fp);
842 }
843 
844 char *
raisestr(char * str)845 raisestr(char *str)
846 {
847 	char *cp = str;
848 
849 	while (*str) {
850 		if (islower(*str))
851 			*str = toupper(*str);
852 		str++;
853 	}
854 	return (cp);
855 }
856