fmt.c revision 28478
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
351590Srgrimesstatic char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
4127185Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)fmt.c	8.1 (Berkeley) 7/20/93";
4327185Scharnier#else
4427185Scharnierstatic const char rcsid[] =
4528478Sjlemon	"$Id: fmt.c,v 1.9 1997/07/03 07:19:46 charnier Exp $";
4627185Scharnier#endif
471590Srgrimes#endif /* not lint */
481590Srgrimes
491590Srgrimes#include <ctype.h>
5027185Scharnier#include <err.h>
5111765Sache#include <locale.h>
5227185Scharnier#include <stdio.h>
5312317Sjoerg#include <stdlib.h>
5427185Scharnier#include <string.h>
551590Srgrimes
561590Srgrimes/*
571590Srgrimes * fmt -- format the concatenation of input files or standard input
581590Srgrimes * onto standard output.  Designed for use with Mail ~|
591590Srgrimes *
601590Srgrimes * Syntax : fmt [ goal [ max ] ] [ name ... ]
611590Srgrimes * Authors: Kurt Shoens (UCB) 12/7/78;
621590Srgrimes *          Liz Allen (UMCP) 2/24/83 [Addition of goal length concept].
631590Srgrimes */
641590Srgrimes
651590Srgrimes/* LIZ@UOM 6/18/85 -- Don't need LENGTH any more.
661590Srgrimes * #define	LENGTH	72		Max line length in output
671590Srgrimes */
681590Srgrimes#define	NOSTR	((char *) 0)	/* Null string pointer for lint */
691590Srgrimes
701590Srgrimes/* LIZ@UOM 6/18/85 --New variables goal_length and max_length */
711590Srgrimes#define GOAL_LENGTH 65
721590Srgrimes#define MAX_LENGTH 75
731590Srgrimesint	goal_length;		/* Target or goal line length in output */
741590Srgrimesint	max_length;		/* Max line length in output */
751590Srgrimesint	pfx;			/* Current leading blank count */
761590Srgrimesint	lineno;			/* Current input line */
771590Srgrimesint	mark;			/* Last place we saw a head line */
7818227Sphkint	center;
791590Srgrimes
801590Srgrimeschar	*headnames[] = {"To", "Subject", "Cc", 0};
811590Srgrimes
8227185Scharniervoid fmt __P((FILE *));
8327185Scharnierint ispref __P((char *, char *));
8427185Scharniervoid leadin __P((void));
8527185Scharniervoid oflush __P((void));
8627185Scharniervoid pack __P((char [], int));
8727185Scharniervoid prefix __P((char []));
8827185Scharniervoid setout __P((void));
8927185Scharniervoid split __P((char []));
9027185Scharniervoid tabulate __P((char []));
9127185Scharnier
921590Srgrimes/*
931590Srgrimes * Drive the whole formatter by managing input files.  Also,
941590Srgrimes * cause initialization of the output stuff and flush it out
951590Srgrimes * at the end.
961590Srgrimes */
971590Srgrimes
9827185Scharnierint
991590Srgrimesmain(argc, argv)
1001590Srgrimes	int argc;
1011590Srgrimes	char **argv;
1021590Srgrimes{
1031590Srgrimes	register FILE *fi;
1041590Srgrimes	register int errs = 0;
1051590Srgrimes	int number;		/* LIZ@UOM 6/18/85 */
1061590Srgrimes
10711765Sache	(void) setlocale(LC_CTYPE, "");
10811765Sache
1091590Srgrimes	goal_length = GOAL_LENGTH;
1101590Srgrimes	max_length = MAX_LENGTH;
1111590Srgrimes	setout();
1121590Srgrimes	lineno = 1;
1131590Srgrimes	mark = -10;
1141590Srgrimes	/*
1158874Srgrimes	 * LIZ@UOM 6/18/85 -- Check for goal and max length arguments
1161590Srgrimes	 */
11718227Sphk	if (argc > 1 && !strcmp(argv[1], "-c")) {
11818227Sphk		center++;
11918227Sphk		argc--;
12018227Sphk		argv++;
12118227Sphk	}
1221590Srgrimes	if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) {
1231590Srgrimes		argv++;
1241590Srgrimes		argc--;
1251590Srgrimes		goal_length = number;
1261590Srgrimes		if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) {
1271590Srgrimes			argv++;
1281590Srgrimes			argc--;
1291590Srgrimes			max_length = number;
1301590Srgrimes		}
1311590Srgrimes	}
13227185Scharnier	if (max_length <= goal_length)
13327185Scharnier		errx(1, "max length must be greater than goal length");
1341590Srgrimes	if (argc < 2) {
1351590Srgrimes		fmt(stdin);
1361590Srgrimes		oflush();
1371590Srgrimes		exit(0);
1381590Srgrimes	}
1391590Srgrimes	while (--argc) {
1401590Srgrimes		if ((fi = fopen(*++argv, "r")) == NULL) {
1411590Srgrimes			perror(*argv);
1421590Srgrimes			errs++;
1431590Srgrimes			continue;
1441590Srgrimes		}
1451590Srgrimes		fmt(fi);
1461590Srgrimes		fclose(fi);
1471590Srgrimes	}
1481590Srgrimes	oflush();
1491590Srgrimes	exit(errs);
1501590Srgrimes}
1511590Srgrimes
1521590Srgrimes/*
1531590Srgrimes * Read up characters from the passed input file, forming lines,
1541590Srgrimes * doing ^H processing, expanding tabs, stripping trailing blanks,
1551590Srgrimes * and sending each line down for analysis.
1561590Srgrimes */
15727185Scharniervoid
1581590Srgrimesfmt(fi)
1591590Srgrimes	FILE *fi;
1601590Srgrimes{
16112317Sjoerg	static char *linebuf = 0, *canonb = 0;
1628461Sache	register char *cp, *cp2, cc;
1631590Srgrimes	register int c, col;
16412317Sjoerg#define CHUNKSIZE 1024
16528478Sjlemon	static int lbufsize = 0, cbufsize = CHUNKSIZE;
1661590Srgrimes
16728478Sjlemon	canonb = malloc(CHUNKSIZE);
16828478Sjlemon	if (canonb == 0)
16928478Sjlemon		abort();
17028478Sjlemon
17118227Sphk	if (center) {
17218227Sphk		linebuf = malloc(BUFSIZ);
17318227Sphk		while (1) {
17418227Sphk			cp = fgets(linebuf, BUFSIZ, fi);
17518227Sphk			if (!cp)
17618227Sphk				return;
17718227Sphk			while (*cp && isspace(*cp))
17818227Sphk				cp++;
17918227Sphk			cp2 = cp + strlen(cp) - 1;
18018227Sphk			while (cp2 > cp && isspace(*cp2))
18118227Sphk				cp2--;
18218227Sphk			if (cp == cp2)
18318227Sphk				putchar('\n');
18418227Sphk			col = cp2 - cp;
18518227Sphk			for (c = 0; c < (goal_length-col)/2; c++)
18618227Sphk				putchar(' ');
18718227Sphk			while (cp <= cp2)
18818227Sphk				putchar(*cp++);
18918227Sphk			putchar('\n');
19018227Sphk		}
19118227Sphk	}
1921590Srgrimes	c = getc(fi);
1931590Srgrimes	while (c != EOF) {
1941590Srgrimes		/*
1951590Srgrimes		 * Collect a line, doing ^H processing.
1961590Srgrimes		 * Leave tabs for now.
1971590Srgrimes		 */
1981590Srgrimes		cp = linebuf;
19912317Sjoerg		while (c != '\n' && c != EOF) {
20012317Sjoerg			if (cp - linebuf >= lbufsize) {
20112317Sjoerg				int offset = cp - linebuf;
20212317Sjoerg				lbufsize += CHUNKSIZE;
20312317Sjoerg				linebuf = realloc(linebuf, lbufsize);
20412317Sjoerg				if(linebuf == 0)
20512317Sjoerg					abort();
20612317Sjoerg				cp = linebuf + offset;
20712317Sjoerg			}
2081590Srgrimes			if (c == '\b') {
2091590Srgrimes				if (cp > linebuf)
2101590Srgrimes					cp--;
2111590Srgrimes				c = getc(fi);
2121590Srgrimes				continue;
2131590Srgrimes			}
2148461Sache			if (!isprint(c) && c != '\t') {
2151590Srgrimes				c = getc(fi);
2161590Srgrimes				continue;
2171590Srgrimes			}
2181590Srgrimes			*cp++ = c;
2191590Srgrimes			c = getc(fi);
2201590Srgrimes		}
2211590Srgrimes
2221590Srgrimes		/*
2231590Srgrimes		 * Toss anything remaining on the input line.
2241590Srgrimes		 */
2251590Srgrimes		while (c != '\n' && c != EOF)
2261590Srgrimes			c = getc(fi);
2278874Srgrimes
22815344Ssmpatel		if (cp != NULL) {
22915344Ssmpatel			*cp = '\0';
23015344Ssmpatel		} else {
23115344Ssmpatel			putchar('\n');
23215344Ssmpatel			c = getc(fi);
23315344Ssmpatel			continue;
23415344Ssmpatel		}
23515344Ssmpatel
2361590Srgrimes		/*
2371590Srgrimes		 * Expand tabs on the way to canonb.
2381590Srgrimes		 */
2391590Srgrimes		col = 0;
2401590Srgrimes		cp = linebuf;
2411590Srgrimes		cp2 = canonb;
24227185Scharnier		while ((cc = *cp++)) {
2438461Sache			if (cc != '\t') {
2441590Srgrimes				col++;
24512317Sjoerg				if (cp2 - canonb >= cbufsize) {
24612317Sjoerg					int offset = cp2 - canonb;
24712317Sjoerg					cbufsize += CHUNKSIZE;
24812317Sjoerg					canonb = realloc(canonb, cbufsize);
24912317Sjoerg					if(canonb == 0)
25012317Sjoerg						abort();
25112317Sjoerg					cp2 = canonb + offset;
25212317Sjoerg				}
25312317Sjoerg				*cp2++ = cc;
2541590Srgrimes				continue;
2551590Srgrimes			}
2561590Srgrimes			do {
25712317Sjoerg				if (cp2 - canonb >= cbufsize) {
25812317Sjoerg					int offset = cp2 - canonb;
25912317Sjoerg					cbufsize += CHUNKSIZE;
26012317Sjoerg					canonb = realloc(canonb, cbufsize);
26112317Sjoerg					if(canonb == 0)
26212317Sjoerg						abort();
26312317Sjoerg					cp2 = canonb + offset;
26412317Sjoerg				}
26512317Sjoerg				*cp2++ = ' ';
2661590Srgrimes				col++;
2671590Srgrimes			} while ((col & 07) != 0);
2681590Srgrimes		}
2691590Srgrimes
2701590Srgrimes		/*
2711590Srgrimes		 * Swipe trailing blanks from the line.
2721590Srgrimes		 */
2731590Srgrimes		for (cp2--; cp2 >= canonb && *cp2 == ' '; cp2--)
2741590Srgrimes			;
2751590Srgrimes		*++cp2 = '\0';
2761590Srgrimes		prefix(canonb);
2771590Srgrimes		if (c != EOF)
2781590Srgrimes			c = getc(fi);
2791590Srgrimes	}
2801590Srgrimes}
2811590Srgrimes
2821590Srgrimes/*
2831590Srgrimes * Take a line devoid of tabs and other garbage and determine its
2841590Srgrimes * blank prefix.  If the indent changes, call for a linebreak.
2851590Srgrimes * If the input line is blank, echo the blank line on the output.
2861590Srgrimes * Finally, if the line minus the prefix is a mail header, try to keep
2871590Srgrimes * it on a line by itself.
2881590Srgrimes */
28927185Scharniervoid
2901590Srgrimesprefix(line)
2911590Srgrimes	char line[];
2921590Srgrimes{
2931590Srgrimes	register char *cp, **hp;
2941590Srgrimes	register int np, h;
2951590Srgrimes
2968461Sache	if (!*line) {
2971590Srgrimes		oflush();
2981590Srgrimes		putchar('\n');
2991590Srgrimes		return;
3001590Srgrimes	}
3011590Srgrimes	for (cp = line; *cp == ' '; cp++)
3021590Srgrimes		;
3031590Srgrimes	np = cp - line;
3041590Srgrimes
3051590Srgrimes	/*
3061590Srgrimes	 * The following horrible expression attempts to avoid linebreaks
3071590Srgrimes	 * when the indent changes due to a paragraph.
3081590Srgrimes	 */
3091590Srgrimes	if (np != pfx && (np > pfx || abs(pfx-np) > 8))
3101590Srgrimes		oflush();
31127185Scharnier	if ((h = ishead(cp)))
3121590Srgrimes		oflush(), mark = lineno;
3131590Srgrimes	if (lineno - mark < 3 && lineno - mark > 0)
3141590Srgrimes		for (hp = &headnames[0]; *hp != (char *) 0; hp++)
3151590Srgrimes			if (ispref(*hp, cp)) {
3161590Srgrimes				h = 1;
3171590Srgrimes				oflush();
3181590Srgrimes				break;
3191590Srgrimes			}
3201590Srgrimes	if (!h && (h = (*cp == '.')))
3211590Srgrimes		oflush();
3221590Srgrimes	pfx = np;
3231590Srgrimes	if (h)
3241590Srgrimes		pack(cp, strlen(cp));
3251590Srgrimes	else	split(cp);
3261590Srgrimes	if (h)
3271590Srgrimes		oflush();
3281590Srgrimes	lineno++;
3291590Srgrimes}
3301590Srgrimes
3311590Srgrimes/*
3321590Srgrimes * Split up the passed line into output "words" which are
3331590Srgrimes * maximal strings of non-blanks with the blank separation
3341590Srgrimes * attached at the end.  Pass these words along to the output
3351590Srgrimes * line packer.
3361590Srgrimes */
33727185Scharniervoid
3381590Srgrimessplit(line)
3391590Srgrimes	char line[];
3401590Srgrimes{
3411590Srgrimes	register char *cp, *cp2;
3421590Srgrimes	char word[BUFSIZ];
3431590Srgrimes	int wordl;		/* LIZ@UOM 6/18/85 */
3441590Srgrimes
3451590Srgrimes	cp = line;
3461590Srgrimes	while (*cp) {
3471590Srgrimes		cp2 = word;
3481590Srgrimes		wordl = 0;	/* LIZ@UOM 6/18/85 */
3491590Srgrimes
3501590Srgrimes		/*
3511590Srgrimes		 * Collect a 'word,' allowing it to contain escaped white
3528874Srgrimes		 * space.
3531590Srgrimes		 */
3541590Srgrimes		while (*cp && *cp != ' ') {
3551590Srgrimes			if (*cp == '\\' && isspace(cp[1]))
3561590Srgrimes				*cp2++ = *cp++;
3571590Srgrimes			*cp2++ = *cp++;
3581590Srgrimes			wordl++;/* LIZ@UOM 6/18/85 */
3591590Srgrimes		}
3601590Srgrimes
3611590Srgrimes		/*
3621590Srgrimes		 * Guarantee a space at end of line. Two spaces after end of
3638874Srgrimes		 * sentence punctuation.
3641590Srgrimes		 */
3651590Srgrimes		if (*cp == '\0') {
3661590Srgrimes			*cp2++ = ' ';
3671590Srgrimes			if (index(".:!", cp[-1]))
3681590Srgrimes				*cp2++ = ' ';
3691590Srgrimes		}
3701590Srgrimes		while (*cp == ' ')
3711590Srgrimes			*cp2++ = *cp++;
3721590Srgrimes		*cp2 = '\0';
3731590Srgrimes		/*
3748874Srgrimes		 * LIZ@UOM 6/18/85 pack(word);
3751590Srgrimes		 */
3761590Srgrimes		pack(word, wordl);
3771590Srgrimes	}
3781590Srgrimes}
3791590Srgrimes
3801590Srgrimes/*
3811590Srgrimes * Output section.
3821590Srgrimes * Build up line images from the words passed in.  Prefix
3831590Srgrimes * each line with correct number of blanks.  The buffer "outbuf"
3841590Srgrimes * contains the current partial line image, including prefixed blanks.
3851590Srgrimes * "outp" points to the next available space therein.  When outp is NOSTR,
3861590Srgrimes * there ain't nothing in there yet.  At the bottom of this whole mess,
3871590Srgrimes * leading tabs are reinserted.
3881590Srgrimes */
3891590Srgrimeschar	outbuf[BUFSIZ];			/* Sandbagged output line image */
3901590Srgrimeschar	*outp;				/* Pointer in above */
3911590Srgrimes
3921590Srgrimes/*
3931590Srgrimes * Initialize the output section.
3941590Srgrimes */
39527185Scharniervoid
3961590Srgrimessetout()
3971590Srgrimes{
3981590Srgrimes	outp = NOSTR;
3991590Srgrimes}
4001590Srgrimes
4011590Srgrimes/*
4021590Srgrimes * Pack a word onto the output line.  If this is the beginning of
4031590Srgrimes * the line, push on the appropriately-sized string of blanks first.
4041590Srgrimes * If the word won't fit on the current line, flush and begin a new
4051590Srgrimes * line.  If the word is too long to fit all by itself on a line,
4061590Srgrimes * just give it its own and hope for the best.
4071590Srgrimes *
4081590Srgrimes * LIZ@UOM 6/18/85 -- If the new word will fit in at less than the
4091590Srgrimes *	goal length, take it.  If not, then check to see if the line
4101590Srgrimes *	will be over the max length; if so put the word on the next
4111590Srgrimes *	line.  If not, check to see if the line will be closer to the
4121590Srgrimes *	goal length with or without the word and take it or put it on
4131590Srgrimes *	the next line accordingly.
4141590Srgrimes */
4151590Srgrimes
4161590Srgrimes/*
4171590Srgrimes * LIZ@UOM 6/18/85 -- pass in the length of the word as well
4181590Srgrimes * pack(word)
4191590Srgrimes *	char word[];
4201590Srgrimes */
42127185Scharniervoid
4221590Srgrimespack(word,wl)
4231590Srgrimes	char word[];
4241590Srgrimes	int wl;
4251590Srgrimes{
4261590Srgrimes	register char *cp;
4271590Srgrimes	register int s, t;
4281590Srgrimes
4291590Srgrimes	if (outp == NOSTR)
4301590Srgrimes		leadin();
4311590Srgrimes	/*
4321590Srgrimes	 * LIZ@UOM 6/18/85 -- change condition to check goal_length; s is the
4331590Srgrimes	 * length of the line before the word is added; t is now the length
4341590Srgrimes	 * of the line after the word is added
4351590Srgrimes	 *	t = strlen(word);
4368874Srgrimes	 *	if (t+s <= LENGTH)
4371590Srgrimes	 */
4381590Srgrimes	s = outp - outbuf;
4391590Srgrimes	t = wl + s;
4401590Srgrimes	if ((t <= goal_length) ||
4411590Srgrimes	    ((t <= max_length) && (t - goal_length <= goal_length - s))) {
4421590Srgrimes		/*
4438874Srgrimes		 * In like flint!
4441590Srgrimes		 */
4451590Srgrimes		for (cp = word; *cp; *outp++ = *cp++);
4461590Srgrimes		return;
4471590Srgrimes	}
4481590Srgrimes	if (s > pfx) {
4491590Srgrimes		oflush();
4501590Srgrimes		leadin();
4511590Srgrimes	}
4521590Srgrimes	for (cp = word; *cp; *outp++ = *cp++);
4531590Srgrimes}
4541590Srgrimes
4551590Srgrimes/*
4561590Srgrimes * If there is anything on the current output line, send it on
4571590Srgrimes * its way.  Set outp to NOSTR to indicate the absence of the current
4581590Srgrimes * line prefix.
4591590Srgrimes */
46027185Scharniervoid
4611590Srgrimesoflush()
4621590Srgrimes{
4631590Srgrimes	if (outp == NOSTR)
4641590Srgrimes		return;
4651590Srgrimes	*outp = '\0';
4661590Srgrimes	tabulate(outbuf);
4671590Srgrimes	outp = NOSTR;
4681590Srgrimes}
4691590Srgrimes
4701590Srgrimes/*
4711590Srgrimes * Take the passed line buffer, insert leading tabs where possible, and
4721590Srgrimes * output on standard output (finally).
4731590Srgrimes */
47427185Scharniervoid
4751590Srgrimestabulate(line)
4761590Srgrimes	char line[];
4771590Srgrimes{
4781590Srgrimes	register char *cp;
4791590Srgrimes	register int b, t;
4801590Srgrimes
4811590Srgrimes	/*
4821590Srgrimes	 * Toss trailing blanks in the output line.
4831590Srgrimes	 */
4841590Srgrimes	cp = line + strlen(line) - 1;
4851590Srgrimes	while (cp >= line && *cp == ' ')
4861590Srgrimes		cp--;
4871590Srgrimes	*++cp = '\0';
4888874Srgrimes
4891590Srgrimes	/*
4901590Srgrimes	 * Count the leading blank space and tabulate.
4911590Srgrimes	 */
4921590Srgrimes	for (cp = line; *cp == ' '; cp++)
4931590Srgrimes		;
4941590Srgrimes	b = cp-line;
4951590Srgrimes	t = b >> 3;
4961590Srgrimes	b &= 07;
4971590Srgrimes	if (t > 0)
4981590Srgrimes		do
4991590Srgrimes			putc('\t', stdout);
5001590Srgrimes		while (--t);
5011590Srgrimes	if (b > 0)
5021590Srgrimes		do
5031590Srgrimes			putc(' ', stdout);
5041590Srgrimes		while (--b);
5051590Srgrimes	while (*cp)
5061590Srgrimes		putc(*cp++, stdout);
5071590Srgrimes	putc('\n', stdout);
5081590Srgrimes}
5091590Srgrimes
5101590Srgrimes/*
5111590Srgrimes * Initialize the output line with the appropriate number of
5121590Srgrimes * leading blanks.
5131590Srgrimes */
51427185Scharniervoid
5151590Srgrimesleadin()
5161590Srgrimes{
5171590Srgrimes	register int b;
5181590Srgrimes	register char *cp;
5191590Srgrimes
5201590Srgrimes	for (b = 0, cp = outbuf; b < pfx; b++)
5211590Srgrimes		*cp++ = ' ';
5221590Srgrimes	outp = cp;
5231590Srgrimes}
5241590Srgrimes
5251590Srgrimes/*
5261590Srgrimes * Save a string in dynamic space.
5271590Srgrimes * This little goodie is needed for
5281590Srgrimes * a headline detector in head.c
5291590Srgrimes */
5301590Srgrimeschar *
5311590Srgrimessavestr(str)
5321590Srgrimes	char str[];
5331590Srgrimes{
5341590Srgrimes	register char *top;
5351590Srgrimes
5361590Srgrimes	top = malloc(strlen(str) + 1);
53727185Scharnier	if (top == NOSTR)
53827185Scharnier		errx(1, "ran out of memory");
5391590Srgrimes	strcpy(top, str);
5401590Srgrimes	return (top);
5411590Srgrimes}
5421590Srgrimes
5431590Srgrimes/*
5441590Srgrimes * Is s1 a prefix of s2??
5451590Srgrimes */
54627185Scharnierint
5471590Srgrimesispref(s1, s2)
5481590Srgrimes	register char *s1, *s2;
5491590Srgrimes{
5501590Srgrimes
5511590Srgrimes	while (*s1++ == *s2)
5521590Srgrimes		;
5531590Srgrimes	return (*s1 == '\0');
5541590Srgrimes}
555