[comp.sources.misc] v02i102: fmt: a simple text formatter

bgray@marque.mu.edu (Bill Gray) (04/21/88)

comp.sources.misc: Volume 2, Issue 102
Submitted-By: "Bill Gray" <bgray@marque.mu.edu>
Archive-Name: usg-fmt

[The Makefile is distinctly System-V-ish.  However, I'm somewhat uncertain as
to whether this came from the BSD "fmt" or not....  ++bsa]

-------------------------------------------------------------

echo x - fmt.1 1>&2
sed 's/^X//' >fmt.1 <<'----enD-oF-fmt.1----'
X.TH FMT 1 LOCAL
X.SH NAME
Xfmt \- a simple text formatter
X.SH SYNOPSIS
X.B fmt
X[
X.B \-i
X] [
X.B \-j
X] [
X.B \-l n
X] [
X.B \-p n
X] [
X.B \-t n
X] [ filenames ]
X.SH DESCRIPTION
X.I Fmt
Xis a simple text formatter.  With no options present, the default
Xbehavior of
X.I fmt
Xis to copy its input (from specified files or from stdin, if no files
Xare specified) to its output but with input reformatted into lines no
Xlonger than 72 characters long.  A blank line is taken to indicate the
Xbeginning of a new paragraph.  Lines that begin with a period are
Xpreserved.
X.PP
XThe following options modify this behavior:
X.TP
X.B \-i
XThis option will cause
X.I fmt 
Xto preserve indentations.  Blanks or tabs at the beginning of a line
Xwill be considered the beginning of a new paragraph.
X.TP
X.B \-j
XJustify output lines.  (The default behavior of
X.I fmt
Xis to output lines with a ragged right margin).
X.TP
X.B \-l n
XThis option can be used to change the line length from the default of 72
Xcharacters.
X.TP
X.B \-p n
XChange the page offset.  This option will cause the output lines to be
Xoffset the indicated number of columns from the left.
X.TP
X.B \-t n
XSet tab size.  This option is useful only with the
X.B \-i 
Xoption since tabs are preserved only at the beginning of lines and are
Xthrown away by default.
X.SH TIPS
XIn
X.IR vi ,
Xyou can define a macro that will reformat paragraphs by typing
X.I ":map V {!}fmt^M" 
Xor by putting the line
X.ti +7n
X.I "map V {!}fmt^M"
X.br
Xin your
X.I .exrc
Xfile.  After defining this macro, pressing
X.I V 
Xwill cause the paragraph under the cursor to be reformatted.  (Use the
X.I u
Xkey to
X.I undo
Xif necessary.
X.SH "SEE ALSO"
Xnroff(1), vi(1)
----enD-oF-fmt.1----
echo x - fmt.c 1>&2
sed 's/^X//' >fmt.c <<'----enD-oF-fmt.c----'
X/* 
Xfile: fmt.c   
X04/88  bgray
X*/
X
X/* a simple text formatter */
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X
X
X#define TRUE 1
X#define FALSE 0
X
Xint iflag = FALSE;
Xint jflag = FALSE;
Xint maxlen = 72;
Xint tabsize = 8;
Xint offset = 0;
Xint spaces = 0;
X
Xchar *progname = NULL;
Xchar *delimiters = " \t\n\r\f";
Xchar *usage = "usage: %s [-ij] [-l n] [-p n] [-t n] [file ...]\n";
X
Xint dir = FALSE;
Xint holecnt = 0;
Xchar *holeptr[256];  /* holeptr[0] is unused */
X
Xchar iline[2048] = "\0";
Xchar *ilp = iline;
Xchar oline[2048] = "\0";
Xchar *olp = oline;
X
Xextern char *optarg;
Xextern int optind;
X
Xint max();
Xvoid exit();
Xchar *basename(), *strtok();
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int c;
X
X	progname = basename(argv[0]);
X	while ((c = getopt(argc, argv, "ijl:p:t:")) != EOF)
X		switch(c) {
X			case 'i' : iflag = TRUE; break;
X			case 'j' : jflag = TRUE; break;
X			case 'l' : maxlen = max(0, atoi(optarg)); break;
X			case 'p' : offset = max(0, atoi(optarg)); break;
X			case 't' : tabsize = max(1, atoi(optarg)); break;
X			default : fprintf(stderr, usage, progname); exit(1); break;
X		}
X	
X	if (optind >= argc)
X		format();
X	else for ( ;  (optind < argc);  optind++) {
X		if (freopen(argv[optind], "r", stdin) != NULL)
X			format();
X		else {
X			fprintf(stderr, "Couldn't open file: %s", argv[optind]);
X			exit(1);
X		}
X	}
X	return(0);
X}  /* main */
X
X
X
Xformat()
X{
X	char *p;
X	
X	while (ilp = gets(iline)) 
X		if (*ilp == '\0')
X			skipline(1);
X		else if (*ilp == '.') {
X			putline();
X			while (*olp++ = *ilp++);
X			putline();
X		}
X		else {
X			if ((iflag) && (isspace(*ilp))) {
X				putline();
X				copyindent();
X			}
X			p = strtok(ilp, delimiters);
X			while (*p) {
X				putword(p);
X				p = strtok(NULL, delimiters);
X			}
X		}
X	putline();
X}  /* format */
X
X
X
Xcopyindent()
X{
X	int col = 1;
X	
X	for (  ;  (isspace(*ilp));  col++) {
X		if (*ilp++ == '\t')
X			for (  ;  (col % tabsize);  col++) 
X				*olp++ = ' ';
X		*olp++ = ' ';
X	}
X}  /* copyindent */
X
X
X
Xputword(p)
Xchar *p;
X{
X	int plen;
X
X	plen = strlen(p);
X	if ((olp - oline) + spaces + plen > maxlen) {
X		if ((jflag) && (holecnt))
X			justifyline();
X		putline();
X	}
X	if (spaces) {
X		holeptr[++holecnt] = olp;
X		for (  ;  (spaces > 0);  spaces--)
X			*olp++ = ' ';
X	}
X	spaces = 1 + endofsentence(p, plen);
X	while (*p)
X		*olp++ = *p++;
X}  /* putword */
X
X
X
Xjustifyline()
X{
X	int n;
X	char *fp;
X	char *tp;
X	
X	dir = (! (dir));
X	fp = olp - 1;
X	olp = &oline[maxlen];
X	tp = olp - 1;
X	while (tp > fp) {
X		while (fp >= holeptr[holecnt])
X			*tp-- = *fp--;
X		if (dir)
X			n = ((tp - fp) - 1) / holecnt + 1;
X		else
X			n = (tp - fp) / holecnt;
X		while (n--) 
X			*tp-- = ' ';
X		holecnt--;
X	}
X}  /* justifyline */
X
X
X
Xputline()
X{
X	*olp = '\0';
X	if (*oline)
X		printf("%*s\n", offset + strlen(oline), oline);
X	*oline = '\0';
X	olp = oline;
X	spaces = 0;
X	holecnt = 0;
X}  /* putline */
X
X
X
Xskipline(n)
Xint n;
X{
X	putline();
X	for (  ;  (n > 0);  n--)
X		printf("\n");
X}  /* skipline */
X
X
X
Xint endofsentence(p, plen)
Xchar *p;
Xint plen;
X{
X	if (plen < 3)
X		return(FALSE);
X	if (!strchr(".:?!", *(p + plen - 1)))
X		return(FALSE);
X	if (abbr(p))
X		return(FALSE);
X	return(TRUE);
X}  /* endofsentence */
X
X
X
Xint abbr(s)
Xchar *s;
X{
X	char *p, *q, *r;
X
X	while (*s == '(') s++;
X	q = ".i.e.g.dr.mr.mrs.st.";
X	for (  ;  (*q);  q++) {
X		p = q;
X		r = s;
X		while ((*r) && (*p++ == (*r++ | 0x20))) ;
X		if (!*r)
X			return(TRUE);
X	}
X	return(FALSE);
X}  /* abbr */
X
X
X
Xchar *basename(s)
Xchar *s;
X{
X	char *p;
X
X	if (p = strrchr(s, '/'))
X		return(++p);
X	else
X		return(s);
X}  /* basename */
X
X
X
Xint max(a, b)
Xint a, b;
X{
X	return((a > b) ? a : b);
X}  /* max */
X
----enD-oF-fmt.c----
echo x - Makefile 1>&2
sed 's/^X//' >Makefile <<'----enD-oF-Makefile----'
X# file: fmt/Makefile
X# 04/88  bgray
X
X
XBINDIR = /usr/lbin
XMANDIR = /usr/man/u_man/man1
XCATMAN = /usr/catman/u_man/man1
X
XLIBS =
XCFLAGS = -O
XLDFLAGS = -s
XCC = /bin/cc
XRM = /bin/rm -f
XMV = /bin/mv -f
XCP = /bin/cp
X
XFORMATTER = nroff
X
XOBJS =
X
X
Xall: fmt fmt.doc
X
Xfmt: fmt.c
X	$(CC) $(LDFLAGS) -o fmt fmt.c
X
Xfmt.doc: fmt.1
X	${FORMATTER} -man fmt.1 > fmt.doc 
X
Xinstall: all
X	$(CP) fmt $(BINDIR)
X	chown bin $(BINDIR)/fmt
X	chgrp bin $(BINDIR)/fmt
X	chmod 755 $(BINDIR)/fmt
X	$(CP) fmt.doc $(CATMAN)/fmt.1
X	chown bin $(CATMAN)/fmt.1
X	chgrp bin $(CATMAN)/fmt.1
X	chmod 644 $(CATMAN)/fmt.1
X
----enD-oF-Makefile----
exit

Bill Gray
--
bgray@marque.mu.edu    { uunet | uwvax }!marque.mu.edu!bgray