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