mkmakefile.c revision 71879
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 71879 2001-01-31 10:30:30Z 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, "ERROR: 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				exit(1);
204			}
205		} else
206			fprintf(stderr,
207			    "Unknown %% construct in generic makefile: %s",
208			    line);
209	}
210	(void) fclose(ifp);
211	(void) fclose(ofp);
212	moveifchanged(path("Makefile.new"), path("Makefile"));
213
214	if (hints) {
215		ifp = fopen(hints, "r");
216		if (ifp == NULL)
217			err(1, "%s", hints);
218	} else {
219		ifp = NULL;
220	}
221	ofp = fopen(path("hints.c.new"), "w");
222	if (ofp == NULL)
223		err(1, "%s", path("hints.c.new"));
224	if (hintmode == 0) {
225		snprintf(line, sizeof(line), "%s.hints", PREFIX);
226		ifp = fopen(line, "r");
227		if (ifp)
228			hintmode = 2;
229	}
230	fprintf(ofp, "int hintmode = %d;\n", hintmode);
231	fprintf(ofp, "char static_hints[] = {\n");
232	if (ifp) {
233		while (fgets(line, BUFSIZ, ifp) != 0) {
234			/* zap trailing CR and/or LF */
235			while ((s = rindex(line, '\n')) != NULL)
236				*s = '\0';
237			while ((s = rindex(line, '\r')) != NULL)
238				*s = '\0';
239			/* remove # comments */
240			s = index(line, '#');
241			if (s)
242				*s = '\0';
243			/* remove any whitespace and " characters */
244			s = line;
245			while (*s) {
246				if (*s == ' ' || *s == '\t' || *s == '"') {
247					while (*s) {
248						s[0] = s[1];
249						s++;
250					}
251					/* start over */
252					s = line;
253					continue;
254				}
255				s++;
256			}
257			/* anything left? */
258			if (*line == '\0')
259				continue;
260			fprintf(ofp, "\"%s\\0\"\n", line);
261		}
262	}
263	fprintf(ofp, "\"\\0\"\n};\n");
264	if (ifp)
265		fclose(ifp);
266	fclose(ofp);
267	moveifchanged(path("hints.c.new"), path("hints.c"));
268
269	printf("Don't forget to do a ``make depend''\n");
270}
271
272/*
273 * Read in the information about files used in making the system.
274 * Store it in the ftab linked list.
275 */
276static void
277read_files(void)
278{
279	FILE *fp;
280	struct file_list *tp, *pf;
281	struct device *dp;
282	struct device *save_dp;
283	struct opt *op;
284	char *wd, *this, *needs, *special, *depends, *clean, *warn;
285	char fname[MAXPATHLEN];
286	int ddwarned = 0;
287	int nreqs, first = 1, configdep, isdup, std, filetype,
288	    imp_rule, no_obj, needcount, before_depend, mandatory;
289
290	ftab = 0;
291	save_dp = NULL;
292	if (ident == NULL) {
293		printf("no ident line specified\n");
294		exit(1);
295	}
296	(void) snprintf(fname, sizeof(fname), "../../conf/files");
297openit:
298	fp = fopen(fname, "r");
299	if (fp == 0)
300		err(1, "%s", fname);
301next:
302	/*
303	 * filename    [ standard | mandatory | optional | count ]
304	 *	[ config-dependent ]
305	 *	[ dev* | profiling-routine ] [ no-obj ]
306	 *	[ compile-with "compile rule" [no-implicit-rule] ]
307	 *      [ dependency "dependency-list"] [ before-depend ]
308	 *	[ clean "file-list"] [ warning "text warning" ]
309	 */
310	wd = get_word(fp);
311	if (wd == (char *)EOF) {
312		(void) fclose(fp);
313		if (first == 1) {
314			first++;
315			(void) snprintf(fname, sizeof(fname),
316			    "../../conf/files.%s", machinename);
317			fp = fopen(fname, "r");
318			if (fp != 0)
319				goto next;
320			(void) snprintf(fname, sizeof(fname),
321			    "files.%s", machinename);
322			goto openit;
323		}
324		if (first == 2) {
325			first++;
326			(void) snprintf(fname, sizeof(fname),
327			    "files.%s", raisestr(ident));
328			fp = fopen(fname, "r");
329			if (fp != 0)
330				goto next;
331		}
332		return;
333	}
334	if (wd == 0)
335		goto next;
336	if (wd[0] == '#')
337	{
338		while (((wd = get_word(fp)) != (char *)EOF) && wd)
339			;
340		goto next;
341	}
342	this = ns(wd);
343	next_word(fp, wd);
344	if (wd == 0) {
345		printf("%s: No type for %s.\n",
346		    fname, this);
347		exit(1);
348	}
349	if ((pf = fl_lookup(this)) && (pf->f_type != INVISIBLE || pf->f_flags))
350		isdup = ISDUP;
351	else
352		isdup = 0;
353	tp = 0;
354	if (first == 3 && pf == 0 && (tp = fltail_lookup(this)) != 0) {
355		if (tp->f_type != INVISIBLE || tp->f_flags)
356			printf("%s: Local file %s overrides %s.\n",
357			    fname, this, tp->f_fn);
358		else
359			printf("%s: Local file %s could override %s"
360			    " with a different kernel configuration.\n",
361			    fname, this, tp->f_fn);
362	}
363	nreqs = 0;
364	special = 0;
365	depends = 0;
366	clean = 0;
367	warn = 0;
368	configdep = 0;
369	needs = 0;
370	std = mandatory = 0;
371	imp_rule = 0;
372	no_obj = 0;
373	needcount = 0;
374	before_depend = 0;
375	filetype = NORMAL;
376	if (eq(wd, "standard")) {
377		std = 1;
378	/*
379	 * If an entry is marked "mandatory", config will abort if it's
380	 * not called by a configuration line in the config file.  Apart
381	 * from this, the device is handled like one marked "optional".
382	 */
383	} else if (eq(wd, "mandatory")) {
384		mandatory = 1;
385	} else if (eq(wd, "count")) {
386		needcount = 1;
387	} else if (!eq(wd, "optional")) {
388		printf("%s: %s must be count, optional, mandatory or standard\n",
389		       fname, this);
390		exit(1);
391	}
392nextparam:
393	next_word(fp, wd);
394	if (wd == 0)
395		goto doneparam;
396	if (eq(wd, "config-dependent")) {
397		configdep++;
398		goto nextparam;
399	}
400	if (eq(wd, "no-obj")) {
401		no_obj++;
402		goto nextparam;
403	}
404	if (eq(wd, "no-implicit-rule")) {
405		if (special == 0) {
406			printf("%s: alternate rule required when "
407			       "\"no-implicit-rule\" is specified.\n",
408			       fname);
409		}
410		imp_rule++;
411		goto nextparam;
412	}
413	if (eq(wd, "before-depend")) {
414		before_depend++;
415		goto nextparam;
416	}
417	if (eq(wd, "dependency")) {
418		next_quoted_word(fp, wd);
419		if (wd == 0) {
420			printf("%s: %s missing compile command string.\n",
421			       fname, this);
422			exit(1);
423		}
424		depends = ns(wd);
425		goto nextparam;
426	}
427	if (eq(wd, "clean")) {
428		next_quoted_word(fp, wd);
429		if (wd == 0) {
430			printf("%s: %s missing clean file list.\n",
431			       fname, this);
432			exit(1);
433		}
434		clean = ns(wd);
435		goto nextparam;
436	}
437	if (eq(wd, "compile-with")) {
438		next_quoted_word(fp, wd);
439		if (wd == 0) {
440			printf("%s: %s missing compile command string.\n",
441			       fname, this);
442			exit(1);
443		}
444		special = ns(wd);
445		goto nextparam;
446	}
447	if (eq(wd, "warning")) {
448		next_quoted_word(fp, wd);
449		if (wd == 0) {
450			printf("%s: %s missing warning text string.\n",
451				fname, this);
452			exit(1);
453		}
454		warn = ns(wd);
455		goto nextparam;
456	}
457	nreqs++;
458	if (eq(wd, "local")) {
459		filetype = LOCAL;
460		goto nextparam;
461	}
462	if (eq(wd, "no-depend")) {
463		filetype = NODEPEND;
464		goto nextparam;
465	}
466	if (eq(wd, "device-driver")) {
467		if (!ddwarned) {
468			printf("%s: `device-driver' flag ignored.\n", fname);
469			ddwarned++;
470		}
471		goto nextparam;
472	}
473	if (eq(wd, "profiling-routine")) {
474		filetype = PROFILING;
475		goto nextparam;
476	}
477	if (needs == 0 && nreqs == 1)
478		needs = ns(wd);
479	if (isdup)
480		goto invis;
481	for (dp = dtab; dp != 0; save_dp = dp, dp = dp->d_next)
482		if (eq(dp->d_name, wd)) {
483			if (std && 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_name = ns(wd);
496		dp->d_count = 1;
497		save_dp->d_next = dp;
498		goto nextparam;
499	}
500	for (op = opt; op != 0; op = op->op_next)
501		if (op->op_value == 0 && opteq(op->op_name, wd)) {
502			if (nreqs == 1) {
503				free(needs);
504				needs = 0;
505			}
506			goto nextparam;
507		}
508invis:
509	while ((wd = get_word(fp)) != 0)
510		;
511	if (tp == 0)
512		tp = new_fent();
513	tp->f_fn = this;
514	tp->f_type = INVISIBLE;
515	tp->f_needs = needs;
516	tp->f_flags |= isdup;
517	if (needcount)
518		tp->f_flags |= NEED_COUNT;
519	tp->f_special = special;
520	tp->f_depends = depends;
521	tp->f_clean = clean;
522	tp->f_warn = warn;
523	goto next;
524
525doneparam:
526	if (std == 0 && nreqs == 0) {
527		printf("%s: what is %s optional on?\n",
528		    fname, this);
529		exit(1);
530	}
531
532	if (wd) {
533		printf("%s: syntax error describing %s\n",
534		    fname, this);
535		exit(1);
536	}
537	if (filetype == PROFILING && profiling == 0)
538		goto next;
539	if (tp == 0)
540		tp = new_fent();
541	tp->f_fn = this;
542	tp->f_type = filetype;
543	tp->f_flags &= ~ISDUP;
544	if (configdep)
545		tp->f_flags |= CONFIGDEP;
546	if (imp_rule)
547		tp->f_flags |= NO_IMPLCT_RULE;
548	if (no_obj)
549		tp->f_flags |= NO_OBJ;
550	if (before_depend)
551		tp->f_flags |= BEFORE_DEPEND;
552	if (imp_rule)
553		tp->f_flags |= NO_IMPLCT_RULE;
554	if (no_obj)
555		tp->f_flags |= NO_OBJ;
556	if (needcount)
557		tp->f_flags |= NEED_COUNT;
558	tp->f_needs = needs;
559	tp->f_special = special;
560	tp->f_depends = depends;
561	tp->f_clean = clean;
562	tp->f_warn = warn;
563	if (pf && pf->f_type == INVISIBLE)
564		pf->f_flags |= ISDUP;		/* mark as duplicate */
565	goto next;
566}
567
568static int
569opteq(char *cp, char *dp)
570{
571	char c, d;
572
573	for (; ; cp++, dp++) {
574		if (*cp != *dp) {
575			c = isupper(*cp) ? tolower(*cp) : *cp;
576			d = isupper(*dp) ? tolower(*dp) : *dp;
577			if (c != d)
578				return (0);
579		}
580		if (*cp == 0)
581			return (1);
582	}
583}
584
585static void
586do_before_depend(FILE *fp)
587{
588	struct file_list *tp;
589	int lpos, len;
590
591	fputs("BEFORE_DEPEND=", fp);
592	lpos = 15;
593	for (tp = ftab; tp; tp = tp->f_next)
594		if (tp->f_flags & BEFORE_DEPEND) {
595			len = strlen(tp->f_fn);
596			if ((len = 3 + len) + lpos > 72) {
597				lpos = 8;
598				fputs("\\\n\t", fp);
599			}
600			if (tp->f_flags & NO_IMPLCT_RULE)
601				fprintf(fp, "%s ", tp->f_fn);
602			else
603				fprintf(fp, "$S/%s ", tp->f_fn);
604			lpos += len + 1;
605		}
606	if (lpos != 8)
607		putc('\n', fp);
608}
609
610static void
611do_objs(FILE *fp)
612{
613	struct file_list *tp;
614	int lpos, len;
615	char *cp, och, *sp;
616
617	fprintf(fp, "OBJS=");
618	lpos = 6;
619	for (tp = ftab; tp != 0; tp = tp->f_next) {
620		if (tp->f_type == INVISIBLE || tp->f_flags & NO_OBJ)
621			continue;
622		sp = tail(tp->f_fn);
623		cp = sp + (len = strlen(sp)) - 1;
624		och = *cp;
625		*cp = 'o';
626		if (len + lpos > 72) {
627			lpos = 8;
628			fprintf(fp, "\\\n\t");
629		}
630		fprintf(fp, "%s ", sp);
631		lpos += len + 1;
632		*cp = och;
633	}
634	if (lpos != 8)
635		putc('\n', fp);
636}
637
638static void
639do_xxfiles(char *tag, FILE *fp)
640{
641	struct file_list *tp;
642	int lpos, len, slen;
643	char *suff, *SUFF;
644
645	if (tag[strlen(tag) - 1] == '\n')
646		tag[strlen(tag) - 1] = '\0';
647
648	suff = ns(tag + 7);
649	SUFF = ns(suff);
650	raisestr(SUFF);
651	slen = strlen(suff);
652
653	fprintf(fp, "%sFILES=", SUFF);
654	lpos = 8;
655	for (tp = ftab; tp; tp = tp->f_next)
656		if (tp->f_type != INVISIBLE && tp->f_type != NODEPEND) {
657			len = strlen(tp->f_fn);
658			if (tp->f_fn[len - slen - 1] != '.')
659				continue;
660			if (strcasecmp(&tp->f_fn[len - slen], suff) != 0)
661				continue;
662			if ((len = 3 + len) + lpos > 72) {
663				lpos = 8;
664				fputs("\\\n\t", fp);
665			}
666			if (tp->f_type != LOCAL)
667				fprintf(fp, "$S/%s ", tp->f_fn);
668			else
669				fprintf(fp, "%s ", tp->f_fn);
670			lpos += len + 1;
671		}
672	if (lpos != 8)
673		putc('\n', fp);
674}
675
676static char *
677tail(char *fn)
678{
679	char *cp;
680
681	cp = rindex(fn, '/');
682	if (cp == 0)
683		return (fn);
684	return (cp+1);
685}
686
687/*
688 * Create the makerules for each file
689 * which is part of the system.
690 * Devices are processed with the special c2 option -i
691 * which avoids any problem areas with i/o addressing
692 * (e.g. for the VAX); assembler files are processed by as.
693 */
694static void
695do_rules(FILE *f)
696{
697	char *cp, *np, och, *tp;
698	struct file_list *ftp;
699	char *special;
700
701	for (ftp = ftab; ftp != 0; ftp = ftp->f_next) {
702		if (ftp->f_type == INVISIBLE)
703			continue;
704		if (ftp->f_warn)
705			printf("WARNING: %s\n", ftp->f_warn);
706		cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
707		och = *cp;
708		if (ftp->f_flags & NO_IMPLCT_RULE) {
709			if (ftp->f_depends)
710				fprintf(f, "%s: %s\n", np, ftp->f_depends);
711			else
712				fprintf(f, "%s: \n", np);
713		}
714		else {
715			*cp = '\0';
716			if (och == 'o') {
717				fprintf(f, "%so:\n\t-cp $S/%so .\n\n",
718					tail(np), np);
719				continue;
720			}
721			if (ftp->f_depends)
722				fprintf(f, "%so: $S/%s%c %s\n", tail(np),
723					np, och, ftp->f_depends);
724			else
725				fprintf(f, "%so: $S/%s%c\n", tail(np),
726					np, och);
727		}
728		tp = tail(np);
729		special = ftp->f_special;
730		if (special == 0) {
731			char *ftype = NULL;
732			static char cmd[128];
733
734			switch (ftp->f_type) {
735
736			case NORMAL:
737				ftype = "NORMAL";
738				break;
739
740			case PROFILING:
741				if (!profiling)
742					continue;
743				ftype = "PROFILE";
744				break;
745
746			default:
747				printf("config: don't know rules for %s\n", np);
748				break;
749			}
750			(void)snprintf(cmd, sizeof(cmd), "${%s_%c%s}", 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
759static void
760do_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; 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
781char *
782raisestr(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