home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-09 | 57.4 KB | 1,787 lines |
- Newsgroups: comp.sources.misc
- From: amc@wuecl.wustl.edu (Adam Costello)
- Subject: v40i126: par - paragraph reformatter, v1.41, Part03/03
- Message-ID: <1993Nov9.184204.1166@sparky.sterling.com>
- X-Md4-Signature: 2337b3125fef3f0c9747a44f7a978c0c
- Sender: kent@sparky.sterling.com (Kent Landfield)
- Organization: Sterling Software
- Date: Tue, 9 Nov 1993 18:42:04 GMT
- Approved: kent@sparky.sterling.com
-
- Submitted-by: amc@wuecl.wustl.edu (Adam Costello)
- Posting-number: Volume 40, Issue 126
- Archive-name: par/part03
- Environment: ANSI-C
- Supersedes: par131: Volume 39, Issue 83-85
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: Par141 Par141/reformat.h Par141/charset.h Par141/buffer.h
- # Par141/releasenotes Par141/reformat.c Par141/par.c
- # Wrapped by amc@siesta on Sun Oct 31 01:26:08 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test ! -d 'Par141' ; then
- echo shar: Creating directory \"'Par141'\"
- mkdir 'Par141'
- fi
- if test -f 'Par141/reformat.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Par141/reformat.h'\"
- else
- echo shar: Extracting \"'Par141/reformat.h'\" \(1069 characters\)
- sed "s/^X//" >'Par141/reformat.h' <<'END_OF_FILE'
- X/*********************/
- X/* reformat.h */
- X/* for Par 1.41 */
- X/* Copyright 1993 by */
- X/* Adam M. Costello */
- X/*********************/
- X
- X/* This is ANSI C code. */
- X
- X
- X#include "errmsg.h"
- X
- X
- Xchar **reformat(
- X const char * const *inlines, const char * const *endline, int afp, int fs,
- X int hang, int prefix, int suffix, int width, int cap, int fit, int guess,
- X int just, int last, int Report, int touch, errmsg_t errmsg
- X);
- X /* inlines is an array of pointers to input lines, up to but not */
- X /* including endline. inlines and endline must not be equal. */
- X /* The other parameters are the variables of the same name as */
- X /* described in "par.doc". reformat(inlines, endline, afp, fs, */
- X /* hang, prefix, suffix, width, cap, fit, guess, just, last, */
- X /* Report, touch, errmsg) returns a NULL-terminated array of */
- X /* pointers to output lines containing the reformatted paragraph, */
- X /* according to the specification in "par.doc". None of the */
- X /* integer parameters may be negative. Returns NULL on failure. */
- END_OF_FILE
- if test 1069 -ne `wc -c <'Par141/reformat.h'`; then
- echo shar: \"'Par141/reformat.h'\" unpacked with wrong size!
- fi
- # end of 'Par141/reformat.h'
- fi
- if test -f 'Par141/charset.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Par141/charset.h'\"
- else
- echo shar: Extracting \"'Par141/charset.h'\" \(1853 characters\)
- sed "s/^X//" >'Par141/charset.h' <<'END_OF_FILE'
- X/*********************/
- X/* charset.h */
- X/* for Par 1.41 */
- X/* Copyright 1993 by */
- X/* Adam M. Costello */
- X/*********************/
- X
- X/* This is ANSI C code. */
- X
- X
- X/* Note: Those functions declared here which do not use errmsg */
- X/* always succeed, provided that they are passed valid arguments. */
- X
- X
- X#include "errmsg.h"
- X
- X
- Xtypedef struct charset charset;
- X
- X
- Xcharset *parsecharset(const char *str, errmsg_t errmsg);
- X
- X /* parsecharset(str,errmsg) returns the set of characters defined by */
- X /* str using charset syntax (see par.doc). Returns NULL on failure. */
- X
- X
- Xvoid freecharset(charset *cset);
- X
- X /* freecharset(cset) frees any memory associated with */
- X /* *cset. cset may not be used after this call. */
- X
- X
- Xint csmember(char c, const charset *cset);
- X
- X /* csmember(c,cset) returns 1 if c is a member of *cset, 0 otherwise. */
- X
- X
- Xcharset *csunion(const charset *cset1, const charset *cset2, errmsg_t errmsg);
- X
- X /* csunion(cset1,cset2) returns a pointer to the */
- X /* union of *cset1 and *cset2, or NULL on failure. */
- X
- X
- Xcharset *csdiff(const charset *cset1, const charset *cset2, errmsg_t errmsg);
- X
- X /* csdiff(cset1,cset2) returns a pointer to the set */
- X /* difference *cset1 - *cset2 , or NULL on failure. */
- X
- X
- Xvoid csadd(charset *cset1, const charset *cset2, errmsg_t errmsg);
- X
- X /* csadd(cset1,cset2) adds the members of *cset2 */
- X /* to *cset1. On failure, *cset1 is not changed. */
- X
- X
- Xvoid csremove(charset *cset1, const charset *cset2, errmsg_t errmsg);
- X
- X /* csremove(cset1,cset2) removes the members of *cset2 */
- X /* from *cset1. On failure, *cset1 is not changed. */
- X
- X
- Xcharset *cscopy(const charset *cset, errmsg_t errmsg);
- X
- X /* cscopy(cset) returns a copy of cset, or NULL on failure. */
- X
- X
- Xvoid csswap(charset *cset1, charset *cset2);
- X
- X /* csswap(cset1,cset2) swaps the contents of *cset1 and *cset2. */
- END_OF_FILE
- if test 1853 -ne `wc -c <'Par141/charset.h'`; then
- echo shar: \"'Par141/charset.h'\" unpacked with wrong size!
- fi
- # end of 'Par141/charset.h'
- fi
- if test -f 'Par141/buffer.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Par141/buffer.h'\"
- else
- echo shar: Extracting \"'Par141/buffer.h'\" \(2292 characters\)
- sed "s/^X//" >'Par141/buffer.h' <<'END_OF_FILE'
- X/*********************/
- X/* buffer.h */
- X/* for Par 1.41 */
- X/* Copyright 1993 by */
- X/* Adam M. Costello */
- X/*********************/
- X
- X/* This is ANSI C code. */
- X
- X
- X/* Note: Those functions declared here which do not use errmsg */
- X/* always succeed, provided that they are passed valid arguments. */
- X
- X
- X#include "errmsg.h"
- X
- X#include <stddef.h>
- X
- X
- Xtypedef struct buffer buffer;
- X
- X
- Xbuffer *newbuffer(size_t itemsize, errmsg_t errmsg);
- X
- X /* newbuffer(itemsize,errmsg) returns a pointer to a */
- X /* new empty buffer which holds items of size itemsize. */
- X /* itemsize must not be 0. Returns NULL on failure. */
- X
- X
- Xvoid freebuffer(buffer *buf);
- X
- X /* freebuffer(buf) frees the memory associated with */
- X /* *buf. buf may not be used after this call. */
- X
- X
- Xvoid clearbuffer(buffer *buf);
- X
- X /* clearbuffer(buf) removes */
- X /* all items from *buf, but */
- X /* does not free any memory. */
- X
- X
- Xvoid additem(buffer *buf, const void *item, errmsg_t errmsg);
- X
- X /* additem(buf,item,errmsg) copies *item to the end of */
- X /* *buf. item must point to an object of the proper size */
- X /* for *buf. If additem() fails, *buf will be unaffected. */
- X
- X
- Xint numitems(buffer *buf);
- X
- X /* numitems(buf) returns the number of items in *buf. */
- X
- X
- Xvoid *copyitems(buffer *buf, errmsg_t errmsg);
- X
- X /* copyitems(buf,errmsg) returns an array of objects of */
- X /* the proper size for *buf, one for each item in *buf, */
- X /* or NULL if there are no items in buf. The elements */
- X /* of the array are copied from the items in *buf, in */
- X /* order. The array is allocated with malloc(), so it */
- X /* may be freed with free(). Returns NULL on failure. */
- X
- X
- Xvoid *nextitem(buffer *buf);
- X
- X /* When buf was created by newbuffer, a pointer associated with buf */
- X /* was initialized to point at the first slot in *buf. If there is */
- X /* an item in the slot currently pointed at, nextitem(buf) advances */
- X /* the pointer to the next slot and returns the old value. If there */
- X /* is no item in the slot, nextitem(buf) leaves the pointer where it */
- X /* is and returns NULL. */
- X
- X
- Xvoid rewindbuffer(buffer *buf);
- X
- X /* rewindbuffer(buf) resets the pointer used by */
- X /* nextitem() to point at the first slot in *buf. */
- END_OF_FILE
- if test 2292 -ne `wc -c <'Par141/buffer.h'`; then
- echo shar: \"'Par141/buffer.h'\" unpacked with wrong size!
- fi
- # end of 'Par141/buffer.h'
- fi
- if test -f 'Par141/releasenotes' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Par141/releasenotes'\"
- else
- echo shar: Extracting \"'Par141/releasenotes'\" \(8910 characters\)
- sed "s/^X//" >'Par141/releasenotes' <<'END_OF_FILE'
- X *********************
- X * releasenotes *
- X * for Par 1.41 *
- X * Copyright 1993 by *
- X * Adam M. Costello *
- X *********************
- X
- X
- XEach entry below describes changes since the previous version.
- X
- XPar 1.00 released 25 July 1993
- X The first release.
- X
- XPar 1.10 released 2 August 1993
- X Fixed the following bugs:
- X In reformat.c I used sprintf() but forgot to #include <stdio.h>.
- X I forgot to verify that <width> > <prefix> + <suffix>.
- X The first word of a paragraph was expanded to include initial white
- X characters, not just spaces, contrary to par.doc.
- X Some invalid options were not complained about.
- X NUL characters in the input were not handled.
- X A pointer foul-up in freelines() in par.c could cause a crash.
- X Added the following features:
- X The f, j, and t options.
- X The PARBODY environment variable.
- X Multiple options may be concatenated into a single argument.
- X Removed the m option:
- X Its function is better performed by the f and t options. Normally
- X I would avoid making incompatible changes, unless I were doing a
- X complete overhaul of the whole program, in which case I'd make the
- X version number 2.00 to alert users to possible incompatibilities.
- X However, in this particular instance I allowed an incompatibility in
- X a minor upgrade because version 1.00 was distributed to only four
- X people.
- X Changed the handling of white characters:
- X par now changes all of them (except newlines) to spaces as they are
- X read. This is another incompatible change, excused for the same
- X reason.
- X Made all error messages begin with "par error:".
- X
- XPar 1.20 released 10 August 1993
- X Since Par 1.10 was distributed to no one, I've made some more
- X incompatible changes in Par 1.20.
- X Added the following features:
- X The d option.
- X Paragraphs are now separated by vacant lines, not just blank lines.
- X <hang> now affects not only <prefix> but also <suffix>.
- X
- XPar 1.30 released 18 August 1993
- X Since Par 1.20 was posted to comp.sources.misc, I have made only
- X backward-compatible changes in Par 1.30.
- X Fixed the following bugs:
- X One wrong word in par.c sometimes caused par to crash. Thanks go to
- X vogelke@c-17igp.wpafb.af.mil (Contr Karl Vogel) for sending me
- X an input file that caused a crash.
- X Too-long words were chopped up before the first word in a paragraph
- X was expanded to include initial spaces, allowing impossibility
- X #1 to occur. The order of the two operations has been reversed.
- X Thanks go to splat@deakin.oz.au (Andrew Cashin) for reporting
- X the error message.
- X Added the following features:
- X The g option (motivated by suggestions from several people).
- X The q option (inspired by a suggestion from splat@deakin.oz.au
- X (Andrew Cashin)).
- X The R option (my attempt to squash a bad idea from Par 1.00).
- X The PARQUOTE environment variable (comes with the q option).
- X The PARPROTECT environment variable (inspired by a suggestion from
- X dennisf@se01.elk.miles.com (Dennis Flaherty)).
- X Altered the terminology:
- X Several terms have been added, and the meaning of some terms has
- X been slightly modified. This is a change in the language used to
- X describe par's behavior, not a change in par's actual behavior.
- X Added a clean target to protoMakefile (suggested by hlj@posix.com (Hal
- X Jespersen)).
- X
- XPar 1.31 released 7 September 1993
- X The version number is 1.31 rather than 1.40 because all added features
- X are really just enhancements of existing features.
- X Fixed the following bug:
- X In par.doc, in the example of a paragraph produced by a greedy
- X algorithm, the word "establish" appeared twice in a row. Thanks
- X go to daniel@astro.rug.nl (Daniel Kussendrager) for first
- X pointing this out. (The example is now even better because the
- X paragraph looks even worse than before.)
- X Added the following features:
- X A usage message to accompany command line or environment variable
- X syntax errors (first suggested by qarl@ecl.wustl.edu (Karl
- X Stiefvater)).
- X The help and c options.
- X The B, P, and Q options, which render PARBODY, PARPROTECT, and
- X PARQUOTE no longer necessary. They are retained, though, for
- X compatibility and convenience.
- X The _b, _q, and _Q escape sequences for charset syntax.
- X Added the term "charset syntax".
- X Isolated the character set code in charset.c and charset.h.
- X
- XPar 1.32 released 13 September 1993
- X Fixed the following bugs:
- X par could crash when the + or - operator was used with the B, P, and
- X Q options. Thanks go to splat@deakin.oz.au (Andrew Cashin) for
- X reporting this.
- X If <quote> were 1 and two adjacent lines had different
- X quoteprefixes, one of which was a prefix of the other, and only
- X the line with the shorter quoteprefix contained a non-quote
- X character, then nothing would be altered. According to
- X par.doc 1.31, this was correct, but since neither line is
- X vacant, I consider this a bug in the design of the <quote>
- X feature. Now the longer quoteprefix will be truncated to match
- X the shorter one, and will therefore be vacant. Thanks go to
- X splat@deakin.oz.au (Andrew Cashin) for asking about this.
- X Made slight changes to the documentation.
- X
- XPar 1.40 released 10 Oct 1993
- X Fixed the following bugs:
- X The phrase "containing at least two lines" was left out of the
- X definition of "vacant line" in par.doc and par.1, although
- X the code implemented the correct definition. (The phrase now
- X appears in the definition of "order <k> bodiless line".)
- X There was still a flaw in the design of the <quote> feature. If two
- X adjacent lines had quoteprefixes neither of which was a prefix
- X of the other, no line would be inserted between them, possibly
- X causing other inserted lines not to be vacant. Now it should
- X be true that every line inserted or truncated by the <quote>
- X feature will turn out to be vacant.
- X When <hang> began affecting the default value of <suffix> (as of Par
- X 1.20), it should also have begun affecting the choice of source
- X of characters for the suffixes of lines in OPs.
- X Added the following features:
- X The i option (suggested by barrett@ee.und.ac.za (Alan Barrett)).
- X The e option (inspired by a suggestion from tim@ben.dciem.dnd.ca
- X (Tim Pointing)).
- X The r option.
- X The p, s, and w options are now accepted without numbers.
- X par no longer gives up so easily when choosing default values for
- X <prefix> and <suffix> for an IP with less than <hang>+2 lines,
- X nor when choosing the source of characters for the prefix and
- X suffix of the <i>th output line when <i> > <n> and <n> <=
- X <hang>. These are incompatible changes, but I cannot imagine
- X anyone preferring the old behavior.
- X Altered the terminology:
- X Added the terms "bodiless line" (a generalization of "vacant line"),
- X "fallback prelen", and "fallback suflen".
- X Made miscellaneous changes to the documentation, including the addition
- X of the Quick Start section.
- X
- XPar 1.41 released 31 Oct 1993
- X Moved the former Release Notes section of par.doc into its own file.
- X Fixed the following bugs:
- X A couple of inconsistencies of style in the code (pointed out by
- X dickey@software.org (Thomas E. Dickey).
- X If <quote> and <hang> were 1 and a one-line paragraph beginning with
- X quote characters was reformatted into a multi-line paragraph,
- X the new lines began with spaces instead of quote characters.
- X This was because the policy for copying prefixes used the
- X fallback prelen rather than the augmented version of it used
- X for computing the default value of <prefix>. Now both use the
- X same formula. Thanks go to king@rtsg.mot.com (Steven King) for
- X reporting the problem.
- X If the t option were given without a number, it was unset instead of
- X being set to 1.
- X Added the following feature:
- X The E option (suggested by alex@bilver.oau.org (Alex Matulich)).
- X Altered the terminology:
- X Added the term "augmented fallback prelen".
- X Added to the Rights and Responsibilities section of par.doc a guideline
- X for handling version numbers in patched versions of Par.
- X Added a useful suggestion to protoMakefile.
- END_OF_FILE
- if test 8910 -ne `wc -c <'Par141/releasenotes'`; then
- echo shar: \"'Par141/releasenotes'\" unpacked with wrong size!
- fi
- # end of 'Par141/releasenotes'
- fi
- if test -f 'Par141/reformat.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Par141/reformat.c'\"
- else
- echo shar: Extracting \"'Par141/reformat.c'\" \(14681 characters\)
- sed "s/^X//" >'Par141/reformat.c' <<'END_OF_FILE'
- X/*********************/
- X/* reformat.c */
- X/* for Par 1.41 */
- X/* Copyright 1993 by */
- X/* Adam M. Costello */
- X/*********************/
- X
- X/* This is ANSI C code. */
- X
- X
- X#include "reformat.h" /* Makes sure we're consistent with the */
- X /* prototype. Also includes "errmsg.h". */
- X#include "buffer.h" /* Also includes <stddef.h>. */
- X
- X#include <stdio.h>
- X#include <stdlib.h>
- X#include <ctype.h>
- X#include <string.h>
- X
- X#undef NULL
- X#define NULL ((void *) 0)
- X
- X#ifdef DONTFREE
- X#define free(ptr)
- X#endif
- X
- X
- Xtypedef unsigned char wflag_t;
- X
- Xtypedef struct word {
- X const char *chrs; /* Pointer to the characters in the word */
- X /* (NOT terminated by '\0'). */
- X struct word *prev, /* Pointer to previous word. */
- X *next, /* Pointer to next word. */
- X /* Supposing this word were the first... */
- X *nextline; /* Pointer to first word in next line. */
- X int score, /* Value of the objective function. */
- X length; /* Length of this word. */
- X wflag_t flags; /* Notable properties of this word. */
- X} word;
- X
- X/* The following may be bitwise-OR'd together */
- X/* to set the flags field of a word: */
- X
- Xstatic const wflag_t
- X W_SHIFTED = 1, /* This word should have an extra space before */
- X /* it unless it's the first word in the line. */
- X W_CURIOUS = 2, /* This is a curious word (see par.doc). */
- X W_CAPITAL = 4; /* This is a capitalized word (see par.doc). */
- X
- X#define isshifted(w) ( (w)->flags & 1)
- X#define iscurious(w) (((w)->flags & 2) != 0)
- X#define iscapital(w) (((w)->flags & 4) != 0)
- X
- X
- Xstatic int checkcapital(word *w)
- X/* Returns 1 if *w is capitalized according to the definition */
- X/* in par.doc (assuming <cap> is 0), or 0 if not. */
- X{
- X const char *p, *end;
- X
- X for (p = w->chrs, end = p + w->length; p < end && !isalnum(*p); ++p);
- X return p < end && !islower(*p);
- X}
- X
- X
- Xstatic int checkcurious(word *w)
- X/* Returns 1 if *w is curious according to */
- X/* the definition in par.doc, or 0 if not. */
- X{
- X const char *start, *p;
- X char ch;
- X
- X for (start = w->chrs, p = start + w->length; p > start; --p) {
- X ch = p[-1];
- X if (isalnum(ch)) return 0;
- X if (ch == '.' || ch == '?' || ch == '!' || ch == ':') break;
- X }
- X
- X if (p <= start + 1) return 0;
- X
- X --p;
- X do if (isalnum(*--p)) return 1;
- X while (p > start);
- X
- X return 0;
- X}
- X
- X
- Xstatic int simplebreaks(word *head, word *tail, int L, int last)
- X
- X/* Chooses line breaks in a list of words which maximize the length of the */
- X/* shortest line. L is the maximum line length. The last line counts as a */
- X/* line only if last is non-zero. _head must point to a dummy word, and tail */
- X/* must point to the last word, whose next field must be NULL. Returns the */
- X/* length of the shortest line on success, -1 if there is a word of length */
- X/* greater than L, or L if there are no lines. */
- X{
- X word *w1, *w2;
- X int linelen, score;
- X
- X if (!head->next) return L;
- X
- X for (w1 = tail, linelen = w1->length;
- X w1 != head && linelen <= L;
- X linelen += isshifted(w1), w1 = w1->prev, linelen += 1 + w1->length) {
- X w1->score = last ? linelen : L;
- X w1->nextline = NULL;
- X }
- X
- X for ( ; w1 != head; w1 = w1->prev) {
- X w1->score = -1;
- X for (linelen = w1->length, w2 = w1->next;
- X linelen <= L;
- X linelen += 1 + isshifted(w2) + w2->length, w2 = w2->next) {
- X score = w2->score;
- X if (linelen < score) score = linelen;
- X if (score >= w1->score) {
- X w1->nextline = w2;
- X w1->score = score;
- X }
- X }
- X }
- X
- X return head->next->score;
- X}
- X
- X
- Xstatic void normalbreaks(
- X word *head, word *tail, int L, int fit, int last, errmsg_t errmsg
- X)
- X/* Chooses line breaks in a list of words according to the policy */
- X/* in "par.doc" for <just> = 0 (L is <L>, fit is <fit>, and last is */
- X/* <last>). head must point to a dummy word, and tail must point */
- X/* to the last word, whose next field must be NULL. */
- X{
- X word *w1, *w2;
- X int tryL, shortest, score, target, linelen, extra, minlen;
- X
- X *errmsg = '\0';
- X if (!head->next) return;
- X
- X target = L;
- X
- X/* Determine minimum possible difference between */
- X/* the lengths of the shortest and longest lines: */
- X
- X if (fit) {
- X score = L + 1;
- X for (tryL = L; ; --tryL) {
- X shortest = simplebreaks(head,tail,tryL,last);
- X if (shortest < 0) break;
- X if (tryL - shortest < score) {
- X target = tryL;
- X score = target - shortest;
- X }
- X }
- X }
- X
- X/* Determine maximum possible length of the shortest line: */
- X
- X shortest = simplebreaks(head,tail,target,last);
- X if (shortest < 0) {
- X sprintf(errmsg,impossibility,1);
- X return;
- X }
- X
- X/* Minimize the sum of the squares of the differences */
- X/* between target and the lengths of the lines: */
- X
- X w1 = tail;
- X do {
- X w1->score = -1;
- X for (linelen = w1->length, w2 = w1->next;
- X linelen <= target;
- X linelen += 1 + isshifted(w2) + w2->length, w2 = w2->next) {
- X extra = target - linelen;
- X minlen = shortest;
- X if (w2)
- X score = w2->score;
- X else {
- X score = 0;
- X if (!last) extra = minlen = 0;
- X }
- X if (linelen >= minlen && score >= 0) {
- X score += extra * extra;
- X if (w1->score < 0 || score <= w1->score) {
- X w1->nextline = w2;
- X w1->score = score;
- X }
- X }
- X if (!w2) break;
- X }
- X w1 = w1->prev;
- X } while (w1 != head);
- X
- X if (head->next->score < 0)
- X sprintf(errmsg,impossibility,2);
- X}
- X
- X
- Xstatic void justbreaks(
- X word *head, word *tail, int L, int last, errmsg_t errmsg
- X)
- X/* Chooses line breaks in a list of words according to the */
- X/* policy in "par.doc" for <just> = 1 (L is <L> and last is */
- X/* <last>). head must point to a dummy word, and tail must */
- X/* point to the last word, whose next field must be NULL. */
- X{
- X word *w1, *w2;
- X int numgaps, extra, score, gap, maxgap, numbiggaps;
- X
- X *errmsg = '\0';
- X if (!head->next) return;
- X
- X/* Determine the minimum possible largest inter-word gap: */
- X
- X w1 = tail;
- X do {
- X w1->score = L;
- X for (numgaps = 0, extra = L - w1->length, w2 = w1->next;
- X extra >= 0;
- X ++numgaps, extra -= 1 + isshifted(w2) + w2->length, w2 = w2->next) {
- X gap = numgaps ? (extra + numgaps - 1) / numgaps : L;
- X if (w2)
- X score = w2->score;
- X else {
- X score = 0;
- X if (!last) gap = 0;
- X }
- X if (gap > score) score = gap;
- X if (score < w1->score) {
- X w1->nextline = w2;
- X w1->score = score;
- X }
- X if (!w2) break;
- X }
- X w1 = w1->prev;
- X } while (w1 != head);
- X
- X maxgap = head->next->score;
- X if (maxgap >= L) {
- X strcpy(errmsg, "Cannot justify.\n");
- X return;
- X }
- X
- X/* Minimize the sum of the squares of the numbers */
- X/* of extra spaces required in each inter-word gap: */
- X
- X w1 = tail;
- X do {
- X w1->score = -1;
- X for (numgaps = 0, extra = L - w1->length, w2 = w1->next;
- X extra >= 0;
- X ++numgaps, extra -= 1 + isshifted(w2) + w2->length, w2 = w2->next) {
- X gap = numgaps ? (extra + numgaps - 1) / numgaps : L;
- X if (w2)
- X score = w2->score;
- X else {
- X if (!last) {
- X w1->nextline = NULL;
- X w1->score = 0;
- X break;
- X }
- X score = 0;
- X }
- X if (gap <= maxgap && score >= 0) {
- X numbiggaps = extra % numgaps;
- X score += (extra / numgaps) * (extra + numbiggaps) + numbiggaps;
- X /* The above may not look like the sum of the squares of the numbers */
- X /* of extra spaces required in each inter-word gap, but trust me, it */
- X /* is. It's easier to prove graphically than algebraicly. */
- X if (w1->score < 0 || score <= w1->score) {
- X w1->nextline = w2;
- X w1->score = score;
- X }
- X }
- X if (!w2) break;
- X }
- X w1 = w1->prev;
- X } while (w1 != head);
- X
- X if (head->next->score < 0)
- X sprintf(errmsg,impossibility,3);
- X}
- X
- X
- Xchar **reformat(
- X const char * const *inlines, const char * const *endline, int afp, int fs,
- X int hang, int prefix, int suffix, int width, int cap, int fit, int guess,
- X int just, int last, int Report, int touch, errmsg_t errmsg
- X)
- X{
- X int numin, affix, L, onfirstword = 1, linelen, numout, numgaps, extra, phase;
- X const char * const *line, **suffixes = NULL, **suf, *end, *p1, *p2;
- X char *q1, *q2, **outlines = NULL;
- X word dummy, *head, *tail, *w1, *w2;
- X buffer *pbuf = NULL;
- X
- X/* Initialization: */
- X
- X *errmsg = '\0';
- X dummy.next = dummy.prev = NULL;
- X dummy.flags = 0;
- X head = tail = &dummy;
- X numin = endline - inlines;
- X if (numin <= 0) {
- X sprintf(errmsg,impossibility,4);
- X goto rfcleanup;
- X }
- X
- X/* Allocate space for pointers to the suffixes: */
- X
- X suffixes = malloc(numin * sizeof (const char *));
- X if (!suffixes) {
- X strcpy(errmsg,outofmem);
- X goto rfcleanup;
- X }
- X
- X/* Set the pointers to the suffixes, and create the words: */
- X
- X affix = prefix + suffix;
- X L = width - prefix - suffix;
- X
- X line = inlines, suf = suffixes;
- X do {
- X for (end = *line; *end; ++end);
- X if (end - *line < affix) {
- X sprintf(errmsg,
- X "Line %d shorter than <prefix> + <suffix> = %d + %d = %d\n",
- X line - inlines + 1, prefix, suffix, affix);
- X goto rfcleanup;
- X }
- X end -= suffix;
- X *suf = end;
- X p1 = *line + prefix;
- X for (;;) {
- X while (p1 < end && *p1 == ' ') ++p1;
- X if (p1 == end) break;
- X p2 = p1;
- X if (onfirstword) {
- X p1 = *line + prefix;
- X onfirstword = 0;
- X }
- X while (p2 < end && *p2 != ' ') ++p2;
- X w1 = malloc(sizeof (word));
- X if (!w1) {
- X strcpy(errmsg,outofmem);
- X goto rfcleanup;
- X }
- X w1->next = NULL;
- X w1->prev = tail;
- X tail = tail->next = w1;
- X w1->chrs = p1;
- X w1->length = p2 - p1;
- X w1->flags = 0;
- X p1 = p2;
- X }
- X ++line, ++suf;
- X } while (line < endline);
- X
- X/* If guess is 1, set flag values and merge words: */
- X
- X if (guess) {
- X for (w1 = head, w2 = head->next; w2; w1 = w2, w2 = w2->next) {
- X if (checkcurious(w2)) w2->flags |= W_CURIOUS;
- X if (cap || checkcapital(w2)) {
- X w2->flags |= W_CAPITAL;
- X if (iscurious(w1))
- X if (w1->chrs[w1->length] && w1->chrs + w1->length + 1 == w2->chrs) {
- X w2->length += w1->length + 1;
- X w2->chrs = w1->chrs;
- X w2->prev = w1->prev;
- X w2->prev->next = w2;
- X if (iscapital(w1)) w2->flags |= W_CAPITAL;
- X else w2->flags &= ~W_CAPITAL;
- X if (isshifted(w1)) w2->flags |= W_SHIFTED;
- X else w2->flags &= ~W_SHIFTED;
- X free(w1);
- X }
- X else
- X w2->flags |= W_SHIFTED;
- X }
- X }
- X tail = w1;
- X }
- X
- X/* Check for too-long words: */
- X
- X if (Report)
- X for (w2 = head->next; w2; w2 = w2->next) {
- X if (w2->length > L) {
- X linelen = w2->length;
- X if (linelen > errmsg_size - 17)
- X linelen = errmsg_size - 17;
- X sprintf(errmsg, "Word too long: %.*s\n", linelen, w2->chrs);
- X goto rfcleanup;
- X }
- X }
- X else
- X for (w2 = head->next; w2; w2 = w2->next)
- X while (w2->length > L) {
- X w1 = malloc(sizeof (word));
- X if (!w1) {
- X strcpy(errmsg,outofmem);
- X goto rfcleanup;
- X }
- X w1->next = w2;
- X w1->prev = w2->prev;
- X w1->prev->next = w1;
- X w2->prev = w1;
- X w1->chrs = w2->chrs;
- X w2->chrs += L;
- X w1->length = L;
- X w2->length -= L;
- X w1->flags = 0;
- X if (iscapital(w2)) {
- X w1->flags |= W_CAPITAL;
- X w2->flags &= ~W_CAPITAL;
- X }
- X if (isshifted(w2)) {
- X w1->flags |= W_SHIFTED;
- X w2->flags &= ~W_SHIFTED;
- X }
- X }
- X
- X/* Choose line breaks according to policy in "par.doc": */
- X
- X if (just) justbreaks(head,tail,L,last,errmsg);
- X else normalbreaks(head,tail,L,fit,last,errmsg);
- X if (*errmsg) goto rfcleanup;
- X
- X/* Change L to the length of the longest line if required: */
- X
- X if (!just && touch) {
- X L = 0;
- X w1 = head->next;
- X while (w1) {
- X for (linelen = w1->length, w2 = w1->next;
- X w2 != w1->nextline;
- X linelen += 1 + isshifted(w2) + w2->length, w2 = w2->next);
- X if (linelen > L) L = linelen;
- X w1 = w2;
- X }
- X }
- X
- X/* Construct the lines: */
- X
- X pbuf = newbuffer(sizeof (char *), errmsg);
- X if (*errmsg) goto rfcleanup;
- X
- X numout = 0;
- X w1 = head->next;
- X while (numout < hang || w1) {
- X if (w1)
- X for (w2 = w1->next, numgaps = 0, extra = L - w1->length;
- X w2 != w1->nextline;
- X ++numgaps, extra -= 1 + isshifted(w2) + w2->length, w2 = w2->next);
- X linelen = suffix || just && (w2 || last) ?
- X L + affix :
- X w1 ? prefix + L - extra : prefix;
- X q1 = malloc((linelen + 1) * sizeof (char));
- X if (!q1) {
- X strcpy(errmsg,outofmem);
- X goto rfcleanup;
- X }
- X additem(pbuf, &q1, errmsg);
- X if (*errmsg) goto rfcleanup;
- X ++numout;
- X q2 = q1 + prefix;
- X if (numout <= numin) memcpy(q1, inlines[numout - 1], prefix);
- X else if (numin > hang ) memcpy(q1, endline[-1], prefix);
- X else {
- X if (afp > prefix) afp = prefix;
- X memcpy(q1, endline[-1], afp);
- X q1 += afp;
- X while (q1 < q2) *q1++ = ' ';
- X }
- X q1 = q2;
- X if (w1) {
- X phase = numgaps / 2;
- X for (w2 = w1; ; ) {
- X memcpy(q1, w2->chrs, w2->length);
- X q1 += w2->length;
- X w2 = w2->next;
- X if (w2 == w1->nextline) break;
- X *q1++ = ' ';
- X if (just && (w1->nextline || last)) {
- X phase += extra;
- X while (phase >= numgaps) {
- X *q1++ = ' ';
- X phase -= numgaps;
- X }
- X }
- X if (isshifted(w2)) *q1++ = ' ';
- X }
- X }
- X q2 += linelen - affix;
- X while (q1 < q2) *q1++ = ' ';
- X q2 = q1 + suffix;
- X if (numout <= numin) memcpy(q1, suffixes[numout - 1], suffix);
- X else if (numin > hang ) memcpy(q1, suffixes[numin - 1], suffix);
- X else {
- X if (fs > suffix) fs = suffix;
- X memcpy(q1, suffixes[numin - 1], fs);
- X q1 += fs;
- X while(q1 < q2) *q1++ = ' ';
- X }
- X *q2 = '\0';
- X if (w1) w1 = w1->nextline;
- X }
- X
- X q1 = NULL;
- X additem(pbuf, &q1, errmsg);
- X if (*errmsg) goto rfcleanup;
- X
- X outlines = copyitems(pbuf,errmsg);
- X
- Xrfcleanup:
- X
- X if (suffixes) free(suffixes);
- X
- X while (tail != head) {
- X tail = tail->prev;
- X free(tail->next);
- X }
- X
- X if (pbuf) {
- X if (!outlines)
- X for (;;) {
- X outlines = nextitem(pbuf);
- X if (!outlines) break;
- X free(*outlines);
- X }
- X freebuffer(pbuf);
- X }
- X
- X return outlines;
- X}
- END_OF_FILE
- if test 14681 -ne `wc -c <'Par141/reformat.c'`; then
- echo shar: \"'Par141/reformat.c'\" unpacked with wrong size!
- fi
- # end of 'Par141/reformat.c'
- fi
- if test -f 'Par141/par.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Par141/par.c'\"
- else
- echo shar: Extracting \"'Par141/par.c'\" \(24516 characters\)
- sed "s/^X//" >'Par141/par.c' <<'END_OF_FILE'
- X/*********************/
- X/* par.c */
- X/* for Par 1.41 */
- X/* Copyright 1993 by */
- X/* Adam M. Costello */
- X/*********************/
- X
- X/* This is ANSI C code. */
- X
- X
- X#include "charset.h" /* Also includes "errmsg.h". */
- X#include "buffer.h" /* Also includes <stddef.h>. */
- X#include "reformat.h"
- X
- X#include <stdio.h>
- X#include <string.h>
- X#include <stdlib.h>
- X#include <ctype.h>
- X
- X#undef NULL
- X#define NULL ((void *) 0)
- X
- X#ifdef DONTFREE
- X#define free(ptr)
- X#endif
- X
- X
- Xstatic const char * const usagemsg =
- X"\n"
- X"Usage:\n"
- X"\n"
- X"par [help] [version] [B<op><set>] [P<op><set>] [Q<op><set>] [h[<hang>]]\n"
- X" [p[<prefix>]] [r[<repeat>]] [s[<suffix>]] [w[<width>]] [c[<cap>]]\n"
- X" [d[<div>]] [E[<Err>]] [e[<expel>]] [f[<fit>]] [g[<guess>]] [i[<invis>]]\n"
- X" [j[<just>]] [l[<last>]] [q[<quote>]] [R[<Report>]] [t[<touch>]]\n"
- X"\n"
- X"help print usage message "
- X " ---------- Boolean parameters: ---------\n"
- X"version print version number "
- X " Option: If 1:\n"
- X"B<op><set> as <op> is =/+/-, "
- X " c<cap> count all words as capitalized\n"
- X" replace/augment/diminish "
- X " d<div> use indentation as a delimiter\n"
- X" body chars by <set> "
- X " E<Err> send messages to stderr\n"
- X"P<op><set> ditto for protective chars"
- X " e<expel> discard superfluous lines\n"
- X"Q<op><set> ditto for quote chars "
- X " f<fit> narrow paragraph for best fit\n"
- X"-------- Integer parameters: --------"
- X " g<guess> preserve wide sentence breaks\n"
- X"h<hang> skip IP's 1st <hang> lines"
- X " i<invis> hide lines inserted by <quote>\n"
- X" in scan for common affixes"
- X " j<just> justify paragraphs\n"
- X"p<prefix> prefix length "
- X " l<last> treat last lines like others\n"
- X"r<repeat> if not 0, force bodiless "
- X " q<quote> supply vacant lines between\n"
- X" lines to length <width> "
- X " different quote nesting levels\n"
- X"s<suffix> suffix length "
- X " R<Report> print error for too-long words\n"
- X"w<width> max output line length "
- X " t<touch> move suffixes left\n"
- X"\n"
- X"See par.doc or par.1 (the man page) for more information.\n"
- X;
- X
- X
- X/* Structure for recording properties of lines within segments: */
- X
- Xtypedef unsigned char lflag_t;
- X
- Xtypedef struct lineprop {
- X short p, s; /* Length of the prefix and suffix of a bodiless */
- X /* line, or the fallback prelen and suflen */
- X /* of the IP containing a non-bodiless line. */
- X lflag_t flags; /* Boolean properties (see below). */
- X char rc; /* The repeated character of a bodiless line. */
- X} lineprop;
- X
- X/* Flags for marking boolean properties: */
- X
- Xstatic const lflag_t L_BODILESS = 1, /* Bodiless line. */
- X L_INVIS = 2, /* Invisible line. */
- X L_FIRST = 4, /* First line of a paragraph. */
- X L_SUPERF = 8; /* Superfluous line. */
- X
- X#define isbodiless(prop) ( (prop)->flags & 1)
- X#define isinvis(prop) (((prop)->flags & 2) != 0)
- X#define isfirst(prop) (((prop)->flags & 4) != 0)
- X#define issuperf(prop) (((prop)->flags & 8) != 0)
- X#define isvacant(prop) (isbodiless(prop) && (prop)->rc == ' ')
- X
- X
- Xstatic int digtoint(char c)
- X
- X/* Returns the value represented by the digit c, or -1 if c is not a digit. */
- X{
- X const char *p, * const digits = "0123456789";
- X
- X if (!c) return -1;
- X p = strchr(digits,c);
- X return p ? p - digits : -1;
- X
- X /* We can't simply return c - '0' because this is ANSI C code, */
- X /* so it has to work for any character set, not just ones which */
- X /* put the digits together in order. Also, an array that could */
- X /* be referenced as digtoint[c] might be bad because there's no */
- X /* upper limit on CHAR_MAX. */
- X}
- X
- X
- Xstatic int strtoudec(const char *s, int *pn)
- X
- X/* Converts the longest prefix of string s consisting of decimal */
- X/* digits to an integer, which is stored in *pn. Normally returns */
- X/* 1. If *s is not a digit, then *pn is not changed, but 1 is */
- X/* still returned. If the integer represented is greater than */
- X/* 9999, then *pn is not changed and 0 is returned. */
- X{
- X int n = 0, d;
- X
- X d = digtoint(*s);
- X if (d < 0) return 1;
- X
- X do {
- X if (n >= 1000) return 0;
- X n = 10 * n + d;
- X d = digtoint(*++s);
- X } while (d >= 0);
- X
- X *pn = n;
- X
- X return 1;
- X}
- X
- X
- Xstatic void parsearg(
- X const char *arg, int *phelp, int *pversion, charset *bodychars,
- X charset *protectchars, charset *quotechars, int *phang, int *pprefix,
- X int *prepeat, int *psuffix, int *pwidth, int *pcap, int *pdiv, int *pErr,
- X int *pexpel, int *pfit, int *pguess, int *pinvis, int *pjust, int *plast,
- X int *pquote, int *pReport, int *ptouch, errmsg_t errmsg
- X)
- X/* Parses the command line argument in *arg, setting the objects pointed to */
- X/* by the other pointers as appropriate. *phelp and *pversion are boolean */
- X/* flags indicating whether the help and version options were supplied. */
- X{
- X const char *savearg = arg;
- X charset *chars, *change;
- X char oc;
- X int n;
- X
- X *errmsg = '\0';
- X
- X if (*arg == '-') ++arg;
- X
- X if (!strcmp(arg, "help")) {
- X *phelp = 1;
- X return;
- X }
- X
- X if (!strcmp(arg, "version")) {
- X *pversion = 1;
- X return;
- X }
- X
- X if (*arg == 'B' || *arg == 'P' || *arg == 'Q' ) {
- X chars = *arg == 'B' ? bodychars :
- X *arg == 'P' ? protectchars :
- X /* *arg == 'Q' */ quotechars ;
- X ++arg;
- X if (*arg != '=' && *arg != '+' && *arg != '-') goto badarg;
- X change = parsecharset(arg + 1, errmsg);
- X if (change) {
- X if (*arg == '=') csswap(chars,change);
- X else if (*arg == '+') csadd(chars,change,errmsg);
- X else /* *arg == '-' */ csremove(chars,change,errmsg);
- X freecharset(change);
- X }
- X return;
- X }
- X
- X if (isdigit(*arg)) {
- X if (!strtoudec(arg, &n)) goto badarg;
- X if (n <= 8) *pprefix = n;
- X else *pwidth = n;
- X }
- X
- X for (;;) {
- X while (isdigit(*arg)) ++arg;
- X oc = *arg;
- X if (!oc) break;
- X n = -1;
- X if (!strtoudec(++arg, &n)) goto badarg;
- X if (oc == 'h' || oc == 'p' || oc == 'r' || oc == 's' || oc == 'w') {
- X if (oc == 'h') *phang = n >= 0 ? n : 1;
- X else if (oc == 'w') *pwidth = n >= 0 ? n : 79;
- X else if (oc == 'p') *pprefix = n;
- X else if (oc == 'r') *prepeat = n >= 0 ? n : 3;
- X else /* oc == 's' */ *psuffix = n;
- X }
- X else {
- X if (n < 0) n = 1;
- X if (n > 1) goto badarg;
- X if (oc == 'c') *pcap = n;
- X else if (oc == 'd') *pdiv = n;
- X else if (oc == 'E') *pErr = n;
- X else if (oc == 'e') *pexpel = n;
- X else if (oc == 'f') *pfit = n;
- X else if (oc == 'g') *pguess = n;
- X else if (oc == 'i') *pinvis = n;
- X else if (oc == 'j') *pjust = n;
- X else if (oc == 'l') *plast = n;
- X else if (oc == 'q') *pquote = n;
- X else if (oc == 'R') *pReport = n;
- X else if (oc == 't') *ptouch = n;
- X else goto badarg;
- X }
- X }
- X
- X return;
- X
- Xbadarg:
- X
- X sprintf(errmsg, "Bad argument: %.*s\n", errmsg_size - 16, savearg);
- X *phelp = 1;
- X}
- X
- X
- Xstatic char **readlines(
- X lineprop **pprops, const charset *protectchars,
- X const charset *quotechars, int invis, int quote, errmsg_t errmsg
- X)
- X/* Reads lines from stdin until EOF, or until a line beginning with a */
- X/* protective character is encountered (in which case the protective */
- X/* character is pushed back onto the input stream), or until a blank */
- X/* line is encountered (in which case the newline is pushed back onto */
- X/* the input stream). Returns a NULL-terminated array of pointers to */
- X/* individual lines, stripped of their newline characters. Every NUL */
- X/* character is stripped, and every white character is changed to a */
- X/* space unless it is a newline. If quote is 1, vacant lines will be */
- X/* supplied as described for the q option in par.doc. *pprops is set */
- X/* to an array of lineprop structures, one for each line, each of whose */
- X/* flags field is either 0 or L_INVIS (the other fields are 0). If */
- X/* there are no lines, *pprops is set to NULL. The returned array may */
- X/* be freed with freelines(). *pprops may be freed with free() if */
- X/* it's not NULL. On failure, returns NULL and sets *pprops to NULL. */
- X{
- X buffer *cbuf = NULL, *lbuf = NULL, *lpbuf = NULL;
- X int c, empty, blank, firstline, qsonly, oldqsonly = 0, vlnlen;
- X char ch, *ln = NULL, nullchar = '\0', *nullline = NULL, *qpend,
- X *oldln = NULL, *oldqpend = NULL, *p, *op, *vln = NULL, **lines = NULL;
- X lineprop vprop = { 0, 0, 0, '\0' }, iprop = { 0, 0, 0, '\0' };
- X
- X /* oldqsonly, oldln, and oldquend don't really need to be initialized. */
- X /* They are initialized only to appease compilers that try to be helpful */
- X /* by issuing warnings about unitialized automatic variables. */
- X
- X iprop.flags = L_INVIS;
- X *errmsg = '\0';
- X
- X *pprops = NULL;
- X
- X cbuf = newbuffer(sizeof (char), errmsg);
- X if (*errmsg) goto rlcleanup;
- X lbuf = newbuffer(sizeof (char *), errmsg);
- X if (*errmsg) goto rlcleanup;
- X lpbuf = newbuffer(sizeof (lineprop), errmsg);
- X if (*errmsg) goto rlcleanup;
- X
- X for (empty = blank = firstline = 1; ; ) {
- X c = getchar();
- X if (c == EOF) break;
- X if (c == '\n') {
- X if (blank) {
- X ungetc(c,stdin);
- X break;
- X }
- X additem(cbuf, &nullchar, errmsg);
- X if (*errmsg) goto rlcleanup;
- X ln = copyitems(cbuf,errmsg);
- X if (*errmsg) goto rlcleanup;
- X if (quote) {
- X for (qpend = ln;
- X *qpend && csmember(*qpend, quotechars);
- X ++qpend);
- X for (p = qpend; *p == ' ' || csmember(*p, quotechars); ++p);
- X qsonly = *p == '\0';
- X while (qpend > ln && qpend[-1] == ' ') --qpend;
- X if (!firstline) {
- X for (p = ln, op = oldln;
- X p < qpend && op < oldqpend && *p == *op;
- X ++p, ++op);
- X if (!(p == qpend && op == oldqpend))
- X if (!invis && (oldqsonly || qsonly)) {
- X if (oldqsonly) {
- X *op = '\0';
- X oldqpend = op;
- X }
- X if (qsonly) {
- X *p = '\0';
- X qpend = p;
- X }
- X }
- X else {
- X vlnlen = p - ln;
- X vln = malloc((vlnlen + 1) * sizeof (char));
- X if (!vln) {
- X strcpy(errmsg,outofmem);
- X goto rlcleanup;
- X }
- X strncpy(vln,ln,vlnlen);
- X vln[vlnlen] = '\0';
- X additem(lbuf, &vln, errmsg);
- X if (*errmsg) goto rlcleanup;
- X additem(lpbuf, invis ? &iprop : &vprop, errmsg);
- X if (*errmsg) goto rlcleanup;
- X vln = NULL;
- X }
- X }
- X oldln = ln;
- X oldqpend = qpend;
- X oldqsonly = qsonly;
- X }
- X additem(lbuf, &ln, errmsg);
- X if (*errmsg) goto rlcleanup;
- X ln = NULL;
- X additem(lpbuf, &vprop, errmsg);
- X if (*errmsg) goto rlcleanup;
- X clearbuffer(cbuf);
- X empty = blank = 1;
- X firstline = 0;
- X }
- X else {
- X if (empty) {
- X if (csmember((char) c, protectchars)) {
- X ungetc(c,stdin);
- X break;
- X }
- X empty = 0;
- X }
- X if (!c) continue;
- X if (isspace(c)) c = ' ';
- X else blank = 0;
- X ch = c;
- X additem(cbuf, &ch, errmsg);
- X if (*errmsg) goto rlcleanup;
- X }
- X }
- X
- X if (!blank) {
- X additem(cbuf, &nullchar, errmsg);
- X if (*errmsg) goto rlcleanup;
- X ln = copyitems(cbuf,errmsg);
- X if (*errmsg) goto rlcleanup;
- X additem(lbuf, &ln, errmsg);
- X if (*errmsg) goto rlcleanup;
- X ln = NULL;
- X additem(lpbuf, &vprop, errmsg);
- X if (*errmsg) goto rlcleanup;
- X }
- X
- X additem(lbuf, &nullline, errmsg);
- X if (*errmsg) goto rlcleanup;
- X *pprops = copyitems(lpbuf,errmsg);
- X if (*errmsg) goto rlcleanup;
- X lines = copyitems(lbuf,errmsg);
- X
- Xrlcleanup:
- X
- X if (cbuf) freebuffer(cbuf);
- X if (lpbuf) freebuffer(lpbuf);
- X if (lbuf) {
- X if (!lines)
- X for (;;) {
- X lines = nextitem(lbuf);
- X if (!lines) break;
- X free(*lines);
- X }
- X freebuffer(lbuf);
- X }
- X if (ln) free(ln);
- X if (vln) free(vln);
- X
- X return lines;
- X}
- X
- X
- Xstatic void compresuflen(
- X const char * const *lines, const char * const *endline,
- X const charset *bodychars, int pre, int suf, int *ppre, int *psuf
- X)
- X/* lines is an array of strings, up to but not including endline. */
- X/* Writes into *ppre and *psuf the comprelen and comsuflen of the */
- X/* lines in lines. Assumes that they have already been determined */
- X/* to be at least pre and suf. endline must not equal lines. */
- X{
- X const char *start, *end, * const *line, *p1, *p2, *start2;
- X
- X start = *lines;
- X for (end = start + pre; *end && !csmember(*end, bodychars); ++end);
- X for (line = lines + 1; line < endline; ++line) {
- X for (p1 = start + pre, p2 = *line + pre;
- X p1 < end && *p1 == *p2;
- X ++p1, ++p2);
- X end = p1;
- X }
- X *ppre = end - start;
- X
- X start2 = *lines + *ppre;
- X for (end = start2; *end; ++end);
- X for (start = end - suf;
- X start > start2 && !csmember(start[-1], bodychars);
- X --start);
- X for (line = lines + 1; line < endline; ++line) {
- X start2 = *line + *ppre;
- X for (p2 = start2; *p2; ++p2);
- X for (p1 = end - suf, p2 -= suf;
- X p1 > start && p2 > start2 && p1[-1] == p2[-1];
- X --p1, --p2);
- X start = p1;
- X }
- X while (end - start >= 2 && *start == ' ' && start[1] == ' ') ++start;
- X *psuf = end - start;
- X}
- X
- X
- Xstatic void delimit(
- X const char * const *lines, const char * const *endline,
- X const charset *bodychars, int repeat, int div,
- X int pre, int suf, lineprop *props
- X)
- X/* lines is an array of strings, up to but not including */
- X/* endline. Sets fields in each lineprop in the parallel */
- X/* array props as appropriate, except for the L_SUPERF flag, */
- X/* which is never set. It is assumed that the comprelen */
- X/* and comsuflen of the lines in lines have already been */
- X/* determined to be at least pre and suf, respectively. */
- X{
- X const char * const *line, *end, *p, * const *nextline;
- X char rc;
- X lineprop *prop, *nextprop;
- X int anybodiless = 0, status;
- X
- X if (endline == lines) return;
- X
- X if (endline == lines + 1) {
- X props->flags |= L_FIRST;
- X props->p = pre, props->s = suf;
- X return;
- X }
- X
- X compresuflen(lines, endline, bodychars, pre, suf, &pre, &suf);
- X
- X line = lines, prop = props;
- X do {
- X prop->flags |= L_BODILESS;
- X prop->p = pre, prop->s = suf;
- X for (end = *line; *end; ++end);
- X end -= suf;
- X p = *line + pre;
- X rc = p < end ? *p : ' ';
- X if (rc != ' ' && (!repeat || end - p < repeat))
- X prop->flags &= ~L_BODILESS;
- X else
- X while (p < end) {
- X if (*p != rc) {
- X prop->flags &= ~L_BODILESS;
- X break;
- X }
- X ++p;
- X }
- X if (isbodiless(prop)) {
- X anybodiless = 1;
- X prop->rc = rc;
- X }
- X ++line, ++prop;
- X } while (line < endline);
- X
- X if (anybodiless) {
- X line = lines, prop = props;
- X do {
- X if (isbodiless(prop)) {
- X ++line, ++prop;
- X continue;
- X }
- X
- X for (nextline = line + 1, nextprop = prop + 1;
- X nextline < endline && !isbodiless(nextprop);
- X ++nextline, ++nextprop);
- X
- X delimit(line,nextline,bodychars,repeat,div,pre,suf,prop);
- X
- X line = nextline, prop = nextprop;
- X } while (line < endline);
- X
- X return;
- X }
- X
- X if (!div) {
- X props->flags |= L_FIRST;
- X return;
- X }
- X
- X line = lines, prop = props;
- X status = ((*lines)[pre] == ' ');
- X do {
- X if (((*line)[pre] == ' ') == status)
- X prop->flags |= L_FIRST;
- X ++line, ++prop;
- X } while (line < endline);
- X}
- X
- X
- Xstatic void marksuperf(
- X const char * const * lines, const char * const * endline, lineprop *props
- X)
- X/* lines points to the first line of a segment, and endline to one */
- X/* line beyond the last line in the segment. Sets L_SUPERF bits in */
- X/* the flags fields of the props array whenever the corresponding */
- X/* line is superfluous. L_BODILESS bits must already be set. */
- X{
- X const char * const *line, *p;
- X lineprop *prop, *mprop, dummy;
- X int inbody, num, mnum;
- X
- X for (line = lines, prop = props; line < endline; ++line, ++prop)
- X if (isvacant(prop))
- X prop->flags |= L_SUPERF;
- X
- X inbody = mnum = 0;
- X mprop = &dummy;
- X for (line = lines, prop = props; line < endline; ++line, ++prop)
- X if (isvacant(prop)) {
- X for (num = 0, p = *line; *p; ++p)
- X if (*p != ' ') ++num;
- X if (inbody || num < mnum)
- X mnum = num, mprop = prop;
- X inbody = 0;
- X } else {
- X if (!inbody) mprop->flags &= ~L_SUPERF;
- X inbody = 1;
- X }
- X}
- X
- X
- Xstatic void setaffixes(
- X const char * const *inlines, const char * const *endline,
- X const lineprop *props, const charset *bodychars, const charset *quotechars,
- X int hang, int quote, int *pafp, int *pfs, int *pprefix, int *psuffix
- X)
- X/* inlines is an array of strings, up to but not including endline, */
- X/* representing an IP. inlines and endline must not be equal. props */
- X/* is the the parallel array of lineprop structures. *pafp and *pfs */
- X/* are set to the augmented fallback prelen and fallback suflen of the */
- X/* IP. If either of *pprefix, *psuffix is less than 0, it is set to a */
- X/* default value as specified in "par.doc". */
- X{
- X int numin, pre, suf;
- X const char *p;
- X
- X numin = endline - inlines;
- X
- X if ((*pprefix < 0 || *psuffix < 0) && numin > hang + 1)
- X compresuflen(inlines + hang, endline, bodychars, 0, 0, &pre, &suf);
- X
- X p = *inlines + props->p;
- X if (numin == 1 && quote)
- X while (*p && csmember (*p, quotechars))
- X ++p;
- X *pafp = p - *inlines;
- X *pfs = props->s;
- X
- X if (*pprefix < 0)
- X *pprefix = numin > hang + 1 ? pre : *pafp;
- X
- X if (*psuffix < 0)
- X *psuffix = numin > hang + 1 ? suf : *pfs;
- X}
- X
- X
- Xstatic void freelines(char **lines)
- X/* Frees the elements of lines, and lines itself. */
- X/* lines is a NULL-terminated array of strings. */
- X{
- X char **line;
- X
- X for (line = lines; *line; ++line)
- X free(*line);
- X
- X free(lines);
- X}
- X
- X
- Xint main(int argc, const char * const *argv)
- X{
- X int help = 0, version = 0, hang = 0, prefix = -1, repeat = 0, suffix = -1,
- X width = 72, cap = 0, div = 0, Err = 0, expel = 0, fit = 0, guess = 0,
- X invis = 0, just = 0, last = 0, quote = 0, Report = 0, touch = -1,
- X prefixbak, suffixbak, c, sawnonblank, oweblank, n, i, afp, fs;
- X charset *bodychars = NULL, *protectchars = NULL, *quotechars = NULL;
- X char *parinit = NULL, *arg, **inlines = NULL, **endline, **firstline, *end,
- X **nextline, **outlines = NULL, **line;
- X const char *env, * const whitechars = " \f\n\r\t\v";
- X errmsg_t errmsg = { '\0' };
- X lineprop *props = NULL, *firstprop, *nextprop;
- X FILE *errout;
- X
- X/* Process environment variables: */
- X
- X env = getenv("PARBODY");
- X if (!env) env = "";
- X bodychars = parsecharset(env,errmsg);
- X if (*errmsg) {
- X help = 1;
- X goto parcleanup;
- X }
- X
- X env = getenv("PARPROTECT");
- X if (!env) env = "";
- X protectchars = parsecharset(env,errmsg);
- X if (*errmsg) {
- X help = 1;
- X goto parcleanup;
- X }
- X
- X env = getenv("PARQUOTE");
- X if (!env) env = "> ";
- X quotechars = parsecharset(env,errmsg);
- X if (*errmsg) {
- X help = 1;
- X goto parcleanup;
- X }
- X
- X env = getenv("PARINIT");
- X if (env) {
- X parinit = malloc((strlen(env) + 1) * sizeof (char));
- X if (!parinit) {
- X strcpy(errmsg,outofmem);
- X goto parcleanup;
- X }
- X strcpy(parinit,env);
- X arg = strtok(parinit,whitechars);
- X while (arg) {
- X parsearg(arg, &help, &version, bodychars, protectchars,
- X quotechars, &hang, &prefix, &repeat, &suffix,
- X &width, &cap, &div, &Err, &expel, &fit, &guess,
- X &invis, &just, &last, "e, &Report, &touch, errmsg);
- X if (*errmsg || help || version) goto parcleanup;
- X arg = strtok(NULL,whitechars);
- X }
- X free(parinit);
- X parinit = NULL;
- X }
- X
- X/* Process command line arguments: */
- X
- X while (*++argv) {
- X parsearg(*argv, &help, &version, bodychars, protectchars,
- X quotechars, &hang, &prefix, &repeat, &suffix,
- X &width, &cap, &div, &Err, &expel, &fit, &guess,
- X &invis, &just, &last, "e, &Report, &touch, errmsg);
- X if (*errmsg || help || version) goto parcleanup;
- X }
- X
- X if (touch < 0) touch = fit || last;
- X prefixbak = prefix;
- X suffixbak = suffix;
- X
- X/* Main loop: */
- X
- X for (sawnonblank = 0, oweblank = 0; ; ) {
- X for (;;) {
- X c = getchar();
- X if (expel && c == '\n') {
- X oweblank = sawnonblank;
- X continue;
- X }
- X if (csmember((char) c, protectchars)) {
- X sawnonblank = 1;
- X if (oweblank) {
- X putchar('\n');
- X oweblank = 0;
- X }
- X while (c != '\n' && c != EOF) {
- X putchar(c);
- X c = getchar();
- X }
- X }
- X if (c != '\n') break;
- X putchar(c);
- X }
- X if (c == EOF) break;
- X ungetc(c,stdin);
- X
- X inlines =
- X readlines(&props, protectchars, quotechars, invis, quote, errmsg);
- X if (*errmsg) goto parcleanup;
- X
- X for (endline = inlines; *endline; ++endline);
- X if (endline == inlines) {
- X free(inlines);
- X inlines = NULL;
- X continue;
- X }
- X
- X sawnonblank = 1;
- X if (oweblank) {
- X putchar('\n');
- X oweblank = 0;
- X }
- X
- X delimit((const char * const *) inlines,
- X (const char * const *) endline,
- X bodychars, repeat, div, 0, 0, props);
- X
- X if (expel)
- X marksuperf((const char * const *) inlines,
- X (const char * const *) endline, props);
- X
- X firstline = inlines, firstprop = props;
- X do {
- X if (isbodiless(firstprop)) {
- X if (!isinvis(firstprop) && !(expel && issuperf(firstprop))) {
- X for (end = *firstline; *end; ++end);
- X if (!repeat || firstprop->rc == ' ' && !firstprop->s) {
- X while (end > *firstline && end[-1] == ' ') --end;
- X *end = '\0';
- X puts(*firstline);
- X }
- X else {
- X n = width - firstprop->p - firstprop->s;
- X if (n < 0) {
- X sprintf(errmsg,impossibility,5);
- X goto parcleanup;
- X }
- X printf("%.*s", firstprop->p, *firstline);
- X for (i = n; i; --i)
- X putchar(firstprop->rc);
- X puts(end - firstprop->s);
- X }
- X }
- X ++firstline, ++firstprop;
- X continue;
- X }
- X
- X for (nextline = firstline + 1, nextprop = firstprop + 1;
- X nextline < endline && !isbodiless(nextprop) && !isfirst(nextprop);
- X ++nextline, ++nextprop);
- X
- X prefix = prefixbak, suffix = suffixbak;
- X setaffixes((const char * const *) firstline,
- X (const char * const *) nextline, firstprop, bodychars,
- X quotechars, hang, quote, &afp, &fs, &prefix, &suffix);
- X if (width <= prefix + suffix) {
- X sprintf(errmsg,
- X "<width> (%d) <= <prefix> (%d) + <suffix> (%d)\n",
- X width, prefix, suffix);
- X goto parcleanup;
- X }
- X
- X outlines =
- X reformat((const char * const *) firstline,
- X (const char * const *) nextline,
- X afp, fs, hang, prefix, suffix, width, cap,
- X fit, guess, just, last, Report, touch, errmsg);
- X if (*errmsg) goto parcleanup;
- X
- X for (line = outlines; *line; ++line)
- X puts(*line);
- X
- X freelines(outlines);
- X outlines = NULL;
- X
- X firstline = nextline, firstprop = nextprop;
- X } while (firstline < endline);
- X
- X freelines(inlines);
- X inlines = NULL;
- X
- X free(props);
- X props = NULL;
- X }
- X
- Xparcleanup:
- X
- X if (bodychars) freecharset(bodychars);
- X if (protectchars) freecharset(protectchars);
- X if (quotechars) freecharset(quotechars);
- X if (parinit) free(parinit);
- X if (inlines) freelines(inlines);
- X if (props) free(props);
- X if (outlines) freelines(outlines);
- X
- X errout = Err ? stderr : stdout;
- X if (*errmsg) fprintf(errout, "par error:\n%.*s", errmsg_size, errmsg);
- X if (version) fputs("par 1.41\n",errout);
- X if (help) fputs(usagemsg,errout);
- X
- X return *errmsg ? EXIT_FAILURE : EXIT_SUCCESS;
- X}
- END_OF_FILE
- if test 24516 -ne `wc -c <'Par141/par.c'`; then
- echo shar: \"'Par141/par.c'\" unpacked with wrong size!
- fi
- # end of 'Par141/par.c'
- fi
- echo shar: End of shell archive.
- exit 0
-
- exit 0 # Just in case...
-