home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume39 / par131 / part03 < prev    next >
Encoding:
Text File  |  1993-09-11  |  47.0 KB  |  1,666 lines

  1. Newsgroups: comp.sources.misc
  2. From: amc@wuecl.wustl.edu (Adam Costello)
  3. Subject: v39i085:  par131 - paragraph reformatter, v1.31, Part03/03
  4. Message-ID: <1993Sep11.143738.9328@sparky.sterling.com>
  5. X-Md4-Signature: 056689b60fbfd3f67e689811f8ce248a
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 11 Sep 1993 14:37:38 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: amc@wuecl.wustl.edu (Adam Costello)
  12. Posting-number: Volume 39, Issue 85
  13. Archive-name: par131/part03
  14. Environment: ANSI-C
  15. Supersedes: par: Volume 39, Issue 40-42
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of shell archive."
  24. # Contents:  Par131 Par131/par.c Par131/reformat.h Par131/reformat.c
  25. #   Par131/buffer.h Par131/buffer.c Par131/errmsg.h Par131/errmsg.c
  26. # Wrapped by amc@wuecl on Fri Sep 10 18:43:54 1993
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test ! -d 'Par131' ; then
  29.     echo shar: Creating directory \"'Par131'\"
  30.     mkdir 'Par131'
  31. fi
  32. if test -f 'Par131/par.c' -a "${1}" != "-c" ; then 
  33.   echo shar: Will not clobber existing file \"'Par131/par.c'\"
  34. else
  35. echo shar: Extracting \"'Par131/par.c'\" \(18832 characters\)
  36. sed "s/^X//" >'Par131/par.c' <<'END_OF_FILE'
  37. X/*********************/
  38. X/* par.c             */
  39. X/* for Par 1.31      */
  40. X/* Copyright 1993 by */
  41. X/* Adam M. Costello  */
  42. X/*********************/
  43. X
  44. X/* This is ANSI C code. */
  45. X
  46. X
  47. X#include "charset.h"   /* Also includes "errmsg.h". */
  48. X#include "buffer.h"    /* Also includes <stddef.h>. */
  49. X#include "reformat.h"
  50. X
  51. X#include <stdio.h>
  52. X#include <string.h>
  53. X#include <stdlib.h>
  54. X#include <ctype.h>
  55. X
  56. X#undef NULL
  57. X#define NULL ((void *) 0)
  58. X
  59. X#ifdef DONTFREE
  60. X#define free(ptr)
  61. X#endif
  62. X
  63. X
  64. Xconst char * const usagemsg =
  65. X"\n"
  66. X"Usage:\n"
  67. X"\n"
  68. X"par [help] [version] [B<op><set>] [P<op><set>] [Q<op><set>] [h[<hang>]]\n"
  69. X"    [p<prefix>] [s<suffix>] [w<width>] [c[<cap>]] [d[<div>]] [f[<fit>]]\n"
  70. X"    [g[<guess>]] [j[<just>]] [l[<last>]] [q[<quote>]] [R[<Report>]]\n"
  71. X"    [t[<touch>]]\n"
  72. X"\n"
  73. X"help       usage message             |"
  74. X                                  "Boolean parameters:\n"
  75. X"version    version number            |"
  76. X                                  "Option:   If 1:\n"
  77. X"B<op><set> as <op> is =/+/-,         |"
  78. X                                  "c<cap>    all words count as capitalized\n"
  79. X"           replace/augment/diminish  |"
  80. X                                  "d<div>    indentation delimits paragraphs\n"
  81. X"           body chars by <set>       |"
  82. X                                  "f<fit>    paragraphs are narrowed to\n"
  83. X"P<op><set> ditto for protective chars|"
  84. X                                  "          smoothen the right edge\n"
  85. X"Q<op><set> ditto for quote chars     |"
  86. X                                  "g<guess>  wide sentence breaks preserved\n"
  87. X"h<hang>    first <hang> lines of each|"
  88. X                                  "j<just>   paragraphs are justified\n"
  89. X"           paragraph not searched for|"
  90. X                                  "l<last>   last lines treated like others\n"
  91. X"           common prefixes & suffixes|"
  92. X                                  "q<quote>  vacant lines inserted between\n"
  93. X"p<prefix>  prefix length             |"
  94. X                                  "          different quote nesting levels\n"
  95. X"s<suffix>  suffix length             |"
  96. X                                  "R<Report> too-long words cause errors\n"
  97. X"w<width>   max output line length    |"
  98. X                                  "t<touch>  suffixes are moved left\n"
  99. X"\n"
  100. X"See par.doc or par.1 (the man page) for more information.\n"
  101. X;
  102. X
  103. X
  104. Xstatic int digtoint(char c)
  105. X
  106. X/* Returns the value represented by the digit c, or -1 if c is not a digit. */
  107. X{
  108. X  const char *p, * const digits = "0123456789";
  109. X
  110. X  if (!c) return -1;
  111. X  p = strchr(digits,c);
  112. X  return  p  ?  p - digits  :  -1;
  113. X
  114. X  /* We can't simply return c - '0' because this is ANSI C code,  */
  115. X  /* so it has to work for any character set, not just ones which */
  116. X  /* put the digits together in order.  Also, an array that could */
  117. X  /* be referenced as digtoint[c] might be bad because there's no */
  118. X  /* upper limit on CHAR_MAX.                                     */
  119. X}
  120. X
  121. X
  122. Xstatic int strtoudec(const char *s, int *pn)
  123. X
  124. X/* Converts the longest prefix of string s consisting of decimal   */
  125. X/* digits to an integer, which is stored in *pn.  Normally returns */
  126. X/* 1.  If *s is not a digit, then *pn is not changed, but 1 is     */
  127. X/* still returned.  If the integer represented is greater than     */
  128. X/* 9999, then *pn is not changed and 0 is returned.                */
  129. X{
  130. X  int n = 0, d;
  131. X
  132. X  d = digtoint(*s);
  133. X  if (d < 0) return 1;
  134. X
  135. X  do {
  136. X    if (n >= 1000) return 0;
  137. X    n = 10 * n + d;
  138. X    d = digtoint(*++s);
  139. X  } while (d >= 0);
  140. X
  141. X  *pn = n;
  142. X
  143. X  return 1;
  144. X}
  145. X
  146. X
  147. Xstatic void parsearg(
  148. X  const char *arg, int *phelp, int *pversion, charset *bodychars,
  149. X  charset *protectchars, charset *quotechars, int *phang, int *pprefix,
  150. X  int *psuffix, int *pwidth, int *pcap, int *pdiv, int *pfit, int *pguess,
  151. X  int *pjust, int *plast, int *pquote, int *pReport, int *ptouch,
  152. X  errmsg_t errmsg
  153. X)
  154. X/* Parses the command line argument in *arg, setting the objects pointed to */
  155. X/* by the other pointers as appropriate. *phelp and *pversion are boolean   */
  156. X/* flags indicating whether the help and version options were supplied.     */
  157. X{
  158. X  const char *savearg = arg;
  159. X  charset *chars, *change;
  160. X  char oc;
  161. X  int n;
  162. X
  163. X  *errmsg = '\0';
  164. X
  165. X  if (*arg == '-') ++arg;
  166. X
  167. X  if (!strcmp(arg, "help")) {
  168. X    *phelp = 1;
  169. X    return;
  170. X  }
  171. X
  172. X  if (!strcmp(arg, "version")) {
  173. X    *pversion = 1;
  174. X    return;
  175. X  }
  176. X
  177. X  if (*arg == 'B' || *arg == 'P' || *arg == 'Q' ) {
  178. X    chars =  *arg == 'B'  ?  bodychars    :
  179. X             *arg == 'P'  ?  protectchars :
  180. X          /* *arg == 'Q' */  quotechars   ;
  181. X    ++arg;
  182. X    if (*arg != '='  &&  *arg != '+'  &&  *arg != '-') goto badarg;
  183. X    change = parsecharset(arg + 1, errmsg);
  184. X    if (change) {
  185. X      if      (*arg == '=')   csswap(chars,change);
  186. X      else if (*arg == '+')   csadd(chars,change,errmsg);
  187. X      else  /* *arg == '-' */ csremove(chars,change,errmsg);
  188. X      freecharset(change);
  189. X    }
  190. X    return;
  191. X  }
  192. X
  193. X  if (isdigit(*arg)) {
  194. X    if (!strtoudec(arg, &n)) goto badarg;
  195. X    if (n <= 8) *pprefix = n;
  196. X    else *pwidth = n;
  197. X  }
  198. X
  199. X  for (;;) {
  200. X    while (isdigit(*arg)) ++arg;
  201. X    oc = *arg;
  202. X    if (!oc) break;
  203. X    n = 1;
  204. X    if (!strtoudec(++arg, &n)) goto badarg;
  205. X    if (oc == 'h' || oc == 'p' || oc == 's' || oc == 'w') {
  206. X      if (oc == 'h') *phang = n;
  207. X      else {
  208. X        if (!isdigit(*arg)) goto badarg;
  209. X        if      (oc == 'w')   *pwidth  = n;
  210. X        else if (oc == 'p')   *pprefix = n;
  211. X        else  /* oc == 's' */ *psuffix = n;
  212. X      }
  213. X    }
  214. X    else {
  215. X      if (n > 1) goto badarg;
  216. X      if      (oc == 'c') *pcap    = n;
  217. X      else if (oc == 'd') *pdiv    = n;
  218. X      else if (oc == 'f') *pfit    = n;
  219. X      else if (oc == 'g') *pguess  = n;
  220. X      else if (oc == 'j') *pjust   = n;
  221. X      else if (oc == 'l') *plast   = n;
  222. X      else if (oc == 'q') *pquote  = n;
  223. X      else if (oc == 'R') *pReport = n;
  224. X      else if (oc == 't') *ptouch  = n;
  225. X      else goto badarg;
  226. X    }
  227. X  }
  228. X
  229. X  return;
  230. X
  231. Xbadarg:
  232. X
  233. X  sprintf(errmsg, "Bad argument: %.*s\n", errmsg_size - 16, savearg);
  234. X  *phelp = 1;
  235. X}
  236. X
  237. X
  238. Xstatic char **readlines(const charset *protectchars,
  239. X                        const charset *quotechars, int quote, errmsg_t errmsg)
  240. X
  241. X/* Reads lines from stdin until EOF, or until a line beginning with a */
  242. X/* protective character is encountered (in which case the protective  */
  243. X/* character is pushed back onto the input stream), or until a blank  */
  244. X/* line is encountered (in which case the newline is pushed back onto */
  245. X/* the input stream).  Returns a NULL-terminated array of pointers to */
  246. X/* individual lines, stripped of their newline characters.  Every NUL */
  247. X/* character is stripped, and every white character is changed to a   */
  248. X/* space unless it is a newline.  If quote is 1, vacant lines will be */
  249. X/* inserted as described for the q option in par.doc.  Returns NULL   */
  250. X/* on failure.                                                        */
  251. X{
  252. X  buffer *cbuf = NULL, *lbuf = NULL;
  253. X  int c, empty, blank, nonquote, oldnonquote = 0, qplen;
  254. X  char ch, *ln = NULL, nullchar = '\0', *nullline = NULL, *qpstart, *qpend,
  255. X       *oldqpstart = &nullchar, *oldqpend = &nullchar, *p, *op, *vln = NULL,
  256. X       **lines = NULL;
  257. X
  258. X  *errmsg = '\0';
  259. X
  260. X  cbuf = newbuffer(sizeof (char), errmsg);
  261. X  if (*errmsg) goto rlcleanup;
  262. X  lbuf = newbuffer(sizeof (char *), errmsg);
  263. X  if (*errmsg) goto rlcleanup;
  264. X
  265. X  for (empty = blank = 1;  ; ) {
  266. X    c = getchar();
  267. X    if (c == EOF) break;
  268. X    if (c == '\n') {
  269. X      if (blank) {
  270. X        ungetc(c,stdin);
  271. X        break;
  272. X      }
  273. X      additem(cbuf, &nullchar, errmsg);
  274. X      if (*errmsg) goto rlcleanup;
  275. X      ln = copyitems(cbuf,errmsg);
  276. X      if (*errmsg) goto rlcleanup;
  277. X      if (quote) {
  278. X        qpstart = ln;
  279. X        for (qpend = qpstart;
  280. X             *qpend && csmember(*qpend, quotechars);
  281. X             ++qpend);
  282. X        nonquote = *qpend != '\0';
  283. X        while (qpend > qpstart && qpend[-1] == ' ') --qpend;
  284. X        for (p = qpstart, op = oldqpstart;
  285. X             p < qpend && op < oldqpend && *p == *op;
  286. X             ++p, ++op);
  287. X        if (   (p < qpend && op == oldqpend  ||  p == qpend && op < oldqpend)
  288. X            && nonquote && oldnonquote) {
  289. X          qplen = p - qpstart;
  290. X          vln = malloc((qplen + 1) * sizeof (char));
  291. X          if (!vln) {
  292. X            strcpy(errmsg,outofmem);
  293. X            goto rlcleanup;
  294. X          }
  295. X          strncpy(vln,qpstart,qplen);
  296. X          vln[qplen] = '\0';
  297. X          additem(lbuf, &vln, errmsg);
  298. X          if (*errmsg) goto rlcleanup;
  299. X          vln = NULL;
  300. X        }
  301. X        oldqpstart = qpstart;
  302. X        oldqpend = qpend;
  303. X        oldnonquote = nonquote;
  304. X      }
  305. X      additem(lbuf, &ln, errmsg);
  306. X      if (*errmsg) goto rlcleanup;
  307. X      ln = NULL;
  308. X      clearbuffer(cbuf);
  309. X      empty = blank = 1;
  310. X    }
  311. X    else {
  312. X      if (empty) {
  313. X        if (csmember((char) c, protectchars)) {
  314. X          ungetc(c,stdin);
  315. X          break;
  316. X        }
  317. X        empty = 0;
  318. X      }
  319. X      if (!c) continue;
  320. X      if (isspace(c)) c = ' ';
  321. X      else blank = 0;
  322. X      ch = c;
  323. X      additem(cbuf, &ch, errmsg);
  324. X      if (*errmsg) goto rlcleanup;
  325. X    }
  326. X  }
  327. X
  328. X  if (!blank) {
  329. X    additem(cbuf, &nullchar, errmsg);
  330. X    if (*errmsg) goto rlcleanup;
  331. X    ln = copyitems(cbuf,errmsg);
  332. X    if (*errmsg) goto rlcleanup;
  333. X    additem(lbuf, &ln, errmsg);
  334. X    if (*errmsg) goto rlcleanup;
  335. X    ln = NULL;
  336. X  }
  337. X
  338. X  additem(lbuf, &nullline, errmsg);
  339. X  if (*errmsg) goto rlcleanup;
  340. X  lines = copyitems(lbuf,errmsg);
  341. X
  342. Xrlcleanup:
  343. X
  344. X  if (cbuf) freebuffer(cbuf);
  345. X  if (lbuf) {
  346. X    if (!lines)
  347. X      for (;;) {
  348. X        lines = nextitem(lbuf);
  349. X        if (!lines) break;
  350. X        free(*lines);
  351. X      }
  352. X    freebuffer(lbuf);
  353. X  }
  354. X  if (ln) free(ln);
  355. X  if (vln) free(vln);
  356. X
  357. X  return lines;
  358. X}
  359. X
  360. X
  361. Xstatic void compresuflen(
  362. X  const char * const *lines, const char * const *endline,
  363. X  const charset *bodychars, int pre, int suf, int *ppre, int *psuf
  364. X)
  365. X/* lines is an array of strings, up to but not including endline.  */
  366. X/* Writes into *ppre and *psuf the comprelen and comsuflen of the  */
  367. X/* lines in lines.  Assumes that they have already been determined */
  368. X/* to be at least pre and suf. endline must not equal lines.       */
  369. X{
  370. X  const char *start, *end, * const *line, *p1, *p2, *start2;
  371. X
  372. X  start = *lines;
  373. X  for (end = start + pre;  *end && !csmember(*end, bodychars);  ++end);
  374. X  for (line = lines + 1;  line < endline;  ++line) {
  375. X    for (p1 = start + pre, p2 = *line + pre;
  376. X         p1 < end && *p1 == *p2;
  377. X         ++p1, ++p2);
  378. X    end = p1;
  379. X  }
  380. X  *ppre = end - start;
  381. X
  382. X  start2 = *lines + *ppre;
  383. X  for (end = start2;  *end;  ++end);
  384. X  for (start = end - suf;
  385. X       start > start2 && !csmember(start[-1], bodychars);
  386. X       --start);
  387. X  for (line = lines + 1;  line < endline;  ++line) {
  388. X    start2 = *line + *ppre;
  389. X    for (p2 = start2;  *p2;  ++p2);
  390. X    for (p1 = end - suf, p2 -= suf;
  391. X         p1 > start && p2 > start2 && p1[-1] == p2[-1];
  392. X         --p1, --p2);
  393. X    start = p1;
  394. X  }
  395. X  while (end - start >= 2 && *start == ' ' && start[1] == ' ') ++start;
  396. X  *psuf = end - start;
  397. X}
  398. X
  399. X
  400. Xstatic void delimit(
  401. X  const char * const *lines, const char * const *endline,
  402. X  const charset *bodychars, int div, int pre, int suf, char *tags
  403. X)
  404. X/* lines is an array of strings, up to but not including endline.     */
  405. X/* Sets each character in the parallel array tags to 'f', 'p', or     */
  406. X/* 'v' according to whether the corresponding line in lines is the    */
  407. X/* first line of a paragraph, some other line in a paragraph, or a    */
  408. X/* vacant line, respectively, depending on the values of bodychars    */
  409. X/* and div, according to "par.doc".  It is assumed that the comprelen */
  410. X/* and comsuflen of the lines in lines have already been determined   */
  411. X/* to be at least pre and suf, respectively.                          */
  412. X{
  413. X  const char * const *line, *end, *p, * const *nextline;
  414. X  char *tag, *nexttag;
  415. X  int anyvacant = 0, status;
  416. X
  417. X  if (endline == lines) return;
  418. X
  419. X  if (endline == lines + 1) {
  420. X    *tags = 'f';
  421. X    return;
  422. X  }
  423. X
  424. X  compresuflen(lines, endline, bodychars, pre, suf, &pre, &suf);
  425. X
  426. X  line = lines;
  427. X  tag = tags;
  428. X  do {
  429. X    *tag = 'v';
  430. X    for (end = *line;  *end;  ++end);
  431. X    end -= suf;
  432. X    for (p = *line + pre;  p < end;  ++p)
  433. X      if (*p != ' ') {
  434. X        *tag = 'p';
  435. X        break;
  436. X      }
  437. X    if (*tag == 'v') anyvacant = 1;
  438. X    ++line;
  439. X    ++tag;
  440. X  } while (line < endline);
  441. X
  442. X  if (anyvacant) {
  443. X    line = lines;
  444. X    tag = tags;
  445. X    do {
  446. X      if (*tag == 'v') {
  447. X        ++line;
  448. X        ++tag;
  449. X        continue;
  450. X      }
  451. X
  452. X      for (nextline = line + 1, nexttag = tag + 1;
  453. X           nextline < endline && *nexttag == 'p';
  454. X           ++nextline, ++nexttag);
  455. X
  456. X      delimit(line,nextline,bodychars,div,pre,suf,tag);
  457. X
  458. X      line = nextline;
  459. X      tag = nexttag;
  460. X    } while (line < endline);
  461. X
  462. X    return;
  463. X  }
  464. X
  465. X  if (!div) {
  466. X    *tags = 'f';
  467. X    return;
  468. X  }
  469. X
  470. X  line = lines;
  471. X  tag = tags;
  472. X  status = ((*lines)[pre] == ' ');
  473. X  do {
  474. X    if (((*line)[pre] == ' ') == status)
  475. X      *tag = 'f';
  476. X    ++line;
  477. X    ++tag;
  478. X  } while (line < endline);
  479. X}
  480. X
  481. X
  482. Xstatic void setaffixes(
  483. X  const char * const *inlines, const char * const *endline,
  484. X  const charset *bodychars, const charset *quotechars,
  485. X  int hang, int quote, int *pprefix, int *psuffix
  486. X)
  487. X/* inlines is an array of strings, up to but not including   */
  488. X/* endline.  If either of *pprefix, *psuffix is less than 0, */
  489. X/* sets it to a default value based on inlines, bodychars,   */
  490. X/* quotechars, hang, and quote, according to "par.doc".      */
  491. X{
  492. X  int numin, pre, suf;
  493. X  const char *start, *p;
  494. X
  495. X  numin = endline - inlines;
  496. X
  497. X  if ((*pprefix < 0 || *psuffix < 0) && numin > hang + 1)
  498. X    compresuflen(inlines + hang, endline, bodychars, 0, 0, &pre, &suf);
  499. X
  500. X  if (*pprefix < 0)
  501. X    if (quote && numin == hang + 1) {
  502. X      start = inlines[hang];
  503. X      for (p = start;  *p && csmember(*p, quotechars);  ++p);
  504. X      *pprefix = p - start;
  505. X    }
  506. X    else *pprefix = numin > hang + 1  ?  pre  :  0;
  507. X
  508. X  if (*psuffix < 0)
  509. X    *psuffix = numin > hang + 1  ?  suf  :  0;
  510. X}
  511. X
  512. X
  513. Xstatic void freelines(char **lines)
  514. X/* Frees the elements of lines, and lines itself. */
  515. X/* lines is a NULL-terminated array of strings.   */
  516. X{
  517. X  char **line;
  518. X
  519. X  for (line = lines;  *line;  ++line)
  520. X    free(*line);
  521. X
  522. X  free(lines);
  523. X}
  524. X
  525. X
  526. Xmain(int argc, const char * const *argv)
  527. X{
  528. X  int help = 0, version = 0, hang = 0, prefix = -1, suffix = -1, width = 72,
  529. X      cap = 0, div = 0, fit = 0, guess = 0, just = 0, last = 0, quote = 0,
  530. X      Report = 0, touch = -1, prefixbak, suffixbak, c;
  531. X  charset *bodychars = NULL, *protectchars = NULL, *quotechars = NULL;
  532. X  char *parinit = NULL, *arg, **inlines = NULL, **endline,
  533. X       *tags = NULL, **firstline, *firsttag, *end, **nextline, *nexttag,
  534. X       **outlines = NULL, **line;
  535. X  const char *env, * const whitechars = " \f\n\r\t\v";
  536. X  errmsg_t errmsg = { '\0' };
  537. X
  538. X/* Process environment variables: */
  539. X
  540. X  env = getenv("PARBODY");
  541. X  if (!env) env = "";
  542. X  bodychars = parsecharset(env,errmsg);
  543. X  if (*errmsg) {
  544. X    help = 1;
  545. X    goto parcleanup;
  546. X  }
  547. X
  548. X  env = getenv("PARPROTECT");
  549. X  if (!env) env = "";
  550. X  protectchars = parsecharset(env,errmsg);
  551. X  if (*errmsg) {
  552. X    help = 1;
  553. X    goto parcleanup;
  554. X  }
  555. X
  556. X  env = getenv("PARQUOTE");
  557. X  if (!env) env = "> ";
  558. X  quotechars = parsecharset(env,errmsg);
  559. X  if (*errmsg) {
  560. X    help = 1;
  561. X    goto parcleanup;
  562. X  }
  563. X
  564. X  env = getenv("PARINIT");
  565. X  if (env) {
  566. X    parinit = malloc((strlen(env) + 1) * sizeof (char));
  567. X    if (!parinit) {
  568. X      strcpy(errmsg,outofmem);
  569. X      goto parcleanup;
  570. X    }
  571. X    strcpy(parinit,env);
  572. X    arg = strtok(parinit,whitechars);
  573. X    while (arg) {
  574. X      parsearg(arg, &help, &version, bodychars, protectchars,
  575. X               quotechars, &hang, &prefix, &suffix, &width, &cap, &div,
  576. X               &fit, &guess, &just, &last, "e, &Report, &touch, errmsg);
  577. X      if (*errmsg || help || version) goto parcleanup;
  578. X      arg = strtok(NULL,whitechars);
  579. X    }
  580. X    free(parinit);
  581. X    parinit = NULL;
  582. X  }
  583. X
  584. X/* Process command line arguments: */
  585. X
  586. X  while (*++argv) {
  587. X    parsearg(*argv, &help, &version, bodychars, protectchars,
  588. X             quotechars, &hang, &prefix, &suffix, &width, &cap, &div,
  589. X             &fit, &guess, &just, &last, "e, &Report, &touch, errmsg);
  590. X    if (*errmsg || help || version) goto parcleanup;
  591. X  }
  592. X
  593. X  if (touch < 0) touch = fit || last;
  594. X  prefixbak = prefix;
  595. X  suffixbak = suffix;
  596. X
  597. X/* Main loop: */
  598. X
  599. X  for (;;) {
  600. X    for (;;) {
  601. X      c = getchar();
  602. X      if (csmember((char) c, protectchars))
  603. X        while (c != '\n' && c != EOF) {
  604. X          putchar(c);
  605. X          c = getchar();
  606. X        }
  607. X      if (c != '\n') break;
  608. X      putchar(c);
  609. X    }
  610. X    if (c == EOF) break;
  611. X    ungetc(c,stdin);
  612. X
  613. X    inlines = readlines(protectchars,quotechars,quote,errmsg);
  614. X    if (*errmsg) goto parcleanup;
  615. X
  616. X    for (endline = inlines;  *endline;  ++endline);
  617. X    if (endline == inlines) {
  618. X      free(inlines);
  619. X      inlines = NULL;
  620. X      continue;
  621. X    }
  622. X
  623. X    tags = malloc((endline - inlines) * sizeof(char));
  624. X    if (!tags) {
  625. X      strcpy(errmsg,outofmem);
  626. X      goto parcleanup;
  627. X    }
  628. X
  629. X    delimit((const char * const *) inlines,
  630. X            (const char * const *) endline, bodychars, div, 0, 0, tags);
  631. X
  632. X    firstline = inlines;
  633. X    firsttag = tags;
  634. X    do {
  635. X      if (*firsttag == 'v') {
  636. X        for (end = *firstline;  *end;  ++end);
  637. X        while (end > *firstline && end[-1] == ' ') --end;
  638. X        *end = '\0';
  639. X        puts(*firstline);
  640. X        ++firsttag;
  641. X        ++firstline;
  642. X        continue;
  643. X      }
  644. X
  645. X      for (nexttag = firsttag + 1, nextline = firstline + 1;
  646. X           nextline < endline && *nexttag == 'p';
  647. X           ++nexttag, ++nextline);
  648. X
  649. X      prefix = prefixbak;
  650. X      suffix = suffixbak;
  651. X      setaffixes((const char * const *) firstline,
  652. X                 (const char * const *) nextline,
  653. X                 bodychars, quotechars, hang, quote, &prefix, &suffix);
  654. X      if (width <= prefix + suffix) {
  655. X        sprintf(errmsg,
  656. X                "<width> (%d) <= <prefix> (%d) + <suffix> (%d)\n",
  657. X                width, prefix, suffix);
  658. X        goto parcleanup;
  659. X      }
  660. X
  661. X      outlines =
  662. X        reformat((const char * const *) firstline,
  663. X                 (const char * const *) nextline, hang, prefix, suffix,
  664. X                  width, cap, fit, guess, just, last, Report, touch, errmsg);
  665. X      if (*errmsg) goto parcleanup;
  666. X
  667. X      for (line = outlines;  *line;  ++line)
  668. X        puts(*line);
  669. X
  670. X      freelines(outlines);
  671. X      outlines = NULL;
  672. X
  673. X      firsttag = nexttag;
  674. X      firstline = nextline;
  675. X    } while (firstline < endline);
  676. X
  677. X    free(tags);
  678. X    tags = NULL;
  679. X
  680. X    freelines(inlines);
  681. X    inlines = NULL;
  682. X  }
  683. X
  684. Xparcleanup:
  685. X
  686. X  if (bodychars) freecharset(bodychars);
  687. X  if (protectchars) freecharset(protectchars);
  688. X  if (quotechars) freecharset(quotechars);
  689. X  if (parinit) free(parinit);
  690. X  if (inlines) freelines(inlines);
  691. X  if (tags) free(tags);
  692. X  if (outlines) freelines(outlines);
  693. X
  694. X  if (*errmsg) printf("par error:\n%.*s", errmsg_size, errmsg);
  695. X  if (version) puts("par 1.31");
  696. X  if (help)    fputs(usagemsg,stdout);
  697. X
  698. X  exit(*errmsg ? EXIT_FAILURE : EXIT_SUCCESS);
  699. X}
  700. END_OF_FILE
  701. if test 18832 -ne `wc -c <'Par131/par.c'`; then
  702.     echo shar: \"'Par131/par.c'\" unpacked with wrong size!
  703. fi
  704. # end of 'Par131/par.c'
  705. fi
  706. if test -f 'Par131/reformat.h' -a "${1}" != "-c" ; then 
  707.   echo shar: Will not clobber existing file \"'Par131/reformat.h'\"
  708. else
  709. echo shar: Extracting \"'Par131/reformat.h'\" \(1005 characters\)
  710. sed "s/^X//" >'Par131/reformat.h' <<'END_OF_FILE'
  711. X/*********************/
  712. X/* reformat.h        */
  713. X/* for Par 1.31      */
  714. X/* Copyright 1993 by */
  715. X/* Adam M. Costello  */
  716. X/*********************/
  717. X
  718. X/* This is ANSI C code. */
  719. X
  720. X
  721. X#include "errmsg.h"
  722. X
  723. X
  724. Xchar **reformat(
  725. X  const char * const *inlines, const char * const *endline,
  726. X  int hang, int prefix, int suffix, int width, int cap, int fit,
  727. X  int guess, int just, int last, int Report, int touch, errmsg_t errmsg
  728. X);
  729. X  /* inlines is an array of pointers to input lines, up to but not     */
  730. X  /* including endline.  The other parameters are the variables of the */
  731. X  /* same name as described in "par.doc". reformat(inlines, endline,   */
  732. X  /* hang, prefix, suffix, width, cap, fit, guess, just, last, Report, */
  733. X  /* touch, errmsg) returns a NULL-terminated array of pointers to     */
  734. X  /* output lines containing the reformatted paragraph, according to   */
  735. X  /* the specification in "par.doc".  None of the integer parameters   */
  736. X  /* may be negative. Returns NULL on failure.                         */
  737. END_OF_FILE
  738. if test 1005 -ne `wc -c <'Par131/reformat.h'`; then
  739.     echo shar: \"'Par131/reformat.h'\" unpacked with wrong size!
  740. fi
  741. # end of 'Par131/reformat.h'
  742. fi
  743. if test -f 'Par131/reformat.c' -a "${1}" != "-c" ; then 
  744.   echo shar: Will not clobber existing file \"'Par131/reformat.c'\"
  745. else
  746. echo shar: Extracting \"'Par131/reformat.c'\" \(14546 characters\)
  747. sed "s/^X//" >'Par131/reformat.c' <<'END_OF_FILE'
  748. X/*********************/
  749. X/* reformat.c        */
  750. X/* for Par 1.31      */
  751. X/* Copyright 1993 by */
  752. X/* Adam M. Costello  */
  753. X/*********************/
  754. X
  755. X/* This is ANSI C code. */
  756. X
  757. X
  758. X#include "reformat.h"  /* Makes sure we're consistent with the */
  759. X                       /* prototype. Also includes "errmsg.h". */
  760. X#include "buffer.h"    /* Also includes <stddef.h>.            */
  761. X
  762. X#include <stdio.h>
  763. X#include <stdlib.h>
  764. X#include <ctype.h>
  765. X#include <string.h>
  766. X
  767. X#undef NULL
  768. X#define NULL ((void *) 0)
  769. X
  770. X#ifdef DONTFREE
  771. X#define free(ptr)
  772. X#endif
  773. X
  774. X
  775. Xtypedef struct word {
  776. X  const char *chrs;       /* Pointer to the characters in the word */
  777. X                          /* (NOT terminated by '\0').             */
  778. X  struct word *prev,      /* Pointer to previous word.             */
  779. X              *next,      /* Pointer to next word.                 */
  780. X                          /* Supposing this word were the first... */
  781. X              *nextline;  /*   Pointer to first word in next line. */
  782. X  int score,              /*   Value of the objective function.    */
  783. X      length;             /* Length of this word.                  */
  784. X  short flags;            /* Notable properties of this word.      */
  785. X} word;
  786. X
  787. X/* The following may be bitwise-OR'd together */
  788. X/* to set the flags field of a word:          */
  789. X
  790. Xconst short W_SHIFTED = 1,  /* This word should have an extra space before */
  791. X                            /* it unless it's the first word in the line.  */
  792. X            W_CURIOUS = 2,  /* This is a curious word (see par.doc).       */
  793. X            W_CAPITAL = 4;  /* This is a capitalized word (see par.doc).   */
  794. X
  795. X#define isshifted(w) ((w)->flags & 1)
  796. X#define iscurious(w) (((w)->flags & 2) >> 1)
  797. X#define iscapital(w) (((w)->flags & 4) >> 2)
  798. X
  799. Xconst char * const impossibility =
  800. X  "Impossibility #%d has occurred. Please report it.\n";
  801. X
  802. X
  803. Xstatic int checkcapital(word *w)
  804. X/* Returns 1 if *w is capitalized according to the definition */
  805. X/* in par.doc (assuming <cap> is 0), or 0 if not.             */
  806. X{
  807. X  const char *p, *end;
  808. X
  809. X  for (p = w->chrs, end = p + w->length;  p < end && !isalnum(*p);  ++p);
  810. X  return p < end && !islower(*p);
  811. X}
  812. X
  813. X
  814. Xstatic int checkcurious(word *w)
  815. X/* Returns 1 if *w is curious according to */
  816. X/* the definition in par.doc, or 0 if not. */
  817. X{
  818. X  const char *start, *p;
  819. X  char ch;
  820. X
  821. X  for (start = w->chrs, p = start + w->length;  p > start;  --p) {
  822. X    ch = p[-1];
  823. X    if (isalnum(ch)) return 0;
  824. X    if (ch == '.' || ch == '?' || ch == '!' || ch == ':') break;
  825. X  }
  826. X
  827. X  if (p <= start + 1) return 0;
  828. X
  829. X  --p;
  830. X  do if (isalnum(*--p)) return 1;
  831. X  while (p > start);
  832. X
  833. X  return 0;
  834. X}
  835. X
  836. X
  837. Xstatic int simplebreaks(word *head, word *tail, int L, int last)
  838. X
  839. X/* Chooses line breaks in a list of words which maximize the length of the   */
  840. X/* shortest line.  L is the maximum line length.  The last line counts as a  */
  841. X/* line only if last is non-zero. _head must point to a dummy word, and tail */
  842. X/* must point to the last word, whose next field must be NULL.  Returns the  */
  843. X/* length of the shortest line on success, -1 if there is a word of length   */
  844. X/* greater than L, or L if there are no lines.                               */
  845. X{
  846. X  word *w1, *w2;
  847. X  int linelen, score;
  848. X
  849. X  if (!head->next) return L;
  850. X
  851. X  for (w1 = tail, linelen = w1->length;
  852. X       w1 != head && linelen <= L;
  853. X       linelen += isshifted(w1), w1 = w1->prev, linelen += 1 + w1->length) {
  854. X    w1->score = last ? linelen : L;
  855. X    w1->nextline = NULL;
  856. X  }
  857. X
  858. X  for ( ;  w1 != head;  w1 = w1->prev) {
  859. X    w1->score = -1;
  860. X    for (linelen = w1->length,  w2 = w1->next;
  861. X         linelen <= L;
  862. X         linelen += 1 + isshifted(w2) + w2->length,  w2 = w2->next) {
  863. X      score = w2->score;
  864. X      if (linelen < score) score = linelen;
  865. X      if (score >= w1->score) {
  866. X        w1->nextline = w2;
  867. X        w1->score = score;
  868. X      }
  869. X    }
  870. X  }
  871. X
  872. X  return head->next->score;
  873. X}
  874. X
  875. X
  876. Xstatic void normalbreaks(word *head, word *tail, int L,
  877. X                         int fit, int last, errmsg_t errmsg)
  878. X
  879. X/* Chooses line breaks in a list of words according to the policy   */
  880. X/* in "par.doc" for <just> = 0 (L is <L>, fit is <fit>, and last is */
  881. X/* <last>).  head must point to a dummy word, and tail must point   */
  882. X/* to the last word, whose next field must be NULL.                 */
  883. X{
  884. X  word *w1, *w2;
  885. X  int tryL, shortest, score, target, linelen, extra, minlen;
  886. X
  887. X  *errmsg = '\0';
  888. X  if (!head->next) return;
  889. X
  890. X  target = L;
  891. X
  892. X/* Determine minimum possible difference between  */
  893. X/* the lengths of the shortest and longest lines: */
  894. X
  895. X  if (fit) {
  896. X    score = L + 1;
  897. X    for (tryL = L;  ;  --tryL) {
  898. X      shortest = simplebreaks(head,tail,tryL,last);
  899. X      if (shortest < 0) break;
  900. X      if (tryL - shortest < score) {
  901. X        target = tryL;
  902. X        score = target - shortest;
  903. X      }
  904. X    }
  905. X  }
  906. X
  907. X/* Determine maximum possible length of the shortest line: */
  908. X
  909. X  shortest = simplebreaks(head,tail,target,last);
  910. X  if (shortest < 0) {
  911. X    sprintf(errmsg,impossibility,1);
  912. X    return;
  913. X  }
  914. X
  915. X/* Minimize the sum of the squares of the differences */
  916. X/* between target and the lengths of the lines:       */
  917. X
  918. X  w1 = tail;
  919. X  do {
  920. X    w1->score = -1;
  921. X    for (linelen = w1->length,  w2 = w1->next;
  922. X         linelen <= target;
  923. X         linelen += 1 + isshifted(w2) + w2->length,  w2 = w2->next) {
  924. X      extra = target - linelen;
  925. X      minlen = shortest;
  926. X      if (w2)
  927. X        score = w2->score;
  928. X      else {
  929. X        score = 0;
  930. X        if (!last) extra = minlen = 0;
  931. X      }
  932. X      if (linelen >= minlen  &&  score >= 0) {
  933. X        score += extra * extra;
  934. X        if (w1->score < 0  ||  score <= w1->score) {
  935. X          w1->nextline = w2;
  936. X          w1->score = score;
  937. X        }
  938. X      }
  939. X      if (!w2) break;
  940. X    }
  941. X    w1 = w1->prev;
  942. X  } while (w1 != head);
  943. X
  944. X  if (head->next->score < 0)
  945. X    sprintf(errmsg,impossibility,2);
  946. X}
  947. X
  948. X
  949. Xstatic void justbreaks(word *head, word *tail,
  950. X                       int L, int last, errmsg_t errmsg)
  951. X
  952. X/* Chooses line breaks in a list of words according to the  */
  953. X/* policy in "par.doc" for <just> = 1 (L is <L> and last is */
  954. X/* <last>).  head must point to a dummy word, and tail must */
  955. X/* point to the last word, whose next field must be NULL.   */
  956. X{
  957. X  word *w1, *w2;
  958. X  int numgaps, extra, score, gap, maxgap, numbiggaps;
  959. X
  960. X  *errmsg = '\0';
  961. X  if (!head->next) return;
  962. X
  963. X/* Determine the minimum possible largest inter-word gap: */
  964. X
  965. X  w1 = tail;
  966. X  do {
  967. X    w1->score = L;
  968. X    for (numgaps = 0, extra = L - w1->length, w2 = w1->next;
  969. X         extra >= 0;
  970. X         ++numgaps, extra -= 1 + isshifted(w2) + w2->length, w2 = w2->next) {
  971. X      gap = numgaps ? (extra + numgaps - 1) / numgaps : L;
  972. X      if (w2)
  973. X        score = w2->score;
  974. X      else {
  975. X        score = 0;
  976. X        if (!last) gap = 0;
  977. X      }
  978. X      if (gap > score) score = gap;
  979. X      if (score < w1->score) {
  980. X        w1->nextline = w2;
  981. X        w1->score = score;
  982. X      }
  983. X      if (!w2) break;
  984. X    }
  985. X    w1 = w1->prev;
  986. X  } while (w1 != head);
  987. X
  988. X  maxgap = head->next->score;
  989. X  if (maxgap >= L) {
  990. X    strcpy(errmsg, "Cannot justify.\n");
  991. X    return;
  992. X  }
  993. X
  994. X/* Minimize the sum of the squares of the numbers   */
  995. X/* of extra spaces required in each inter-word gap: */
  996. X
  997. X  w1 = tail;
  998. X  do {
  999. X    w1->score = -1;
  1000. X    for (numgaps = 0, extra = L - w1->length, w2 = w1->next;
  1001. X         extra >= 0;
  1002. X         ++numgaps, extra -= 1 + isshifted(w2) + w2->length, w2 = w2->next) {
  1003. X      gap = numgaps ? (extra + numgaps - 1) / numgaps : L;
  1004. X      if (w2)
  1005. X        score = w2->score;
  1006. X      else {
  1007. X        if (!last) {
  1008. X          w1->nextline = NULL;
  1009. X          w1->score = 0;
  1010. X          break;
  1011. X        }
  1012. X        score = 0;
  1013. X      }
  1014. X      if (gap <= maxgap && score >= 0) {
  1015. X        numbiggaps = extra % numgaps;
  1016. X        score += (extra / numgaps) * (extra + numbiggaps) + numbiggaps;
  1017. X        /* The above may not look like the sum of the squares of the numbers */
  1018. X        /* of extra spaces required in each inter-word gap, but trust me, it */
  1019. X        /* is.  It's easier to prove graphically than algebraicly.           */
  1020. X        if (w1->score < 0  ||  score <= w1->score) {
  1021. X          w1->nextline = w2;
  1022. X          w1->score = score;
  1023. X        }
  1024. X      }
  1025. X      if (!w2) break;
  1026. X    }
  1027. X    w1 = w1->prev;
  1028. X  } while (w1 != head);
  1029. X
  1030. X  if (head->next->score < 0)
  1031. X    sprintf(errmsg,impossibility,3);
  1032. X}
  1033. X
  1034. X
  1035. Xchar **reformat(
  1036. X  const char * const *inlines, const char * const *endline,
  1037. X  int hang, int prefix, int suffix, int width, int cap, int fit,
  1038. X  int guess, int just, int last, int Report, int touch, errmsg_t errmsg
  1039. X)
  1040. X{
  1041. X  int numin, affix, L, onfirstword = 1, linelen, numout, numgaps, extra, phase;
  1042. X  const char * const *line, **suffixes = NULL, **suf, *end, *p1, *p2;
  1043. X  char *q1, *q2, **outlines = NULL;
  1044. X  word dummy, *head, *tail, *w1, *w2;
  1045. X  buffer *pbuf = NULL;
  1046. X
  1047. X/* Initialization: */
  1048. X
  1049. X  *errmsg = '\0';
  1050. X  dummy.next = dummy.prev = NULL;
  1051. X  dummy.flags = 0;
  1052. X  head = tail = &dummy;
  1053. X  numin = endline - inlines;
  1054. X
  1055. X/* Allocate space for pointers to the suffixes: */
  1056. X
  1057. X  if (numin) {
  1058. X    suffixes = malloc(numin * sizeof (const char *));
  1059. X    if (!suffixes) {
  1060. X      strcpy(errmsg,outofmem);
  1061. X      goto rfcleanup;
  1062. X    }
  1063. X  }
  1064. X
  1065. X/* Set the pointers to the suffixes, and create the words: */
  1066. X
  1067. X  affix = prefix + suffix;
  1068. X  L = width - prefix - suffix;
  1069. X
  1070. X  for (line = inlines, suf = suffixes;  line < endline;  ++line, ++suf) {
  1071. X    for (end = *line;  *end;  ++end);
  1072. X    if (end - *line < affix) {
  1073. X      sprintf(errmsg,
  1074. X              "Line %d shorter than <prefix> + <suffix> = %d + %d = %d\n",
  1075. X              line - inlines + 1, prefix, suffix, affix);
  1076. X      goto rfcleanup;
  1077. X    }
  1078. X    end -= suffix;
  1079. X    *suf = end;
  1080. X    p1 = *line + prefix;
  1081. X    for (;;) {
  1082. X      while (p1 < end && *p1 == ' ') ++p1;
  1083. X      if (p1 == end) break;
  1084. X      p2 = p1;
  1085. X      if (onfirstword) {
  1086. X        p1 = *line + prefix;
  1087. X        onfirstword = 0;
  1088. X      }
  1089. X      while (p2 < end && *p2 != ' ') ++p2;
  1090. X      w1 = malloc(sizeof (word));
  1091. X      if (!w1) {
  1092. X        strcpy(errmsg,outofmem);
  1093. X        goto rfcleanup;
  1094. X      }
  1095. X      w1->next = NULL;
  1096. X      w1->prev = tail;
  1097. X      tail = tail->next = w1;
  1098. X      w1->chrs = p1;
  1099. X      w1->length = p2 - p1;
  1100. X      w1->flags = 0;
  1101. X      p1 = p2;
  1102. X    }
  1103. X  }
  1104. X
  1105. X/* If guess is 1, set flag values and merge words: */
  1106. X
  1107. X  if (guess) {
  1108. X    for (w1 = head, w2 = head->next;  w2;  w1 = w2, w2 = w2->next) {
  1109. X      if (checkcurious(w2)) w2->flags |= W_CURIOUS;
  1110. X      if (cap || checkcapital(w2)) {
  1111. X        w2->flags |= W_CAPITAL;
  1112. X        if (iscurious(w1))
  1113. X          if (w1->chrs[w1->length] && w1->chrs + w1->length + 1 == w2->chrs) {
  1114. X            w2->length += w1->length + 1;
  1115. X            w2->chrs = w1->chrs;
  1116. X            w2->prev = w1->prev;
  1117. X            w2->prev->next = w2;
  1118. X            if (iscapital(w1)) w2->flags |= W_CAPITAL;
  1119. X            else w2->flags &= ~W_CAPITAL;
  1120. X            if (isshifted(w1)) w2->flags |= W_SHIFTED;
  1121. X            else w2->flags &= ~W_SHIFTED;
  1122. X            free(w1);
  1123. X          }
  1124. X          else
  1125. X            w2->flags |= W_SHIFTED;
  1126. X      }
  1127. X    }
  1128. X    tail = w1;
  1129. X  }
  1130. X
  1131. X/* Check for too-long words: */
  1132. X
  1133. X  if (Report)
  1134. X    for (w2 = head->next;  w2;  w2 = w2->next) {
  1135. X      if (w2->length > L) {
  1136. X        linelen = w2->length;
  1137. X        if (linelen > errmsg_size - 17)
  1138. X          linelen = errmsg_size - 17;
  1139. X        sprintf(errmsg, "Word too long: %.*s\n", linelen, w2->chrs);
  1140. X        goto rfcleanup;
  1141. X      }
  1142. X    }
  1143. X  else
  1144. X    for (w2 = head->next;  w2;  w2 = w2->next)
  1145. X      while (w2->length > L) {
  1146. X        w1 = malloc(sizeof (word));
  1147. X        if (!w1) {
  1148. X          strcpy(errmsg,outofmem);
  1149. X          goto rfcleanup;
  1150. X        }
  1151. X        w1->next = w2;
  1152. X        w1->prev = w2->prev;
  1153. X        w1->prev->next = w1;
  1154. X        w2->prev = w1;
  1155. X        w1->chrs = w2->chrs;
  1156. X        w2->chrs += L;
  1157. X        w1->length = L;
  1158. X        w2->length -= L;
  1159. X        w1->flags = 0;
  1160. X        if (iscapital(w2)) {
  1161. X          w1->flags |= W_CAPITAL;
  1162. X          w2->flags &= ~W_CAPITAL;
  1163. X        }
  1164. X        if (isshifted(w2)) {
  1165. X          w1->flags |= W_SHIFTED;
  1166. X          w2->flags &= ~W_SHIFTED;
  1167. X        }
  1168. X      }
  1169. X
  1170. X/* Choose line breaks according to policy in "par.doc": */
  1171. X
  1172. X  if (just) justbreaks(head,tail,L,last,errmsg);
  1173. X  else normalbreaks(head,tail,L,fit,last,errmsg);
  1174. X  if (*errmsg) goto rfcleanup;
  1175. X
  1176. X/* Change L to the length of the longest line if required: */
  1177. X
  1178. X  if (!just && touch) {
  1179. X    L = 0;
  1180. X    w1 = head->next;
  1181. X    while (w1) {
  1182. X      for (linelen = w1->length, w2 = w1->next;
  1183. X           w2 != w1->nextline;
  1184. X           linelen += 1 + isshifted(w2) + w2->length, w2 = w2->next);
  1185. X      if (linelen > L) L = linelen;
  1186. X      w1 = w2;
  1187. X    }
  1188. X  }
  1189. X
  1190. X/* Construct the lines: */
  1191. X
  1192. X  pbuf = newbuffer(sizeof (char *), errmsg);
  1193. X  if (*errmsg) goto rfcleanup;
  1194. X
  1195. X  numout = 0;
  1196. X  w1 = head->next;
  1197. X  while (numout < hang || w1) {
  1198. X    if (w1)
  1199. X      for (w2 = w1->next, numgaps = 0, extra = L - w1->length;
  1200. X           w2 != w1->nextline;
  1201. X           ++numgaps, extra -= 1 + isshifted(w2) + w2->length, w2 = w2->next);
  1202. X    linelen = suffix  ||  just && (w2 || last) ?
  1203. X                L + affix :
  1204. X                w1 ? prefix + L - extra : prefix;
  1205. X    q1 = malloc((linelen + 1) * sizeof (char));
  1206. X    if (!q1) {
  1207. X      strcpy(errmsg,outofmem);
  1208. X      goto rfcleanup;
  1209. X    }
  1210. X    additem(pbuf, &q1, errmsg);
  1211. X    if (*errmsg) goto rfcleanup;
  1212. X    ++numout;
  1213. X    q2 = q1 + prefix;
  1214. X    if      (numout <= numin) memcpy(q1, inlines[numout - 1], prefix);
  1215. X    else if (numin > hang)    memcpy(q1, inlines[numin - 1], prefix);
  1216. X    else                      while (q1 < q2) *q1++ = ' ';
  1217. X    q1 = q2;
  1218. X    if (w1) {
  1219. X      phase = numgaps / 2;
  1220. X      for (w2 = w1;  ;  ) {
  1221. X        memcpy(q1, w2->chrs, w2->length);
  1222. X        q1 += w2->length;
  1223. X        w2 = w2->next;
  1224. X        if (w2 == w1->nextline) break;
  1225. X        *q1++ = ' ';
  1226. X        if (just && (w1->nextline || last)) {
  1227. X          phase += extra;
  1228. X          while (phase >= numgaps) {
  1229. X            *q1++ = ' ';
  1230. X            phase -= numgaps;
  1231. X          }
  1232. X        }
  1233. X        if (isshifted(w2)) *q1++ = ' ';
  1234. X      }
  1235. X    }
  1236. X    q2 += linelen - affix;
  1237. X    while (q1 < q2) *q1++ = ' ';
  1238. X    q2 = q1 + suffix;
  1239. X    if      (numout <= numin) memcpy(q1, suffixes[numout - 1], suffix);
  1240. X    else if (numin)           memcpy(q1, suffixes[numin - 1], suffix);
  1241. X    else                      while(q1 < q2) *q1++ = ' ';
  1242. X    *q2 = '\0';
  1243. X    if (w1) w1 = w1->nextline;
  1244. X  }
  1245. X
  1246. X  q1 = NULL;
  1247. X  additem(pbuf, &q1, errmsg);
  1248. X  if (*errmsg) goto rfcleanup;
  1249. X
  1250. X  outlines = copyitems(pbuf,errmsg);
  1251. X
  1252. Xrfcleanup:
  1253. X
  1254. X  if (suffixes) free(suffixes);
  1255. X
  1256. X  while (tail != head) {
  1257. X    tail = tail->prev;
  1258. X    free(tail->next);
  1259. X  }
  1260. X
  1261. X  if (pbuf) {
  1262. X    if (!outlines)
  1263. X      for (;;) {
  1264. X        outlines = nextitem(pbuf);
  1265. X        if (!outlines) break;
  1266. X        free(*outlines);
  1267. X      }
  1268. X    freebuffer(pbuf);
  1269. X  }
  1270. X
  1271. X  return outlines;
  1272. X}
  1273. END_OF_FILE
  1274. if test 14546 -ne `wc -c <'Par131/reformat.c'`; then
  1275.     echo shar: \"'Par131/reformat.c'\" unpacked with wrong size!
  1276. fi
  1277. # end of 'Par131/reformat.c'
  1278. fi
  1279. if test -f 'Par131/buffer.h' -a "${1}" != "-c" ; then 
  1280.   echo shar: Will not clobber existing file \"'Par131/buffer.h'\"
  1281. else
  1282. echo shar: Extracting \"'Par131/buffer.h'\" \(2311 characters\)
  1283. sed "s/^X//" >'Par131/buffer.h' <<'END_OF_FILE'
  1284. X/*********************/
  1285. X/* buffer.h          */
  1286. X/* for Par 1.31      */
  1287. X/* Copyright 1993 by */
  1288. X/* Adam M. Costello  */
  1289. X/*********************/
  1290. X
  1291. X/* This is ANSI C code. */
  1292. X
  1293. X
  1294. X/* Note: Those functions declared here which do not use errmsg    */
  1295. X/* always succeed, provided that they are passed valid arguments. */
  1296. X
  1297. X
  1298. X#include "errmsg.h"
  1299. X
  1300. X#include <stddef.h>
  1301. X
  1302. X
  1303. Xtypedef struct buffer buffer;
  1304. X
  1305. X
  1306. Xbuffer *newbuffer(size_t itemsize, errmsg_t errmsg);
  1307. X
  1308. X  /* newbuffer(itemsize,errmsg) returns a pointer to a    */
  1309. X  /* new empty buffer which holds items of size itemsize. */
  1310. X  /* itemsize must not be 0.  Returns NULL on failure.    */
  1311. X
  1312. X
  1313. Xvoid freebuffer(buffer *buf);
  1314. X
  1315. X  /* freebuffer(buf) frees the memory associated with */
  1316. X  /* *buf.  buf may not be used after this call.      */
  1317. X
  1318. X
  1319. Xvoid clearbuffer(buffer *buf);
  1320. X
  1321. X  /* clearbuffer(buf) removes  */
  1322. X  /* all items from *buf, but  */
  1323. X  /* does not free any memory. */
  1324. X
  1325. X
  1326. Xvoid additem(buffer *buf, const void *item, errmsg_t errmsg);
  1327. X
  1328. X  /* additem(buf,item,errmsg) copies *item to the end of     */
  1329. X  /* *buf.  item must point to an object of the proper size  */
  1330. X  /* for *buf.  If additem() fails, *buf will be unaffected. */
  1331. X
  1332. X
  1333. Xint numitems(buffer *buf);
  1334. X
  1335. X  /* numitems(buf) returns the number of items in *buf. */
  1336. X
  1337. X
  1338. Xvoid *copyitems(buffer *buf, errmsg_t errmsg);
  1339. X
  1340. X  /* copyitems(buf,errmsg) returns an array of objects of the proper size */
  1341. X  /* for *buf, one for each item in *buf, or (void *) 0 if there are no   */
  1342. X  /* items in buf.  The elements of the array are copied from the items   */
  1343. X  /* in *buf, in order.  The array is allocated with malloc(), so it may  */
  1344. X  /* be freed with free().  Returns NULL on failure.                      */
  1345. X
  1346. X
  1347. Xvoid *nextitem(buffer *buf);
  1348. X
  1349. X  /* When buf was created by newbuffer, a pointer associated with buf  */
  1350. X  /* was initialized to point at the first slot in *buf.  If there is  */
  1351. X  /* an item in the slot currently pointed at, nextitem(buf) advances  */
  1352. X  /* the pointer to the next slot and returns the old value.  If there */
  1353. X  /* is no item in the slot, nextitem(buf) leaves the pointer where it */
  1354. X  /* is and returns NULL.                                              */
  1355. X
  1356. X
  1357. Xvoid rewindbuffer(buffer *buf);
  1358. X
  1359. X  /* rewindbuffer(buf) resets the pointer used by   */
  1360. X  /* nextitem() to point at the first slot in *buf. */
  1361. END_OF_FILE
  1362. if test 2311 -ne `wc -c <'Par131/buffer.h'`; then
  1363.     echo shar: \"'Par131/buffer.h'\" unpacked with wrong size!
  1364. fi
  1365. # end of 'Par131/buffer.h'
  1366. fi
  1367. if test -f 'Par131/buffer.c' -a "${1}" != "-c" ; then 
  1368.   echo shar: Will not clobber existing file \"'Par131/buffer.c'\"
  1369. else
  1370. echo shar: Extracting \"'Par131/buffer.c'\" \(4554 characters\)
  1371. sed "s/^X//" >'Par131/buffer.c' <<'END_OF_FILE'
  1372. X/*********************/
  1373. X/* buffer.c          */
  1374. X/* for Par 1.31      */
  1375. X/* Copyright 1993 by */
  1376. X/* Adam M. Costello  */
  1377. X/*********************/
  1378. X
  1379. X/* This is ANSI C code. */
  1380. X
  1381. X
  1382. X/* additem(), copyitems(), and nextitem() rely on the fact that */
  1383. X/* sizeof (char) is 1.  See section A7.4.8 of The C Programming */
  1384. X/* Language, Second Edition, by Kerninghan and Ritchie.         */
  1385. X
  1386. X
  1387. X#include "buffer.h"  /* Makes sure we're consistent with the prototypes. */
  1388. X                     /* Also includes <stddef.h> and "errmsg.h".         */
  1389. X
  1390. X#include <stdlib.h>
  1391. X#include <string.h>
  1392. X
  1393. X#undef NULL
  1394. X#define NULL ((void *) 0)
  1395. X
  1396. X#ifdef DONTFREE
  1397. X#define free(ptr)
  1398. X#endif
  1399. X
  1400. X
  1401. Xstruct buffer {
  1402. X  struct block *firstblk, /* The first block.                    */
  1403. X               *current,  /* The last non-empty block, or        */
  1404. X                          /* firstblk if all are empty.          */
  1405. X               *nextblk;  /* The block containing the item to be */
  1406. X                          /* returned by nextitem(), or NULL.    */
  1407. X  int nextindex;          /* Index of item in nextblock->items.  */
  1408. X  size_t itemsize;        /* The size of an item.                */
  1409. X};
  1410. X
  1411. Xtypedef struct block {
  1412. X  struct block *next;  /* The next block, or NULL if none.              */
  1413. X  void *items;         /* Storage for the items in this block.          */
  1414. X  int maxhere,         /* Number of items that fit in *items.           */
  1415. X      numprevious,     /* Total of numhere for all previous blocks.     */
  1416. X      numhere;         /* The first numhere slots in *items are filled. */
  1417. X} block;
  1418. X
  1419. X
  1420. Xbuffer *newbuffer(size_t itemsize, errmsg_t errmsg)
  1421. X{
  1422. X  buffer *buf;
  1423. X  block *blk;
  1424. X  void *items;
  1425. X  int maxhere;
  1426. X
  1427. X  maxhere = 124 / itemsize;
  1428. X  if (maxhere < 4) maxhere = 4;
  1429. X
  1430. X  buf = (buffer *) malloc(sizeof (buffer));
  1431. X  blk = (block *) malloc(sizeof (block));
  1432. X  items = malloc(maxhere * itemsize);
  1433. X  if (!buf || !blk || !items) {
  1434. X    strcpy(errmsg,outofmem);
  1435. X    goto nberror;
  1436. X  }
  1437. X
  1438. X  buf->itemsize = itemsize;
  1439. X  buf->firstblk = buf->current = buf->nextblk = blk;
  1440. X  buf->nextindex = 0;
  1441. X  blk->next = NULL;
  1442. X  blk->numprevious = blk->numhere = 0;
  1443. X  blk->maxhere = maxhere;
  1444. X  blk->items = items;
  1445. X
  1446. X  *errmsg = '\0';
  1447. X  return buf;
  1448. X
  1449. Xnberror:
  1450. X
  1451. X  if (buf) free(buf);
  1452. X  if (blk) free(blk);
  1453. X  if (items) free(items);
  1454. X  return NULL;
  1455. X}
  1456. X
  1457. X
  1458. Xvoid freebuffer(buffer *buf)
  1459. X{
  1460. X  block *blk, *tmp;
  1461. X
  1462. X  blk = buf->firstblk;
  1463. X  while (blk) {
  1464. X    tmp = blk;
  1465. X    blk = blk->next;
  1466. X    if (tmp->items) free(tmp->items);
  1467. X    free(tmp);
  1468. X  }
  1469. X
  1470. X  free(buf);
  1471. X}
  1472. X
  1473. X
  1474. Xvoid clearbuffer(buffer *buf)
  1475. X{
  1476. X  block *blk;
  1477. X
  1478. X  for (blk = buf->firstblk;  blk;  blk = blk->next)
  1479. X    blk->numhere = 0;
  1480. X
  1481. X  buf->current = buf->firstblk;
  1482. X}
  1483. X
  1484. X
  1485. Xvoid additem(buffer *buf, const void *item, errmsg_t errmsg)
  1486. X{
  1487. X  block *blk, *new;
  1488. X  void *items;
  1489. X  int maxhere;
  1490. X  size_t itemsize = buf->itemsize;
  1491. X
  1492. X  blk = buf->current;
  1493. X
  1494. X  if (blk->numhere == blk->maxhere) {
  1495. X    new = blk->next;
  1496. X    if (!new) {
  1497. X      maxhere = 2 * blk->maxhere;
  1498. X      new = (block * ) malloc(sizeof (block));
  1499. X      items = malloc(maxhere * itemsize);
  1500. X      if (!new || !items) {
  1501. X        strcpy(errmsg,outofmem);
  1502. X        goto aierror;
  1503. X      }
  1504. X      blk->next = new;
  1505. X      new->next = NULL;
  1506. X      new->maxhere = maxhere;
  1507. X      new->numprevious = blk->numprevious + blk->numhere;
  1508. X      new->numhere = 0;
  1509. X      new->items = items;
  1510. X    }
  1511. X    blk = buf->current = new;
  1512. X  }
  1513. X
  1514. X  memcpy( ((char *) blk->items) + (blk->numhere * itemsize), item, itemsize );
  1515. X
  1516. X  ++blk->numhere;
  1517. X
  1518. X  *errmsg = '\0';
  1519. X  return;
  1520. X
  1521. Xaierror:
  1522. X
  1523. X  if (new) free(new);
  1524. X  if (items) free(items);
  1525. X}
  1526. X
  1527. X
  1528. Xint numitems(buffer *buf)
  1529. X{
  1530. X  block *blk = buf->current;
  1531. X  return blk->numprevious + blk->numhere;
  1532. X}
  1533. X
  1534. X
  1535. Xvoid *copyitems(buffer *buf, errmsg_t errmsg)
  1536. X{
  1537. X  int n;
  1538. X  void *r;
  1539. X  block *blk, *b;
  1540. X  size_t itemsize = buf->itemsize;
  1541. X
  1542. X  b = buf->current;
  1543. X  n = b->numprevious + b->numhere;
  1544. X  if (!n) return NULL;
  1545. X
  1546. X  r = malloc(n * itemsize);
  1547. X  if (!r) {
  1548. X    strcpy(errmsg,outofmem);
  1549. X    return NULL;
  1550. X  }
  1551. X
  1552. X  b = b->next;
  1553. X
  1554. X  for (blk = buf->firstblk;  blk != b;  blk = blk->next)
  1555. X    memcpy( ((char *) r) + (blk->numprevious * itemsize),
  1556. X            blk->items, blk->numhere * itemsize);
  1557. X
  1558. X  *errmsg = '\0';
  1559. X  return r;
  1560. X}
  1561. X
  1562. X
  1563. Xvoid rewindbuffer(buffer *buf)
  1564. X{
  1565. X  buf->nextblk = buf->firstblk;
  1566. X  buf->nextindex = 0;
  1567. X}
  1568. X
  1569. X
  1570. Xvoid *nextitem(buffer *buf)
  1571. X{
  1572. X  void *r;
  1573. X
  1574. X  if (!buf->nextblk || buf->nextindex >= buf->nextblk->numhere)
  1575. X    return NULL;
  1576. X
  1577. X  r = ((char *) buf->nextblk->items) + (buf->nextindex * buf->itemsize);
  1578. X
  1579. X  if (++buf->nextindex >= buf->nextblk->maxhere) {
  1580. X    buf->nextblk = buf->nextblk->next;
  1581. X    buf->nextindex = 0;
  1582. X  }
  1583. X
  1584. X  return r;
  1585. X}
  1586. END_OF_FILE
  1587. if test 4554 -ne `wc -c <'Par131/buffer.c'`; then
  1588.     echo shar: \"'Par131/buffer.c'\" unpacked with wrong size!
  1589. fi
  1590. # end of 'Par131/buffer.c'
  1591. fi
  1592. if test -f 'Par131/errmsg.h' -a "${1}" != "-c" ; then 
  1593.   echo shar: Will not clobber existing file \"'Par131/errmsg.h'\"
  1594. else
  1595. echo shar: Extracting \"'Par131/errmsg.h'\" \(887 characters\)
  1596. sed "s/^X//" >'Par131/errmsg.h' <<'END_OF_FILE'
  1597. X/*********************/
  1598. X/* errmsg.h          */
  1599. X/* for Par 1.31      */
  1600. X/* Copyright 1993 by */
  1601. X/* Adam M. Costello  */
  1602. X/*********************/
  1603. X
  1604. X/* This is ANSI C code. */
  1605. X
  1606. X
  1607. X#ifndef ERRMSG_H
  1608. X#define ERRMSG_H
  1609. X
  1610. X
  1611. X#define errmsg_size 163
  1612. X
  1613. X/* This is the maximum number of characters that will fit  */
  1614. X/* in an errmsg_t, including the terminating '\0'. It will */
  1615. X/* never decrease, but may increase in future versions of  */
  1616. X/* this header file.                                       */
  1617. X
  1618. X
  1619. Xtypedef char errmsg_t[errmsg_size];
  1620. X
  1621. X/* Any function which takes the argument errmsg_t errmsg must, before */
  1622. X/* returning, either set errmsg[0] to '\0' (indicating success), or   */
  1623. X/* write an error message string into errmsg, (indicating failure),   */
  1624. X/* being careful not to overrun the space.                            */
  1625. X
  1626. X
  1627. Xextern const char * const outofmem;  /* "Out of memory.\n" */
  1628. X
  1629. X
  1630. X#endif
  1631. END_OF_FILE
  1632. if test 887 -ne `wc -c <'Par131/errmsg.h'`; then
  1633.     echo shar: \"'Par131/errmsg.h'\" unpacked with wrong size!
  1634. fi
  1635. # end of 'Par131/errmsg.h'
  1636. fi
  1637. if test -f 'Par131/errmsg.c' -a "${1}" != "-c" ; then 
  1638.   echo shar: Will not clobber existing file \"'Par131/errmsg.c'\"
  1639. else
  1640. echo shar: Extracting \"'Par131/errmsg.c'\" \(303 characters\)
  1641. sed "s/^X//" >'Par131/errmsg.c' <<'END_OF_FILE'
  1642. X/*********************/
  1643. X/* errmsg.c          */
  1644. X/* for Par 1.31      */
  1645. X/* Copyright 1993 by */
  1646. X/* Adam M. Costello  */
  1647. X/*********************/
  1648. X
  1649. X/* This is ANSI C code. */
  1650. X
  1651. X
  1652. X#include "errmsg.h"  /* Makes sure we're consistent with the declaration. */
  1653. X
  1654. X
  1655. Xconst char * const outofmem = "Out of memory.\n";
  1656. END_OF_FILE
  1657. if test 303 -ne `wc -c <'Par131/errmsg.c'`; then
  1658.     echo shar: \"'Par131/errmsg.c'\" unpacked with wrong size!
  1659. fi
  1660. # end of 'Par131/errmsg.c'
  1661. fi
  1662. echo shar: End of shell archive.
  1663. exit 0
  1664.  
  1665. exit 0 # Just in case...
  1666.