home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / BDSC / BDSC-4 / NRO.C < prev    next >
Text File  |  2000-06-30  |  59KB  |  2,247 lines

  1. /*
  2.  *      Word Processor
  3.  *      similar to Unix NROFF or RSX-11M RNO -
  4.  *      adaptation of text processor given in
  5.  *      "Software Tools", Kernighan and Plauger.
  6.  *
  7.  *      Stephen L. Browning
  8.  *      5723 North Parker Avenue
  9.  *      Indianapolis, Indiana 46220
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include "nro.h"
  14. #include "nrocom.c"
  15.  
  16. abs(foo)
  17. int foo;
  18. {
  19.         return( (foo > 0) ? foo : -foo);
  20. }
  21.  
  22.  
  23. main(argc,argv)
  24. int argc;
  25. char *argv[];
  26. {
  27.         int i;
  28.         int swflg;
  29.         int ifp, ofp;
  30.         
  31.         swflg = FALSE;
  32.         pout = stdout;
  33.         ifp = ofp = 0;
  34.         init();
  35.         for (i=1; i<argc; ++i) {
  36.                 if (*argv[i] == '-' || *argv[i] == '+') {
  37.                         if (pswitch(argv[i],&swflg) == ERR) exit(-1);
  38.                 }
  39.                 else if (*argv[i] == '>') {
  40.                         if (ofp == 0) {
  41.                                 if (!strcmp(argv[i]+1,"$P")) {
  42.                                         ofp = 1;
  43.                                         co.lpr = TRUE;
  44.                                 }
  45.                                 else if ((oub = fopen(argv[i]+1,"w")) == NULL) {
  46.                                         printf("nro: cannot create %s\n",argv[i]+1);
  47.                                         exit(-1);
  48.                                 }
  49.                                 else {
  50.                                         pout = oub;
  51.                                 }
  52.                         }
  53.                         else {
  54.                                 puts("nro: too many output files\n");
  55.                                 exit(-1);
  56.                         }
  57.                 }
  58.         }
  59.         for (i=1; i<argc; ++i) {
  60.                 if (*argv[i] != '-' && *argv[i] != '+' && *argv[i] != '>') {
  61.                         if ((sofile[0] = fopen(argv[i],"r")) == NULL) {
  62.                                 printf("nro: unable to open file %s\n",argv[i]);
  63.                                 exit(-1);
  64.                         }
  65.                         else {
  66.                                 profile();
  67.                                 fclose(sofile[0]);
  68.                         }
  69.                 }
  70.         }
  71.         if (argc == 1) {
  72.                 puts("Usage: nro [-n] [+n] [-pxx] [-v] [-b] [-mmacfile] infile ... [>outfile]\n");
  73.                 exit(-1);
  74.         }
  75.         if (pout != stdout) {
  76.                 putc(CPMEOF,pout);
  77.                 fflush(pout);
  78.                 fclose(pout);
  79.         }
  80. }
  81.  
  82.  
  83.  
  84. /*
  85.  *      retrieve one line of input text
  86.  */
  87.  
  88. getlin(p,in_buf)
  89. char *p;
  90. FILE *in_buf;
  91. {
  92.         int i;
  93.         int c;
  94.         char *q;
  95.  
  96.         q = p;
  97.         for (i=0; i<MAXLINE-1; ++i) {
  98.                 c = ngetc(in_buf);
  99.                 if (c == CPMEOF || c == EOF) {
  100.                         *q = EOS;
  101.                         c = strlen(p);
  102.                         return(c == 0 ? EOF : c);
  103.                 }
  104.                 *q++ = c;
  105.                 if (c == '\n') break;
  106.         }
  107.         *q = EOS;
  108.         return(strlen(p));
  109. }
  110.  
  111.  
  112.  
  113. /*
  114.  *      initialize parameters for nro word processor
  115.  */
  116.  
  117. init()
  118. {
  119.         int i;
  120.  
  121.         dc.fill = YES;
  122.         dc.lsval = 1;
  123.         dc.inval = 0;
  124.         dc.rmval = PAGEWIDTH - 1;
  125.         dc.tival = 0;
  126.         dc.ceval = 0;
  127.         dc.ulval = 0;
  128.         dc.cuval = 0;
  129.         dc.juval = YES;
  130.         dc.boval = 0;
  131.         dc.bsflg = FALSE;
  132.         dc.pgchr = '#';
  133.         dc.cmdchr = '.';
  134.         dc.prflg = TRUE;
  135.         dc.sprdir = 0;
  136.         for (i=0; i<26; ++i) dc.nr[i] = 0;
  137.         pg.curpag = 0;
  138.         pg.newpag = 1;
  139.         pg.lineno = 2;
  140.         pg.plval = PAGELEN;
  141.         pg.m1val = 2;
  142.         pg.m2val = 2;
  143.         pg.m3val = 2;
  144.         pg.m4val = 2;
  145.         pg.bottom = pg.plval - pg.m4val - pg.m3val;
  146.         pg.offset = 0;
  147.         pg.frstpg = 0;
  148.         pg.lastpg = 30000;
  149.         pg.ehead[0] = pg.ohead[0] = '\n';
  150.         pg.efoot[0] = pg.ofoot[0] = '\n';
  151.         for (i=1; i<MAXLINE; ++i) {
  152.                 pg.ehead[i] = pg.ohead[i] = EOS;
  153.                 pg.efoot[i] = pg.ofoot[i] = EOS;
  154.         }
  155.         pg.ehlim[LEFT] = pg.ohlim[LEFT] = dc.inval;
  156.         pg.eflim[LEFT] = pg.oflim[LEFT] = dc.inval;
  157.         pg.ehlim[RIGHT] = pg.ohlim[RIGHT] = dc.rmval;
  158.         pg.eflim[RIGHT] = pg.oflim[RIGHT] = dc.rmval;
  159.         co.outp = 0;
  160.         co.outw = 0;
  161.         co.outwds = 0;
  162.         co.lpr = FALSE;
  163.         for (i=0; i<MAXLINE; ++i) co.outbuf[i] = EOS;
  164.         for (i=0; i<MXMDEF; ++i) mac.mnames[i] = NULL;
  165.         mac.lastp = 0;
  166.         mac.emb = &mac.mb[0];
  167.         mac.ppb = NULL;
  168. }
  169.  
  170.  
  171. /*
  172.  *      get character from input file or push back buffer
  173.  */
  174.  
  175. ngetc(infp)
  176. FILE *infp;
  177. {
  178.         int c;
  179.  
  180.         if (mac.ppb >= &mac.pbb[0]) {
  181.                 c = *mac.ppb--;
  182.         }
  183.         else {
  184.                 c = getc(infp);
  185.         }
  186.         return(c);
  187. }
  188.  
  189.  
  190.  
  191. /*
  192.  *      process input files from command line
  193.  */
  194.  
  195. profile()
  196. {
  197.         char ibuf[MAXLINE];
  198.  
  199.         for (dc.flevel=0; dc.flevel>=0; --dc.flevel) {
  200.                 while (getlin(ibuf,sofile[dc.flevel]) != EOF) {
  201.                         if (ibuf[0] == dc.cmdchr) comand(ibuf);
  202.                         else text(ibuf);
  203.                 }
  204.                 if (dc.flevel > 0) fclose(sofile[dc.flevel]);
  205.         }
  206.         if (pg.lineno > 0) space(HUGE);
  207. }
  208.  
  209.  
  210.  
  211. /*
  212.  *      process switch values from command line
  213.  */
  214.  
  215. pswitch(p,q)
  216. char *p;
  217. int *q;
  218. {
  219.         int swgood;
  220.  
  221.         swgood = TRUE;
  222.         if (*p == '-') {
  223.                 switch (newlower(*++p)) {
  224.                 case 'b':
  225.                         dc.bsflg = TRUE;
  226.                         break;
  227.                 case 'm':
  228.                         if ((sofile[0] = fopen(++p,"r")) == NULL) {
  229.                                 printf("***nro: unable to open file %s\n",p);
  230.                                 exit(-1);
  231.                         }
  232.                         profile();
  233.                         fclose(sofile[0]);
  234.                         break;
  235.                 case 'p':
  236.                    set(&pg.offset,ctod(++p),'1',0,0,HUGE);
  237.                         break;
  238.                 case 'v':
  239.                         printf("NRO version 1.0\n");
  240.                         *q = TRUE;
  241.                         break;
  242.                 case '0':
  243.                 case '1':
  244.                 case '2':
  245.                 case '3':
  246.                 case '4':
  247.                 case '5':
  248.                 case '6':
  249.                 case '7':
  250.                 case '8':
  251.                 case '9':
  252.                         pg.lastpg = ctod(p);
  253.                         break;
  254.                 default:
  255.                         swgood = FALSE;
  256.                         break;
  257.                 }
  258.         }
  259.         else if (*p == '+') {
  260.                 pg.frstpg = ctod(++p);
  261.         }
  262.         else {
  263.                 swgood = FALSE;
  264.         }
  265.         if (swgood == FALSE) {
  266.                 printf("nro: illegal switch %s\n",p);
  267.                 return(ERR);
  268.         }
  269.         return(OK);
  270. }
  271.  
  272. *************
  273.     \nro.h/
  274. *************
  275. /*
  276.  *      Parameter file for NRO word processor
  277.  *
  278.  *      Stephen L. Browning
  279.  *      5723 North Parker Avenue
  280.  *      Indianapolis, Indiana 46220
  281.  */
  282.  
  283.  
  284. /* some or all of this may be unnecessary for you */
  285.  
  286. #include <ctype.h>
  287. #define EOS '\0'
  288. #define CPMEOF 0x1a
  289. #define TRUE -1
  290. #define FALSE 0
  291. #define OK 0
  292.  
  293. /* end of possible bogus hacks */
  294.  
  295. #define MACRO    0      /* macro definition */
  296. #define BP       1      /* begin page   */
  297. #define BR       2      /* break        */
  298. #define CE       3      /* center       */
  299. #define FI       4      /* fill         */
  300. #define FO       5      /* footer       */
  301. #define HE       6      /* header       */
  302. #define IN       7      /* indent       */
  303. #define LS       8      /* line spacing */
  304. #define NF       9      /* no fill      */
  305. #define PL      10      /* page lenght  */
  306. #define RM      11      /* right margin */
  307. #define SP      12      /* line space   */
  308. #define TI      13      /* temp indent  */
  309. #define UL      14      /* underline    */
  310. #define JU      15      /* justify      */
  311. #define NJ      16      /* no justify   */
  312. #define M1      17      /* top margin   */
  313. #define M2      18      /* second top margin    */
  314. #define M3      19      /* first bottom margin  */
  315. #define M4      20      /* bottom-most margin   */
  316. #define BS      21      /* allow/disallow '\b' in output */
  317. #define NE      22      /* need n lines */
  318. #define PC      23      /* page number character */
  319. #define CC      24      /* control character    */
  320. #define PO      25      /* page offset  */
  321. #define BO      26      /* bold face    */
  322. #define EH      27      /* header for even numbered pages       */
  323. #define OH      28      /* header for odd numbered pages        */
  324. #define EF      29      /* footer for even numbered pages       */
  325. #define OF      30      /* footer for odd numbered pages        */
  326. #define SO      31      /* source file  */
  327. #define CU      32      /* continuous underline */
  328. #define DE      33      /* define macro */
  329. #define EN      34      /* end macro definition */
  330. #define NR      35      /* set number register  */
  331.  
  332. #define UNKNOWN -1
  333.  
  334. /*
  335.  *      MAXLINE is set to a value slightly larger
  336.  *      than twice the longest expected input line.
  337.  *      Because of the way underlining is handled, the
  338.  *      input line which is to be underlined, can almost
  339.  *      triple in length.  Unlike normal underlining and
  340.  *      boldfacing, continuous underlining affects all
  341.  *      characters in the buffer, and represents the
  342.  *      worst case condition.  If the distance between
  343.  *      the left margin and the right margin is greater
  344.  *      than about 65 characters, and continuous underlining
  345.  *      is in effect, there is a high probability of buffer
  346.  *      overflow.
  347.  */
  348.  
  349. #define MAXLINE 200
  350. #define PAGELEN  66
  351. #define PAGEWIDTH 80
  352. #define HUGE    256
  353. #define LEFT    0               /* indecies into header margin limit arrays */
  354. #define RIGHT   1
  355. #define NFILES  4               /* nesting depth for input files */
  356.  
  357. /*
  358.  *      The following parameters may be defined in bdscio.h
  359.  */
  360.  
  361. #define YES     1
  362. #define NO      0
  363. #define ERR     -1
  364.  
  365. /*
  366.  *      The parameter values selected for macro definitions
  367.  *      are somewhat arbitrary.  MACBUF is the storage area
  368.  *      for both macro names and definitions.  Since macro
  369.  *      processing is handled by pushing back the expansion
  370.  *      into the input buffer, the longest possible expansion
  371.  *      would be MAXLINE characters.  Allowing for argument
  372.  *      expansion, MXMLEN was chosen slightly less than MAXLINE.
  373.  *      It is assumed that most macro definitions will not
  374.  *      exceed 20 characters, hence MXMDEF of 100.
  375.  */
  376.  
  377. #define MXMDEF  100             /* maximum no. of macro definitions */
  378. #define MACBUF  2000            /* macro definition buffer */
  379. #define MXMLEN  150             /* maximum length of each macro definition */
  380. #define MNLEN   10              /* maximum length of macro name */
  381.  
  382. struct macros {
  383.         char *mnames[MXMDEF];   /* table of pointers to macro names */
  384.         int lastp;              /* index to last mname  */
  385.         char *emb;              /* next char avail in macro defn buffer */
  386.         char mb[MACBUF];        /* table of macro definitions */
  387.         char *ppb;              /* pointer into push back buffer */
  388.         char pbb[MAXLINE];      /* push back buffer */
  389. };
  390.  
  391.  
  392. /* control parameters for nro */
  393.  
  394. struct docctl {
  395.         int fill;       /* fill if YES, init = YES              */
  396.         int lsval;      /* current line spacing, init = 1       */
  397.         int inval;      /* current indent, >= 0, init = 0       */
  398.         int rmval;      /* current right margin, init = 60      */
  399.         int tival;      /* current temp indent, init = 0        */
  400.         int ceval;      /* number of lines to center, init = 0  */
  401.         int ulval;      /* number of lines to underline, init = 0 */
  402.         int cuval;      /* no. lines to continuously underline, init = 0 */
  403.         int juval;      /* justify if YES, init = YES           */
  404.         int boval;      /* number of lines to bold face, init = 0 */
  405.         int bsflg;      /* can output contain '\b', init = FALSE */
  406.         char pgchr;     /* page number character, init = '#'    */
  407.         char cmdchr;    /* command character, init = '.'        */
  408.         int prflg;      /* print on or off, init = TRUE         */
  409.         int sprdir;     /* direction for spread(), init = 0     */
  410.         int flevel;     /* nesting depth for source cmd, init = 0 */
  411.         int nr[26];     /* number registers     */
  412. };
  413.  
  414.  
  415. /* output buffer control parameters */
  416.  
  417. struct cout {
  418.         int outp;       /* next avail char position in outbuf, init = 0 */
  419.         int outw;       /* width of text currently in buffer    */
  420.         int outwds;     /* number of words in buffer, init = 0  */
  421.         int lpr;        /* output to printer, init = FALSE      */
  422.         char outbuf[MAXLINE];   /* output of filled text        */
  423. };
  424.  
  425. /* page control parameters for nro */
  426.  
  427. struct page {
  428.         int curpag;     /* current output page number, init =0  */
  429.         int newpag;     /* next output page number, init = 1    */
  430.         int lineno;     /* next line to be printed, init = 0    */
  431.         int plval;      /* page length in lines, init = 66      */
  432.         int m1val;      /* margin before and including header   */
  433.         int m2val;      /* margin after header                  */
  434.         int m3val;      /* margin after last text line          */
  435.         int m4val;      /* bottom margin, including footer      */
  436.         int bottom;     /* last live line on page
  437.                                         = plval - m3val - m4val */
  438.         int offset;     /* page offset from left, init = 0      */
  439.         int frstpg;     /* first page to print, init = 0        */
  440.         int lastpg;     /* last page to print, init = 30000     */
  441.         int ehlim[2];   /* left/right margins for headers/footers       */
  442.         int ohlim[2];   /* init = 0 and PAGEWIDTH                       */
  443.         int eflim[2];
  444.         int oflim[2];
  445.         char ehead[MAXLINE];    /* top of page title, init = '\n'       */
  446.         char ohead[MAXLINE];
  447.         char efoot[MAXLINE];    /* bottom of page title, init = '\n'    */
  448.         char ofoot[MAXLINE];
  449. };
  450.  
  451. char *getmac();
  452.  
  453.  
  454. ***********
  455.    \nrocmd.c/
  456. ***********
  457. /*
  458.  *      Command processor for NRO text processor
  459.  *
  460.  *      Stephen L. Browning
  461.  *      5723 North Parker Avenue
  462.  *      Indianapolis, Indiana 46220
  463.  */
  464.  
  465. #include <stdio.h>
  466. #include "nro.h"
  467. #include "nroxtrn.c"
  468.  
  469. char *skipbl();
  470. char *skipwd();
  471.  
  472. comand(p)
  473. char *p;
  474. {
  475.         int ct, val;
  476.         int spval;
  477.         int index;
  478.         char argtyp;
  479.         char name[MAXLINE];
  480.         char macexp[MXMLEN];
  481.  
  482.         ct = comtyp(p,macexp);
  483.         if (ct == UNKNOWN) {
  484.                 printf("*** nro: unrecognized command %s\n",p);
  485.                 return;
  486.         }
  487.         expesc(p,name);
  488.         val = getval(p,&argtyp);
  489.         switch (ct) {
  490.         case BO: /* bold face */
  491.                 set(&dc.boval,val,argtyp,1,0,HUGE);
  492.                 dc.cuval = dc.ulval = 0;
  493.                 break;
  494.         case BP: /* begin page */
  495.                 if(pg.lineno > 0) space(HUGE);
  496.                 set(&pg.curpag,val,argtyp,pg.curpag+1,-HUGE,HUGE);
  497.                 pg.newpag = pg.curpag;
  498.                 break;
  499.         case BR: /* break */
  500.                 brk();
  501.                 break;
  502.         case BS: /* backspaces in output */
  503.                 set(&dc.bsflg,val,argtyp,1,0,1);
  504.                 break;
  505.         case CC: /* command character */
  506.                 if (argtyp == '\r' || argtyp == '\n') dc.cmdchr = '.';
  507.                 else dc.cmdchr = argtyp;
  508.                 break;
  509.         case CE: /* center */
  510.                 brk();
  511.                 set(&dc.ceval,val,argtyp,1,0,HUGE);
  512.                 break;
  513.         case CU: /* continuous underline */
  514.                 set(&dc.cuval,val,argtyp,1,0,HUGE);
  515.                 dc.ulval = dc.boval = 0;
  516.                 break;
  517.         case DE: /* define macro */
  518.                 defmac(p,sofile[dc.flevel]);
  519.                 break;
  520.         case EF: /* even footer */
  521.                 gettl(p,pg.efoot,&pg.eflim[0]);
  522.                 break;
  523.         case EH: /* even header */
  524.                 gettl(p,pg.ehead,&pg.ehlim[0]);
  525.                 break;
  526.         case EN: /* end macro definition */
  527.                 puts("***nro: missing .de command\n");
  528.                 break;
  529.         case FI: /* fill */
  530.                 brk();
  531.                 dc.fill = YES;
  532.                 break;
  533.         case FO: /* footer */
  534.                 gettl(p,pg.efoot,&pg.eflim[0]);
  535.                 gettl(p,pg.ofoot,&pg.oflim[0]);
  536.                 break;
  537.         case HE: /* header */
  538.                 gettl(p,pg.ehead,&pg.ehlim[0]);
  539.                 gettl(p,pg.ohead,&pg.ohlim[0]);
  540.                 break;
  541.         case IN: /* indenting */
  542.                 set(&dc.inval,val,argtyp,0,0,dc.rmval-1);
  543.                 dc.tival = dc.inval;
  544.                 break;
  545.         case JU: /* justify */
  546.                 dc.juval = YES;
  547.                 break;
  548.         case LS: /* line spacing */
  549.                 set(&dc.lsval,val,argtyp,1,1,HUGE);
  550.                 break;
  551.         case M1: /* set topmost margin */
  552.                 set(&pg.m1val,val,argtyp,2,0,HUGE);
  553.                 break;
  554.         case M2: /* set second top margin */
  555.                 set(&pg.m2val,val,argtyp,2,0,HUGE);
  556.                 break;
  557.         case M3: /* set first bottom margin */
  558.                 set(&pg.m3val,val,argtyp,2,0,HUGE);
  559.                 pg.bottom = pg.plval - pg.m4val - pg.m3val;
  560.                 break;
  561.         case M4: /* set bottom-most margin */
  562.                 set(&pg.m4val,val,argtyp,2,0,HUGE);
  563.                 pg.bottom = pg.plval - pg.m4val - pg.m3val;
  564.                 break;
  565.         case MACRO: /* macro expansion */
  566.                 maceval(p,macexp);
  567.                 break;
  568.         case NE: /* need n lines */
  569.                 brk();
  570.                 if ((pg.bottom-pg.lineno+1) < (val*dc.lsval)) {
  571.                         space(HUGE);
  572.                 }
  573.                 break;
  574.         case NF: /* no fill */
  575.                 brk();
  576.                 dc.fill = NO;
  577.                 break;
  578.         case NJ: /* no justify */
  579.                 dc.juval = NO;
  580.                 break;
  581.         case NR: /* set number register */
  582.                 p = skipwd(p);
  583.                 p = skipbl(p);
  584.                 if (!isalpha(*p)) {
  585.                         puts("***nro: invalid or missing number register name\n");
  586.                 }
  587.                 else {
  588.                         index = newlower(*p) - 'a';
  589.                         p = skipwd(p);
  590.                         val = getval(p,&argtyp);
  591.                         set(&dc.nr[index],val,argtyp,0,-HUGE,HUGE);
  592.                 }
  593.                 break;
  594.         case OF: /* odd footer */
  595.                 gettl(p,pg.ofoot,&pg.oflim[0]);
  596.                 break;
  597.         case OH: /* odd header */
  598.                 gettl(p,pg.ohead,&pg.ohlim[0]);
  599.                 break;
  600.         case PC: /* page number character */
  601.                 if (argtyp == '\r' || argtyp == '\n') dc.pgchr = EOS;
  602.                 else dc.pgchr = argtyp;
  603.                 break;
  604.         case PL: /* page length */
  605.                 set(&pg.plval,val,argtyp,PAGELEN,
  606.                         pg.m1val+pg.m2val+pg.m3val+pg.m4val+1,HUGE);
  607.                 pg.bottom = pg.plval - pg.m3val - pg.m4val;
  608.                 break;
  609.         case PO: /* page offset */
  610.                 set(&pg.offset,val,argtyp,0,0,HUGE);
  611.                 break;
  612.         case RM: /* right margin */
  613.                 set(&dc.rmval,val,argtyp,PAGEWIDTH,dc.tival+1,HUGE);
  614.                 break;
  615.         case SO: /* source file */
  616.                 p = skipwd(p);
  617.                 p = skipbl(p);
  618.                 if (getwrd(p,name) == 0) break;
  619.                 if (dc.flevel+1 >= NFILES) {
  620.                         puts("***nro: .so commands nested too deeply\n");
  621.                         exit(-1);
  622.                 }
  623.                 if ((sofile[dc.flevel+1] = fopen(name,"r")) == NULL) {
  624.                         printf("***nro: unable to open %s\n",name);
  625.                         exit(-1);
  626.                 }
  627.                 ++dc.flevel;
  628.                 break;
  629.         case SP: /* space */
  630.                 set(&spval,val,argtyp,1,0,HUGE);
  631.                 space(spval);
  632.                 break;
  633.         case TI: /* temporary indent */
  634.                 brk();
  635.                 set(&dc.tival,val,argtyp,0,0,dc.rmval);
  636.                 break;
  637.         case UL: /* underline */
  638.                 set(&dc.ulval,val,argtyp,0,1,HUGE);
  639.                 dc.cuval = dc.boval = 0;
  640.                 break;
  641.         }
  642. }
  643.  
  644.  
  645.  
  646. /*
  647.  *      convert ascii character to decimal.
  648.  */
  649.  
  650. atod(c)
  651. char c;
  652. {
  653.         return(((c < '0') || (c > '9')) ? -1 : c-'0');
  654. }
  655.  
  656.  
  657.  
  658. /*
  659.  *      end current filled line
  660.  */
  661.  
  662. brk()
  663. {
  664.         if(co.outp > 0) {
  665.                 co.outbuf[co.outp] = '\r';
  666.                 co.outbuf[co.outp + 1] = '\n';
  667.                 co.outbuf[co.outp + 2] = EOS;
  668.                 put(co.outbuf);
  669.         }
  670.         co.outp = 0;
  671.         co.outw = 0;
  672.         co.outwds = 0;
  673. }
  674.  
  675.  
  676. /*
  677.  *      Collect macro definition from input stream
  678.  */
  679.  
  680. colmac(p,d,i)
  681. char *p, d[];
  682. int i;
  683. {
  684.         while (*p != EOS) {
  685.                 if (i >= MXMLEN-1) {
  686.                         d[i-1] = EOS;
  687.                         return(ERR);
  688.                 }
  689.                 d[i++] = *p++;
  690.         }
  691.         d[i] = EOS;
  692.         return(i);
  693. }
  694.  
  695.  
  696.  
  697.  
  698. /*
  699.  *      decodes nro command and returns its associated
  700.  *      value.
  701.  */
  702.  
  703. comtyp(p,m)
  704. char *p;
  705. char *m;
  706. {
  707.         char c1, c2;
  708.         char macnam[MNLEN];
  709.         char *s;
  710.  
  711.         p++;
  712.         /*
  713.         *       First check to see if the command is a macro.
  714.         *       If it is, truncate to two characters and return
  715.         *       expansion in m.  Note that upper and lower case
  716.         *       characters are handled differently for macro names,
  717.         *       but not for normal command names.
  718.         */
  719.         getwrd(p,macnam);
  720.         macnam[2] = EOS;
  721.         if ((s = getmac(macnam)) != NULL) {
  722.                 strcpy(m,s);
  723.                 return(MACRO);
  724.         }
  725.         c1 = newlower(*p++);
  726.         c2 = newlower(*p);
  727.         if (c1 == 'b' && c2 == 'o') return(BO);
  728.         if (c1 == 'b' && c2 == 'p') return(BP);
  729.         if (c1 == 'b' && c2 == 'r') return(BR);
  730.         if (c1 == 'b' && c2 == 's') return(BS);
  731.         if (c1 == 'c' && c2 == 'c') return(CC);
  732.         if (c1 == 'c' && c2 == 'e') return(CE);
  733.         if (c1 == 'c' && c2 == 'u') return(CU);
  734.         if (c1 == 'd' && c2 == 'e') return(DE);
  735.         if (c1 == 'e' && c2 == 'f') return(EF);
  736.         if (c1 == 'e' && c2 == 'h') return(EH);
  737.         if (c1 == 'e' && c2 == 'n') return(EN);
  738.         if (c1 == 'f' && c2 == 'i') return(FI);
  739.         if (c1 == 'f' && c2 == 'o') return(FO);
  740.         if (c1 == 'h' && c2 == 'e') return(HE);
  741.         if (c1 == 'i' && c2 == 'n') return(IN);
  742.         if (c1 == 'j' && c2 == 'u') return(JU);
  743.         if (c1 == 'l' && c2 == 's') return(LS);
  744.         if (c1 == 'm' && c2 == '1') return(M1);
  745.         if (c1 == 'm' && c2 == '2') return(M2);
  746.         if (c1 == 'm' && c2 == '3') return(M3);
  747.         if (c1 == 'm' && c2 == '4') return(M4);
  748.         if (c1 == 'n' && c2 == 'e') return(NE);
  749.         if (c1 == 'n' && c2 == 'f') return(NF);
  750.         if (c1 == 'n' && c2 == 'j') return(NJ);
  751.         if (c1 == 'n' && c2 == 'r') return(NR);
  752.         if (c1 == 'o' && c2 == 'f') return(OF);
  753.         if (c1 == 'o' && c2 == 'h') return(OH);
  754.         if (c1 == 'p' && c2 == 'c') return(PC);
  755.         if (c1 == 'p' && c2 == 'l') return(PL);
  756.         if (c1 == 'p' && c2 == 'o') return(PO);
  757.         if (c1 == 'r' && c2 == 'm') return(RM);
  758.         if (c1 == 's' && c2 == 'o') return(SO);
  759.         if (c1 == 's' && c2 == 'p') return(SP);
  760.         if (c1 == 't' && c2 == 'i') return(TI);
  761.         if (c1 == 'u' && c2 == 'l') return(UL);
  762.         return(UNKNOWN);
  763. }
  764.  
  765.  
  766.  
  767. /*
  768.  *      convert string to decimal.
  769.  *      processes only positive values.
  770.  */
  771.  
  772. ctod(p)
  773. char *p;
  774. {
  775.         int val, d;
  776.  
  777.         val = 0;
  778.         while(*p != EOS) {
  779.                 d = atod(*p++);
  780.                 if(d == -1) return(val);
  781.                 val = 10 * val + d;
  782.         }
  783.         return(val);
  784. }
  785.  
  786.  
  787. /*
  788.  *      Define a macro
  789.  */
  790.  
  791. defmac(p,infp)
  792. char *p;
  793. FILE *infp;
  794. {
  795.         int i;
  796.         char name[MNLEN];
  797.         char defn[MXMLEN];
  798.         char *q;
  799.  
  800.         q = skipwd(p);
  801.         q = skipbl(q);
  802.         i = getwrd(q,name);
  803.         if (!isalpha(*name)) {
  804.                 puts("***nro: missing or illegal macro definition name\n");
  805.                 exit(-1);
  806.         }
  807.         if (i > 2) name[2] = EOS;
  808.         i = 0;
  809.         while (getlin(p,infp) != EOF) {
  810.                 if (p[0] == dc.cmdchr && newlower(p[1]) == 'e' && newlower(p[2]) == 'n') {
  811.                         break;
  812.                 }
  813.                 if ((i = colmac(p,defn,i)) == ERR) {
  814.                         puts("***nro: macro definition too long\n");
  815.                         exit(-1);
  816.                 }
  817.         }
  818.         if (putmac(name,defn) == ERR) {
  819.                 puts("***nro: macro definition table full\n");
  820.                 exit(-1);
  821.         }
  822. }
  823.  
  824.  
  825. /*
  826.  *      Expand escape sequences
  827.  */
  828.  
  829. expesc(p,q)
  830. char *p;
  831. char *q;
  832. {
  833.         char *s, *t;
  834.  
  835.         s = p;
  836.         t = q;
  837.         while (*s != EOS) {
  838.                 if (*s != '@') {
  839.                         *t++ = *s++;
  840.                 }
  841.                 else if (*(s+1) == '@') {
  842.                         *t++ = *s++;
  843.                         ++s;
  844.                 }
  845.                 else if (newlower(*(s+1)) == 'n' && isalpha(*(s+2))) {
  846.                         s += 2;
  847.                         t += itoda(dc.nr[newlower(*s)-'a'],t,6) - 1;
  848.                         ++s;
  849.                 }
  850.                 else {
  851.                         *t++ = *s++;
  852.                 }
  853.         }
  854.         *t = EOS;
  855.         strcpy(p,q);
  856. }
  857.  
  858.  
  859.  
  860. /*
  861.  *      Get macro definition from table
  862.  */
  863.  
  864. char *getmac(name)
  865. char *name;
  866. {
  867.         int i;
  868.  
  869.         for (i = mac.lastp; i >= 0; --i) {
  870.                 if (!strcmp(name,mac.mnames[i])) {
  871.                         return(mac.mnames[i] + 3);
  872.                 }
  873.         }
  874.         return(NULL);
  875. }
  876.  
  877.  
  878.  
  879.  
  880. /*
  881.  *      get header or footer title
  882.  */
  883.  
  884. gettl(p,q,limit)
  885. char *p;
  886. char *q;
  887. int limit[];
  888. {
  889.         p = skipwd(p);
  890.         p = skipbl(p);
  891.         strcpy(q,p);
  892.         limit[LEFT] = dc.inval;
  893.         limit[RIGHT] = dc.rmval;
  894. }
  895.  
  896.  
  897.  
  898. /*
  899.  *      retrieves optional argument following nro command.
  900.  *      returns positive integer value with sign (if any)
  901.  *      saved in character addressed by p_argt.
  902.  */
  903.  
  904. getval(p,p_argt)
  905. char *p;
  906. char *p_argt;
  907. {
  908.         p = skipwd(p);
  909.         p = skipbl(p);
  910.         *p_argt = *p;
  911.         if((*p == '+') || (*p == '-')) ++p;
  912.         return(ctod(p));
  913. }
  914.  
  915.  
  916. /*
  917.  *      Evaluate macro expansion
  918.  */
  919.  
  920. maceval(p,m)
  921. char *p;
  922. char m[];
  923. {
  924.         int i, j;
  925.         char *argp[10];
  926.         char c;
  927.  
  928.         *p++ = EOS;             /* replace command char with EOS */
  929.         /*
  930.         *       initialize argp array to substitute command
  931.         *       string for any undefined argument
  932.         */
  933.         for (i=0; i<10; ++i) argp[i] = p;
  934.         p = skipwd(p);
  935.         *p++ = EOS;
  936.         for (i=0; i<10; ++i) {
  937.                 p = skipbl(p);
  938.                 if (*p == '\r' || *p == '\n' || *p == EOS) break;
  939.                 if (*p == '\'' || *p == '"') {
  940.                         c = *p++;
  941.                         argp[i] = p;
  942.                         while (*p != c && *p != '\r' && *p != '\n' && *p != EOS) ++p;
  943.                         *p++ = EOS;
  944.                 }
  945.                 else {
  946.                         argp[i] = p;
  947.                         p = skipwd(p);
  948.                         *p++ = EOS;
  949.                 }
  950.         }
  951.         for (i=strlen(m)-1; i>=0; --i) {
  952.                 if (i > 0 && m[i-1] == '$') {
  953.                         if (!isdigit(m[i])) {
  954.                                 putbak(m[i]);
  955.                         }
  956.                         else {
  957.                                 pbstr(argp[m[i]-'0']);
  958.                                 --i;
  959.                         }
  960.                 }
  961.                 else {
  962.                         putbak(m[i]);
  963.                 }
  964.         }
  965. }
  966.  
  967.  
  968. /*
  969.  *      Push back string into input stream
  970.  */
  971.  
  972. pbstr(p)
  973. char p[];
  974. {
  975.         int i;
  976.  
  977.         for (i=strlen(p)-1; i>=0; --i) {
  978.                 putbak(p[i]);
  979.         }
  980. }
  981.  
  982.  
  983.  
  984. /*
  985.  *      Push character back into input stream
  986.  */
  987.  
  988. putbak(c)
  989. char c;
  990. {
  991.         if (mac.ppb < &mac.pbb[0]) {
  992.                 mac.ppb = &mac.pbb[0];
  993.                 *mac.ppb = c;
  994.         }
  995.         else {
  996.                 if (mac.ppb >= &mac.pbb[MAXLINE-1]) {
  997.                         puts("***nro: push back buffer overflow\n");
  998.                         exit(-1);
  999.                 }
  1000.                 *++mac.ppb = c;
  1001.         }
  1002. }
  1003.  
  1004.  
  1005.  
  1006.  
  1007. /*
  1008.  *      Put macro definition into table
  1009.  */
  1010.  
  1011. putmac(name,p)
  1012. char *name;
  1013. char *p;
  1014. {
  1015.         if (mac.lastp >= MXMDEF) return(ERR);
  1016.         if (mac.emb + strlen(name) + strlen(p) + 1 > &mac.mb[MACBUF]) {
  1017.                 return(ERR);
  1018.         }
  1019.         ++mac.lastp;
  1020.         mac.mnames[mac.lastp] = mac.emb;
  1021.         strcpy(mac.emb,name);
  1022.         strcpy(mac.emb + strlen(name) + 1,p);
  1023.         mac.emb += strlen(name) + strlen(p) + 2;
  1024.         return(OK);
  1025. }
  1026.  
  1027.  
  1028.  
  1029.  
  1030. /*
  1031.  *      set parameter and check range
  1032.  */
  1033.  
  1034. set(param,val,type,defval,minval,maxval)
  1035. int *param;
  1036. int val;
  1037. char type;
  1038. int defval,minval,maxval;
  1039. {
  1040.         switch(type) {
  1041.         case '\r':
  1042.         case '\n':
  1043.                 *param = defval;
  1044.                 break;
  1045.         case '+':
  1046.                 *param += val;
  1047.                 break;
  1048.         case '-':
  1049.                 *param -= val;
  1050.                 break;
  1051.         default:
  1052.                 *param = val;
  1053.                 break;
  1054.         }
  1055.         *param = min(*param,maxval);
  1056.         *param = max(*param,minval);
  1057. }
  1058.  
  1059.  
  1060.  
  1061. /*
  1062.  *      skip blanks and tabs in character buffer.
  1063.  *      return number of characters skipped.
  1064.  */
  1065.  
  1066. char *skipbl(p)
  1067. char *p;
  1068. {
  1069.         while (*p == ' ' || *p == '\t') ++p;
  1070.         return(p);
  1071. }
  1072.  
  1073.  
  1074. /*
  1075.  *      skip over word and punctuation
  1076.  */
  1077.  
  1078. char *skipwd(p)
  1079. char *p;
  1080. {
  1081.         while (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != EOS)
  1082.                 ++p;
  1083.         return(p);
  1084. }
  1085.  
  1086.  
  1087.  
  1088. /*
  1089.  *      space vertically n lines
  1090.  */
  1091.  
  1092. space(n)
  1093. int n;
  1094. {
  1095.         brk();
  1096.         if (pg.lineno > pg.bottom) return;
  1097.         if (pg.lineno == 0) phead();
  1098.         skip(min(n,pg.bottom+1-pg.lineno));
  1099.         pg.lineno += n;
  1100.         if (pg.lineno > pg.bottom) pfoot();
  1101. }
  1102.  
  1103. **********
  1104.    \nrotxt.c/
  1105. **********
  1106. /*
  1107.  *      Text processing portion of NRO word processor
  1108.  *
  1109.  *      Stephen L. Browning
  1110.  *      5723 North Parker Avenue
  1111.  *      Indianapolis, Indiana 46220
  1112.  */
  1113.  
  1114. #include <stdio.h>
  1115. #include "nro.h"
  1116. #include "nroxtrn.c"
  1117.  
  1118. text(p)
  1119. char *p;
  1120. {
  1121.         int i;
  1122.         char wrdbuf[MAXLINE];
  1123.  
  1124.         if (*p == ' ' || *p == '\n' || *p == '\r') leadbl(p);
  1125.         expesc(p,wrdbuf);
  1126.         if (dc.ulval > 0) {
  1127.                 /*
  1128.                 *       Because of the way underlining is handled,
  1129.                 *       MAXLINE should be declared to be three times
  1130.                 *       larger than the longest expected input line
  1131.                 *       for underlining.  Since many of the character
  1132.                 *       buffers use this parameter, a lot of memory
  1133.                 *       can be allocated when it may not really be
  1134.                 *       needed.  A MAXLINE of 180 would allow about
  1135.                 *       60 characters in the output line to be
  1136.                 *       underlined (remember that only alphanumerics
  1137.                 *       get underlined - no spaces or punctuation).
  1138.                 */
  1139.                 underl(p,wrdbuf,MAXLINE);
  1140.                 --dc.ulval;
  1141.         }
  1142.         if (dc.cuval > 0) {
  1143.                 underl(p,wrdbuf,MAXLINE);
  1144.                 --dc.cuval;
  1145.         }
  1146.         if (dc.boval > 0) {
  1147.                 bold(p,wrdbuf,MAXLINE);
  1148.                 --dc.boval;
  1149.         }
  1150.         if (dc.ceval > 0) {
  1151.                 center(p);
  1152.                 put(p);
  1153.                 --dc.ceval;
  1154.         }
  1155.         else if (*p == '\r' || *p == '\n') put(p); /* all blank line */
  1156.         else if (dc.fill == NO) put(p);         /* unfilled */
  1157.         else {
  1158.                 while ((i = getwrd(p,wrdbuf)) > 0) {
  1159.                         putwrd(wrdbuf);
  1160.                         p += i;
  1161.                 }
  1162.         }
  1163. }
  1164.  
  1165.  
  1166. /*
  1167.  *      insert bold face text
  1168.  */
  1169.  
  1170. bold(p0,p1,size)
  1171. char *p0, *p1;
  1172. int size;
  1173. {
  1174.         int i, j;
  1175.  
  1176.         j = 0;
  1177.         for (i=0; (p0[i] != '\n') && (j < size-1); ++i) {
  1178.                 if (isalpha(p0[i]) || isdigit(p0[i])) {
  1179.                         p1[j++] = p0[i];
  1180.                         p1[j++] = '\b';
  1181.                 }
  1182.                 p1[j++] = p0[i];
  1183.         }
  1184.         p1[j++] = '\n';
  1185.         p1[j] = EOS;
  1186.         while (*p1 != EOS) *p0++ = *p1++;
  1187.         *p0 = EOS;
  1188. }
  1189.  
  1190.  
  1191.  
  1192.  
  1193. /*
  1194.  *      center a line by setting tival
  1195.  */
  1196.  
  1197. center(p)
  1198. char *p;
  1199. {
  1200.         dc.tival = max((dc.rmval + dc.tival - width(p)) >> 1,0);
  1201. }
  1202.  
  1203.  
  1204. /*
  1205.  *      expand title buffer to include character string
  1206.  */
  1207.  
  1208. expand(p0,c,s)
  1209. char *p0;
  1210. char c;
  1211. char *s;
  1212. {
  1213.         char tmp[MAXLINE];
  1214.         char *p, *q, *r;
  1215.  
  1216.         p = p0;
  1217.         q = tmp;
  1218.         while (*p != EOS) {
  1219.                 if (*p == c) {
  1220.                         r = s;
  1221.                         while (*r != EOS) *q++ = *r++;
  1222.                 }
  1223.                 else *q++ = *p;
  1224.                 ++p;
  1225.         }
  1226.         *q = EOS;
  1227.         strcpy(p0,tmp);         /* copy it back */
  1228. }
  1229.  
  1230.  
  1231. /*
  1232.  *      get field from title
  1233.  */
  1234.  
  1235. char *getfield(p,q,delim)
  1236. char *p, *q;
  1237. char delim;
  1238. {
  1239.         while (*p != delim && *p != '\r' && *p != '\n' && *p != EOS) {
  1240.                 *q++ = *p++;
  1241.         }
  1242.         *q = EOS;
  1243.         if (*p == delim) ++p;
  1244.         return(p);
  1245. }
  1246.  
  1247.  
  1248.  
  1249. /*
  1250.  *      get non-blank word from p0 into p1.
  1251.  *      return number of characters processed.
  1252.  */
  1253.  
  1254. getwrd(p0,p1)
  1255. char *p0,*p1;
  1256. {
  1257.         int i;
  1258.         char *p, c;
  1259.  
  1260.         i = 0;
  1261.         while (*p0 == ' ' || *p0 == '\t') {
  1262.                 ++i;
  1263.                 ++p0;
  1264.         }
  1265.         p = p0;
  1266.         while (*p0 != ' ' && *p0 != EOS && *p0 != '\t') {
  1267.                 if (*p0 == '\n' || *p0 == '\r') break;
  1268.                 *p1 = *p0++;
  1269.                 ++p1;
  1270.                 ++i;
  1271.         }
  1272.         c = *(p1-1);
  1273.         if (c == '"') c = *(p1-2);
  1274.         if (c == '?' || c == '!') {
  1275.                 *p1++ = ' ';
  1276.                 ++i;
  1277.         }
  1278.         if (c == '.' && (*p0 == '\n' || *p0 == '\r' || islower(*p))) {
  1279.                 *p1++ = ' ';
  1280.                 ++i;
  1281.         }
  1282.         *p1 = EOS;
  1283.         return(i);
  1284. }
  1285.  
  1286.  
  1287. /*
  1288.  *      convert integer to decimal ascii string
  1289.  */
  1290.  
  1291. itoda(value,p,size)
  1292. int value;
  1293. char *p;
  1294. int size;
  1295. {
  1296.         char c[7];
  1297.         int i, j, k;
  1298.         int aval;
  1299.  
  1300.         aval = abs(value);
  1301.         c[0] = EOS;
  1302.         i = 1;
  1303.         do {
  1304.                 c[i++] = (aval % 10) + '0';
  1305.                 aval /= 10;
  1306.         } while (aval > 0 && i <= size);
  1307.         if (value < 0 && i <= size) c[i++] = '-';
  1308.         for (j=0; j<i; ++j) *p++ = c[i-j-1];
  1309.         return(i);
  1310. }
  1311.  
  1312.  
  1313. /*
  1314.  *      center title text into print buffer
  1315.  */
  1316.  
  1317. justcntr(p,q,limit)
  1318. char *p, *q;
  1319. int limit[];
  1320. {
  1321.         int len;
  1322.  
  1323.         len = width(p);
  1324.         q = &q[(limit[RIGHT] + limit[LEFT] - len) >> 1];
  1325.         while (*p != EOS) *q++ = *p++;
  1326. }
  1327.  
  1328.  
  1329.  
  1330. /*
  1331.  *      left justify title text into print buffer
  1332.  */
  1333.  
  1334. justleft(p,q,limit)
  1335. char *p, *q;
  1336. int limit;
  1337. {
  1338.         q = &q[limit];
  1339.         while (*p != EOS) *q++ = *p++;
  1340. }
  1341.  
  1342.  
  1343. /*
  1344.  *      right justify title text into print buffer
  1345.  */
  1346.  
  1347. justrite(p,q,limit)
  1348. char *p, *q;
  1349. int limit;
  1350. {
  1351.         int len;
  1352.  
  1353.         len = width(p);
  1354.         q = &q[limit - len];
  1355.         while (*p != EOS) *q++ = *p++;
  1356. }
  1357.  
  1358.  
  1359.  
  1360.  
  1361. /*
  1362.  *      delete leading blanks, set tival
  1363.  */
  1364.  
  1365. leadbl(p)
  1366. char *p;
  1367. {
  1368.         int i,j;
  1369.  
  1370.         brk();
  1371.         for (i=0; p[i] == ' '; ++i) ;
  1372.         if (p[i] != '\n' && p[i] != '\r') dc.tival = i;
  1373.         for (j=0; p[i] != EOS; ++j) p[j] = p[i++];
  1374.         p[j] = EOS;
  1375. }
  1376.  
  1377.  
  1378.  
  1379. /*
  1380.  *      find minimum of two integer
  1381.  */
  1382.  
  1383. min(v1,v2)
  1384. int v1,v2;
  1385. {
  1386.         return((v1 < v2) ? v1 : v2);
  1387. }
  1388.  
  1389.  
  1390.  
  1391. /*
  1392.  *      find maximum of two integers
  1393.  */
  1394.  
  1395. max(v1,v2)
  1396. int v1,v2;
  1397. {
  1398.         return((v1 > v2) ? v1 : v2);
  1399. }
  1400.  
  1401.  
  1402.  
  1403. /*
  1404.  *      put out page footer
  1405.  */
  1406.  
  1407. pfoot()
  1408. {
  1409.         if (dc.prflg == TRUE) {
  1410.                 skip(pg.m3val);
  1411.                 if (pg.m4val > 0) {
  1412.                         if ((pg.curpag % 2) == 0) {
  1413.                                 puttl(pg.efoot,pg.eflim,pg.curpag);
  1414.                         }
  1415.                         else {
  1416.                                 puttl(pg.ofoot,pg.oflim,pg.curpag);
  1417.                         }
  1418.                         skip(pg.m4val - 1);
  1419.                 }
  1420.         }
  1421. }
  1422.  
  1423.  
  1424.  
  1425. /*
  1426.  *      put out page header
  1427.  */
  1428.  
  1429. phead()
  1430. {
  1431.         pg.curpag = pg.newpag;
  1432.         if (pg.curpag >= pg.frstpg && pg.curpag <= pg.lastpg) {
  1433.                 dc.prflg = TRUE;
  1434.         }
  1435.         else {
  1436.                 dc.prflg = FALSE;
  1437.         }
  1438.         ++pg.newpag;
  1439.         if (dc.prflg == TRUE) {
  1440.                 if (pg.m1val > 0) {
  1441.                         skip(pg.m1val - 1);
  1442.                         if ((pg.curpag % 2) == 0) {
  1443.                                 puttl(pg.ehead,pg.ehlim,pg.curpag);
  1444.                         }
  1445.                         else {
  1446.                                 puttl(pg.ohead,pg.ohlim,pg.curpag);
  1447.                         }
  1448.                 }
  1449.                 skip(pg.m2val);
  1450.         }
  1451.         /*
  1452.         *       initialize lineno for the next page
  1453.         */
  1454.         pg.lineno = pg.m1val + pg.m2val + 1;
  1455. }
  1456.  
  1457.  
  1458. /*
  1459.  *      print character with test for printer
  1460.  */
  1461.  
  1462. prchar(c,fp)
  1463. char c;
  1464. FILE *fp;
  1465. {
  1466.         if (co.lpr == TRUE) {
  1467.                 bdos(5,c);
  1468.         }
  1469.         else {
  1470.                 putc(c,fp);
  1471.         }
  1472. }
  1473.  
  1474.  
  1475.  
  1476.  
  1477. /*
  1478.  *      put out line with proper spacing and indenting
  1479.  */
  1480.  
  1481. put(p)
  1482. char *p;
  1483. {
  1484.         char os[MAXLINE];
  1485.         int j;
  1486.  
  1487.         if (pg.lineno == 0 || pg.lineno > pg.bottom) {
  1488.                 phead();
  1489.         }
  1490.         if (dc.prflg == TRUE) {
  1491.                 if (!dc.bsflg) {
  1492.                         if (strkovr(p,os) == TRUE) {
  1493.                                 for (j=0; j<pg.offset; ++j) prchar(' ',pout);
  1494.                                 for (j=0; j<dc.tival; ++j) prchar(' ',pout);
  1495.                                 putlin(os,pout);
  1496.                         }
  1497.                 }
  1498.                 for (j=0; j<pg.offset; ++j) prchar(' ',pout);
  1499.                 for (j=0; j<dc.tival; ++j) prchar(' ',pout);
  1500.                 putlin(p,pout);
  1501.         }
  1502.         dc.tival = dc.inval;
  1503.         skip(min(dc.lsval-1,pg.bottom-pg.lineno));
  1504.         pg.lineno = pg.lineno + dc.lsval;
  1505.         if (pg.lineno > pg.bottom) pfoot();
  1506. }
  1507.  
  1508.  
  1509. /*
  1510.  *      output a null terminated string to the file
  1511.  *      specified by pbuf.
  1512.  */
  1513.  
  1514. putlin(p,pbuf)
  1515. char *p;
  1516. struct buf *pbuf;
  1517. {
  1518.         while (*p != EOS) prchar(*p++,pbuf);
  1519. }
  1520.  
  1521.  
  1522.  
  1523. /*
  1524.  *      put out title or footer
  1525.  */
  1526.  
  1527. puttl(p,lim,pgno)
  1528. char *p;
  1529. int lim[];
  1530. int pgno;
  1531. {
  1532.         int i;
  1533.         char pn[8];
  1534.         char t[MAXLINE];
  1535.         char h[MAXLINE];
  1536.         char delim;
  1537.  
  1538.         itoda(pgno,pn,6);
  1539.         for (i=0; i<MAXLINE; ++i) h[i] = ' ';
  1540.         delim = *p++;
  1541.         p = getfield(p,t,delim);
  1542.         expand(t,dc.pgchr,pn);
  1543.         justleft(t,h,lim[LEFT]);
  1544.         p = getfield(p,t,delim);
  1545.         expand(t,dc.pgchr,pn);
  1546.         justcntr(t,h,lim);
  1547.         p = getfield(p,t,delim);
  1548.         expand(t,dc.pgchr,pn);
  1549.         justrite(t,h,lim[RIGHT]);
  1550.         for (i=MAXLINE-4; h[i] == ' '; --i) h[i] = EOS;
  1551.         h[++i] = '\n';
  1552.         h[++i] = '\r';
  1553.         h[++i] = EOS;
  1554.         if (strlen(h) > 2) {
  1555.                 for (i=0; i<pg.offset; ++i) prchar(' ',pout);
  1556.         }
  1557.         putlin(h,pout);
  1558. }
  1559.  
  1560.  
  1561.  
  1562. /*
  1563.  *      put word in output buffer
  1564.  */
  1565.  
  1566. putwrd(wrdbuf)
  1567. char *wrdbuf;
  1568. {
  1569.         int w;
  1570.         int last;
  1571.         int llval;
  1572.         char *p0, *p1;
  1573.         int nextra;
  1574.  
  1575.         w = width(wrdbuf);
  1576.         last = strlen(wrdbuf) + co.outp;
  1577.         llval = dc.rmval - dc.tival;
  1578.         if(((co.outp > 0) && ((co.outw + w) > llval)) || (last > MAXLINE)) {
  1579.                 last -= co.outp;
  1580.                 if(dc.juval == YES) {
  1581.                         nextra = llval - co.outw + 1;
  1582.                         /*
  1583.                         *       Check whether last word was end of
  1584.                         *       sentence and modify counts so that
  1585.                         *       it is right justified.
  1586.                         */
  1587.                         if (co.outbuf[co.outp-2] == ' ') {
  1588.                                 --co.outp;
  1589.                                 ++nextra;
  1590.                         }
  1591.                         spread(co.outbuf,co.outp-1,nextra,co.outwds);
  1592.                         if((nextra > 0) && (co.outwds > 1)) {
  1593.                                 co.outp += (nextra - 1);
  1594.                         }
  1595.                 }
  1596.                 brk();
  1597.         }
  1598.         p0 = wrdbuf;
  1599.         p1 = co.outbuf + co.outp;
  1600.         while(*p0 != EOS) *p1++ = *p0++;
  1601.         co.outp = last;
  1602.         co.outbuf[co.outp++] = ' ';
  1603.         co.outw += w + 1;
  1604.         ++co.outwds;
  1605. }
  1606.  
  1607.  
  1608. /*
  1609.  *      skips the number of lines specified by n.
  1610.  */
  1611.  
  1612. skip(n)
  1613. int n;
  1614. {
  1615.         int i;
  1616.  
  1617.         if (dc.prflg == TRUE && n > 0) {
  1618.                 for(i=0; i<n; ++i) {
  1619.                         prchar('\n',pout);
  1620.                 }
  1621.                 prchar('\r',pout);
  1622.         }
  1623. }
  1624.  
  1625.  
  1626.  
  1627. /*
  1628.  *      spread words to justify right margin
  1629.  */
  1630.  
  1631. spread(p,outp,nextra,outwds)
  1632. char p[];
  1633. int outp,nextra,outwds;
  1634. {
  1635.         int i,j;
  1636.         int nb,ne,nholes;
  1637.  
  1638.         if((nextra <= 0) || (outwds <= 1)) return;
  1639.         dc.sprdir = ~dc.sprdir;
  1640.         ne = nextra;
  1641.         nholes = outwds - 1;    /* holes between words */
  1642.         i = outp - 1;   /* last non-blank character */
  1643.         j = min(MAXLINE-3,i+ne); /* leave room for CR, LF, EOS  */
  1644.         while(i < j) {
  1645.                 p[j] = p[i];
  1646.                 if(p[i] == ' ') {
  1647.                         if(dc.sprdir == 0) nb = (ne - 1)/nholes + 1;
  1648.                         else nb = ne/nholes;
  1649.                         ne -= nb;
  1650.                         --nholes;
  1651.                         for(; nb>0; --nb) {
  1652.                                 --j;
  1653.                                 p[j] = ' ';
  1654.                         }
  1655.                 }
  1656.                 --i;
  1657.                 --j;
  1658.         }
  1659. }
  1660.  
  1661.  
  1662.  
  1663. /*
  1664.  *      split overstrikes (backspaces) into seperate buffer
  1665.  */
  1666.  
  1667. strkovr(p,q)
  1668. char *p, *q;
  1669. {
  1670.         char *pp;
  1671.         int bsflg;
  1672.  
  1673.         bsflg = FALSE;
  1674.         pp = p;
  1675.         while (*p != EOS) {
  1676.                 *q = ' ';
  1677.                 *pp = *p;
  1678.                 ++p;
  1679.                 if (*p == '\b') {
  1680.                         if (*pp >= ' ' && *pp <= '~') {
  1681.                                 bsflg = TRUE;
  1682.                                 *q = *pp;
  1683.                                 ++p;
  1684.                                 *pp = *p;
  1685.                                 ++p;
  1686.                         }
  1687.                 }
  1688.                 ++q;
  1689.                 ++pp;
  1690.         }
  1691.         *q++ = '\r';
  1692.         *q = *pp = EOS;
  1693.         return(bsflg);
  1694. }
  1695.  
  1696.  
  1697.  
  1698. /*
  1699.  *      underline a line
  1700.  */
  1701.  
  1702. underl(p0,p1,size)
  1703. char *p0,*p1;
  1704. int size;
  1705. {
  1706.         int i,j;
  1707.  
  1708.         j = 0;
  1709.         for (i=0; (p0[i] != '\n') && (j < size-1); ++i) {
  1710.                 if (p0[i] >= ' ' && p0[i] <= '~') {
  1711.                         if (isalpha(p0[i]) || isdigit(p0[i]) || dc.cuval > 0) {
  1712.  
  1713.                                 p1[j++] = '_';
  1714.                                 p1[j++] = '\b';
  1715.                         }
  1716.                 }
  1717.                 p1[j++] = p0[i];
  1718.         }
  1719.         p1[j++] = '\n';
  1720.         p1[j] = EOS;
  1721.         while (*p1 != EOS) *p0++ = *p1++;
  1722.         *p0 = EOS;
  1723. }
  1724.  
  1725.  
  1726. /*
  1727.  *      compute width of character string
  1728.  */
  1729.  
  1730. width(s)
  1731. char *s;
  1732. {
  1733.         int w;
  1734.  
  1735.         w = 0;
  1736.         while (*s != EOS) {
  1737.                 if (*s == '\b') --w;
  1738.                 else if (*s != '\n' && *s != '\r') ++w;
  1739.                 ++s;
  1740.         }
  1741.         return(w);
  1742. }
  1743.  
  1744.  
  1745. *********
  1746.     \an.nro/
  1747. *********
  1748. .de TH
  1749. .in 5
  1750. .rm 75
  1751. .he |$0 ($1)|$2|$0 ($1)|
  1752. .fo ||-#-||
  1753. .in 10
  1754. .rm 70
  1755. .en
  1756. .de PP
  1757. .sp 1
  1758. .ti +5
  1759. .en
  1760. .de SH
  1761. .sp 1
  1762. .ti -5
  1763. .bo
  1764. $0
  1765. .br
  1766. .en
  1767. ********
  1768. \nrocom.c/
  1769. ********
  1770.  
  1771. /*
  1772.  *      external "common" for NRO word processor
  1773.  *
  1774.  *      Stephen L. Browning
  1775.  *      5723 North Parker Avenue
  1776.  *      Indianapolis, Indiana 46220
  1777.  */
  1778.  
  1779. struct docctl dc;
  1780. struct page pg;
  1781. FILE   *oub;
  1782. FILE   *pout;
  1783. struct cout co;
  1784. FILE   *sofile[NFILES]; /* input file buffers   */
  1785. struct macros mac;
  1786.  
  1787. char newlower(c)
  1788. char c;
  1789. {
  1790.     return (( c >= 'A' && c <= 'Z' ) ? ( c - 'A' + 'a' ) : c) ;
  1791. }
  1792.  
  1793. bdos(foo,bar)
  1794. int foo,bar;
  1795. {}
  1796.  
  1797.  
  1798. ********
  1799. \nroxtrn.c/
  1800. ********
  1801. /*
  1802.  *      external "common" for NRO word processor
  1803.  *
  1804.  *      Stephen L. Browning
  1805.  *      5723 North Parker Avenue
  1806.  *      Indianapolis, Indiana 46220
  1807.  */
  1808.  
  1809. extern struct docctl dc;
  1810. extern struct page pg;
  1811. extern FILE   *oub;
  1812. extern FILE   *pout;
  1813. extern struct cout co;
  1814. extern FILE   *sofile[NFILES];  /* input file buffers   */
  1815. extern struct macros mac;
  1816.  
  1817.  
  1818. *********
  1819. \nro.nro/
  1820. *********
  1821. .TH NRO 1 "Unix V7 Version"
  1822. .SH NAME
  1823. nro - text processor
  1824. .SH SYNOPSIS
  1825. .bo
  1826. nro [-n] [+n] [-pxx] [-v] [-b] [-mmfile] ifile ... [>ofile]
  1827. .SH DESCRIPTION
  1828. .ul
  1829. NRO
  1830. is a text processor and formatter based on the design
  1831. provided in 
  1832. .bo
  1833. "Software Tools"
  1834. by Kernighan and Plauger.
  1835. The text and commands found in the
  1836. .cu
  1837. ifile(s)
  1838. are processed to
  1839. generate formatted text.
  1840. The output may be directed into a file or to the printer if
  1841. .ul
  1842. ofile
  1843. is present
  1844. in the command line; otherwise, the output will appear at
  1845. the user console.
  1846. Directing the output to the special filename,
  1847. .bo
  1848. $P,
  1849. will cause the output to be sent to the printer.
  1850. .sp
  1851. The
  1852. .ul
  1853. +n
  1854. option causes the output to start with page
  1855. .ul
  1856. n.
  1857. The
  1858. .ul
  1859. -n
  1860. option causes the output to stop after page
  1861. .ul
  1862. n.
  1863. .sp
  1864. The
  1865. .ul
  1866. -v
  1867. option prints the version number to the console.
  1868. .sp
  1869. The
  1870. .ul
  1871. -p
  1872. option causes the output to be shifted to the right by
  1873. .ul
  1874. xx
  1875. spaces.
  1876. This has the same effect as the
  1877. .cc +
  1878. +bo
  1879. .po
  1880. command.
  1881. +cc .
  1882. .sp
  1883. The
  1884. .ul
  1885. -b
  1886. option allows backspaces to appear in the output text when
  1887. underlining or overstriking.
  1888. This has the same effect as the
  1889. .cc +
  1890. +bo
  1891. .bs
  1892. command with a non-zero argument.
  1893. +cc .
  1894. .sp
  1895. The
  1896. .ul
  1897. -m
  1898. option processes the file
  1899. .ul
  1900. mfile
  1901. for macro definitions.
  1902. Note that files processed in this way should contain only macro
  1903. definitions, no immediate output should be generated from this file.
  1904. .sp
  1905. Commands typically are distinguished by a period in column one of the input
  1906. followed by a two character abbreviation for the command funtion.
  1907. The abbreviation may then be followed by an optional numeric or
  1908. character argument.
  1909. The numeric argument may be an absolute value such as setting
  1910. the right margin to a particular column, or the argument may be
  1911. preceded by a plus sign or a minus sign to indicate that the
  1912. parameter should be modified relative to a previous setting.
  1913. The following commands are recognized:
  1914. .sp
  1915. .nj
  1916. .in +6
  1917. .br
  1918. .ti -6
  1919. .cc !
  1920. .bo - causes the following lines of text to appear in
  1921. boldface.
  1922. The optional argument specifies the number of lines to
  1923. be typed in boldface.
  1924. Boldface and underlining are mutually exclusive features.
  1925. The appearance of a boldface command will cause any underlining
  1926. to cease.
  1927. !sp
  1928. !ti -6
  1929. .bp - causes succeeding text to appear at the top of
  1930. a new page.
  1931. The optional argument specifies the page number for the new page.
  1932. The initial value is one and the default value is one more than
  1933. the previous page number.
  1934. !sp
  1935. !ti -6
  1936. .br - causes succeeding text to start on a new line at the
  1937. current left margin.
  1938. There is no numeric argument for this command.
  1939. !sp
  1940. !ti -6
  1941. .bs - enables or disables the appearance of backspaces
  1942. in the output text.
  1943. Underlining and boldface options are implemented by inserting
  1944. character - backspace - character combinations into the output
  1945. buffer.
  1946. This is fine for devices which properly recognize the backspace
  1947. character.
  1948. Some printers, however, do not recognize backspaces, so the option is
  1949. provided to overprint one line buffer with another.
  1950. The first line buffer is terminated with just a carriage return
  1951. rather than the carriage return - linefeed combination.
  1952. A zero argument or no argument to the backspace command removes
  1953. backspaces from the output.
  1954. A non-zero argument leaves them in the output.
  1955. The default is to remove backspaces.
  1956. !sp
  1957. !ti -6
  1958. .cc - changes the
  1959. !ul
  1960. NRO
  1961. command character to that specified by the character argument.
  1962. If no argument is provided, the default is a period.
  1963. !sp
  1964. !ti -6
  1965. .ce - causes the next line of text to appear centered on the output.
  1966. The optional argument specifies if more than one line is to be centered.
  1967. !sp
  1968. !ti -6
  1969. .de - causes all text and commands following to be used to define
  1970. a macro.
  1971. The definition is terminated by a
  1972. !bo
  1973. .en
  1974. command.
  1975. The first two characters of the argument following the
  1976. !bo
  1977. .de
  1978. command become the name of the new command.
  1979. It should be noted that upper and lower case arguments are considered
  1980. different.
  1981. Thus, the commands
  1982. !bo
  1983. .PP
  1984. and
  1985. !bo
  1986. .pp
  1987. could define two different macros.
  1988. Care should be exercised since existing commands may be redefined.
  1989. !sp
  1990. A macro may contain up to ten arguments.
  1991. In the macro definition, the placement of arguments is designated by the
  1992. two character sequences, $0, $1, ... $9.
  1993. When the macro is invoked, each argument of the macro command line is
  1994. substituted for its corresponding designator in the expansion.
  1995. The first argument of the macro command is substituted for the $0
  1996. in the expansion, the second argument for the $1, and so forth.
  1997. Arguments are typically strings which do not contain blanks or tabs.
  1998. If an argument is to contain blanks, then it should be surrounded by
  1999. either single or double quotes. 
  2000. !sp
  2001. !ti -6
  2002. .cu - causes the next line(s) of text to be continuously underlined.
  2003. Unlike the underline command (see
  2004. !bo
  2005. .ul)
  2006. which underlines only alphanumerics, continuous underlining underlines
  2007. all printable characters.
  2008. The optional argument specifies the number of lines of text to underlined.
  2009. Any normal underlining or boldface commands currently in effect will be
  2010. terminated.
  2011. !sp
  2012. !ti -6
  2013. .ef - specifies the text for the footer on even numbered pages.
  2014. The format is the same as for the footer command (see
  2015. !bo
  2016. .fo).
  2017. !sp
  2018. !ti -6
  2019. .eh - specifies the text for the header on even numbered pages.
  2020. The format is the same as for the footer command (see
  2021. !bo
  2022. .fo).
  2023. !sp
  2024. !ti -6
  2025. .en - designates the end of a macro definition.
  2026. !sp
  2027. !ti -6
  2028. .fi - causes the input text to be rearranged or filled to obtain the
  2029. maximum word count possible between the previously set left and
  2030. right margins.
  2031. No argument is expected.
  2032. !sp
  2033. !ti -6
  2034. .fo - specifies text to be used for a footer.
  2035. The footer text contains three strings seperated by a delimiter
  2036. character.
  2037. The first non-blank character following the command is designated
  2038. as the delimiter.
  2039. The first text string is left justified to the current indentation
  2040. value (specified by
  2041. !bo
  2042. .in).
  2043. The second string is centered between the current indentation value
  2044. and the current right margin value (specified by
  2045. !bo
  2046. .rm).
  2047. The third string is right justified to the current right margin value.
  2048. The absence of footer text will result in the footer being printed as
  2049. one blank line.
  2050. The presence of the page number character (set by
  2051. !bo
  2052. .pc)
  2053. in the footer text results
  2054. in the current page number being inserted at that position.
  2055. Multiple occurrances of the page number character are allowed.
  2056. !sp
  2057. !ti -6
  2058. .he - specifies text to be used for a header.
  2059. The format is the same as for the footer (see
  2060. !bo
  2061. .fo).
  2062. !sp
  2063. !ti -6
  2064. .in - indents the left margin to the column value specified by the argument.
  2065. The default left margin is set to zero.
  2066. !sp
  2067. !ti -6
  2068. .ju - causes blanks to be inserted between words in a line of
  2069. output in order to align or justify the right margin.
  2070. The default is to justify.
  2071. !sp
  2072. !ti -6
  2073. .ls - sets the line spacing to the value specified by the argument.
  2074. The default is for single spacing.
  2075. !sp
  2076. !ti -6
  2077. .m1 - specifies the number of lines in the header margin.
  2078. This is the space from the physical top of page to and including
  2079. the header text.
  2080. A value of zero causes the header to not be printed.
  2081. A value of one causes the header to appear at the physical top of page.
  2082. Larger argument values cause the appropriate number of blank
  2083. lines to appear before the header is printed.
  2084. !sp
  2085. !ti -6
  2086. .m2 - specifies the number of blank lines to be printed between
  2087. the header line and the first line of the processed text.
  2088. !sp
  2089. !ti -6
  2090. .m3 - specifies the number of blank lines to be printed between
  2091. the last line of processed text and the footer line.
  2092. !sp
  2093. !ti -6
  2094. .m4 - specifies the number of lines in the footer margin.
  2095. This command affects the footer the same way the
  2096. !bo
  2097. .m1
  2098. command
  2099. affects the header.
  2100. !sp
  2101. !ti -6
  2102. .ne - specifies a number of lines which should not be broken
  2103. across a page boundary.
  2104. If the number of lines remaining on a page is less than the
  2105. value needed, then a new output page is started.
  2106. !sp
  2107. !ti -6
  2108. .nf - specifies that succeeding text should be printed without
  2109. rearrangement, or with no fill.
  2110. No argument is expected.
  2111. !sp
  2112. !ti -6
  2113. .nj - specifies that no attempt should be made to align or justify
  2114. the right margin.
  2115. No argument is expected.
  2116. !sp
  2117. !ti -6
  2118. .nr - causes the value of a number register to be set or modified.
  2119. A total of twenty-six number registers are available designated
  2120. @@na through @@nz (either upper or lower case is allowed).
  2121. When the sequence @@nc is imbedded in the text, the current value
  2122. of number register c replaces the sequence, thus, such things as
  2123. paragraph numbering can be accomplished with relative ease.
  2124. !sp
  2125. !ti -6
  2126. .of - specifies the text for the footer on odd numbered pages.
  2127. The format is the same as the footer command (see
  2128. !bo
  2129. .fo).
  2130. !sp
  2131. !ti -6
  2132. .oh - specifies the text for the header on odd numbered pages.
  2133. The format is the same as the footer command (see
  2134. !bo
  2135. .fo).
  2136. !sp
  2137. !ti -6
  2138. .pc - specifies the page number character to be used in headers
  2139. and footers.
  2140. The occurrance of this character in the header or footer text
  2141. results in the current page number being printed.
  2142. The default for this character is the hash mark (#).
  2143. !sp
  2144. !ti -6
  2145. .pl - specifies the page lenght or the number of lines per output page.
  2146. The default is sixty-six.
  2147. !sp
  2148. !ti -6
  2149. .po - specifies a page offset value.
  2150. This allows the formatted text to be shifted to the right by
  2151. the number of spaces specified.
  2152. This feature may also be invoked by a switch on the command line.
  2153. !sp
  2154. !ti -6
  2155. .rm - sets the column value for the right margin.
  2156. The default is eighty.
  2157. !sp
  2158. !ti -6
  2159. .so - causes input to be retrieved from the file specified
  2160. by the command's character string argument.
  2161. The contents of the new file are inserted into the output
  2162. stream until an EOF is detected.
  2163. Processing of the original file is then resumed.
  2164. Command nesting is allowed.
  2165. !sp
  2166. !ti -6
  2167. .sp - specifies a number of blank lines to be output before
  2168. printing the next line of text.
  2169. !sp
  2170. !ti -6
  2171. .ti - temporarily alters the indentation or left margin value for a single
  2172. succeeding line of text.
  2173. !sp
  2174. !ti -6
  2175. .ul - underlines the alphanumeric text in the following line(s).
  2176. The optional argument specifies the number of lines to be underlined.
  2177. Underlining and boldface are mutually exclusive features.
  2178. The appearance of an underline command cancels any existing
  2179. boldface operations.
  2180.  
  2181.  
  2182. *******
  2183. \skelton.nro/
  2184. *******
  2185. .TH SKELETON 1 "New Manual Name"
  2186. .SH NAME
  2187. skeleton - sample manual page
  2188. .SH SYNOPSIS
  2189. .bo
  2190. skeleton
  2191. [options]
  2192. .SH DESCRIPTION
  2193. This section describes the program or file.
  2194. .SH CAVEATS
  2195. .SH EXAMPLES
  2196. Just what the name implies.
  2197. .SH FILES
  2198. an.nro
  2199. .SH "RETURN VALUE"
  2200. .SH "SEE ALSO"
  2201. nro(1),
  2202. man(7)
  2203. .SH WARNINGS
  2204. .SH BUGS
  2205. They are everywhere
  2206. .SH MISCELLANEOUS
  2207. .SH NOTES
  2208.  
  2209.  
  2210. ******
  2211. \newlower/
  2212. *******
  2213. char newlower(c)
  2214. char c;
  2215. {
  2216.     return (( c >= 'A' && c <= 'Z' ) ? ( c - 'A' + 'a' ) : c) ;
  2217. }
  2218.  
  2219.  
  2220. *********
  2221. \READ_ME/
  2222. *********
  2223. This version of NRO came from the C User's Group in Yates, Kansas.
  2224. The I/O was changed to run under Unix V7 style I/O, and other than that, no
  2225. modifications have been made to it.
  2226.     In the init() function, pg.lineno must be modified to suit your
  2227. printer; it wants the line number the print head is on when you do a top
  2228. of form.  On my printer, the way I position the paper, it will start printing
  2229. on the second line, so there is a value of 2 there.
  2230.  
  2231.     I would be interested in seeing any modifications anyone makes to
  2232. this program in the way of extended capabilities, macro packages, and printer
  2233. enhancements.  If you have problems in the logic itself, you should contact
  2234. the author.
  2235.  
  2236.         Happy Hacking,
  2237.  
  2238.         Jordan Bortz
  2239.  
  2240.         (..decvax!cbosgd!mddc!jordan)
  2241.  
  2242.  
  2243. P.S. I tried compiling it on 4.1 BSD, and it didn't work.  It works okay
  2244.     on my MS-DOS computer running Computer Innovations Ci C86, so
  2245.     there may be portability problems.
  2246.  
  2247.