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