home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume29 / nruff / part01 < prev    next >
Encoding:
Text File  |  1992-05-18  |  46.2 KB  |  2,067 lines

  1. Newsgroups: comp.sources.misc
  2. From: pgf@Cayman.COM (Paul Fox)
  3. Subject:  v29i126:  nruff - text formatter for KXP-1124, Part01/01
  4. Message-ID: <1992May17.185427.1177@sparky.imd.sterling.com>
  5. X-Md4-Signature: bf20db3759941b0887056b8d146ea759
  6. Date: Sun, 17 May 1992 18:54:27 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: pgf@Cayman.COM (Paul Fox)
  10. Posting-number: Volume 29, Issue 126
  11. Archive-name: nruff/part01
  12. Environment: Panasonic KXP-1124, SYSV386, UNIX-PC
  13.  
  14. #!/bin/sh
  15. # This is nruff, a shell archive (shar 3.47)
  16. # made 04/28/1992 15:20 UTC by pgf@cayman.com
  17. # Source directory /tmp_mnt/home/cuba/pgf/nruff
  18. #
  19. # existing files WILL be overwritten
  20. #
  21. # This shar contains:
  22. # length  mode       name
  23. # ------ ---------- ------------------------------------------
  24. #  39419 -r--r--r-- nruff.c
  25. #   4488 -rw-rw-r-- nruff.doc
  26. #    114 -rw-rw-r-- Makefile
  27. #
  28. # ============= nruff.c ==============
  29. echo 'x - extracting nruff.c (Text)'
  30. sed 's/^X//' << 'SHAR_EOF' > 'nruff.c' &&
  31. /*
  32. X *    This is nruff, a simple text formatter, which I wrote a couple of
  33. X *    years ago to kill time while looking for a job.  I needed to write
  34. X *    and print a resume, and had no word processor or formatter to drive
  35. X *    my printer.
  36. X * 
  37. X *    It drives the Panasonic KXP-1124, in its Epson (750?  850?)
  38. X *    emulation mode.  It's pretty printer specific, but it runs that
  39. X *    printer quite well, should be portable to other hosts, since it's
  40. X *    fairly straightforward code.  (I've run it on the UNIX PC and AT&T
  41. X *    386 UNIX.)  I'm posting it in the hopes that someone finds it useful,
  42. X *    before the 1124 is totally obsolete.  (Does anyone have a PostScript
  43. X *    driver for...  :-)
  44. X *
  45. X *    It supports all the built in fonts, including the proportionally
  46. X *    spaced versions.  It supports super- and sub-script modes.  You can
  47. X *    do page headers and footers, and marked and indexed lists.  Left,
  48. X *    right, top, and bottom margins are all specifyable in inches.
  49. X *
  50. X *    Documentation consists of a single crib sheet, called nruff.doc,
  51. X *    which you should have found with this file.
  52. X *
  53. X *    Paul Fox, pgf@cayman.com,  April 28, 1992
  54. X *
  55. X *    (I started adding multi-column support, but never finished...)
  56. X */
  57. X
  58. #include "stdio.h"
  59. #include "ctype.h"
  60. X
  61. /* initial defaults, for some things that are user settable */
  62. /*   some other defaults, like margins, are based on these */
  63. X
  64. #define DEF_FWID 85    /* physical page width, tenths of inches */
  65. #define DEF_FLEN 110    /* physical page length, tenths of inches */
  66. X
  67. /* these are sent to the printer on startup */
  68. #define DEFLPI 6    /* line pitch, in lpi */
  69. #define DEFPITCH 10    /* character pitch, in cpi */
  70. #define DEFFONT "draft"
  71. X
  72. /* miscellaneous junk */
  73. #define BAD 0
  74. #define GOOD 1
  75. #define FALSE 0
  76. #define TRUE 1
  77. #define eq(s1,s2) (!strcmp(s1,s2))
  78. #define eqn(s1,s2,n) (!strncmp(s1,s2,n))
  79. X
  80. /* some ascii characters */
  81. #define ESC 0x1b
  82. #define DC2 0x12
  83. #define SI  0x0f
  84. X
  85. /* font types */
  86. /* these values (except draft) match printer manual, p.6-6 */
  87. #define SA 1        /* sans serif */
  88. #define CO 2        /* courier */
  89. #define PR 3        /* prestige */
  90. #define SC 4        /* script */
  91. #define BO 6        /* bold PS */
  92. #define DR 7        /* draft */
  93. /* none */
  94. #define NO 0        /* none -- not selectable, just the initial default */
  95. X
  96. int font;  /* keeps track of current font setting */
  97. X
  98. /* text enhancements */
  99. #define NONE    0
  100. X
  101. #define BASIC 0xff /* mask for the basic enhancements */
  102. #define BOLD    'B'
  103. #define ITALIC    'I'
  104. #define UNDER    'U'
  105. #define LARGE    'L'
  106. #define GRAPHIC1 'G'
  107. #define GRAPHIC2 'g'
  108. /* sub and super are independent of the others */
  109. #define EXTRA 0xff00 /* mask for the extra enhancements */
  110. #define SUPER    ('S'<<8)
  111. #define SUB    ('s'<<8)
  112. X
  113. /* All widths are kept internally as 180'ths of an inch */
  114. #define H_INCH 180
  115. /* the user, sees 10'ths of an inch, i.e. pica character widths, or inches */
  116. X
  117. /* page lengths are kept internally in 360'ths of an inch */
  118. #define V_INCH 360
  119. /* externally, it is in 10'ths of an inch, or inches */
  120. X
  121. /* we can only get within a quarter inch of the left edge of the page */
  122. #define MINLW H_INCH/4
  123. /* we seem to lose about half an inch at the top of each sheet */
  124. #define MINPL V_INCH/2
  125. X
  126. X
  127. /* character pitch can be 10, 12, 15, 17, 20, or proportional (-1) */
  128. int pitch = DEFPITCH;
  129. X
  130. char *Prog;  /* saves argv[0] */
  131. X
  132. /* the current word of text, and one word of history */
  133. char word1[100] = "";
  134. char word2[100] = "";
  135. char *lastword = word1;
  136. char *thisword = word2;
  137. X
  138. /* commands with text arguments poke the rest of their line
  139. X   in here, where it is then doled out one word at a time */
  140. char *pokestuff = NULL;
  141. X
  142. /* if we want a line break when those arguments are used up (like after 
  143. X    centering, as opposed to makeing bold), this tells us so */
  144. int breakafterpoke = FALSE;
  145. X
  146. /* if we want a different enhancement after the poked text, put it here */
  147. int enhanceafterpoke = FALSE;
  148. X
  149. /*  done_enhance keeps track of what we've _really_ done, want_enhace
  150. X    keeps track of what we want for the next word of output.
  151. X   we suppress enhancements across linefeeds, because the 
  152. X   printer will underline the left margin, and it makes calculating 
  153. X   indents work correctly in large mode.
  154. */
  155. int want_enhance = NONE;
  156. int done_enhance = NONE;
  157. int enhoffatendofline = 0; /* if an enhance command is alone on a line, it */
  158. X             /*    is "permanent" 'til the next enhancement */
  159. X
  160. /* space between pair of words or at the start of the line is figured out 
  161. X    just before the next word is printed */
  162. char *space;
  163. X
  164. /* always printed a fixed distance above and below the top and bottom
  165. X    margins, unless too close to the edge of the paper -- then they
  166. X    go at the top or bottom line of the page (unless that's the top
  167. X    (or bottom) margin, then the headers/footers are dropped */
  168. char pageheader[100];
  169. char pagefooter[100];
  170. /* footer depth and header height -- distance below or above margin */
  171. int ftdepth = V_INCH/2;
  172. int hdheight = V_INCH/2;
  173. int allheaders;  /* should header go at top of first page?*/
  174. int allfooters;  /* should footer go at bottom of last page?*/
  175. X
  176. /* a few flags to tell us where we are in both input and output streams */
  177. int inpendofline = TRUE;
  178. int inpstartofline = TRUE;
  179. int outpstartofline = TRUE;
  180. X
  181. /* do we want a newline because of this command? */
  182. int donewline = FALSE;
  183. X
  184. /* how many blank lines have been requested? */
  185. int leaveblanklines = 0;
  186. X
  187. /* line fill mode */
  188. int filling = TRUE;
  189. X
  190. int indent = 0;
  191. int rightjustcol = 0;
  192. X
  193. int tmpindent = 0;
  194. int paraindent = 0;
  195. int usetmpind = FALSE;    /* flag -- is tmpindent valid? */
  196. X
  197. /* these hold the size of the form we're dealing with */
  198. int formwidth = DEF_FWID * H_INCH/10;
  199. int formlength = DEF_FLEN * V_INCH/10;
  200. X
  201. /* these two keep track of where we are on the page */
  202. /*  they keep track of the _lower_left_ corner of the _next_ character */
  203. int curlinewidth;
  204. int curpagelen;
  205. X
  206. /* current line and page, numbered starting with 0 */
  207. int linenumber;
  208. int pagenumber;
  209. X
  210. /* the inital left and top margins are one inch each */
  211. int leftmargin = H_INCH;
  212. int topmargin = V_INCH;
  213. X
  214. /* the inital right and bottom margins are set to make the margins symmetric */
  215. int rightmargin = DEF_FWID*H_INCH/10 - H_INCH;
  216. int bottommargin = DEF_FLEN*V_INCH/10 - V_INCH;
  217. X
  218. /* how many columns, how wide are they, and how wide is the gutter */
  219. int columns;  /* usually 0 */
  220. int colwidth;
  221. int gutwidth;
  222. X
  223. int unitsperline = V_INCH/DEFLPI;
  224. X
  225. /* for the ".seq" command, which allows numbered or lettered lists */
  226. /* if not explicitly started, do a numeric list */
  227. int sequencer = 1;
  228. int numericseq = TRUE;
  229. char seqbuff[54];
  230. char seqsep[50];
  231. X
  232. /* forward declarations */
  233. char *calcspaces();
  234. char *calcleftwhite();
  235. char *restofline();
  236. char *getstrarg();
  237. char *getpoked();
  238. X
  239. FILE *Ifile;
  240. FILE *Ofile;
  241. X
  242. /* for getopt() */
  243. extern char *optarg;
  244. extern int optind;
  245. X
  246. /* debugging:  print item V in format F (i.e. printf format) */
  247. #define DEBUGVAL(V,F) { if (debug) errr("debug: V is F\n",V); }
  248. X
  249. int debug = FALSE;
  250. int draftonly = FALSE;
  251. int rflag = FALSE;
  252. X
  253. int inches = TRUE;
  254. X
  255. prusage()
  256. {
  257. X    fprintf(stderr,"usage: %s [-dr] [files...]\n",Prog);
  258. X    fprintf(stderr,"    -d forces draft mode\n");
  259. X    fprintf(stderr,"    -r forces carriage returns in output\n");
  260. X    fprintf(stderr,"    files are used in place of stdin.\n");
  261. X    fprintf(stderr,"    output always goes to stdout.\n");
  262. X    fprintf(stderr,"        This is nruff version 1.0\n");
  263. }
  264. X
  265. main(argc,argv)
  266. char *argv[];
  267. {
  268. X    int optc;
  269. X    FILE *f = NULL;
  270. X
  271. X    Prog = argv[0];
  272. X
  273. X    /* input and output may be changed by arguments, below */
  274. X    Ofile = stdout;
  275. X
  276. X    /* command line options */
  277. X    while ((optc = getopt(argc,argv,"Ddr")) != EOF) {
  278. X        switch(optc) {
  279. X        case 'D':
  280. X            debug = TRUE;
  281. X            break;
  282. X        case 'd':
  283. X            draftonly = TRUE;
  284. X            break;
  285. X        case 'r':
  286. X            rflag = TRUE;
  287. X            break;
  288. X        case '?':
  289. X        default:
  290. X            prusage();
  291. X            exit(1);
  292. X            break;
  293. X        }
  294. X    }
  295. X    /* set up defaults */
  296. X    esc('!',0,-1); /* reset all of printer's enhancements */
  297. X    dofont(DEFFONT,TRUE);
  298. X    dopitch(DEFPITCH,TRUE);
  299. X    dolinesperinch(DEFLPI * 10);
  300. X
  301. X    if (optind == argc) {
  302. X        Ifile = stdin;
  303. X        process();
  304. X    } else {
  305. X        while (optind < argc) { /* process every input file */
  306. X
  307. X            if (f != NULL)
  308. X                fclose(f);
  309. X
  310. X            f = fopen(argv[optind],"r");
  311. X            if (f == NULL) {
  312. X                fprintf(stderr, "%s: ",Prog);
  313. X                perror(argv[optind]);
  314. X                exit(1);
  315. X            }
  316. X            Ifile = f;
  317. X
  318. X            process();
  319. X
  320. X            optind++;
  321. X        }
  322. X    }
  323. X
  324. X    exit(0);
  325. }
  326. X
  327. /* zip through some input.  essentially, get a word, and either process it
  328. X    as a command, or spit it out */
  329. process()
  330. {
  331. X    while (getword(thisword)) {
  332. X        /* commands begin with '.' at front of line */
  333. X        if (inpstartofline && thisword[0] == '.') {
  334. X            docommand(thisword);
  335. X        } else {
  336. X            char *tmpwordptr;
  337. X
  338. X            emitword(thisword);
  339. X            /* shuffle some history */
  340. X            tmpwordptr = lastword;
  341. X            lastword = thisword;
  342. X            thisword = tmpwordptr;
  343. X        }
  344. X    }
  345. }
  346. X
  347. /* get a single word from the input stream */
  348. /*  manipulate some flags that indicate where we are relative to 
  349. X    input and output lines */
  350. /* if there is a poked buffer present, get the word from it rather than the
  351. X    input stream */
  352. getword(word)
  353. char *word;
  354. {
  355. X    int wascommand;
  356. X    int c;
  357. X
  358. X    if (inpendofline) {
  359. X        /* if we found the end before, we must be at the 
  360. X            start now */
  361. X        inpstartofline = TRUE;
  362. X        inpendofline = FALSE;
  363. X    } else {
  364. X        inpstartofline = FALSE;
  365. X    }
  366. X
  367. X    if (pokestuff != NULL) {
  368. X        /* get the first word of the poked word list */
  369. X        strcpy(word,getpoked());
  370. X        inpstartofline = FALSE;
  371. X    } else {
  372. X        /* no poked stuff */
  373. X        if (breakafterpoke) {
  374. X            /* did we request a line break when we poked? */
  375. X            donewline = TRUE;
  376. X            breakafterpoke = FALSE;
  377. X        }
  378. X        if (enhanceafterpoke) {
  379. X            /* did we request an enhancement when we poked? */
  380. X            want_enhance = enhanceafterpoke;
  381. X            enhanceafterpoke = FALSE;
  382. X        }
  383. X
  384. X        /* grab a word from the input stream.
  385. X            this ignores whitespace */
  386. X        if (fscanf(Ifile,"%s",word) == EOF)
  387. X            return BAD;
  388. X
  389. X        /* is it the last word on the line?
  390. X            checkforEOL() sets flags */
  391. X        if (checkforEOL() == EOF)
  392. X            return BAD;
  393. X
  394. X    }
  395. X    return GOOD;
  396. }
  397. X
  398. /* get a single word out of the previously poked input buffer */
  399. char *
  400. getpoked()
  401. {
  402. X    char *cp,*waspoked;
  403. X
  404. X    /* point at the stored stuff */
  405. X    cp = pokestuff; 
  406. X
  407. X    /* find the start of the word, just in case.  can't happen, i think */
  408. X    while (*cp == ' ') cp++;
  409. X
  410. X    waspoked = cp;
  411. X
  412. X    /* find the end of the word */
  413. X    while (*cp != ' ' && *cp != '\0') cp++;
  414. X
  415. X    if (*cp) {
  416. X        /* mark it, and if there's more poked stuff,
  417. X           find the next word */
  418. X        *cp++ = '\0';
  419. X        while (*cp == ' ' && *cp != '\0')
  420. X            cp++;
  421. X        if (*cp) {
  422. X            pokestuff = cp;
  423. X        } else {
  424. X            /* no more for next time */
  425. X            pokestuff = NULL;
  426. X        }
  427. X    } else {
  428. X        /* no more for next time */
  429. X        pokestuff = NULL;
  430. X    }
  431. X    if (pokestuff == NULL) {
  432. X        /* if that's the end of it... */
  433. X        inpendofline = TRUE;
  434. X        inpstartofline = FALSE;
  435. X    }
  436. X    /* return the first word we found */
  437. X    return waspoked;
  438. }
  439. X
  440. emitword(word)
  441. char *word;
  442. {
  443. X    /* couple of one-time flags:
  444. X        to get the whitespace right on the first line, where no
  445. X        linefeed preceded to call calcleftwhite() for the margin
  446. X        and to get the top margin and header done on the first page */
  447. X    static int firstline = TRUE;
  448. X    static int firstpage = TRUE;
  449. X
  450. X    if (firstpage) {
  451. X        curpagelen = MINPL + unitsperline;
  452. X        curlinewidth = MINLW;
  453. X        outc('\r');
  454. X        toppage(TRUE);
  455. X        firstpage = FALSE;
  456. X    }
  457. X    if (donewline) {  /* newline was requested */
  458. X        newline();  /* sets space */
  459. X    } else {
  460. X        if (firstline) {
  461. X            space = calcleftwhite();
  462. X        } else {
  463. X            space = calcspaces(lastword);
  464. X        }
  465. X    }
  466. X    firstline = FALSE;
  467. X
  468. X    /* turn off underlining before putting out spaces, if we're about
  469. X        to turn it off anyway */
  470. X    if (done_enhance == UNDER && want_enhance != UNDER)
  471. X        enh_off(BASIC|EXTRA);
  472. X
  473. X    /* if the line will grow too long, break it, unless
  474. X        the following word is lone punctuation */
  475. X    if (strlen(word) == 1 && 
  476. X            (word[0] == ',' ||
  477. X             word[0] == ';' ||
  478. X             word[0] == '.')    ) {
  479. X        space = "";  /* butt lone punctuation agains their neighbor */
  480. X    } else if (strwidth(space) +
  481. X           strwidth(word) +
  482. X           curlinewidth > rightmargin) {
  483. X        DEBUGVAL(strwidth(space),%d);
  484. X        DEBUGVAL(strwidth(word),%d);
  485. X        DEBUGVAL(curlinewidth,%d);
  486. X        DEBUGVAL(rightmargin,%d);
  487. X        newline();
  488. X    }
  489. X
  490. X    outstr(space);
  491. X    curlinewidth += strwidth(space);
  492. X
  493. X    /* justification from the .r command */
  494. X    if (rightjustcol) {
  495. X        moveover(rightjustcol);
  496. X        rightjustcol = 0;
  497. X    }
  498. X
  499. X    /* turn on enhancement before spitting a word */
  500. X    if (done_enhance != want_enhance) {
  501. X        enh_on(want_enhance);
  502. X    }
  503. X
  504. X    outstr(word);
  505. X    curlinewidth += strwidth(word);
  506. X    usetmpind = FALSE;  /* once we're sure it's been used */
  507. X    tmpindent = 0;
  508. X
  509. X    outpstartofline = FALSE; /* obviously not true anymore */
  510. X
  511. X    if ( inpendofline ) {  /* end of a line from the input */
  512. X
  513. X        /* if it was a one line enhancement, stop it */
  514. X        want_enhance &= ~enhoffatendofline;
  515. X        enhoffatendofline = 0;
  516. X
  517. X        /* in no-fill mode, input linebreaks cause output linebreaks */
  518. X        if (!filling)
  519. X            donewline = TRUE;
  520. X    }
  521. }
  522. X
  523. /* commands all begin with a ".", and occur as the first text on 
  524. X   an input line */
  525. /* some don't break the line if we're already 
  526. X    on a fresh one, by checking outpstartofline (i.e., two
  527. X    .br commands in a row should be equal to one */
  528. /* numeric arguments are adjusted to their internal units immediately */
  529. /* since we don't actually do newlines until later (before the next word)
  530. X    we keep track of how many blank lines were requested. (e.g. .P, .sp)
  531. X    in "leaveblanklines". coincidentally (?), these are also the
  532. X    commands which end previous paragraphs */
  533. docommand(word)
  534. char *word;
  535. {
  536. X    if (eq(word, ".fi")) {
  537. X
  538. X        filling = TRUE;
  539. X        if (!outpstartofline)
  540. X            donewline = TRUE;
  541. X
  542. X    } else if (eq(word, ".nf")) {
  543. X
  544. X        filling = FALSE;
  545. X        if (!outpstartofline)
  546. X            donewline = TRUE;
  547. X
  548. X    } else if (eq(word, ".i") || eq(word, ".in")) {
  549. X
  550. X        indent = getnumarg();
  551. X        if (!inches)    /* then the argument was already tenths, */
  552. X            indent /= 10;    /* and didn't need multiplying */
  553. X        indent *= H_INCH/10;
  554. X        if (indent < 0 || indent >= rightmargin - leftmargin) {
  555. X            errr(".in indent out of range");
  556. X            exit(1);
  557. X        }
  558. X
  559. X    } else if (eq(word, ".P")) {
  560. X
  561. X        int *indp, i;
  562. X
  563. X        /* from the arguments, first get tmpindent, then paraindent */
  564. X        /*   they both need adjusting and constraining, so  */
  565. X        /*   do this trickily, with a loop */
  566. X        for (i = 0, indp = &tmpindent; i<= 1; i++, indp = ¶indent) {
  567. X            *indp = getnumarg();
  568. X
  569. X            if (!inches)    /* then the arg was already tenths, */
  570. X                *indp /= 10;  /* and didn't need multiplying */
  571. X            *indp *= H_INCH/10;
  572. X
  573. X            if (*indp < -indent) /* keep inside the left margin */
  574. X                *indp = -indent;
  575. X            else if (*indp >= rightmargin - indent - leftmargin)
  576. X                *indp = rightmargin - indent - leftmargin - 1;
  577. X        }
  578. X        usetmpind = TRUE;
  579. X
  580. X        donewline = TRUE;
  581. X        leaveblanklines++;
  582. X
  583. X    } else if (eq(word, ".sp")) { /* force one or more blank line */
  584. X        int l;
  585. X
  586. X        l = getnumarg()/10;    /* getnumarg multiplies by 10 */
  587. X
  588. X        if (l <= 0) /* quietly correct errors */
  589. X            l = 1;
  590. X
  591. X        donewline = TRUE;
  592. X        leaveblanklines += l;
  593. X        paraindent = 0;
  594. X
  595. X    } else if (eq(word, ".c")) {  /* centering */
  596. X        /* we use tmpindent for centering.  it is shared by the
  597. X            first-line indent for paragraphs, but if we center
  598. X            the first line of a paragraph, we want centering to
  599. X            take precedence anyway  */
  600. X        int m;
  601. X
  602. X        /* leave the args around in "pokestuff" -- they'll be
  603. X            picked up in getword() when it tries to advance */
  604. X        pokestuff = restofline(TRUE);
  605. X        breakafterpoke = TRUE;
  606. X
  607. X        /* strwidth() normally takes care of this, but not for
  608. X            margin calculations (they're done single-width) */
  609. X        if (want_enhance == LARGE)
  610. X            m = 2;
  611. X        else
  612. X            m = 1;
  613. X
  614. X        /* start column is center of margins minus half the text:
  615. X            i.e.  (r+l)/2 - w/2
  616. X         */
  617. X        tmpindent = (rightmargin + leftmargin - 
  618. X                    m*strwidth(pokestuff))/2;
  619. X
  620. X        /* take off the margin, since it'll be put back on later */
  621. X        tmpindent -= (leftmargin + indent);
  622. X
  623. X        usetmpind = TRUE;
  624. X        if (!outpstartofline)
  625. X            donewline = TRUE;
  626. X
  627. X    } else if (eq(word, ".r")) { /* right justification */
  628. X
  629. X        pokestuff = restofline(TRUE);
  630. X
  631. X        /* just set this up -- it'll be used in the next emitword() */
  632. X        rightjustcol = rightmargin - strwidth(pokestuff);
  633. X
  634. X    } else if (eq(word, ".nop")) {
  635. X        /* this is a no-op -- useful for formatting words that begin
  636. X            with "." */
  637. X        pokestuff = restofline(FALSE);
  638. X
  639. X    } else if (eq(word, ".\\") || eq(word, ".#")) {
  640. X        /* this is a comment -- throw what follows away */
  641. X        (void)restofline(FALSE);
  642. X
  643. X    } else if (eq(word, ".pf")) {
  644. X        char *cp;
  645. X
  646. X        cp = restofline(TRUE);
  647. X        strcpy(pagefooter, cp ? cp : "");
  648. X
  649. X    } else if (eq(word, ".ph")) {
  650. X        char *cp;
  651. X
  652. X        cp = restofline(TRUE);
  653. X        strcpy(pageheader, cp ? cp : "");
  654. X
  655. X    } else if (eqn(word, ".allheaders",5)) {
  656. X
  657. X        allheaders = TRUE;
  658. X
  659. X    } else if (eqn(word, ".allfooters",5)) {
  660. X
  661. X        allfooters = TRUE;
  662. X
  663. X    } else if (eq(word, ".inches")) {
  664. X
  665. X        inches = TRUE;
  666. X
  667. X    } else if (eq(word, ".tenths")) {
  668. X
  669. X        inches = FALSE;
  670. X
  671. X    } else if (eq(word, ".br")) {
  672. X        /* force a line break -- not a blank line */
  673. X
  674. X        if (!outpstartofline)
  675. X            donewline = TRUE;
  676. X
  677. X    } else if (eq(word, ".lm")) { /* left margin has a .25 inch minimum */
  678. X
  679. X        leftmargin = getnumarg();
  680. X        if (!inches)    /* then the argument was already tenths, */
  681. X            leftmargin /= 10; /* and didn't need multiplying */
  682. X        leftmargin *= H_INCH/10;
  683. X        if (leftmargin < MINLW) {
  684. X            fprintf(stderr,
  685. X        "%s: warning: leftmargin too small, setting to minimum\n",
  686. X                     Prog);
  687. X            leftmargin = MINLW;
  688. X        } else if (leftmargin > rightmargin) {
  689. X    errr("warning:  leftmargin wrong side of rightmargin -- readjusting");
  690. X            leftmargin = rightmargin - strwidth(" ");
  691. X        }
  692. X        DEBUGVAL(leftmargin,%d);
  693. X
  694. X    } else if (eq(word, ".rm")) {
  695. X
  696. X        /* externally, rightmargin is measured from the right
  697. X            edge of the form.  Internally, we measure from
  698. X            the left edge */
  699. X
  700. X        rightmargin = getnumarg();
  701. X        if (!inches)    /* then the argument was already tenths, */
  702. X            rightmargin /= 10; /* and didn't need multiplying */
  703. X        rightmargin *= H_INCH/10;
  704. X
  705. X        if (rightmargin > 3*H_INCH)  /* three inches */
  706. X    errr("warning:  rightmargin seems too big -- measure from the right?");
  707. X
  708. X        rightmargin = formwidth - rightmargin;
  709. X
  710. X        if (rightmargin < 0) {
  711. X            errr("error: negative right margin not allowed");
  712. X            exit(1);
  713. X        }
  714. X
  715. X
  716. X        if (rightmargin < leftmargin) {
  717. X    errr("warning:  rightmargin wrong side of leftmargin -- readjusting");
  718. X            rightmargin = leftmargin + strwidth(" ");
  719. X        }
  720. X
  721. X        DEBUGVAL(rightmargin,%d);
  722. X
  723. X    } else if (eq(word, ".tm")) {    /* top margin -- half inch minimum */
  724. X
  725. X        topmargin = getnumarg();
  726. X        if (!inches)    /* then the argument was already tenths, */
  727. X            topmargin /= 10; /* and didn't need multiplying */
  728. X        topmargin *= V_INCH/10;
  729. X        if (topmargin < MINPL) {
  730. X            fprintf(stderr,
  731. X        "%s: warning: topmargin too small, setting to minimum\n",
  732. X                     Prog);
  733. X            topmargin = MINLW;
  734. X        } else if (topmargin > bottommargin) {
  735. X        errr("warning:  topmargin below bottommargin -- readjusting");
  736. X            topmargin = bottommargin - unitsperline;
  737. X        }
  738. X
  739. X        DEBUGVAL(topmargin,%d);
  740. X
  741. X    } else if (eq(word, ".bm")) {  /* bottom margin */
  742. X
  743. X        bottommargin = getnumarg();
  744. X        if (!inches)    /* then the argument was already tenths, */
  745. X            bottommargin /= 10; /* and didn't need multiplying */
  746. X        bottommargin *= V_INCH/10;
  747. X
  748. X        if (bottommargin < 0) {
  749. X            errr("error: negative margin not allowed");
  750. X            exit(1);
  751. X        }
  752. X
  753. X        if (bottommargin > 5*V_INCH)  /* five inches */
  754. X    errr("warning:  bottom margin seems too big -- measure from the bottom?");
  755. X
  756. X        bottommargin = formlength - bottommargin;
  757. X
  758. X
  759. X        if (bottommargin < topmargin) {
  760. X        errr("warning:  bottommargin below topmargin -- readjusting");
  761. X            bottommargin = topmargin + unitsperline;
  762. X        }
  763. X
  764. X        DEBUGVAL(bottommargin,%d);
  765. X
  766. X    } else if (eqn(word, ".hdheight",4)) {  /* header height from margin */
  767. X
  768. X        hdheight = getnumarg();
  769. X        if (!inches)    /* then the argument was already tenths, */
  770. X            hdheight /= 10; /* and didn't need multiplying */
  771. X        hdheight *= V_INCH/10;
  772. X
  773. X        if (topmargin - hdheight < unitsperline) {
  774. X        errr("warning: header height too big -- resetting to max");
  775. X            hdheight = topmargin - unitsperline;
  776. X        }
  777. X
  778. X    } else if (eqn(word, ".ftdepth",4)) {  /* footer depth from margin */
  779. X        ftdepth = getnumarg();
  780. X        if (!inches)    /* then the argument was already tenths, */
  781. X            ftdepth /= 10; /* and didn't need multiplying */
  782. X        ftdepth *= V_INCH/10;
  783. X
  784. X        if (bottommargin + ftdepth > formlength) {
  785. X        errr("warning: footer depth too big -- resetting to max");
  786. X            ftdepth = formlength - bottommargin;
  787. X        }
  788. X
  789. X    } else if (eq(word, ".ln")) {
  790. X
  791. X        formlength = getnumarg();
  792. X        if (!inches)    /* then the argument was already tenths, */
  793. X            formlength /= 10;  /* and didn't need multiplying */
  794. X
  795. X        /* the printer supports 11, 12, 14, 8, 8.5, 11 2/3 inch forms */
  796. X        switch(formlength) {
  797. X        case 120:
  798. X        case 140:
  799. X        case 80:
  800. X        case 851:
  801. X        case 116:
  802. X        case 117:
  803. X          errr("warning:  be sure to set form length on front panel");
  804. X        case 110:
  805. X            break;
  806. X            
  807. X        default:
  808. X          errr("warning:  this length not supported by printer\n\
  809. X    and will only work for single sheets");
  810. X            break;
  811. X
  812. X        }
  813. X        formlength *= V_INCH/10;
  814. X        if (formlength < 1) {
  815. X            errr(".ln form length too small");
  816. X            exit(1);
  817. X        }
  818. X
  819. X        DEBUGVAL(formlength,%d);
  820. X
  821. X    } else if (eq(word, ".wd")) {
  822. X
  823. X        formwidth = getnumarg();
  824. X        if (!inches)    /* then the argument was already tenths, */
  825. X            formwidth /= 10;  /* and didn't need multiplying */
  826. X        formwidth *= H_INCH/10;
  827. X        if (formwidth < strwidth("  ")) {
  828. X            errr(".wd form width too small");
  829. X            exit(1);
  830. X        }
  831. X
  832. X        DEBUGVAL(formwidth,%d);
  833. X
  834. X    } else if (eq(word, ".fo")) {
  835. X
  836. X        dofont(getstrarg(),FALSE);
  837. X
  838. X    } else if (eq(word, ".lpi")) {
  839. X
  840. X        dolinesperinch(getnumarg());
  841. X
  842. X    } else if (eq(word, ".pi")) {
  843. X
  844. X        /* getnumarg multiplies by 10 */
  845. X        dopitch(getnumarg()/10,FALSE);
  846. X
  847. X    } else if (eq(word, ".dot")) {
  848. X        enhanceafterpoke = want_enhance;
  849. X        want_enhance = GRAPHIC1;
  850. X        pokestuff = "y";
  851. X        pokestuff[0] |= 0x80;
  852. X        enhoffatendofline = 0;
  853. X
  854. X    } else if (eq(word, ".seq")) {
  855. X
  856. X        char *cp;
  857. X
  858. X        /* if there's an arg (i.e. ".seq a") then start a 
  859. X            sequence with it.  if there's no arg, simply
  860. X            continue the sequence (i.e. first 'b', then 'c', etc.
  861. X           numeric sequences must be treated differently than 
  862. X            character sequences.
  863. X        */
  864. X        cp = getstrarg();
  865. X        if (cp[0]) {
  866. X            if (numericseq = isdigit(cp[0])) {
  867. X                sscanf(cp,"%d",&sequencer);
  868. X            } else {
  869. X                sequencer = cp[0];
  870. X            }
  871. X            strcpy(seqsep,getstrarg());
  872. X        }
  873. X        if (numericseq && sequencer >= 10000)
  874. X            sequencer = 1;
  875. X
  876. X        sprintf(seqbuff,numericseq?"%-4d%s":"%c%s",sequencer++,seqsep);
  877. X
  878. X        if (!isprint(seqbuff[0])) {
  879. X            errr("warning: sequence value unprintable");
  880. X            seqbuff[0] = '?';
  881. X            seqbuff[1] = '\0';
  882. X        }
  883. X        pokestuff = seqbuff;
  884. X
  885. X    } else if (eqn(word, ".superscript",4) ||
  886. X            eqn(word, ".subscript",4)) {
  887. X        /* turn on super/subscript */
  888. X        /* these are recorded in the 2nd byte of want/done_enhance,
  889. X            to keep them independent of bold, italic, etc. */
  890. X
  891. X        pokestuff = restofline(FALSE);
  892. X        if (pokestuff) {
  893. X            enhoffatendofline = EXTRA;
  894. X            enhanceafterpoke = want_enhance;
  895. X        } else {
  896. X            enhoffatendofline = 0;
  897. X        }
  898. X
  899. X        want_enhance = (want_enhance & ~EXTRA) | 
  900. X                    (word[3] == 'p') ? SUPER : SUB;
  901. X
  902. X    } else if (eqn(word, ".nosu",5)) {  /* turn off super or sub */
  903. X
  904. X        want_enhance &= ~EXTRA;
  905. X
  906. X    } else if (eqn(word, ".columns",4)) {  /* set columns per page */
  907. X        columns = getnumarg()/10;
  908. X        if (columns != 0) {
  909. X            gutwidth = getnumarg();  /* gutter width, in tenths */
  910. X            if (!inches)    /* then argument was already tenths, */
  911. X                gutwidth /= 10; /* didn't need multiplying */
  912. X            gutwidth *= H_INCH/10;
  913. X        }
  914. X
  915. X    } else if (strlen(word) <= 3) { /* remaining 1 and 2 letter commands */
  916. X        switch(word[1]) {
  917. X        case BOLD:    /* B */
  918. X        case ITALIC:    /* I */
  919. X        case UNDER:    /* U */
  920. X        case LARGE:    /* L */
  921. X        case 'R':    /* NONE */
  922. X            switch(word[2]) {
  923. X            case '\0':
  924. X                /* all the enhancements (bold, underline,
  925. X                 * italics, doublewide) can affect a
  926. X                 * single line:
  927. X                 *    .B embolden this line
  928. X                 * or many lines:
  929. X                 *    .B
  930. X                 *    embolden
  931. X                 *    these
  932. X                 *    lines
  933. X                 *    .R
  934. X                 */
  935. X                pokestuff = restofline(FALSE);
  936. X                if (pokestuff) {
  937. X                    enhoffatendofline = BASIC;
  938. X                    enhanceafterpoke = want_enhance;
  939. X                } else {
  940. X                    enhoffatendofline = 0;
  941. X                }
  942. X
  943. X                if (word[1] == 'R')
  944. X                    want_enhance = want_enhance & ~BASIC;
  945. X                else
  946. X                    want_enhance = want_enhance & ~BASIC |
  947. X                            word[1];
  948. X                break;
  949. X            default:
  950. X                fprintf(stderr, 
  951. X                "%s: warning: %s command not understood\n",
  952. X                     Prog, word);
  953. X            }
  954. X            break;
  955. X        default:
  956. X            fprintf(stderr, 
  957. X            "%s: warning: %s command not understood\n", Prog, word);
  958. X        }
  959. X    } else {
  960. X        fprintf(stderr, "%s: warning: %s command not understood\n",
  961. X                Prog, word);
  962. X    }
  963. X
  964. }
  965. X
  966. /* set pitch value.  printer only supports selected values */
  967. dopitch(pit,force)
  968. {
  969. X
  970. X    /* release proportional and compressed */
  971. X    /*         esc p 0        DC2    */
  972. X    esc('p','0',DC2);
  973. X
  974. X    /* can't have a draft font in proportional pitch */
  975. X    if (!force && draftonly && pit == -1)
  976. X        pit = DEFPITCH;
  977. X
  978. X    switch (pit) {
  979. X
  980. X    default:
  981. X        errr("warning: pitch not recognized. using 10 cpi.\n");
  982. X        /* fall through */
  983. X    case 10:        /* pica */
  984. X        pitch = 10;
  985. X        esc('P',-1,-1);
  986. X        break;
  987. X
  988. X    case 12:        /* elite */
  989. X        pitch = 12;
  990. X        esc('M',-1,-1);
  991. X        break;
  992. X
  993. X    case 15:        /* micron */
  994. X        pitch = 15;
  995. X        esc('g',-1,-1);
  996. X        break;
  997. X
  998. X    case 17:        /* compressed */
  999. X        /* set both pica and compressed */
  1000. X        /*        esc P    SI    */
  1001. X        pitch = 17;
  1002. X        esc('P',SI,-1);
  1003. X        break;
  1004. X
  1005. X    case 20:        /* elite compressed */
  1006. X        /* set both elite and compressed */
  1007. X        /*        esc M    SI    */
  1008. X        pitch = 20;
  1009. X        esc('M',SI,-1);
  1010. X        break;
  1011. X
  1012. X    case -1:
  1013. X        /* ".pi prop" would be nice, but args must be
  1014. X            either alpha or numeric */
  1015. X        pitch = -1;
  1016. X        esc('p','1',-1);
  1017. X        break;
  1018. X    }
  1019. }
  1020. X
  1021. /* all the allowable values (3, 4, 6, 7.5, 8, 12) go into 360 evenly,
  1022. X    so we use that printer control command  (see pp 6-17, 6-18 of manual) */
  1023. /* argument is ten times the lines-per-inch value wanted */
  1024. dolinesperinch(ttlpi)
  1025. int ttlpi;
  1026. {
  1027. X
  1028. X    /* lpi changes cause a line break */
  1029. X    if (!outpstartofline)
  1030. X        donewline = TRUE;
  1031. X
  1032. #ifdef BEFORE
  1033. X    switch (ttlpi) {
  1034. X
  1035. X    case 70:    /* previously allowed 7 or 75 instead of 7.5 */
  1036. X    case 750:
  1037. X        ttlpi = 75;
  1038. X
  1039. X    default:
  1040. X        unitsperline = (V_INCH*10)/ttlpi;
  1041. X        break;
  1042. X
  1043. X    }
  1044. #else
  1045. X    /* ttlpi is ten times too big, so numerator must be too */
  1046. X    unitsperline = (V_INCH*10)/ttlpi;
  1047. #endif
  1048. X    esc('+',unitsperline,-1);
  1049. }
  1050. X
  1051. /* font changes take effect immediately, no line break */
  1052. /* for the letter quality fonts, need to get out of draft mode _and_
  1053. X    select which font */
  1054. dofont(ft,force)
  1055. char *ft;
  1056. {
  1057. X    if (!force && draftonly)
  1058. X        goto draft;
  1059. X
  1060. X    if (eqn(ft, "courier", 2)) {
  1061. X        font = CO;
  1062. X        esc('x','1',-1);
  1063. X        esc('k',CO+'0',-1);
  1064. X
  1065. X    } else if (eqn(ft, "prestige", 2)) {
  1066. X        font = PR;
  1067. X        esc('x','1',-1);
  1068. X        esc('k',PR+'0',-1);
  1069. X
  1070. X    } else if (eqn(ft, "boldPS", 2)) {
  1071. X        font = BO;
  1072. X        esc('x','1',-1);
  1073. X        esc('k',BO+'0',-1);
  1074. X
  1075. X    } else if (eqn(ft, "script", 2)) {
  1076. X        font = SC;
  1077. X        esc('x','1',-1);
  1078. X        esc('k',SC+'0',-1);
  1079. X
  1080. X    } else if (eqn(ft, "sansserif", 2)) {
  1081. X        font = SA;
  1082. X        esc('x','1',-1);
  1083. X        esc('k',SA+'0',-1);
  1084. X
  1085. X    } else {  /* no match */
  1086. X        if (!eqn(ft, "draft", 2)) {
  1087. X            fprintf(stderr,
  1088. X             "%s: warning: %s font not recognized. using draft.\n",
  1089. X                Prog, ft);
  1090. X        }
  1091. X    draft:
  1092. X        font = DR;
  1093. X        esc('x','0',-1);
  1094. X    }
  1095. }
  1096. X
  1097. /* change or turn on an enhancement. */
  1098. /*     asks, for each half (BASIC or EXTRA) of the given enhancement,
  1099. X    if something's already on in that half to turn off.  does so, then
  1100. X    turns what was requested on */
  1101. enh_on(e)
  1102. int e;
  1103. {
  1104. X    if ((e & BASIC) != (done_enhance & BASIC)) {
  1105. X        enh_off(BASIC);
  1106. X        switch(e & BASIC) {
  1107. X        case BOLD:
  1108. X            esc('G',-1,-1);
  1109. X            break;
  1110. X        case ITALIC:
  1111. X            esc('4',-1,-1);
  1112. X            break;
  1113. X        case UNDER:
  1114. X            esc('-','1',-1);
  1115. X            break;
  1116. X        case LARGE:
  1117. X            esc('W','1',-1);
  1118. X            break;
  1119. X        case GRAPHIC1:
  1120. X            esc('t','1',-1);
  1121. X            esc('7',-1,-1);
  1122. X            break;
  1123. X        case GRAPHIC2:
  1124. X            esc('t','1',-1);
  1125. X            esc('6',-1,-1);
  1126. X            break;
  1127. X        }
  1128. X    }
  1129. X    if ((e & EXTRA) != (done_enhance & EXTRA)) {
  1130. X        enh_off(EXTRA);
  1131. X        switch(e & EXTRA) {
  1132. X        case SUPER:
  1133. X            esc('S',0,-1);
  1134. X            break;
  1135. X        case SUB:
  1136. X            esc('S',1,-1);
  1137. X            break;
  1138. X        }
  1139. X    }
  1140. X    done_enhance = e;
  1141. }
  1142. X
  1143. /* turn off an enhancement.  takes the BASIC or EXTRA masks or both as arg */
  1144. enh_off(whichtype)
  1145. {
  1146. X    
  1147. X    /* only turn off what was on */
  1148. X    switch(done_enhance & whichtype & BASIC) {
  1149. X    case BOLD:
  1150. X        esc('H',-1,-1);
  1151. X        break;
  1152. X    case ITALIC:
  1153. X        esc('5',-1,-1);
  1154. X        break;
  1155. X    case UNDER:
  1156. X        esc('-','0',-1);
  1157. X        break;
  1158. X    case LARGE:
  1159. X        esc('W','0',-1);
  1160. X        break;
  1161. X    case GRAPHIC1:
  1162. X        esc('t','0',-1);
  1163. X        break;
  1164. X    case GRAPHIC2:
  1165. X        esc('t','0',-1);
  1166. X        break;
  1167. X    }
  1168. X
  1169. X    switch(done_enhance & whichtype & EXTRA) {  /* turn off what was on */
  1170. X    case SUPER:
  1171. X    case SUB:
  1172. X        esc('T',-1,-1);
  1173. X        break;
  1174. X    }
  1175. X    done_enhance &= ~whichtype;
  1176. }
  1177. X
  1178. /* emit an escape sequence */
  1179. esc(a,b,c)
  1180. int a,b,c;
  1181. {
  1182. X    outc(ESC);
  1183. X    if (a >= 0) {
  1184. X        outc(a);
  1185. X        if (b >= 0) {
  1186. X            outc(b);
  1187. X            if (c >= 0) {
  1188. X                outc(c);
  1189. X            }
  1190. X        }
  1191. X    }
  1192. }
  1193. X
  1194. /* fetches a numeric argument, along with leading and trailing
  1195. X    whitespace, from a line */
  1196. /* always attempts to read N.M, and returns N*10+M */
  1197. /* this means the return value is sometimes ten times too big, */
  1198. /* and the caller must correct this */
  1199. /* we're trying to avoid %f, which the astute programmer will 
  1200. X   note would do most of this for us.  we may port to machines without it */
  1201. getnumarg()
  1202. {
  1203. X    int c, whol, frac, minus, ret;
  1204. X
  1205. X    if ((c = checkforEOL()) == EOF)
  1206. X        goto errout;
  1207. X    else if (c == '\n')
  1208. X        return 0;  /* no argument on the line */
  1209. X
  1210. X    if (c == '-') {  /* fscanf doesn't help with negatives, e.g. -0.5 */
  1211. X        minus = -1;
  1212. X        (void)fgetc(Ifile); /* eat the '-' */
  1213. X        if ((c = checkforEOL()) == EOF)
  1214. X            goto errout;
  1215. X        else if (c == '\n')
  1216. X            return 0;
  1217. X    } else {
  1218. X        minus = 1;
  1219. X    }
  1220. X
  1221. X    if (c == '.') { /* we already have the point, just match the fraction */
  1222. X        if ((ret = fscanf(Ifile,".%d",&frac)) == EOF)
  1223. X            goto errout;
  1224. X
  1225. X        whol = 0;  /* pretend we successfully matched whol */
  1226. X        ret += 1;
  1227. X    } else {
  1228. X        /* attempt to match two fields, before and after the point */
  1229. X        if ((ret = fscanf(Ifile,"%d.%d",&whol,&frac)) == EOF)
  1230. X            goto errout;
  1231. X    }
  1232. X
  1233. X    if (ret < 2) {  /* then we only got the whol part */
  1234. X        frac = 0;
  1235. X        if (ret < 1) /* then we didn't get either */
  1236. X            whol = 0;
  1237. X    } else while (frac > 9) { /* make sure we didn't get 1.5478 */
  1238. X        frac /= 10; /* will give frac == 5 eventually */
  1239. X    }
  1240. X
  1241. X    if (whol < 0)
  1242. X        whol = -whol;
  1243. X    if (frac < 0)
  1244. X        frac = -frac;
  1245. X
  1246. X    (void)checkforEOL();
  1247. X
  1248. X    return minus*(whol*10 + frac);
  1249. X
  1250. X    errout:
  1251. X    errr("EOF while trying for argument");
  1252. X    exit(1);
  1253. }
  1254. X
  1255. /* fetches next string argument, along with leading and trailing
  1256. X    whitespace, from a line */
  1257. char *
  1258. getstrarg()
  1259. {
  1260. X    int c;
  1261. X    static char arg[50];
  1262. X
  1263. X    arg[0] = '\0';
  1264. X
  1265. X    if ((c = checkforEOL()) == EOF) {
  1266. X        errr("EOF while trying for argument");
  1267. X        exit(1);
  1268. X    } else if (c == '\n') {
  1269. X        return "";  /* no argument on the line */
  1270. X    }
  1271. X
  1272. X    if (fscanf(Ifile,"%50s",arg) == EOF) {
  1273. X        errr("EOF while trying for argument");
  1274. X        exit(1);
  1275. X    }
  1276. X    if (checkforEOL() == EOF) {
  1277. X        errr("EOF after argument");
  1278. X        exit(1);
  1279. X    }
  1280. X
  1281. X    return arg;
  1282. }
  1283. X
  1284. /* restofline fetches the rest of the input line.
  1285. X    if requested, does spacing on it, puts it in a buffer.
  1286. X    this is usually then poked away, and fetched as needed.
  1287. X    Unfortunately, the space calculations will be redone then.
  1288. X    We need them here, though, so we can center and right justify
  1289. X    correctly */
  1290. char *
  1291. restofline(spacing)
  1292. {
  1293. X    static char linebuff[100];
  1294. X    char word[100];
  1295. X    char *sp = "";
  1296. X    int c;
  1297. X
  1298. X    linebuff[0] = '\0';
  1299. X    word[0] = '\0';
  1300. X
  1301. X    for(;;) {
  1302. X        if ((c = checkforEOL()) == EOF) {
  1303. X            errr("EOF in mid-line");
  1304. X            exit(1);
  1305. X        } else if (c == '\n') {
  1306. X            break;
  1307. X        }
  1308. X
  1309. X        if (fscanf(Ifile,"%s",word) == EOF) {
  1310. X            errr("EOF while reading rest of line");
  1311. X            exit(1);
  1312. X        }
  1313. X        strcat(linebuff,sp);
  1314. X        strcat(linebuff,word);
  1315. X        sp = spacing ? calcspaces(word) : " ";
  1316. X
  1317. X    }
  1318. X
  1319. X    if (linebuff[0] == '\0')
  1320. X        return NULL;
  1321. X    else
  1322. X        return linebuff;
  1323. }
  1324. X
  1325. /* next line processing: turn off all enhancements temporarily,
  1326. X    add extra linefeeds if requested, and calculate leading
  1327. X    space for the next line */
  1328. newline()
  1329. {
  1330. X    enh_off(BASIC|EXTRA);  /* no enhancements across newlines */
  1331. X    while (leaveblanklines-- > 0) {
  1332. X        emitlinefeed();
  1333. X    }
  1334. X    emitlinefeed();
  1335. X    outpstartofline = TRUE;
  1336. X    space = calcleftwhite();
  1337. X    donewline = FALSE;
  1338. X    leaveblanklines = 0;
  1339. X    curlinewidth = MINLW;
  1340. }
  1341. X
  1342. /* do the linefeed, checking for page breaks */
  1343. emitlinefeed()
  1344. {
  1345. X
  1346. X    if ((curpagelen += unitsperline) > bottommargin ) {
  1347. X
  1348. X        /* don't do the newline if it'll take us past end of form! */
  1349. X        if (curpagelen <= formlength) {
  1350. X            outc('\n');
  1351. X            curlinewidth = MINLW;
  1352. X            linenumber++;
  1353. X
  1354. X            bottompage(FALSE);
  1355. X        }
  1356. X
  1357. X        newpage();
  1358. X        toppage(FALSE);
  1359. X
  1360. X    } else {
  1361. X        outc('\n');
  1362. X        curlinewidth = MINLW;
  1363. X        linenumber++;
  1364. X    }
  1365. X
  1366. }
  1367. X
  1368. /* process the page footer and bottom margin at the bottom of the page */
  1369. bottompage(lastpage)
  1370. {
  1371. X    int footerline;
  1372. X
  1373. X    /* nothing to do if there's no footer */
  1374. X    if ((lastpage && !allfooters) || pagefooter[0] == '\0')
  1375. X        return;
  1376. X
  1377. X    /* try to put the footer half an inch down */
  1378. X    footerline = bottommargin + ftdepth;
  1379. X
  1380. X    /* go to that line and print it */
  1381. X    while (curpagelen < footerline &&
  1382. X        curpagelen + unitsperline <= formlength ) {
  1383. X        outc('\n');
  1384. X        curpagelen += unitsperline;
  1385. X        linenumber++;
  1386. X    }
  1387. X
  1388. X    moveover(rightmargin - strwidth(pagefooter));
  1389. X    outstr(pagefooter);
  1390. X
  1391. }
  1392. X
  1393. /* any time we need a  new page */
  1394. newpage()
  1395. {
  1396. X    outstr("\007\f\r");    /* bell, formfeed, return */
  1397. X    curlinewidth = MINLW;
  1398. X    curpagelen = MINPL + unitsperline;
  1399. X    pagenumber++;
  1400. X    linenumber = 0;
  1401. }
  1402. X
  1403. /* generic top-of-page processing */
  1404. /* does header unless first page, and leaves room for top margin */
  1405. toppage(firstpage)
  1406. {
  1407. X    int headerline;
  1408. X    int newcpl;
  1409. X
  1410. X    headerline = 0;
  1411. X
  1412. X    if ((allheaders || !firstpage) && pageheader[0] != '\0')
  1413. X        headerline = topmargin - hdheight;
  1414. X    else
  1415. X        headerline = 0;
  1416. X
  1417. X    while (curpagelen <= topmargin) {
  1418. X        if (headerline && curpagelen > headerline)  {
  1419. X            moveover(rightmargin - strwidth(pageheader));
  1420. X            outstr(pageheader);
  1421. X            headerline = 0;
  1422. X        }
  1423. X        outc('\n');
  1424. X        curpagelen += unitsperline;
  1425. X        linenumber++;
  1426. X    }
  1427. X    DEBUGVAL(curpagelen,%d);
  1428. X
  1429. X    outc('\r');
  1430. X    curlinewidth = MINLW;
  1431. X
  1432. }
  1433. X
  1434. /* pad the output to the "to" width.  used for right justifying */
  1435. moveover(to)
  1436. int to;
  1437. {
  1438. X    int spw = strwidth(" ");
  1439. X
  1440. X    while (curlinewidth + spw <= to) {
  1441. X        outc(' ');
  1442. X        curlinewidth += spw;
  1443. X    }
  1444. X
  1445. }
  1446. X
  1447. /* calculate the true width of a string, 180'ths of an inch */
  1448. strwidth(s)
  1449. char *s;
  1450. {
  1451. X    char *cp;
  1452. X    int wid;
  1453. X    int column;
  1454. X    extern unsigned char PStable[96][2];
  1455. X
  1456. X    /* the fixed pitch modes are easy.  super/subscript has no effect */
  1457. X    if (pitch != -1) {
  1458. X        if ((done_enhance & BASIC) == LARGE)
  1459. X            return strlen(s) * 2*H_INCH/pitch;
  1460. X        else
  1461. X            return strlen(s) * H_INCH/pitch;
  1462. X    }
  1463. X
  1464. X    /* we're in proportional spaceing mode -- 
  1465. X        look up the character widths individually */
  1466. X
  1467. X    column = (font == SC);  /* script characters have different widths */
  1468. X
  1469. X    cp = s;
  1470. X    wid = 0;
  1471. X    while (*cp) {
  1472. X        /* add the table value -- those units are 360'ths */
  1473. X        wid += PStable[(*cp & 0x7f) - ' '][column];
  1474. X        cp++;
  1475. X    }
  1476. X
  1477. X    /* double width */
  1478. X    if ((done_enhance & BASIC) == LARGE)
  1479. X        wid *= 2;
  1480. X
  1481. X    /* super/subscript is 2/3 original size.  we don't know whether
  1482. X        to truncate or round up, so we truncate */
  1483. X    if ((done_enhance & EXTRA) == SUPER ||
  1484. X        (done_enhance & EXTRA) == SUB) {
  1485. X        wid = (wid * 2) / 3;
  1486. X    }
  1487. X
  1488. X    return wid/2;  /* convert to 180'ths */
  1489. }
  1490. X
  1491. /* whitespace on the left is the sum of the leftmargin, the indent, and
  1492. X    the paraindent or the tmpindent. tmpindent is caused by the first 
  1493. X    line of a paragraph or a centered heading.  tmpindent can be negative 
  1494. X    for paragraphs but should never take us past the left margin.  
  1495. X    paraindent is for the rest of a paragraph, and likewise can be
  1496. X    negative  */
  1497. char *
  1498. calcleftwhite()
  1499. {
  1500. X    static char indentbuff[100];
  1501. X    int i,buffwidth,spw,in;
  1502. X
  1503. X    i = 0;
  1504. X    buffwidth = 0;
  1505. X    spw = strwidth(" ");
  1506. X    in = leftmargin - MINLW + indent + (usetmpind ? tmpindent : paraindent);
  1507. X
  1508. X    while (i < sizeof indentbuff - 1 && buffwidth < in) {
  1509. X        indentbuff[i++] = ' ';
  1510. X        buffwidth += spw;
  1511. X    }
  1512. X    indentbuff[--i] = '\0';    /* overwrite the space that took us over */
  1513. X    return indentbuff;
  1514. }
  1515. X
  1516. /* figure out how many spaces, based on the end of the last word put out */
  1517. /*   (which is passed as the arg.) */
  1518. char *
  1519. calcspaces(word)
  1520. char *word;
  1521. {
  1522. X    /* two spaces after periods and colons at end of proper
  1523. X    strings, even if parenhesized or quoted.
  1524. X    regular expression:
  1525. X        .*[a-z0-9A-Z][a-z0-9A-Z)"][\.:][)"]*$
  1526. X    */
  1527. X
  1528. X    int l;
  1529. X
  1530. X    l = strlen(word)-1;
  1531. X
  1532. X    /* failsafe... no string, no spaces */
  1533. X    if (l < 0) return "";
  1534. X
  1535. X    /* nothing changes if last char is ) or ", so dump them */
  1536. X    /* (i.e. 'hello."' and 'hello.)' both end sentences */
  1537. X    if (word[l] == ')' || word[l] == '"')
  1538. X        l--;
  1539. X
  1540. X
  1541. X    /* the word must be long enough, and end in . or : */
  1542. X    /* in regular expression form:
  1543. X        .*[0-9a-zA-Z][0-9a-zA-Z)"][.:]$
  1544. X                   l-2        l-1      l
  1545. X    */
  1546. X    if ( l >= 2 &&
  1547. X        (word[l] == '.' || word[l] == ':') && 
  1548. X        (isalnum(word[l-1]) || word[l-1] == ')' || word[l-1] == '"' ) &&
  1549. X            isalnum(word[l-2]) )
  1550. X    {
  1551. X        /* then it's a sentence, except for common abbreviations */
  1552. X        /* this doesn't work if a sentence ends in one of these abbrs */
  1553. X        if (    !eq(word, "Rd.")  && 
  1554. X            !eq(word, "St.")  && 
  1555. X            !eq(word, "Ave.") && 
  1556. X            !eq(word, "Mr.")  && 
  1557. X            !eq(word, "Ms.")  && 
  1558. X            !eq(word, "Mrs.")
  1559. X            ) {
  1560. X            return "  ";  /* two space */
  1561. X        }
  1562. X    }
  1563. X
  1564. X    /* ends in a hyphen, concatenate with the next word */
  1565. X    /*     i.e.   .*.[0-9a-zA-Z]-$          */
  1566. X    if ( l >= 2 && word[l] == '-' && isalnum(word[l-1]) )
  1567. X        return "";
  1568. X
  1569. X    /* normal word, normal spacing */
  1570. X    return " ";
  1571. }
  1572. X
  1573. /* general purpose messenger */
  1574. errr(s)
  1575. char *s;
  1576. {
  1577. X    fprintf(stderr,"\n%s: %s\n", Prog, s);
  1578. }
  1579. X
  1580. /* returns:  the next non-space non-tab character, or EOF (end of file)
  1581. X       if char was '\n', a newline was found (flag set)
  1582. */
  1583. checkforEOL()
  1584. {
  1585. X    int c;
  1586. X    while ((c = fgetc(Ifile)) != EOF && (c == ' ' || c == '\t'))
  1587. X        ;
  1588. X
  1589. X    if (c == EOF)
  1590. X        return EOF;
  1591. X    else if ( c == '\n')
  1592. X        inpendofline = TRUE;
  1593. X
  1594. X    ungetc(c,Ifile);
  1595. X    return c;
  1596. }
  1597. X
  1598. outstr(s)
  1599. char *s;
  1600. {
  1601. X    while (*s) fputc(*s++,Ofile);
  1602. }
  1603. X
  1604. outc(c)
  1605. {
  1606. X    if (rflag && c == '\n')
  1607. X        fputc('\r',Ofile);
  1608. X    fputc(c,Ofile);
  1609. }
  1610. X
  1611. /* proportional spacing table -- second column for script font */
  1612. /* the values are the width of each character, in 360'ths of an inch */
  1613. unsigned char PStable[96][2] = {
  1614. X    /*   */    { 30, 20 },
  1615. X    /* ! */ { 18, 12 },
  1616. X    /* " */    { 30, 20 },
  1617. X    /* # */    { 30, 20 },
  1618. X    /* $ */    { 30, 20 },
  1619. X    /* % */    { 36, 24 },
  1620. X    /* & */    { 36, 24 },
  1621. X    /* ` */    { 18, 12 },
  1622. X    /* ( */    { 24, 16 },
  1623. X    /* ) */    { 24, 16 },
  1624. X    /* * */    { 30, 20 },
  1625. X    /* + */    { 30, 20 },
  1626. X    /* , */    { 18, 12 },
  1627. X    /* - */    { 30, 20 },
  1628. X    /* . */    { 18, 12 },
  1629. X    /* / */    { 30, 20 },
  1630. X    /* 0 */    { 30, 20 },
  1631. X    /* 1 */    { 30, 20 },
  1632. X    /* 2 */    { 30, 20 },
  1633. X    /* 3 */    { 30, 20 },
  1634. X    /* 4 */    { 30, 20 },
  1635. X    /* 5 */    { 30, 20 },
  1636. X    /* 6 */    { 30, 20 },
  1637. X    /* 7 */    { 30, 20 },
  1638. X    /* 8 */    { 30, 20 },
  1639. X    /* 9 */    { 30, 20 },
  1640. X    /* : */    { 18, 12 },
  1641. X    /* ; */    { 18, 12 },
  1642. X    /* < */    { 30, 20 },
  1643. X    /* = */    { 30, 20 },
  1644. X    /* > */    { 30, 20 },
  1645. X    /* ? */    { 30, 20 },
  1646. X    /* @ */    { 36, 24 },
  1647. X    /* A */    { 36, 24 },
  1648. X    /* B */    { 36, 24 },
  1649. X    /* C */    { 36, 24 },
  1650. X    /* D */    { 36, 24 },
  1651. X    /* E */    { 36, 24 },
  1652. X    /* F */    { 36, 24 },
  1653. X    /* G */    { 36, 24 },
  1654. X    /* H */    { 36, 24 },
  1655. X    /* I */    { 24, 16 },
  1656. X    /* J */    { 30, 20 },
  1657. X    /* K */    { 36, 24 },
  1658. X    /* L */    { 36, 24 },
  1659. X    /* M */    { 42, 28 },
  1660. X    /* N */    { 36, 24 },
  1661. X    /* O */    { 36, 24 },
  1662. X    /* P */    { 36, 24 },
  1663. X    /* Q */    { 36, 24 },
  1664. X    /* R */    { 36, 24 },
  1665. X    /* S */    { 36, 24 },
  1666. X    /* T */    { 36, 24 },
  1667. X    /* U */    { 42, 28 },
  1668. X    /* V */    { 36, 24 },
  1669. X    /* W */    { 42, 28 },
  1670. X    /* X */    { 36, 24 },
  1671. X    /* Y */    { 36, 24 },
  1672. X    /* Z */    { 30, 20 },
  1673. X    /* [ */    { 24, 16 },
  1674. X    /* \ */    { 30, 20 },
  1675. X    /* ] */    { 24, 16 },
  1676. X    /* ^ */    { 30, 20 },
  1677. X    /* _ */    { 30, 20 },
  1678. X    /* ' */    { 18, 12 },
  1679. X    /* a */    { 30, 20 },
  1680. X    /* b */    { 36, 24 },
  1681. X    /* c */    { 30, 20 },
  1682. X    /* d */    { 36, 24 },
  1683. X    /* e */    { 30, 20 },
  1684. X    /* f */    { 24, 16 },
  1685. X    /* g */    { 36, 24 },
  1686. X    /* h */    { 36, 24 },
  1687. X    /* i */    { 18, 12 },
  1688. X    /* j */    { 24, 16 },
  1689. X    /* k */    { 36, 24 },
  1690. X    /* l */    { 18, 12 },
  1691. X    /* m */    { 42, 28 },
  1692. X    /* n */    { 36, 24 },
  1693. X    /* o */    { 30, 20 },
  1694. X    /* p */    { 36, 24 },
  1695. X    /* q */    { 36, 24 },
  1696. X    /* r */    { 30, 20 },
  1697. X    /* s */    { 30, 20 },
  1698. X    /* t */    { 24, 16 },
  1699. X    /* u */    { 36, 24 },
  1700. X    /* v */    { 36, 24 },
  1701. X    /* w */    { 42, 28 },
  1702. X    /* x */    { 30, 20 },
  1703. X    /* y */    { 36, 24 },
  1704. X    /* z */    { 30, 20 },
  1705. X    /* { */    { 24, 16 },
  1706. X    /* | */    { 18, 12 },
  1707. X    /* } */    { 24, 16 }, 
  1708. X    /* ~ */    { 30, 20 },
  1709. X    /* 0 */    { 30, 20 }
  1710. };
  1711. X
  1712. SHAR_EOF
  1713. chmod 0444 nruff.c ||
  1714. echo 'restore of nruff.c failed'
  1715. Wc_c="`wc -c < 'nruff.c'`"
  1716. test 39419 -eq "$Wc_c" ||
  1717.     echo 'nruff.c: original size 39419, current size' "$Wc_c"
  1718. # ============= nruff.doc ==============
  1719. echo 'x - extracting nruff.doc (Text)'
  1720. sed 's/^X//' << 'SHAR_EOF' > 'nruff.doc' &&
  1721. X
  1722. .# proportional, boldPS font
  1723. .pi -1
  1724. .fo boldPS
  1725. X
  1726. .lm .7
  1727. .rm 1.3
  1728. X
  1729. .# page length, lines per inch
  1730. .lpi 7.5
  1731. X
  1732. .pf (cont.)
  1733. .ph nruff commands (cont.)
  1734. X
  1735. .U usage:
  1736. .P .3  1 
  1737. .B nruff 
  1738. .I [-d] [files...]
  1739. .br
  1740. .I -d
  1741. forces
  1742. .fo draft
  1743. .pi 10
  1744. draft
  1745. .fo boldPS
  1746. .pi -1
  1747. mode, which is faster.
  1748. .br
  1749. .I files
  1750. are used in place of stdin.
  1751. .br
  1752. The processed output always goes to stdout.
  1753. .sp 2
  1754. .U nruff commands
  1755. .in 1.0
  1756. .fi
  1757. .P -.7
  1758. .B .fi
  1759. ,
  1760. .B .nf
  1761. .br
  1762. Turn fill mode on and off respectively. Causes a line break.  Fill mode is on
  1763. to begin.
  1764. X
  1765. .P -.7
  1766. .B .lm
  1767. .I N
  1768. ,
  1769. .B .rm
  1770. .I N
  1771. ,
  1772. .B .tm
  1773. .I N
  1774. ,
  1775. .B .bm
  1776. .I N
  1777. ,
  1778. .br
  1779. Set the left, right, top, or bottom margin to
  1780. .I N
  1781. inches.  The right and bottom
  1782. margins are measured from the
  1783. .U right
  1784. and
  1785. .U bottom
  1786. edges of the form.  All of these default to one inch.
  1787. X
  1788. .P -.7
  1789. .B .i
  1790. .I N
  1791. ,
  1792. .B .in
  1793. .I N
  1794. .br
  1795. Set a normal indent, in inches.  This is measured from the left margin.
  1796. X
  1797. .P -.7
  1798. .B .P
  1799. .I [N] [M]
  1800. .br
  1801. Start a new paragraph, optionally offsetting the first line
  1802. .I N
  1803. inches, and the rest of the paragraph
  1804. .I M
  1805. inches, either
  1806. right or left
  1807. with respect to the
  1808. .U indent
  1809. value, not from the left margin.  (The left margin, the normal indent,
  1810. and the paragraph indents are all additive.) The left margin
  1811. cannot be backed over.  The paragraph is considered to end at
  1812. the next
  1813. .B .P
  1814. or
  1815. .B .sp
  1816. command.
  1817. X
  1818. .P -.7
  1819. .B  .sp
  1820. .I [N]
  1821. .br
  1822. Cause
  1823. .I N
  1824. X blank lines to appear in the output.
  1825. X
  1826. .P -.7
  1827. .B .c
  1828. .I text...
  1829. .br
  1830. Center
  1831. .I text
  1832. X on a new line.
  1833. X
  1834. .P -.7
  1835. .B  .r
  1836. .I text...
  1837. .br
  1838. Right justify
  1839. .I text
  1840. X on a new line.
  1841. X
  1842. .P -.7
  1843. .B  .br
  1844. .br
  1845. Cause a line break (but not a blank line) in the output.
  1846. X
  1847. .P -.7
  1848. .B  .wd
  1849. .I N
  1850. ,
  1851. .B  .ln
  1852. .I N
  1853. .br
  1854. Set the physical page width or length to
  1855. .I N
  1856. inches.  All margins are measured with respect to these boundaries.  Defaults
  1857. are 8.5 and 11.
  1858. X
  1859. .P -.7
  1860. .B  .fo
  1861. .I fontstyle
  1862. .br
  1863. Select a new font, which can be one of
  1864. .fo courier
  1865. courier,
  1866. .fo prestige
  1867. prestige,
  1868. .fo script
  1869. script,
  1870. .fo boldPS
  1871. boldPS,
  1872. .fo sansserif
  1873. sansserif,
  1874. .fo boldPS
  1875. or
  1876. .pi 10
  1877. .fo draft
  1878. draft
  1879. .pi -1
  1880. .fo boldPS
  1881. , which is the default.
  1882. X
  1883. .P -.7
  1884. .B  .lpi
  1885. .I N
  1886. .br
  1887. Set the line-per-inch value to any of 3, 4, 6, 7.5, 8, or 12.
  1888. Default is 6.
  1889. X
  1890. .P -.7
  1891. .B  .pi
  1892. .I N
  1893. .br
  1894. Set the character pitch to any of 10, 12, 15, 17, 20 or -1.  Use -1 to
  1895. get proportional pitch. Default is 10.
  1896. X
  1897. .P -.7
  1898. .B .B
  1899. .I [text...]
  1900. ,
  1901. .B .U
  1902. .I [text...]
  1903. ,
  1904. .B .I
  1905. .I [text...]
  1906. ,
  1907. .B .L
  1908. .I [text...]
  1909. ,
  1910. .B .R
  1911. .I [text...]
  1912. .br
  1913. Print
  1914. .I text
  1915. X in
  1916. .B bold
  1917. ,
  1918. .U underlined
  1919. ,
  1920. .I italics
  1921. , or
  1922. .L large
  1923. .nop .  The
  1924. enhancement lasts for a single line, unless it is specified on a line
  1925. by itself (no following text), in which case it lasts until the next
  1926. enhancement command.  (That's what 
  1927. .B .R
  1928. is for.)  When an enhancement affects
  1929. a single line, the enhancement previously in effect is restored
  1930. when the line is done.
  1931. X
  1932. .P -.7
  1933. .B .super
  1934. .I [text...]
  1935. ,
  1936. .B .sub
  1937. .I [text...]
  1938. ,
  1939. .B .nosu
  1940. .br
  1941. Similar to, and independent of, the above enhancements.  Puts the following
  1942. .I text
  1943. into the
  1944. .super superscript
  1945. or
  1946. .sub subscript
  1947. position.  If not followed by
  1948. .I text
  1949. , the enhancement remains until removed by
  1950. .B .nosu
  1951. .nop .
  1952. X
  1953. .P -.7
  1954. .B .pf
  1955. .I [text...]
  1956. ,
  1957. .B .ph
  1958. .I [text...]
  1959. .br
  1960. Set the page footer or header string to
  1961. .I text.
  1962. Headers and footers are placed as close to half an inch from the text
  1963. as possible.  They go
  1964. .U outside
  1965. the top and bottom margins, respectively.
  1966. X
  1967. .P -.7
  1968. .B .hdheight
  1969. .I N
  1970. ,
  1971. .B .ftdepth
  1972. .I N
  1973. .br
  1974. Respectively, cause page headers and footers to go 
  1975. .I N
  1976. inches above or below their respective margins.  The default distance
  1977. is one half inch.
  1978. X
  1979. .P -.7
  1980. .B .allheaders
  1981. ,
  1982. .B .allfooters
  1983. .br
  1984. Respectively, cause page headers and footers to be printed on
  1985. .U all
  1986. pages.  Normally, the header at the top of the first page and
  1987. the footer at the bottom of the last page
  1988. are skipped.
  1989. X
  1990. .P -.7
  1991. .B .tenths
  1992. ,
  1993. .B .inches
  1994. .br
  1995. Cause subsequent page measurements (margins, lengths, etc.) to be taken
  1996. as tenths of inches, or inches.  The default is inches.
  1997. X
  1998. .P -.7
  1999. .B .dot
  2000. .br
  2001. Put a bullet (
  2002. .dot
  2003. ) into the text.
  2004. X
  2005. .P -.7
  2006. .B .seq
  2007. .I [tag start value] [separator]
  2008. .br
  2009. Start (or increment and use a previously started) sequence of
  2010. .I tags
  2011. .nop . 
  2012. .I Tags
  2013. can be
  2014. either numeric (1, 2, 3, etc.) or not (a,b,c... or A,B,C).  The
  2015. .I separator
  2016. is optional, and is concatenated with the
  2017. .I tag
  2018. .nop .
  2019. X
  2020. .P -.7
  2021. .B .nop
  2022. .I [text...],
  2023. .br
  2024. Null command, simply prints
  2025. .I text.
  2026. Useful if the input text looks like a command
  2027. to nruff, i.e. the input line begins with a ".".
  2028. X
  2029. .P -.7
  2030. .B .\
  2031. .I [text...]
  2032. or
  2033. .B .#
  2034. .I [text...]
  2035. .br
  2036. Commenting command, discards
  2037. .I text.
  2038. SHAR_EOF
  2039. chmod 0664 nruff.doc ||
  2040. echo 'restore of nruff.doc failed'
  2041. Wc_c="`wc -c < 'nruff.doc'`"
  2042. test 4488 -eq "$Wc_c" ||
  2043.     echo 'nruff.doc: original size 4488, current size' "$Wc_c"
  2044. # ============= Makefile ==============
  2045. echo 'x - extracting Makefile (Text)'
  2046. sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
  2047. X
  2048. # Not much of a makefile is needed...
  2049. X
  2050. nruff:    nruff.c
  2051. X    $(CC) -o nruff nruff.c
  2052. X
  2053. doc:    nruff
  2054. X    nruff nruff.doc | lpr
  2055. SHAR_EOF
  2056. chmod 0664 Makefile ||
  2057. echo 'restore of Makefile failed'
  2058. Wc_c="`wc -c < 'Makefile'`"
  2059. test 114 -eq "$Wc_c" ||
  2060.     echo 'Makefile: original size 114, current size' "$Wc_c"
  2061. exit 0
  2062. -- 
  2063.         paul fox, pgf@cayman.com, (617)494-1999
  2064.         Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139
  2065.  
  2066. exit 0 # Just in case...
  2067.