#undef OLD_WAY /* * text.c - text output processing portion of nroff word processor * * adapted for atariST/TOS by Bill Rosenkranz 11/89 * net: rosenkra@hall.cray.com * CIS: 71460,17 * GENIE: W.ROSENKRANZ * * original author: * * Stephen L. Browning * 5723 North Parker Avenue * Indianapolis, Indiana 46220 * * history: * * - Originally written in BDS C; * - Adapted for standard C by W. N. Paul * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz * - Heavily modified by Devin Reade to avoid memory trashing bugs. * * $Id: text.c,v 1.2 1997/03/20 06:40:51 gdr Exp $ */ #ifdef __ORCAC__ segment "text______"; #pragma noroot #pragma optimize 78 #endif #include #include #include #ifdef __GNO__ #include #else #include "unix/termcap.h" #endif #include "nroff.h" #include "io.h" #include "escape.h" /* * output buffer control parameters */ static struct { int outp; /* next avail char pos in outbuf, init = 0 */ int outw; /* width of text currently in buffer */ int outwds; /* number of words in buffer, init = 0 */ int lpr; /* output to printer, init = FALSE */ int outesc; /* number of escape char on this line */ char outbuf[MAXLINE];/* output of filled text */ } co; static void bold (char *p0, char *p1, int size); static void center (char *p); static void expand (char *p0, char c, char *s); static void justcntr (char *p, char *q, int *limit); static void justleft (char *p, char *q, int limit); static void justrite (char *p, char *q, int limit); static void leadbl (char *p); static void puttl (char *p, int *lim, int pgno); static void putwrd (char *wrdbuf); static void spread (char *p, int outp, int nextra, int outwds,int escapes); static void underl (char *p0, char *p1, int size); static int width (char *s); static void do_mc (char *p); /* * text * main text processing * * Pre: contains the line we wish to process (and print) * it is MAXLINE characters long, including the * terminating NULL character. * * Post: */ void text (char *line) { register int i; char wrdbuf[MAXLINE]; /* * skip over leading blanks if in fill mode. we indent later. * since leadbl does a robrk, do it if in .nf mode */ if (dc.fill == YES) { if (*line == ' ' || *line == '\n' || *line == '\r') { /* note that leadbl shifts left as necessary */ leadbl (line); } } else { robrk (); } /* * expand escape sequences from into */ expesc (line, wrdbuf, MAXLINE); /* * test for how to output */ if (dc.ulval > 0) { /* * underline (.ul) * * Because of the way underlining is handled, * MAXLINE should be declared to be three times * larger than the longest expected input line * for underlining. Since many of the character * buffers use this parameter, a lot of memory * can be allocated when it may not really be * needed. A MAXLINE of 180 would allow about * 60 characters in the output line to be * underlined (remember that only alphanumerics * get underlined - no spaces or punctuation). */ underl (line, wrdbuf, MAXLINE); --dc.ulval; } if (dc.cuval > 0) { /* * continuous underline (.cu) */ underl (line, wrdbuf, MAXLINE); --dc.cuval; } if (dc.boval > 0) { /* * bold (.bo) */ bold (line, wrdbuf, MAXLINE); --dc.boval; } if (dc.ceval > 0) { /* * centered (.ce) */ center (line); do_mc (line); put (line); --dc.ceval; } else if ((*line == '\r' || *line == '\n') && dc.fill == NO) { /* * all blank line */ do_mc (line); put (line); } else if (dc.fill == NO) { /* * unfilled (.nf) */ do_mc (line); put (line); } else { /* * anything else... * * init escape char counter for this line... */ /* co.outesc = 0;*/ /* * get a word and put it out. increment ptr to the next * word. */ while ((i = getwrd (line, wrdbuf)) > 0) { /* co.outesc += countesc (wrdbuf);*/ putwrd (wrdbuf); line += i; } } } /* * bold * insert bold face text (by overstriking) */ static void bold (register char *p0, register char *p1, int size) { register int i; register int j; j = 0; for (i = 0; (p0[i] != '\n') && (j < size - 1); ++i) { if (isalpha (p0[i]) || isdigit (p0[i])) { p1[j++] = p0[i]; p1[j++] = '\b'; } p1[j++] = p0[i]; } p1[j++] = '\n'; p1[j] = EOS; while (*p1 != EOS) *p0++ = *p1++; *p0 = EOS; } /* * center * center a line by setting tival */ static void center (register char *p) { int t; t = (dc.rmval + dc.tival - width (p)) >> 1; dc.tival = MAX(t, 0); } /* * expand * expand title buffer to include character string */ static void expand (register char *p0, char c, register char *s) { register char *p; register char *q; register char *r; char tmp[MAXLINE]; p = p0; q = tmp; while (*p != EOS) { if (*p == c) { r = s; while (*r != EOS) { *q++ = *r++; } } else { *q++ = *p; } ++p; } *q = EOS; strcpy (p0, tmp); /* copy it back */ } /* * justcntr * center title text into print buffer */ static void justcntr (register char *p, char *q, int *limit) { register int len; len = width (p); q = &q[(limit[RIGHT] + limit[LEFT] - len) >> 1]; while (*p != EOS) { *q++ = *p++; } } /* * justleft * left justify title text into print buffer */ static void justleft (register char *p, char *q, int limit) { q = &q[limit]; while (*p != EOS) { *q++ = *p++; } } /* * justrite * right justify title text into print buffer */ static void justrite (register char *p, char *q, int limit) { register int len; len = width (p); q = &q[limit - len]; while (*p != EOS) { *q++ = *p++; } } /* * leadbl * delete leading blanks, set tival * * REVIEWED */ static void leadbl (register char *p) { register char *q; register int i; /* * end current line and reset co struct */ robrk (); /* * skip spaces */ for (i = 0; p[i] == ' ' || p[i] == '\t'; ++i); /* * if not end of line, reset current temp indent */ if (p[i] != '\n' && p[i] != '\r') { dc.tival = i; } /* * shift string */ q = &p[i]; #ifdef DEBUG i = 0; #endif while (*q) { #ifdef DEBUG i++; ASSERT(i 0) { if ((pg.curpag % 2) == 0) { puttl (pg.efoot, pg.eflim, pg.curpag); } else { puttl (pg.ofoot, pg.oflim, pg.curpag); } skip (pg.m4val - 1); } } } /* * phead * put out page header */ void phead (void) { pg.curpag = pg.newpag; if (pg.curpag >= pg.frstpg && pg.curpag <= pg.lastpg) { dc.prflg = TRUE; } else { dc.prflg = FALSE; } ++pg.newpag; set_ireg ("%", pg.newpag, 0); if (dc.prflg == TRUE) { if (pg.m1val > 0) { skip (pg.m1val - 1); if ((pg.curpag % 2) == 0) { puttl (pg.ehead, pg.ehlim, pg.curpag); } else { puttl (pg.ohead, pg.ohlim, pg.curpag); } } skip (pg.m2val); } /* * initialize lineno for the next page */ pg.lineno = pg.m1val + pg.m2val + 1; set_ireg ("ln", pg.lineno, 0); } /* * puttl * put out title or footer */ static void puttl (register char *p, int *lim, int pgno) { register int i; char pn[8]; char t[MAXLINE]; char h[MAXLINE]; char delim; itoda (pgno, pn, 6); for (i = 0; i < MAXLINE; ++i) { h[i] = ' '; } delim = *p++; p = getfield (p, t, delim); expand (t, dc.pgchr, pn); justleft (t, h, lim[LEFT]); p = getfield (p, t, delim); expand (t, dc.pgchr, pn); justcntr (t, h, lim); p = getfield (p, t, delim); expand (t, dc.pgchr, pn); justrite (t, h, lim[RIGHT]); for (i = MAXLINE - 4; h[i] == ' '; --i) { h[i] = EOS; } h[++i] = '\n'; h[++i] = '\r'; h[++i] = EOS; if (strlen (h) > 2) { for (i = 0; i < pg.offset; ++i) { PRCHAR2(' ', out_stream); } } putlin (h, out_stream); } /* * putwrd * put word in output buffer */ static void putwrd (register char *wrdbuf) { register char *p0; register char *p1; int w; int last; int llval; int nextra; /* * check if this word puts us over the limit */ w = width (wrdbuf); last = strlen (wrdbuf) + co.outp; llval = dc.rmval - dc.tival; /* if (((co.outp > 0) && ((co.outw + w) > llval))*/ co.outesc += countesc (wrdbuf); if (((co.outp > 0) && ((co.outw + w - co.outesc) > llval)) ||(last > MAXLINE)) { /* * last word exceeds limit so prepare to break line, print * it, and reset outbuf. */ last -= co.outp; if (dc.juval == YES) { nextra = llval - co.outw + 1; /* * Do not take in the escape char of the * word that didn't fit on this line anymore */ co.outesc -= countesc (wrdbuf); /* * Check whether last word was end of * sentence and modify counts so that * it is right justified. */ if (co.outbuf[co.outp - 2] == ' ') { --co.outp; ++nextra; } #ifdef OLD_WAY spread (co.outbuf, co.outp - 1, nextra, co.outwds, co.outesc); if ((nextra > 0) && (co.outwds > 1)) { co.outp += (nextra - 1); } #if 0 if (co.outesc > 0) { co.outp += co.outesc; } #endif /* 0 */ #else /* OLD_WAY */ spread (co.outbuf, co.outp - 1, nextra, co.outwds, co.outesc); if ((nextra + co.outesc > 0) && (co.outwds > 1)) { co.outp += (nextra + co.outesc - 1); } #endif } /* * break line, output it, and reset all co members. reset * esc count. */ robrk (); co.outesc = countesc (wrdbuf); } /* * copy the current word to the out buffer which may have been * reset */ p0 = wrdbuf; p1 = co.outbuf + co.outp; while (*p0 != EOS) { *p1++ = *p0++; } co.outp = last; co.outbuf[co.outp++] = ' '; co.outw += w + 1; co.outwds += 1; } /* * skip * skips the number of lines specified by n. */ void skip (register int n) { register int i; register int j; if (dc.prflg == TRUE && n > 0) { for (i = 0; i < n; ++i) { /* * handle blank line with changebar */ if (mc_ing == TRUE) { for (j = 0; j < pg.offset; ++j) { PRCHAR2(' ', out_stream); } for (j = 0; j < dc.rmval; ++j) { PRCHAR2(' ', out_stream); } for (j = 0; j < mc_space; j++) { PRCHAR2(' ', out_stream); } PRCHAR(mc_char, out_stream); } PRCHAR2('\n', out_stream); #if 0 /* gdr: not required */ prchar ('\r', out_stream); #endif } } } /* * spread * spread words to justify right margin */ static void spread (register char *p, int outp, int nextra, int outwds, int escapes) { register int i; register int j; register int nb; register int ne; register int nholes; /* * quick sanity check... */ #ifdef OLDWAY if ((nextra <= 0) || (outwds <= 1)) { return; } #else if ((nextra + escapes < 1) || (outwds < 2)) { return; } #endif /* * set up for the spread and do it... */ dc.sprdir = ~dc.sprdir; #ifdef OLD_WAY ne = nextra; #else ne = nextra + escapes; #endif nholes = outwds - 1; /* holes between words */ i = outp - 1; /* last non-blank character */ j = MIN(MAXLINE - 3, i + ne); /* leave room for CR,LF,EOS */ #if 0 j += escapes; if (p[i-1] == 27) { j += 2; } j = MIN(j, MAXLINE - 3); #endif while (i < j) { p[j] = p[i]; if (p[i] == ' ') { if (dc.sprdir == 0) { nb = (ne - 1) / nholes + 1; } else { nb = ne / nholes; } ne -= nb; --nholes; for (; nb > 0; --nb) { --j; p[j] = ' '; } } --i; --j; } } /* * strkovr * split overstrikes (backspaces) into seperate buffer */ int strkovr (char *p, char *q) { register char *pp; int bsflg; bsflg = FALSE; pp = p; while (*p != EOS) { *q = ' '; *pp = *p; ++p; if (*p == '\b') { if (*pp >= ' ' && *pp <= '~') { bsflg = TRUE; *q = *pp; ++p; *pp = *p; ++p; } } ++q; ++pp; } *q++ = NEWLINE; *q = *pp = EOS; return bsflg; } /* * underl * underline a line */ static void underl (register char *p0, register char *p1, int size) { register int i; register int j; j = 0; for (i = 0; (p0[i] != '\n') && (j < size - 1); ++i) { if (p0[i] >= ' ' && p0[i] <= '~' && (isalpha (p0[i]) || isdigit (p0[i]) || dc.cuval > 0)) { p1[j++] = '_'; p1[j++] = '\b'; } p1[j++] = p0[i]; } p1[j++] = '\n'; p1[j] = EOS; while (*p1 != EOS) { *p0++ = *p1++; } *p0 = EOS; } /* * width * compute width of character string */ static int width (char *s) { register int w; w = 0; for (; *s != '\0'; s++) { ASSERT((*s != '\n' && *s != '\r'), ("\n")); if ((*s >= 32) && (*s < 127)) { ++w; } else if (*s == '\b' || *s == 128) { --w; } /* ignore high-bit chars and other control chars */ } return w; } /* * do_mc * add margin char (change bar) for .nf and .ce lines. * * filled lines handled in robrk(). blank lines (.sp) handled in skip(). * note: robrk() calls this routine, too. */ static void do_mc (char *p) { register char *ps; register int nspaces; register int i; register int has_cr; register int has_lf; int len; int nesc; if (mc_ing == FALSE) { return; } len = strlen (p); /* * get to the end... */ ps = p; while (*ps) { ps++; } /* * check for cr and lf */ ps--; has_lf = 0; has_cr = 0; while (ps >= p && (*ps == '\r' || *ps == '\n')) { if (*ps == '\n') { has_lf++; } else { has_cr++; } len--; ps--; } if (has_lf < has_cr) { has_lf = has_cr; } else if (has_cr < has_lf) { has_cr = has_lf; } /* * remove any trailing blanks here */ while (ps >= p && *ps == ' ') { ps--; len--; } *++ps = EOS; /* * add trailing spaces for short lines. count escapes, subtract * from len. use rmval for rigth margin (minus tival which is * added later in put). */ nesc = countesc (p); len -= nesc; nspaces = dc.rmval - dc.tival - len; for (i = 0; i < nspaces; i++, ps++) { *ps = ' '; } /* * add the bar... */ for (i = 0; i < mc_space; i++, ps++) { *ps = ' '; } *ps++ = mc_char; /* * replace cr, lf, and EOS */ while (has_lf--) { *ps++ = '\r'; *ps++ = '\n'; } *ps = EOS; return; } void initOutbuf (void) { co.outp = 0; co.outw = 0; co.outwds = 0; co.lpr = FALSE; co.outesc = 0; memset(co.outbuf, EOS, MAXLINE); #if 0 for (i = 0; i < MAXLINE; ++i) { co.outbuf[i] = EOS; } #endif } /* * robrk * * End current filled line. References and modifies globals: * co */ void robrk (void) { if (co.outp > 0) { /* * handle margin char (change bar) here for all filled lines */ ASSERT(MAXLINE - co.outp > 2, ("output buffer overrun: >%d:%d:%d<\n", MAXLINE, co.outp, MAXLINE- co.outp)); co.outbuf[co.outp] = '\r'; co.outbuf[co.outp+1] = '\n'; co.outbuf[co.outp+2] = EOS; do_mc (co.outbuf); put (co.outbuf); } co.outp = 0; co.outw = 0; co.outwds = 0; co.outesc = 0; } void setPrinting(int val) { co.lpr = val; }