version 1.3, 1997/01/17 07:12:35 |
version 1.4, 1997/01/26 03:56:52 |
|
|
#ifndef lint |
#ifndef lint |
#if 0 |
#if 0 |
static char sccsid[] = "@(#)fmt.c 8.1 (Berkeley) 7/20/93"; |
static char sccsid[] = "@(#)fmt.c 8.1 (Berkeley) 7/20/93"; |
#endif |
#else |
static char rcsid[] = "$OpenBSD$"; |
static char rcsid[] = "$OpenBSD$"; |
|
#endif |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
|
#include <ctype.h> |
|
#include <err.h> |
|
#include <locale.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <ctype.h> |
|
|
|
/* |
/* |
* fmt -- format the concatenation of input files or standard input |
* fmt -- format the concatenation of input files or standard input |
|
|
int pfx; /* Current leading blank count */ |
int pfx; /* Current leading blank count */ |
int lineno; /* Current input line */ |
int lineno; /* Current input line */ |
int mark; /* Last place we saw a head line */ |
int mark; /* Last place we saw a head line */ |
|
int center; /* Did they ask to center lines? */ |
|
|
char *headnames[] = {"To", "Subject", "Cc", 0}; |
char *headnames[] = {"To", "Subject", "Cc", 0}; |
|
|
|
void fmt __P((FILE *)); |
|
void setout __P((void)); |
|
void prefix __P((char *)); |
|
void split __P((char *)); |
|
void pack __P((char *, int)); |
|
void oflush __P((void)); |
|
void tabulate __P((char *)); |
|
void leadin __P((void)); |
|
char *savestr __P((char *)); |
|
int ispref __P((char *, char *)); |
|
int ishead __P((char *)); |
|
|
/* |
/* |
* Drive the whole formatter by managing input files. Also, |
* Drive the whole formatter by managing input files. Also, |
* cause initialization of the output stuff and flush it out |
* cause initialization of the output stuff and flush it out |
* at the end. |
* at the end. |
*/ |
*/ |
|
|
|
int |
main(argc, argv) |
main(argc, argv) |
int argc; |
int argc; |
char **argv; |
char **argv; |
|
|
register int errs = 0; |
register int errs = 0; |
int number; /* LIZ@UOM 6/18/85 */ |
int number; /* LIZ@UOM 6/18/85 */ |
|
|
|
(void) setlocale(LC_CTYPE, ""); |
|
|
goal_length = GOAL_LENGTH; |
goal_length = GOAL_LENGTH; |
max_length = MAX_LENGTH; |
max_length = MAX_LENGTH; |
setout(); |
setout(); |
lineno = 1; |
lineno = 1; |
mark = -10; |
mark = -10; |
/* |
/* |
* LIZ@UOM 6/18/85 -- Check for goal and max length arguments |
* LIZ@UOM 6/18/85 -- Check for goal and max length arguments |
*/ |
*/ |
|
if (argc > 1 && !strcmp(argv[1], "-c")) { |
|
center++; |
|
argc--; |
|
argv++; |
|
} |
if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) { |
if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) { |
argv++; |
argv++; |
argc--; |
argc--; |
|
|
max_length = number; |
max_length = number; |
} |
} |
} |
} |
if (max_length <= goal_length) { |
if (max_length <= goal_length) |
fprintf(stderr, "Max length must be greater than %s\n", |
errx(1, "Max length (%d) must be greater than goal length: %d", |
"goal length"); |
max_length, goal_length); |
exit(1); |
|
} |
|
if (argc < 2) { |
if (argc < 2) { |
fmt(stdin); |
fmt(stdin); |
oflush(); |
oflush(); |
|
|
* doing ^H processing, expanding tabs, stripping trailing blanks, |
* doing ^H processing, expanding tabs, stripping trailing blanks, |
* and sending each line down for analysis. |
* and sending each line down for analysis. |
*/ |
*/ |
|
void |
fmt(fi) |
fmt(fi) |
FILE *fi; |
FILE *fi; |
{ |
{ |
char linebuf[BUFSIZ], canonb[BUFSIZ]; |
static char *linebuf = 0, *canonb = 0; |
register char *cp, *cp2; |
register char *cp, *cp2, cc; |
register int c, col; |
register int c, col; |
|
#define CHUNKSIZE 1024 |
|
static int lbufsize = 0, cbufsize = 0; |
|
|
|
if (center) { |
|
if ((linebuf = malloc(BUFSIZ)) == NOSTR) |
|
errx(1, "Ran out of memory"); |
|
for (;;) { |
|
cp = fgets(linebuf, BUFSIZ, fi); |
|
if (!cp) |
|
return; |
|
while (*cp && isspace(*cp)) |
|
cp++; |
|
cp2 = cp + strlen(cp) - 1; |
|
while (cp2 > cp && isspace(*cp2)) |
|
cp2--; |
|
if (cp == cp2) |
|
putchar('\n'); |
|
col = cp2 - cp; |
|
for (c = 0; c < (goal_length-col)/2; c++) |
|
putchar(' '); |
|
while (cp <= cp2) |
|
putchar(*cp++); |
|
putchar('\n'); |
|
} |
|
} |
c = getc(fi); |
c = getc(fi); |
while (c != EOF) { |
while (c != EOF) { |
/* |
/* |
|
|
* Leave tabs for now. |
* Leave tabs for now. |
*/ |
*/ |
cp = linebuf; |
cp = linebuf; |
while (c != '\n' && c != EOF && cp-linebuf < BUFSIZ-1) { |
while (c != '\n' && c != EOF) { |
|
if (cp - linebuf >= lbufsize) { |
|
int offset = cp - linebuf; |
|
lbufsize += CHUNKSIZE; |
|
linebuf = realloc(linebuf, lbufsize); |
|
if(linebuf == 0) |
|
abort(); |
|
cp = linebuf + offset; |
|
} |
if (c == '\b') { |
if (c == '\b') { |
if (cp > linebuf) |
if (cp > linebuf) |
cp--; |
cp--; |
c = getc(fi); |
c = getc(fi); |
continue; |
continue; |
} |
} |
if ((c < ' ' || c >= 0177) && c != '\t') { |
if (!isprint(c) && c != '\t') { |
c = getc(fi); |
c = getc(fi); |
continue; |
continue; |
} |
} |
*cp++ = c; |
*cp++ = c; |
c = getc(fi); |
c = getc(fi); |
} |
} |
*cp = '\0'; |
|
|
|
/* |
/* |
* Toss anything remaining on the input line. |
* Toss anything remaining on the input line. |
*/ |
*/ |
while (c != '\n' && c != EOF) |
while (c != '\n' && c != EOF) |
c = getc(fi); |
c = getc(fi); |
|
|
|
if (cp != NULL) { |
|
*cp = '\0'; |
|
} else { |
|
putchar('\n'); |
|
c = getc(fi); |
|
continue; |
|
} |
|
|
/* |
/* |
* Expand tabs on the way to canonb. |
* Expand tabs on the way to canonb. |
*/ |
*/ |
col = 0; |
col = 0; |
cp = linebuf; |
cp = linebuf; |
cp2 = canonb; |
cp2 = canonb; |
while (c = *cp++) { |
while ((cc = *cp++)) { |
if (c != '\t') { |
if (cc != '\t') { |
col++; |
col++; |
if (cp2-canonb < BUFSIZ-1) |
if (cp2 - canonb >= cbufsize) { |
*cp2++ = c; |
int offset = cp2 - canonb; |
|
cbufsize += CHUNKSIZE; |
|
canonb = realloc(canonb, cbufsize); |
|
if(canonb == 0) |
|
abort(); |
|
cp2 = canonb + offset; |
|
} |
|
*cp2++ = cc; |
continue; |
continue; |
} |
} |
do { |
do { |
if (cp2-canonb < BUFSIZ-1) |
if (cp2 - canonb >= cbufsize) { |
*cp2++ = ' '; |
int offset = cp2 - canonb; |
|
cbufsize += CHUNKSIZE; |
|
canonb = realloc(canonb, cbufsize); |
|
if(canonb == 0) |
|
abort(); |
|
cp2 = canonb + offset; |
|
} |
|
*cp2++ = ' '; |
col++; |
col++; |
} while ((col & 07) != 0); |
} while ((col & 07) != 0); |
} |
} |
|
|
* Finally, if the line minus the prefix is a mail header, try to keep |
* Finally, if the line minus the prefix is a mail header, try to keep |
* it on a line by itself. |
* it on a line by itself. |
*/ |
*/ |
|
void |
prefix(line) |
prefix(line) |
char line[]; |
char line[]; |
{ |
{ |
register char *cp, **hp; |
register char *cp, **hp; |
register int np, h; |
register int np, h; |
|
|
if (strlen(line) == 0) { |
if (*line == '\0') { |
oflush(); |
oflush(); |
putchar('\n'); |
putchar('\n'); |
return; |
return; |
|
|
*/ |
*/ |
if (np != pfx && (np > pfx || abs(pfx-np) > 8)) |
if (np != pfx && (np > pfx || abs(pfx-np) > 8)) |
oflush(); |
oflush(); |
if (h = ishead(cp)) |
if ((h = ishead(cp))) |
oflush(), mark = lineno; |
oflush(), mark = lineno; |
if (lineno - mark < 3 && lineno - mark > 0) |
if (lineno - mark < 3 && lineno - mark > 0) |
for (hp = &headnames[0]; *hp != (char *) 0; hp++) |
for (hp = &headnames[0]; *hp != (char *) 0; hp++) |
|
|
* attached at the end. Pass these words along to the output |
* attached at the end. Pass these words along to the output |
* line packer. |
* line packer. |
*/ |
*/ |
|
void |
split(line) |
split(line) |
char line[]; |
char line[]; |
{ |
{ |
|
|
|
|
/* |
/* |
* Collect a 'word,' allowing it to contain escaped white |
* Collect a 'word,' allowing it to contain escaped white |
* space. |
* space. |
*/ |
*/ |
while (*cp && *cp != ' ') { |
while (*cp && *cp != ' ') { |
if (*cp == '\\' && isspace(cp[1])) |
if (*cp == '\\' && isspace(cp[1])) |
|
|
|
|
/* |
/* |
* Guarantee a space at end of line. Two spaces after end of |
* Guarantee a space at end of line. Two spaces after end of |
* sentence punctuation. |
* sentence punctuation. |
*/ |
*/ |
if (*cp == '\0') { |
if (*cp == '\0') { |
*cp2++ = ' '; |
*cp2++ = ' '; |
|
|
*cp2++ = *cp++; |
*cp2++ = *cp++; |
*cp2 = '\0'; |
*cp2 = '\0'; |
/* |
/* |
* LIZ@UOM 6/18/85 pack(word); |
* LIZ@UOM 6/18/85 pack(word); |
*/ |
*/ |
pack(word, wordl); |
pack(word, wordl); |
} |
} |
|
|
/* |
/* |
* Initialize the output section. |
* Initialize the output section. |
*/ |
*/ |
|
void |
setout() |
setout() |
{ |
{ |
outp = NOSTR; |
outp = NOSTR; |
|
|
* pack(word) |
* pack(word) |
* char word[]; |
* char word[]; |
*/ |
*/ |
pack(word,wl) |
void |
|
pack(word, wl) |
char word[]; |
char word[]; |
int wl; |
int wl; |
{ |
{ |
|
|
* length of the line before the word is added; t is now the length |
* length of the line before the word is added; t is now the length |
* of the line after the word is added |
* of the line after the word is added |
* t = strlen(word); |
* t = strlen(word); |
* if (t+s <= LENGTH) |
* if (t+s <= LENGTH) |
*/ |
*/ |
s = outp - outbuf; |
s = outp - outbuf; |
t = wl + s; |
t = wl + s; |
if ((t <= goal_length) || |
if ((t <= goal_length) || |
((t <= max_length) && (t - goal_length <= goal_length - s))) { |
((t <= max_length) && (t - goal_length <= goal_length - s))) { |
/* |
/* |
* In like flint! |
* In like flint! |
*/ |
*/ |
for (cp = word; *cp; *outp++ = *cp++); |
for (cp = word; *cp; *outp++ = *cp++); |
return; |
return; |
|
|
* its way. Set outp to NOSTR to indicate the absence of the current |
* its way. Set outp to NOSTR to indicate the absence of the current |
* line prefix. |
* line prefix. |
*/ |
*/ |
|
void |
oflush() |
oflush() |
{ |
{ |
if (outp == NOSTR) |
if (outp == NOSTR) |
|
|
* Take the passed line buffer, insert leading tabs where possible, and |
* Take the passed line buffer, insert leading tabs where possible, and |
* output on standard output (finally). |
* output on standard output (finally). |
*/ |
*/ |
|
void |
tabulate(line) |
tabulate(line) |
char line[]; |
char line[]; |
{ |
{ |
|
|
while (cp >= line && *cp == ' ') |
while (cp >= line && *cp == ' ') |
cp--; |
cp--; |
*++cp = '\0'; |
*++cp = '\0'; |
|
|
/* |
/* |
* Count the leading blank space and tabulate. |
* Count the leading blank space and tabulate. |
*/ |
*/ |
|
|
* Initialize the output line with the appropriate number of |
* Initialize the output line with the appropriate number of |
* leading blanks. |
* leading blanks. |
*/ |
*/ |
|
void |
leadin() |
leadin() |
{ |
{ |
register int b; |
register int b; |
|
|
savestr(str) |
savestr(str) |
char str[]; |
char str[]; |
{ |
{ |
register char *top; |
char *top; |
|
|
top = malloc(strlen(str) + 1); |
top = strdup(str); |
if (top == NOSTR) { |
if (top == NOSTR) |
fprintf(stderr, "fmt: Ran out of memory\n"); |
errx(1, "Ran out of memory"); |
exit(1); |
|
} |
|
strcpy(top, str); |
|
return (top); |
return (top); |
} |
} |
|
|
/* |
/* |
* Is s1 a prefix of s2?? |
* Is s1 a prefix of s2?? |
*/ |
*/ |
|
int |
ispref(s1, s2) |
ispref(s1, s2) |
register char *s1, *s2; |
register char *s1, *s2; |
{ |
{ |