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