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