mkmakefile.c revision 218544
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 218544 2011-02-11 06:35:53Z imp $";
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 * Open the correct Makefile and return it, or error out.
109 */
110FILE *
111open_makefile_template(void)
112{
113	FILE *ifp;
114	char line[BUFSIZ];
115
116	snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename);
117	ifp = fopen(line, "r");
118	if (ifp == 0) {
119		snprintf(line, sizeof(line), "Makefile.%s", machinename);
120		ifp = fopen(line, "r");
121	}
122	if (ifp == 0)
123		err(1, "%s", line);
124	return (ifp);
125}
126
127/*
128 * Build the makefile from the skeleton
129 */
130void
131makefile(void)
132{
133	FILE *ifp, *ofp;
134	char line[BUFSIZ];
135	struct opt *op, *t;
136
137	read_files();
138	ifp = open_makefile_template();
139	ofp = fopen(path("Makefile.new"), "w");
140	if (ofp == 0)
141		err(1, "%s", path("Makefile.new"));
142	fprintf(ofp, "KERN_IDENT=%s\n", ident);
143	fprintf(ofp, "MACHINE=%s\n", machinename);
144	fprintf(ofp, "MACHINE_ARCH=%s\n", machinearch);
145	SLIST_FOREACH_SAFE(op, &mkopt, op_next, t) {
146		fprintf(ofp, "%s=%s", op->op_name, op->op_value);
147		while ((op = SLIST_NEXT(op, op_append)) != NULL)
148			fprintf(ofp, " %s", op->op_value);
149		fprintf(ofp, "\n");
150	}
151	if (debugging)
152		fprintf(ofp, "DEBUG=-g\n");
153	if (profiling)
154		fprintf(ofp, "PROFLEVEL=%d\n", profiling);
155	if (*srcdir != '\0')
156		fprintf(ofp,"S=%s\n", srcdir);
157	while (fgets(line, BUFSIZ, ifp) != 0) {
158		if (*line != '%') {
159			fprintf(ofp, "%s", line);
160			continue;
161		}
162		if (eq(line, "%BEFORE_DEPEND\n"))
163			do_before_depend(ofp);
164		else if (eq(line, "%OBJS\n"))
165			do_objs(ofp);
166		else if (strncmp(line, "%FILES.", 7) == 0)
167			do_xxfiles(line, ofp);
168		else if (eq(line, "%RULES\n"))
169			do_rules(ofp);
170		else if (eq(line, "%CLEAN\n"))
171			do_clean(ofp);
172		else if (strncmp(line, "%VERSREQ=", 9) == 0)
173			line[0] = '\0'; /* handled elsewhere */
174		else
175			fprintf(stderr,
176			    "Unknown %% construct in generic makefile: %s",
177			    line);
178	}
179	(void) fclose(ifp);
180	(void) fclose(ofp);
181	moveifchanged(path("Makefile.new"), path("Makefile"));
182}
183
184/*
185 * Build hints.c from the skeleton
186 */
187void
188makehints(void)
189{
190	FILE *ifp, *ofp;
191	char line[BUFSIZ];
192	char *s;
193	struct hint *hint;
194
195	ofp = fopen(path("hints.c.new"), "w");
196	if (ofp == NULL)
197		err(1, "%s", path("hints.c.new"));
198	fprintf(ofp, "#include <sys/types.h>\n");
199	fprintf(ofp, "#include <sys/systm.h>\n");
200	fprintf(ofp, "\n");
201	fprintf(ofp, "int hintmode = %d;\n", hintmode);
202	fprintf(ofp, "char static_hints[] = {\n");
203	STAILQ_FOREACH(hint, &hints, hint_next) {
204		ifp = fopen(hint->hint_name, "r");
205		if (ifp == NULL)
206			err(1, "%s", hint->hint_name);
207		while (fgets(line, BUFSIZ, ifp) != 0) {
208			/* zap trailing CR and/or LF */
209			while ((s = rindex(line, '\n')) != NULL)
210				*s = '\0';
211			while ((s = rindex(line, '\r')) != NULL)
212				*s = '\0';
213			/* remove # comments */
214			s = index(line, '#');
215			if (s)
216				*s = '\0';
217			/* remove any whitespace and " characters */
218			s = line;
219			while (*s) {
220				if (*s == ' ' || *s == '\t' || *s == '"') {
221					while (*s) {
222						s[0] = s[1];
223						s++;
224					}
225					/* start over */
226					s = line;
227					continue;
228				}
229				s++;
230			}
231			/* anything left? */
232			if (*line == '\0')
233				continue;
234			fprintf(ofp, "\"%s\\0\"\n", line);
235		}
236		fclose(ifp);
237	}
238	fprintf(ofp, "\"\\0\"\n};\n");
239	fclose(ofp);
240	moveifchanged(path("hints.c.new"), path("hints.c"));
241}
242
243/*
244 * Build env.c from the skeleton
245 */
246void
247makeenv(void)
248{
249	FILE *ifp, *ofp;
250	char line[BUFSIZ];
251	char *s;
252
253	if (env) {
254		ifp = fopen(env, "r");
255		if (ifp == NULL)
256			err(1, "%s", env);
257	} else {
258		ifp = NULL;
259	}
260	ofp = fopen(path("env.c.new"), "w");
261	if (ofp == NULL)
262		err(1, "%s", path("env.c.new"));
263	fprintf(ofp, "#include <sys/types.h>\n");
264	fprintf(ofp, "#include <sys/systm.h>\n");
265	fprintf(ofp, "\n");
266	fprintf(ofp, "int envmode = %d;\n", envmode);
267	fprintf(ofp, "char static_env[] = {\n");
268	if (ifp) {
269		while (fgets(line, BUFSIZ, ifp) != 0) {
270			/* zap trailing CR and/or LF */
271			while ((s = rindex(line, '\n')) != NULL)
272				*s = '\0';
273			while ((s = rindex(line, '\r')) != NULL)
274				*s = '\0';
275			/* remove # comments */
276			s = index(line, '#');
277			if (s)
278				*s = '\0';
279			/* remove any whitespace and " characters */
280			s = line;
281			while (*s) {
282				if (*s == ' ' || *s == '\t' || *s == '"') {
283					while (*s) {
284						s[0] = s[1];
285						s++;
286					}
287					/* start over */
288					s = line;
289					continue;
290				}
291				s++;
292			}
293			/* anything left? */
294			if (*line == '\0')
295				continue;
296			fprintf(ofp, "\"%s\\0\"\n", line);
297		}
298	}
299	fprintf(ofp, "\"\\0\"\n};\n");
300	if (ifp)
301		fclose(ifp);
302	fclose(ofp);
303	moveifchanged(path("env.c.new"), path("env.c"));
304}
305
306static void
307read_file(char *fname)
308{
309	char ifname[MAXPATHLEN];
310	FILE *fp;
311	struct file_list *tp;
312	struct device *dp;
313	struct opt *op;
314	char *wd, *this, *compilewith, *depends, *clean, *warning;
315	int compile, match, nreqs, std, filetype,
316	    imp_rule, no_obj, before_depend, mandatory, nowerror;
317
318	fp = fopen(fname, "r");
319	if (fp == 0)
320		err(1, "%s", fname);
321next:
322	/*
323	 * include "filename"
324	 * filename    [ standard | mandatory | optional ]
325	 *	[ dev* [ | dev* ... ] | profiling-routine ] [ no-obj ]
326	 *	[ compile-with "compile rule" [no-implicit-rule] ]
327	 *      [ dependency "dependency-list"] [ before-depend ]
328	 *	[ clean "file-list"] [ warning "text warning" ]
329	 */
330	wd = get_word(fp);
331	if (wd == (char *)EOF) {
332		(void) fclose(fp);
333		return;
334	}
335	if (wd == 0)
336		goto next;
337	if (wd[0] == '#')
338	{
339		while (((wd = get_word(fp)) != (char *)EOF) && wd)
340			;
341		goto next;
342	}
343	if (eq(wd, "include")) {
344		next_quoted_word(fp, wd);
345		if (wd == 0) {
346			fprintf(stderr, "%s: missing include filename.\n",
347			    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		fprintf(stderr, "%s: No type for %s.\n", fname, this);
360		exit(1);
361	}
362	tp = fl_lookup(this);
363	compile = 0;
364	match = 1;
365	nreqs = 0;
366	compilewith = 0;
367	depends = 0;
368	clean = 0;
369	warning = 0;
370	std = mandatory = 0;
371	imp_rule = 0;
372	no_obj = 0;
373	before_depend = 0;
374	nowerror = 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, "optional")) {
386		fprintf(stderr,
387		    "%s: \"%s\" %s must be optional, mandatory or standard\n",
388		    fname, wd, 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			fprintf(stderr, "%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			fprintf(stderr, "%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			fprintf(stderr,
431			    "%s: %s missing compile command string.\n",
432			    fname, this);
433			exit(1);
434		}
435		depends = ns(wd);
436		goto nextparam;
437	}
438	if (eq(wd, "clean")) {
439		next_quoted_word(fp, wd);
440		if (wd == 0) {
441			fprintf(stderr, "%s: %s missing clean file list.\n",
442			    fname, this);
443			exit(1);
444		}
445		clean = ns(wd);
446		goto nextparam;
447	}
448	if (eq(wd, "compile-with")) {
449		next_quoted_word(fp, wd);
450		if (wd == 0) {
451			fprintf(stderr,
452			    "%s: %s missing compile command string.\n",
453			    fname, this);
454			exit(1);
455		}
456		compilewith = ns(wd);
457		goto nextparam;
458	}
459	if (eq(wd, "warning")) {
460		next_quoted_word(fp, wd);
461		if (wd == 0) {
462			fprintf(stderr,
463			    "%s: %s missing warning text string.\n",
464			    fname, this);
465			exit(1);
466		}
467		warning = ns(wd);
468		goto nextparam;
469	}
470	nreqs++;
471	if (eq(wd, "local")) {
472		filetype = LOCAL;
473		goto nextparam;
474	}
475	if (eq(wd, "no-depend")) {
476		filetype = NODEPEND;
477		goto nextparam;
478	}
479	if (eq(wd, "profiling-routine")) {
480		filetype = PROFILING;
481		goto nextparam;
482	}
483	if (eq(wd, "nowerror")) {
484		nowerror = 1;
485		goto nextparam;
486	}
487	STAILQ_FOREACH(dp, &dtab, d_next)
488		if (eq(dp->d_name, wd)) {
489			dp->d_done |= DEVDONE;
490			goto nextparam;
491		}
492	if (mandatory) {
493		fprintf(stderr, "%s: mandatory device \"%s\" not found\n",
494		       fname, wd);
495		exit(1);
496	}
497	if (std) {
498		fprintf(stderr,
499		    "standard entry %s has a device keyword - %s!\n",
500		    this, wd);
501		exit(1);
502	}
503	SLIST_FOREACH(op, &opt, op_next)
504		if (op->op_value == 0 && opteq(op->op_name, wd))
505			goto nextparam;
506	match = 0;
507	goto nextparam;
508
509doneparam:
510	if (std == 0 && nreqs == 0) {
511		fprintf(stderr, "%s: what is %s optional on?\n",
512		    fname, this);
513		exit(1);
514	}
515
516	if (wd) {
517		fprintf(stderr, "%s: syntax error describing %s\n",
518		    fname, this);
519		exit(1);
520	}
521	if (filetype == PROFILING && profiling == 0)
522		goto next;
523	tp = new_fent();
524	tp->f_fn = this;
525	tp->f_type = filetype;
526	if (imp_rule)
527		tp->f_flags |= NO_IMPLCT_RULE;
528	if (no_obj)
529		tp->f_flags |= NO_OBJ;
530	if (before_depend)
531		tp->f_flags |= BEFORE_DEPEND;
532	if (nowerror)
533		tp->f_flags |= NOWERROR;
534	tp->f_compilewith = compilewith;
535	tp->f_depends = depends;
536	tp->f_clean = clean;
537	tp->f_warn = warning;
538	goto next;
539}
540
541/*
542 * Read in the information about files used in making the system.
543 * Store it in the ftab linked list.
544 */
545static void
546read_files(void)
547{
548	char fname[MAXPATHLEN];
549	struct files_name *nl, *tnl;
550
551	(void) snprintf(fname, sizeof(fname), "../../conf/files");
552	read_file(fname);
553	(void) snprintf(fname, sizeof(fname),
554		       	"../../conf/files.%s", machinename);
555	read_file(fname);
556	for (nl = STAILQ_FIRST(&fntab); nl != NULL; nl = tnl) {
557		read_file(nl->f_name);
558		tnl = STAILQ_NEXT(nl, f_next);
559		free(nl->f_name);
560		free(nl);
561	}
562}
563
564static int
565opteq(const char *cp, const char *dp)
566{
567	char c, d;
568
569	for (; ; cp++, dp++) {
570		if (*cp != *dp) {
571			c = isupper(*cp) ? tolower(*cp) : *cp;
572			d = isupper(*dp) ? tolower(*dp) : *dp;
573			if (c != d)
574				return (0);
575		}
576		if (*cp == 0)
577			return (1);
578	}
579}
580
581static void
582do_before_depend(FILE *fp)
583{
584	struct file_list *tp;
585	int lpos, len;
586
587	fputs("BEFORE_DEPEND=", fp);
588	lpos = 15;
589	STAILQ_FOREACH(tp, &ftab, f_next)
590		if (tp->f_flags & BEFORE_DEPEND) {
591			len = strlen(tp->f_fn);
592			if ((len = 3 + len) + lpos > 72) {
593				lpos = 8;
594				fputs("\\\n\t", fp);
595			}
596			if (tp->f_flags & NO_IMPLCT_RULE)
597				fprintf(fp, "%s ", tp->f_fn);
598			else
599				fprintf(fp, "$S/%s ", tp->f_fn);
600			lpos += len + 1;
601		}
602	if (lpos != 8)
603		putc('\n', fp);
604}
605
606static void
607do_objs(FILE *fp)
608{
609	struct file_list *tp;
610	int lpos, len;
611	char *cp, och, *sp;
612
613	fprintf(fp, "OBJS=");
614	lpos = 6;
615	STAILQ_FOREACH(tp, &ftab, f_next) {
616		if (tp->f_flags & NO_OBJ)
617			continue;
618		sp = tail(tp->f_fn);
619		cp = sp + (len = strlen(sp)) - 1;
620		och = *cp;
621		*cp = 'o';
622		if (len + lpos > 72) {
623			lpos = 8;
624			fprintf(fp, "\\\n\t");
625		}
626		fprintf(fp, "%s ", sp);
627		lpos += len + 1;
628		*cp = och;
629	}
630	if (lpos != 8)
631		putc('\n', fp);
632}
633
634static void
635do_xxfiles(char *tag, FILE *fp)
636{
637	struct file_list *tp;
638	int lpos, len, slen;
639	char *suff, *SUFF;
640
641	if (tag[strlen(tag) - 1] == '\n')
642		tag[strlen(tag) - 1] = '\0';
643
644	suff = ns(tag + 7);
645	SUFF = ns(suff);
646	raisestr(SUFF);
647	slen = strlen(suff);
648
649	fprintf(fp, "%sFILES=", SUFF);
650	lpos = 8;
651	STAILQ_FOREACH(tp, &ftab, f_next)
652		if (tp->f_type != NODEPEND) {
653			len = strlen(tp->f_fn);
654			if (tp->f_fn[len - slen - 1] != '.')
655				continue;
656			if (strcasecmp(&tp->f_fn[len - slen], suff) != 0)
657				continue;
658			if ((len = 3 + len) + lpos > 72) {
659				lpos = 8;
660				fputs("\\\n\t", fp);
661			}
662			if (tp->f_type != LOCAL)
663				fprintf(fp, "$S/%s ", tp->f_fn);
664			else
665				fprintf(fp, "%s ", tp->f_fn);
666			lpos += len + 1;
667		}
668	if (lpos != 8)
669		putc('\n', fp);
670}
671
672static char *
673tail(char *fn)
674{
675	char *cp;
676
677	cp = rindex(fn, '/');
678	if (cp == 0)
679		return (fn);
680	return (cp+1);
681}
682
683/*
684 * Create the makerules for each file
685 * which is part of the system.
686 */
687static void
688do_rules(FILE *f)
689{
690	char *cp, *np, och;
691	struct file_list *ftp;
692	char *compilewith;
693	char cmd[128];
694
695	STAILQ_FOREACH(ftp, &ftab, f_next) {
696		if (ftp->f_warn)
697			fprintf(stderr, "WARNING: %s\n", ftp->f_warn);
698		cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
699		och = *cp;
700		if (ftp->f_flags & NO_IMPLCT_RULE) {
701			if (ftp->f_depends)
702				fprintf(f, "%s: %s\n", np, ftp->f_depends);
703			else
704				fprintf(f, "%s: \n", np);
705		}
706		else {
707			*cp = '\0';
708			if (och == 'o') {
709				fprintf(f, "%so:\n\t-cp $S/%so .\n\n",
710					tail(np), np);
711				continue;
712			}
713			if (ftp->f_depends) {
714				fprintf(f, "%sln: $S/%s%c %s\n", tail(np),
715					np, och, ftp->f_depends);
716				fprintf(f, "\t${NORMAL_LINT}\n\n");
717				fprintf(f, "%so: $S/%s%c %s\n", tail(np),
718					np, och, ftp->f_depends);
719			}
720			else {
721				fprintf(f, "%sln: $S/%s%c\n", tail(np),
722					np, och);
723				fprintf(f, "\t${NORMAL_LINT}\n\n");
724				fprintf(f, "%so: $S/%s%c\n", tail(np),
725					np, och);
726			}
727		}
728		compilewith = ftp->f_compilewith;
729		if (compilewith == 0) {
730			const char *ftype = NULL;
731
732			switch (ftp->f_type) {
733			case NORMAL:
734				ftype = "NORMAL";
735				break;
736			case PROFILING:
737				if (!profiling)
738					continue;
739				ftype = "PROFILE";
740				break;
741			default:
742				fprintf(stderr,
743				    "config: don't know rules for %s\n", np);
744				break;
745			}
746			snprintf(cmd, sizeof(cmd),
747			    "${%s_%c%s}\n\t@${NORMAL_CTFCONVERT}", ftype,
748			    toupper(och),
749			    ftp->f_flags & NOWERROR ? "_NOWERROR" : "");
750			compilewith = cmd;
751		}
752		*cp = och;
753		fprintf(f, "\t%s\n\n", compilewith);
754	}
755}
756
757static void
758do_clean(FILE *fp)
759{
760	struct file_list *tp;
761	int lpos, len;
762
763	fputs("CLEAN=", fp);
764	lpos = 7;
765	STAILQ_FOREACH(tp, &ftab, f_next)
766		if (tp->f_clean) {
767			len = strlen(tp->f_clean);
768			if (len + lpos > 72) {
769				lpos = 8;
770				fputs("\\\n\t", fp);
771			}
772			fprintf(fp, "%s ", tp->f_clean);
773			lpos += len + 1;
774		}
775	if (lpos != 8)
776		putc('\n', fp);
777}
778
779char *
780raisestr(char *str)
781{
782	char *cp = str;
783
784	while (*str) {
785		if (islower(*str))
786			*str = toupper(*str);
787		str++;
788	}
789	return (cp);
790}
791