xref: /dflybsd-src/usr.sbin/config/mkmakefile.c (revision 744c01d0dc2aa1481a40e5b0988d15691602f5c9)
1 /*
2  * Copyright (c) 1993, 19801990
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)mkmakefile.c	8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.sbin/config/mkmakefile.c,v 1.51.2.3 2001/01/23 00:09:32 peter Exp $
35  * $DragonFly: src/usr.sbin/config/mkmakefile.c,v 1.17 2006/11/07 06:57:02 dillon Exp $
36  */
37 
38 /*
39  * Build the makefile for the system, from
40  * the information in the 'files' files and the
41  * additional files for the machine being compiled to.
42  */
43 
44 #include <ctype.h>
45 #include <err.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <sys/param.h>
49 #include "y.tab.h"
50 #include "config.h"
51 #include "configvers.h"
52 
53 #define next_word(fp, wd)						\
54 	{								\
55 		char *word;						\
56 									\
57 		word = get_word(fp);					\
58 		if (word == (char *)EOF)				\
59 			return;						\
60 		else							\
61 			wd = word;					\
62 	}
63 #define next_quoted_word(fp, wd)					\
64 	{								\
65 		char *word;						\
66 									\
67 		word = get_quoted_word(fp);				\
68 		if (word == (char *)EOF)				\
69 			return;						\
70 		else							\
71 			wd = word;					\
72 	}
73 
74 static struct file_list *fcur;
75 
76 static char *tail(char *);
77 static void do_clean(FILE *);
78 static void do_rules(FILE *);
79 static void do_sfiles(FILE *);
80 static void do_mfiles(FILE *);
81 static void do_cfiles(FILE *);
82 static void do_objs(FILE *);
83 static void do_before_depend(FILE *);
84 static int opteq(char *, char *);
85 static void read_files(void);
86 
87 /*
88  * Lookup a file, by name.
89  */
90 static struct file_list *
91 fl_lookup(char *file)
92 {
93 	struct file_list *fp;
94 
95 	for (fp = ftab; fp != NULL; fp = fp->f_next) {
96 		if (strcmp(fp->f_fn, file) == 0)
97 			return(fp);
98 	}
99 	return(0);
100 }
101 
102 /*
103  * Lookup a file, by final component name.
104  */
105 static struct file_list *
106 fltail_lookup(char *file)
107 {
108 	struct file_list *fp;
109 
110 	for (fp = ftab; fp != NULL; fp = fp->f_next) {
111 		if (strcmp(tail(fp->f_fn), tail(file)) == 0)
112 			return(fp);
113 	}
114 	return(0);
115 }
116 
117 /*
118  * Make a new file list entry
119  */
120 static struct file_list *
121 new_fent(void)
122 {
123 	struct file_list *fp;
124 
125 	fp = malloc(sizeof(*fp));
126 	bzero(fp, sizeof(*fp));
127 	if (fcur == NULL)
128 		fcur = ftab = fp;
129 	else
130 		fcur->f_next = fp;
131 	fcur = fp;
132 	return(fp);
133 }
134 
135 /*
136  * Build the makefile from the skeleton
137  */
138 void
139 makefile(void)
140 {
141 	FILE *ifp, *ofp;
142 	char line[BUFSIZ];
143 	struct opt *op;
144 	int versreq;
145 
146 	read_files();
147 	snprintf(line, sizeof(line), "../machine/%s/conf/Makefile",
148 		 machinename);
149 	ifp = fopen(line, "r");
150 	if (ifp == NULL) {
151 		snprintf(line, sizeof(line), "Makefile.%s", machinename);
152 		ifp = fopen(line, "r");
153 	}
154 	if (ifp == NULL)
155 		err(1, "%s", line);
156 	ofp = fopen(path("Makefile.new"), "w");
157 	if (ofp == NULL)
158 		err(1, "%s", path("Makefile.new"));
159 	fprintf(ofp, "KERN_IDENT=%s\n", raisestr(ident));
160 	fprintf(ofp, "MACHINE=%s\n", machinename);
161 	fprintf(ofp, "MACHINE_ARCH=%s\n", machinearchname);
162 	fprintf(ofp, ".makeenv MACHINE\n");
163 	fprintf(ofp, ".makeenv MACHINE_ARCH\n");
164 	fprintf(ofp, "IDENT=");
165 	if (profiling)
166 		fprintf(ofp, " -DGPROF");
167 
168 	if (cputype == 0) {
169 		printf("cpu type must be specified\n");
170 		exit(1);
171 	}
172 	fprintf(ofp, "\n");
173 	for (op = mkopt; op != NULL; op = op->op_next)
174 		fprintf(ofp, "%s=%s\n", op->op_name, op->op_value);
175 	if (debugging)
176 		fprintf(ofp, "DEBUG=-g\n");
177 	if (profiling) {
178 		fprintf(ofp, "PROF=-pg\n");
179 		fprintf(ofp, "PROFLEVEL=%d\n", profiling);
180 	}
181 	if (*srcdir != '\0')
182 		fprintf(ofp,"S=%s\n", srcdir);
183 	while (fgets(line, BUFSIZ, ifp) != 0) {
184 		if (*line != '%') {
185 			fprintf(ofp, "%s", line);
186 			continue;
187 		}
188 		if (strcmp(line, "%BEFORE_DEPEND\n") == 0)
189 			do_before_depend(ofp);
190 		else if (strcmp(line, "%OBJS\n") == 0)
191 			do_objs(ofp);
192 		else if (strcmp(line, "%MFILES\n") == 0)
193 			do_mfiles(ofp);
194 		else if (strcmp(line, "%CFILES\n") == 0)
195 			do_cfiles(ofp);
196 		else if (strcmp(line, "%SFILES\n") == 0)
197 			do_sfiles(ofp);
198 		else if (strcmp(line, "%RULES\n") == 0)
199 			do_rules(ofp);
200 		else if (strcmp(line, "%CLEAN\n") == 0)
201 			do_clean(ofp);
202 		else if (strncmp(line, "%VERSREQ=", sizeof("%VERSREQ=") - 1) == 0) {
203 			versreq = atoi(line + sizeof("%VERSREQ=") - 1);
204 			if (versreq != CONFIGVERS) {
205 				fprintf(stderr, "ERROR: version of config(8) does not match kernel!\n");
206 				fprintf(stderr, "config version = %d, ", CONFIGVERS);
207 				fprintf(stderr, "version required = %d\n\n", versreq);
208 				fprintf(stderr, "Make sure that /usr/src/usr.sbin/config is in sync\n");
209 				fprintf(stderr, "with your /usr/src/sys and install a new config binary\n");
210 				fprintf(stderr, "before trying this again.\n\n");
211 				fprintf(stderr, "If running the new config fails check your config\n");
212 				fprintf(stderr, "file against the GENERIC or LINT config files for\n");
213 				fprintf(stderr, "changes in config syntax, or option/device naming\n");
214 				fprintf(stderr, "conventions\n\n");
215 				exit(1);
216 			}
217 		} else
218 			fprintf(stderr,
219 			    "Unknown %% construct in generic makefile: %s",
220 			    line);
221 	}
222 	fclose(ifp);
223 	fclose(ofp);
224 	moveifchanged(path("Makefile.new"), path("Makefile"));
225 }
226 
227 /*
228  * Read in the information about files used in making the system.
229  * Store it in the ftab linked list.
230  */
231 static void
232 read_files(void)
233 {
234 	FILE *fp;
235 	struct file_list *tp, *pf;
236 	struct device *dp;
237 	struct device *save_dp;
238 	struct opt *op;
239 	char *wd, *this, *needs, *special, *depends, *clean, *warning;
240 	char fname[MAXPATHLEN];
241 	int nonoptional;
242 	int nreqs, first = 1, configdep, isdup, std, filetype,
243 	    imp_rule, no_obj, before_depend, mandatory;
244 
245 	ftab = 0;
246 	save_dp = NULL;
247 	if (ident == NULL) {
248 		printf("no ident line specified\n");
249 		exit(1);
250 	}
251 	snprintf(fname, sizeof(fname), "../conf/files");
252 openit:
253 	fp = fopen(fname, "r");
254 	if (fp == NULL)
255 		err(1, "%s", fname);
256 next:
257 	/*
258 	 * filename    [ standard | mandatory | optional ] [ config-dependent ]
259 	 *	[ dev* | profiling-routine ] [ no-obj ]
260 	 *	[ compile-with "compile rule" [no-implicit-rule] ]
261 	 *      [ dependency "dependency-list"] [ before-depend ]
262 	 *	[ clean "file-list"] [ warning "text warning" ]
263 	 */
264 	wd = get_word(fp);
265 	if (wd == (char *)EOF) {
266 		fclose(fp);
267 		if (first == 1) {
268 			first++;
269 			snprintf(fname, sizeof(fname),
270 			    "../machine/%s/conf/files",
271 			    machinename);
272 			fp = fopen(fname, "r");
273 			if (fp != NULL)
274 				goto next;
275 			snprintf(fname, sizeof(fname),
276 			    "files.%s", machinename);
277 			goto openit;
278 		}
279 		if (first == 2) {
280 			first++;
281 			snprintf(fname, sizeof(fname),
282 			    "files.%s", raisestr(ident));
283 			fp = fopen(fname, "r");
284 			if (fp != NULL)
285 				goto next;
286 		}
287 		return;
288 	}
289 	if (wd == 0)
290 		goto next;
291 	if (wd[0] == '#')
292 	{
293 		while (((wd = get_word(fp)) != (char *)EOF) && wd)
294 			;
295 		goto next;
296 	}
297 	this = strdup(wd);
298 	next_word(fp, wd);
299 	if (wd == 0) {
300 		printf("%s: No type for %s.\n",
301 		    fname, this);
302 		exit(1);
303 	}
304 	if ((pf = fl_lookup(this)) && (pf->f_type != INVISIBLE || pf->f_flags))
305 		isdup = 1;
306 	else
307 		isdup = 0;
308 	tp = 0;
309 	if (first == 3 && pf == NULL && (tp = fltail_lookup(this)) != NULL) {
310 		if (tp->f_type != INVISIBLE || tp->f_flags)
311 			printf("%s: Local file %s overrides %s.\n",
312 			    fname, this, tp->f_fn);
313 		else
314 			printf("%s: Local file %s could override %s"
315 			    " with a different kernel configuration.\n",
316 			    fname, this, tp->f_fn);
317 	}
318 	nreqs = 0;
319 	special = NULL;
320 	depends = NULL;
321 	clean = NULL;
322 	warning = NULL;
323 	configdep = 0;
324 	needs = NULL;
325 	std = mandatory = nonoptional = 0;
326 	imp_rule = 0;
327 	no_obj = 0;
328 	before_depend = 0;
329 	filetype = NORMAL;
330 	if (strcmp(wd, "standard") == 0) {
331 		std = 1;
332 	} else if (strcmp(wd, "mandatory") == 0) {
333 		/*
334 		 * If an entry is marked "mandatory", config will abort if
335 		 * it's not called by a configuration line in the config
336 		 * file.  Apart from this, the device is handled like one
337 		 * marked "optional".
338 		 */
339 		mandatory = 1;
340 	} else if (strcmp(wd, "nonoptional") == 0) {
341 		nonoptional = 1;
342 	} else if (strcmp(wd, "optional") == 0) {
343 		/* don't need to do anything */
344 	} else {
345 		printf("%s: %s must be optional, mandatory or standard\n",
346 		       fname, this);
347 		printf("Alternatively, your version of config(8) may be out of sync with your\nkernel source.\n");
348 		exit(1);
349 	}
350 nextparam:
351 	next_word(fp, wd);
352 	if (wd == NULL)
353 		goto doneparam;
354 	if (strcmp(wd, "config-dependent") == 0) {
355 		configdep++;
356 		goto nextparam;
357 	}
358 	if (strcmp(wd, "no-obj") == 0) {
359 		no_obj++;
360 		goto nextparam;
361 	}
362 	if (strcmp(wd, "no-implicit-rule") == 0) {
363 		if (special == NULL) {
364 			printf("%s: alternate rule required when "
365 			       "\"no-implicit-rule\" is specified.\n",
366 			       fname);
367 		}
368 		imp_rule++;
369 		goto nextparam;
370 	}
371 	if (strcmp(wd, "before-depend") == 0) {
372 		before_depend++;
373 		goto nextparam;
374 	}
375 	if (strcmp(wd, "dependency") == 0) {
376 		next_quoted_word(fp, wd);
377 		if (wd == NULL) {
378 			printf("%s: %s missing compile command string.\n",
379 			       fname, this);
380 			exit(1);
381 		}
382 		depends = strdup(wd);
383 		goto nextparam;
384 	}
385 	if (strcmp(wd, "clean") == 0) {
386 		next_quoted_word(fp, wd);
387 		if (wd == NULL) {
388 			printf("%s: %s missing clean file list.\n",
389 			       fname, this);
390 			exit(1);
391 		}
392 		clean = strdup(wd);
393 		goto nextparam;
394 	}
395 	if (strcmp(wd, "compile-with") == 0) {
396 		next_quoted_word(fp, wd);
397 		if (wd == NULL) {
398 			printf("%s: %s missing compile command string.\n",
399 			       fname, this);
400 			exit(1);
401 		}
402 		special = strdup(wd);
403 		goto nextparam;
404 	}
405 	if (strcmp(wd, "warning") == 0) {
406 		next_quoted_word(fp, wd);
407 		if (wd == NULL) {
408 			printf("%s: %s missing warning text string.\n",
409 				fname, this);
410 			exit(1);
411 		}
412 		warning = strdup(wd);
413 		goto nextparam;
414 	}
415 	nreqs++;
416 	if (strcmp(wd, "local") == 0) {
417 		filetype = LOCAL;
418 		goto nextparam;
419 	}
420 	if (strcmp(wd, "no-depend") == 0) {
421 		filetype = NODEPEND;
422 		goto nextparam;
423 	}
424 	if (strcmp(wd, "device-driver") == 0) {
425 		printf("%s: `device-driver' flag obsolete.\n", fname);
426 		exit(1);
427 	}
428 	if (strcmp(wd, "profiling-routine") == 0) {
429 		filetype = PROFILING;
430 		goto nextparam;
431 	}
432 	if (needs == 0 && nreqs == 1)
433 		needs = strdup(wd);
434 	if (isdup)
435 		goto invis;
436 	for (dp = dtab; dp != NULL; save_dp = dp, dp = dp->d_next)
437 		if (strcmp(dp->d_name, wd) == 0) {
438 			if (std && dp->d_type == PSEUDO_DEVICE &&
439 			    dp->d_count <= 0)
440 				dp->d_count = 1;
441 			goto nextparam;
442 		}
443 	if (mandatory) {
444 		printf("%s: mandatory device \"%s\" not found\n",
445 		       fname, wd);
446 		exit(1);
447 	}
448 	if (std) {
449 		dp = malloc(sizeof(*dp));
450 		bzero(dp, sizeof(*dp));
451 		init_dev(dp);
452 		dp->d_name = strdup(wd);
453 		dp->d_type = PSEUDO_DEVICE;
454 		dp->d_count = 1;
455 		save_dp->d_next = dp;
456 		goto nextparam;
457 	}
458 	for (op = opt; op != NULL; op = op->op_next) {
459 		if (op->op_value == 0 && opteq(op->op_name, wd)) {
460 			if (nreqs == 1) {
461 				free(needs);
462 				needs = NULL;
463 			}
464 			goto nextparam;
465 		}
466 	}
467 	if (nonoptional) {
468 		printf("%s: the option \"%s\" MUST be specified\n",
469 			fname, wd);
470 		exit(1);
471 	}
472 invis:
473 	while ((wd = get_word(fp)) != 0)
474 		;
475 	if (tp == NULL)
476 		tp = new_fent();
477 	tp->f_fn = this;
478 	tp->f_type = INVISIBLE;
479 	tp->f_needs = needs;
480 	tp->f_flags = isdup;
481 	tp->f_special = special;
482 	tp->f_depends = depends;
483 	tp->f_clean = clean;
484 	tp->f_warn = warning;
485 	goto next;
486 
487 doneparam:
488 	if (std == 0 && nreqs == 0) {
489 		printf("%s: what is %s optional on?\n",
490 		    fname, this);
491 		exit(1);
492 	}
493 
494 	if (wd != NULL) {
495 		printf("%s: syntax error describing %s\n",
496 		    fname, this);
497 		exit(1);
498 	}
499 	if (filetype == PROFILING && profiling == 0)
500 		goto next;
501 	if (tp == NULL)
502 		tp = new_fent();
503 	tp->f_fn = this;
504 	tp->f_type = filetype;
505 	tp->f_flags = 0;
506 	if (configdep)
507 		tp->f_flags |= CONFIGDEP;
508 	if (imp_rule)
509 		tp->f_flags |= NO_IMPLCT_RULE;
510 	if (no_obj)
511 		tp->f_flags |= NO_OBJ;
512 	if (before_depend)
513 		tp->f_flags |= BEFORE_DEPEND;
514 	if (imp_rule)
515 		tp->f_flags |= NO_IMPLCT_RULE;
516 	if (no_obj)
517 		tp->f_flags |= NO_OBJ;
518 	tp->f_needs = needs;
519 	tp->f_special = special;
520 	tp->f_depends = depends;
521 	tp->f_clean = clean;
522 	tp->f_warn = warning;
523 	if (pf && pf->f_type == INVISIBLE)
524 		pf->f_flags = 1;		/* mark as duplicate */
525 	goto next;
526 }
527 
528 static int
529 opteq(char *cp, char *dp)
530 {
531 	char c, d;
532 
533 	for (;; cp++, dp++) {
534 		if (*cp != *dp) {
535 			c = isupper(*cp) ? tolower(*cp) : *cp;
536 			d = isupper(*dp) ? tolower(*dp) : *dp;
537 			if (c != d)
538 				return(0);
539 		}
540 		if (*cp == 0)
541 			return(1);
542 	}
543 }
544 
545 static void
546 do_before_depend(FILE *fp)
547 {
548 	struct file_list *tp;
549 	int lpos, len;
550 
551 	fputs("BEFORE_DEPEND=", fp);
552 	lpos = 15;
553 	for (tp = ftab; tp != NULL; tp = tp->f_next)
554 		if (tp->f_flags & BEFORE_DEPEND) {
555 			len = strlen(tp->f_fn);
556 			if ((len = 3 + len) + lpos > 72) {
557 				lpos = 8;
558 				fputs("\\\n\t", fp);
559 			}
560 			if (tp->f_flags & NO_IMPLCT_RULE)
561 				fprintf(fp, "%s ", tp->f_fn);
562 			else
563 				fprintf(fp, "$S/%s ", tp->f_fn);
564 			lpos += len + 1;
565 		}
566 	if (lpos != 8)
567 		putc('\n', fp);
568 }
569 
570 static void
571 do_objs(FILE *fp)
572 {
573 	struct file_list *tp;
574 	int lpos, len;
575 	char *cp, och, *sp;
576 
577 	fprintf(fp, "OBJS=");
578 	lpos = 6;
579 	for (tp = ftab; tp != NULL; tp = tp->f_next) {
580 		if (tp->f_type == INVISIBLE || tp->f_flags & NO_OBJ)
581 			continue;
582 		sp = tail(tp->f_fn);
583 		cp = sp + (len = strlen(sp)) - 1;
584 		och = *cp;
585 		*cp = 'o';
586 		if (len + lpos > 72) {
587 			lpos = 8;
588 			fprintf(fp, "\\\n\t");
589 		}
590 		fprintf(fp, "%s ", sp);
591 		lpos += len + 1;
592 		*cp = och;
593 	}
594 	if (lpos != 8)
595 		putc('\n', fp);
596 }
597 
598 static void
599 do_cfiles(FILE *fp)
600 {
601 	struct file_list *tp;
602 	int lpos, len;
603 
604 	fputs("CFILES=", fp);
605 	lpos = 8;
606 	for (tp = ftab; tp != NULL; tp = tp->f_next)
607 		if (tp->f_type != INVISIBLE && tp->f_type != NODEPEND) {
608 			len = strlen(tp->f_fn);
609 			if (tp->f_fn[len - 1] != 'c')
610 				continue;
611 			if ((len = 3 + len) + lpos > 72) {
612 				lpos = 8;
613 				fputs("\\\n\t", fp);
614 			}
615 			if (tp->f_type != LOCAL)
616 				fprintf(fp, "$S/%s ", tp->f_fn);
617 			else
618 				fprintf(fp, "%s ", tp->f_fn);
619 
620 			lpos += len + 1;
621 		}
622 	if (lpos != 8)
623 		putc('\n', fp);
624 }
625 
626 static void
627 do_mfiles(FILE *fp)
628 {
629 	struct file_list *tp;
630 	int lpos, len;
631 
632 	fputs("MFILES=", fp);
633 	lpos = 8;
634 	for (tp = ftab; tp != NULL; tp = tp->f_next)
635 		if (tp->f_type != INVISIBLE) {
636 			len = strlen(tp->f_fn);
637 			if (tp->f_fn[len - 1] != 'm' || tp->f_fn[len - 2] != '.')
638 				continue;
639 			if ((len = 3 + len) + lpos > 72) {
640 				lpos = 8;
641 				fputs("\\\n\t", fp);
642 			}
643 			fprintf(fp, "$S/%s ", tp->f_fn);
644 			lpos += len + 1;
645 		}
646 	if (lpos != 8)
647 		putc('\n', fp);
648 }
649 
650 static void
651 do_sfiles(FILE *fp)
652 {
653 	struct file_list *tp;
654 	int lpos, len;
655 
656 	fputs("SFILES=", fp);
657 	lpos = 8;
658 	for (tp = ftab; tp != NULL; tp = tp->f_next)
659 		if (tp->f_type != INVISIBLE) {
660 			len = strlen(tp->f_fn);
661 			if (tp->f_fn[len - 1] != 'S' && tp->f_fn[len - 1] != 's')
662 				continue;
663 			if ((len = 3 + len) + lpos > 72) {
664 				lpos = 8;
665 				fputs("\\\n\t", fp);
666 			}
667 			fprintf(fp, "$S/%s ", tp->f_fn);
668 			lpos += len + 1;
669 		}
670 	if (lpos != 8)
671 		putc('\n', fp);
672 }
673 
674 
675 static char *
676 tail(char *fn)
677 {
678 	char *cp;
679 
680 	cp = strrchr(fn, '/');
681 	if (cp == 0)
682 		return(fn);
683 	return(cp + 1);
684 }
685 
686 /*
687  * Create the makerules for each file
688  * which is part of the system.
689  * Devices are processed with the special c2 option -i
690  * which avoids any problem areas with i/o addressing
691  * (e.g. for the VAX); assembler files are processed by as.
692  */
693 static void
694 do_rules(FILE *f)
695 {
696 	char *cp, *np, och, *tp;
697 	struct file_list *ftp;
698 	char *special;
699 
700 	for (ftp = ftab; ftp != NULL; ftp = ftp->f_next) {
701 		if (ftp->f_type == INVISIBLE)
702 			continue;
703 		if (ftp->f_warn != NULL)
704 			printf("WARNING: %s\n", ftp->f_warn);
705 		cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
706 		och = *cp;
707 		if (ftp->f_flags & NO_IMPLCT_RULE) {
708 			if (ftp->f_depends)
709 				fprintf(f, "%s: %s\n", np, ftp->f_depends);
710 			else
711 				fprintf(f, "%s: \n", np);
712 		}
713 		else {
714 			*cp = '\0';
715 			if (och == 'o') {
716 				fprintf(f, "%so:\n\t-cp $S/%so .\n\n",
717 					tail(np), np);
718 				continue;
719 			}
720 			if (ftp->f_depends)
721 				fprintf(f, "%so: $S/%s%c %s\n", tail(np),
722 					np, och, ftp->f_depends);
723 			else
724 				fprintf(f, "%so: $S/%s%c\n", tail(np),
725 					np, och);
726 		}
727 		tp = tail(np);
728 		special = ftp->f_special;
729 		if (special == NULL) {
730 			const char *ftype = NULL;
731 			static char cmd[128];
732 
733 			switch (ftp->f_type) {
734 
735 			case NORMAL:
736 				ftype = "NORMAL";
737 				break;
738 
739 			case PROFILING:
740 				if (!profiling)
741 					continue;
742 				ftype = "PROFILE";
743 				break;
744 
745 			default:
746 				printf("config: don't know rules for %s\n", np);
747 				break;
748 			}
749 			snprintf(cmd, sizeof(cmd), "${%s_%c%s}",
750 			    ftype, toupper(och),
751 			    ftp->f_flags & CONFIGDEP ? "_C" : "");
752 			special = cmd;
753 		}
754 		*cp = och;
755 		fprintf(f, "\t%s\n\n", special);
756 	}
757 }
758 
759 static void
760 do_clean(FILE *fp)
761 {
762 	struct file_list *tp;
763 	int lpos, len;
764 
765 	fputs("CLEAN=", fp);
766 	lpos = 7;
767 	for (tp = ftab; tp != NULL; tp = tp->f_next)
768 		if (tp->f_clean) {
769 			len = strlen(tp->f_clean);
770 			if (len + lpos > 72) {
771 				lpos = 8;
772 				fputs("\\\n\t", fp);
773 			}
774 			fprintf(fp, "%s ", tp->f_clean);
775 			lpos += len + 1;
776 		}
777 	if (lpos != 8)
778 		putc('\n', fp);
779 }
780 
781 char *
782 raisestr(char *str)
783 {
784 	char *cp = str;
785 
786 	while (*str) {
787 		if (islower(*str))
788 			*str = toupper(*str);
789 		str++;
790 	}
791 	return(cp);
792 }
793