/* * escape.c - Escape and special character input 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 */ #undef NRO_MAIN /* extern globals */ #include <stdio.h> #include "nroff.h" /*------------------------------*/ /* expesc */ /*------------------------------*/ expesc (p, q) char *p; char *q; { /* * Expand escape sequences */ register char *s; register char *t; register char *pstr; register int i; register int val; register int autoinc; char c; char fs[5]; /* for font change */ char nrstr[20]; char fmt[20]; char name[10]; int nreg; char *pfs; int inc; int tmp; char delim; s = p; t = q; /* * if escape parsing is not on, just copy string */ if (dc.escon == NO) { while (*s != EOS) { *t++ = *s++; } *t = EOS; strcpy (p, q); return; } /* * do it... */ while (*s != EOS) { if (*s != dc.escchr) { /* * not esc, continue... */ *t++ = *s++; } else if (*(s + 1) == dc.escchr) { /* * \\ escape escape */ *t++ = *s++; ++s; } else if (*(s + 1) == 'n') { /* * \nx, \n(xx register * * first check for \n+... or \n-... (either form) */ s += 2; autoinc = 0; if (*s == '+') { autoinc = 1; s += 1; } if (*s == '-') { autoinc = -1; s += 1; } /* * was this \nx or \n(xx form? */ if (isalpha (*s)) { /* * \nx form. find reg (a-z) */ nreg = tolower (*s) - 'a'; /* * was this \n+x or \n-x? if so, do the * auto incr */ if (autoinc > 0) dc.nr[nreg] += dc.nrauto[nreg]; else if (autoinc < 0) dc.nr[nreg] -= dc.nrauto[nreg]; /* * display format */ if (dc.nrfmt[nreg] == '1') { /* * normal decimal digits */ t += itoda (dc.nr[nreg], t, 6) - 1; } else if (dc.nrfmt[nreg] == 'i') { /* * lower roman */ t += itoroman (dc.nr[nreg], t, 24) - 1; } else if (dc.nrfmt[nreg] == 'I') { /* * upper roman */ t += itoROMAN (dc.nr[nreg], t, 24) - 1; } else if (dc.nrfmt[nreg] == 'a') { /* * lower letters */ t += itoletter (dc.nr[nreg], t, 12) - 1; } else if (dc.nrfmt[nreg] == 'A') { /* * upper letters */ t += itoLETTER (dc.nr[nreg], t, 12) - 1; } else if (dc.nrfmt[nreg] & 0x80) { /* * zero-filled decimal */ sprintf (fmt, "%%0%dld", (int)(dc.nrfmt[nreg] & 0x7F)); fmt[5] = '\0'; sprintf (nrstr, fmt, (long) dc.nr[nreg]); tmp = dc.nrfmt[nreg] & 0x7F; nrstr[tmp] = '\0'; strcpy (t, nrstr); t += strlen (nrstr); } else { /* * normal (default) */ t += itoda (dc.nr[nreg], t, 6) - 1; } ++s; } else if (*s == '%') { /* * \n% form. find index into reg struct */ nreg = findreg ("%"); if (nreg < 0) { fprintf (err_stream, "***%s: no register match\n", myname); err_exit (-1); } /* * was this \n+% or \n-%? if so, do the * auto incr */ if (autoinc > 0) rg[nreg].rval += rg[nreg].rauto; else if (autoinc < 0) rg[nreg].rval -= rg[nreg].rauto; /* * display format */ if (rg[nreg].rfmt == '1') { /* * normal decimal digits */ t += itoda (rg[nreg].rval, t, 6) - 1; } else if (rg[nreg].rfmt == 'i') { /* * lower roman */ t += itoroman (rg[nreg].rval, t, 24) - 1; } else if (rg[nreg].rfmt == 'I') { /* * upper roman */ t += itoROMAN (rg[nreg].rval, t, 24) - 1; } else if (rg[nreg].rfmt == 'a') { /* * lower letters */ t += itoletter (rg[nreg].rval, t, 12) - 1; } else if (rg[nreg].rfmt == 'A') { /* * upper letters */ t += itoLETTER (rg[nreg].rval, t, 12) - 1; } else if (rg[nreg].rfmt & 0x80) { /* * zero-filled decimal */ sprintf (fmt, "%%0%dld", (int)(rg[nreg].rfmt & 0x7F)); fmt[5] = '\0'; sprintf (nrstr, fmt, (long) rg[nreg].rval); tmp = rg[nreg].rfmt & 0x7F; nrstr[tmp] = '\0'; strcpy (t, nrstr); t += strlen (nrstr); } else { /* * normal (default) */ t += itoda (rg[nreg].rval, t, 6) - 1; } s += 1; } else if (*s == '(') { /* * \n(xx form. find index into reg struct */ s += 1; name[0] = *s; name[1] = *(s + 1); if (name[1] == ' ' || name[1] == '\t' || name[1] == '\n' || name[1] == '\r') name[1] = '\0'; name[2] = '\0'; nreg = findreg (name); if (nreg < 0) { fprintf (err_stream, "***%s: no register match\n", myname); err_exit (-1); } /* * was this \n+(xx or \n-(xx? if so, do the * auto incr */ if (rg[nreg].rflag & RF_WRITE) { if (autoinc > 0) rg[nreg].rval += rg[nreg].rauto; else if (autoinc < 0) rg[nreg].rval -= rg[nreg].rauto; } /* * display format */ if (rg[nreg].rfmt == '1') { /* * normal decimal digits */ t += itoda (rg[nreg].rval, t, 6) - 1; } else if (rg[nreg].rfmt == 'i') { /* * lower roman */ t += itoroman (rg[nreg].rval, t, 24) - 1; } else if (rg[nreg].rfmt == 'I') { /* * upper roman */ t += itoROMAN (rg[nreg].rval, t, 24) - 1; } else if (rg[nreg].rfmt == 'a') { /* * lower letters */ t += itoletter (rg[nreg].rval, t, 12) - 1; } else if (rg[nreg].rfmt == 'A') { /* * upper letters */ t += itoLETTER (rg[nreg].rval, t, 12) - 1; } else if (rg[nreg].rfmt & 0x80) { /* * zero-filled decimal */ sprintf (fmt, "%%0%dld", (int)(rg[nreg].rfmt & 0x7F)); fmt[5] = '\0'; sprintf (nrstr, fmt, (long) rg[nreg].rval); tmp = rg[nreg].rfmt & 0x7F; nrstr[tmp] = '\0'; strcpy (t, nrstr); t += strlen (nrstr); } else { /* * normal (default) */ t += itoda (rg[nreg].rval, t, 6) - 1; } s += 2; } } else if (*(s + 1) == '\"') { /* * \" comment */ *s = EOS; *t = *s; return; } else if (*(s + 1) == '*') { /* * \*x, \*(xx string */ s += 2; if (*s == '(') { /* * \*(xx form */ s += 1; name[0] = *s; name[1] = *(s + 1); name[2] = '\0'; pstr = getstr (name); if (!pstr) { fprintf (err_stream, "***%s: string not found\n", myname); err_exit (-1); } while (*pstr) *t++ = *pstr++; s += 2; } else { /* * \*x form */ name[0] = *s; name[1] = '\0'; pstr = getstr (name); if (!pstr) { fprintf (err_stream, "***%s: string not found\n", myname); err_exit (-1); } while (*pstr) *t++ = *pstr++; s += 1; } } else if (*(s + 1) == 'f') { /* * \fx font */ s += 2; pfs = fs; /* set up ret string */ fs[0] = '\0'; /* * it parses 1-2 char of s and returns esc seq for * \fB and \fR (\fI is same as \fB) */ fontchange (*s, pfs); /* * imbed the atari (vt52) escape seq */ while (*pfs) *t++ = *pfs++; ++s; /* skip B,I,R,S,P */ } else if (*(s + 1) == '(') { /* * \(xx special char */ s += 2; /* * it returns num char to skip and sets c to * the ascii value of the char */ inc = specialchar (s, &c); /* * skip proper num char in s and add c to target */ if (inc) { s += inc; *t++ = c; } } else if (*(s + 1) == 'e') { /* * \e printable version of escape */ *t++ = dc.escchr; s += 2; } else if (*(s + 1) == '`') { /* * \` grave, like \(ga */ *t++ = 0x60; s += 2; } else if (*(s + 1) == '\'') { /* * \' accute, like \(aa */ s += 2; *t++ = 0xBA; } else if (*(s + 1) == '-') { /* * \- minus */ s += 2; *t++ = 0x2D; } else if (*(s + 1) == '.') { /* * \. period */ s += 2; *t++ = 0x2E; } else if (*(s + 1) == ' ') { /* * \(space) space */ s += 2; *t++ = 0x20; } else if (*(s + 1) == '0') { /* * \0 digital width space */ s += 2; *t++ = 0x20; } else if (*(s + 1) == '|') { /* * \| narrow width char (0 in nroff) */ s += 2; } else if (*(s + 1) == '^') { /* * \^ narrow width char (0 in nroff) */ s += 2; } else if (*(s + 1) == '&') { /* * \& non-printing zero width */ s += 2; } else if (*(s + 1) == '!') { /* * \! transparent copy line */ s += 2; } else if (*(s + 1) == '$') { /* * \$N interpolate arg 1<=N<=9 */ s += 2; } else if (*(s + 1) == '%') { /* * \% hyphen */ s += 2; *t++ = 0x2D; *t++ = 0x2D; } else if (*(s + 1) == 'a') { /* * \a */ s += 2; } else if (*(s + 1) == 'b') { /* * \b'abc...' */ s += 2; } else if (*(s + 1) == 'c') { /* * \c */ s += 2; } else if (*(s + 1) == 'd') { /* * \d */ s += 2; } else if (*(s + 1) == 'h') { /* * \h'N' horiz motion */ s += 2; delim = *s++; val = atoi (s); for (i = 0; i < val; i++) *t++ = ' '; while (*s != delim) { if (*s == 0) break; s++; } if (*s) s++; } else if (*(s + 1) == 'k') { /* * \kx */ s += 2; } else if (*(s + 1) == 'l') { /* * \l'Nc' */ s += 2; } else if (*(s + 1) == 'L') { /* * \L'Nc' */ s += 2; } else if (*(s + 1) == 'o') { /* * \o'abc...' overstrike */ s += 2; delim = *s++; while (*s != EOS && *s != delim) { *t++ = *s++; *t++ = 0x08; } s++; } else if (*(s + 1) == 'p') { /* * \p */ s += 2; } else if (*(s + 1) == 'r') { /* * \r */ s += 2; } else if (*(s + 1) == 's') { /* * \sN,\s+-N */ s += 2; } else if (*(s + 1) == 't') { /* * \t horizontal tab */ s += 2; *t++ = 0x09; } else if (*(s + 1) == 'u') { /* * \u */ s += 2; } else if (*(s + 1) == 'v') { /* * \v'N' vert tab */ s += 2; delim = *s++; val = atoi (s); for (i = 0; i < val; i++) *t++ = 0x0A; while (*s != delim) { if (*s == 0) break; s++; } if (*s) s++; } else if (*(s + 1) == 'w') { /* * \w'str' */ s += 2; } else if (*(s + 1) == 'x') { /* * \x'N' */ s += 2; } else if (*(s + 1) == 'z') { /* * \zc print c w/o spacing */ s += 2; *t++ = *s++; *t++ = 0x08; } else if (*(s + 1) == '{') { /* * \{ */ s += 2; } else if (*(s + 1) == '}') { /* * \} */ s += 2; } else if (*(s + 1) == '\n' || *(s + 1) == '\r') { /* * \(newline) ignore newline */ s += 2; } else { /* * \X any other character not above */ s += 1; *t++ = *s++; } } /* * end the string and return it in original buf */ *t = EOS; strcpy (p, q); } /*------------------------------*/ /* specialchar */ /*------------------------------*/ specialchar (s, c) register char *s; register char *c; { /* * handles \(xx escape sequences for special characters (atari-specific) */ register char c1; register char c2; c1 = *s; c2 = *(s+1); /* * symbols */ if (c1 == 'c' && c2 == 'o') {*c = 0xBD; return (2);} /* copyrite */ if (c1 == 'r' && c2 == 'g') {*c = 0xBE; return (2);} /* registered */ if (c1 == 't' && c2 == 'm') {*c = 0xBF; return (2);} /* trademark */ if (c1 == '1' && c2 == '2') {*c = 0xAB; return (2);} /* 1/2 */ if (c1 == '1' && c2 == '4') {*c = 0xAC; return (2);} /* 1/4 */ if (c1 == 'p' && c2 == '2') {*c = 0xFD; return (2);} /* ^2 */ if (c1 == 'p' && c2 == '3') {*c = 0xFE; return (2);} /* ^3 */ if (c1 == 'p' && c2 == 'n') {*c = 0xFC; return (2);} /* ^n */ if (c1 == 'a' && c2 == 'a') {*c = 0xBA; return (2);} /* acute */ if (c1 == 'g' && c2 == 'a') {*c = 0x60; return (2);} /* grave */ if (c1 == 'd' && c2 == 'e') {*c = 0xF8; return (2);} /* degree */ if (c1 == 'd' && c2 == 'g') {*c = 0xBB; return (2);} /* dagger */ if (c1 == 'c' && c2 == 't') {*c = 0x9B; return (2);} /* cent */ if (c1 == 'b' && c2 == 'u') {*c = 0xF9; return (2);} /* bullet */ if (c1 == 'd' && c2 == 't') {*c = 0xFA; return (2);} /* dot */ if (c1 == 'p' && c2 == 'p') {*c = 0xBC; return (2);} /* paragraph */ if (c1 == '^' && c2 == 'g') {*c = 0x07; return (2);} /* ring bell */ if (c1 == 'u' && c2 == 'a') {*c = 0x01; return (2);} /* up arrow */ if (c1 == 'd' && c2 == 'a') {*c = 0x02; return (2);} /* dn arrow */ if (c1 == '-' && c2 == '>') {*c = 0x03; return (2);} /* rt arrow */ if (c1 == '<' && c2 == '-') {*c = 0x04; return (2);} /* lf arrow */ if (c1 == 'd' && c2 == 'i') {*c = 0xF6; return (2);} /* divide */ if (c1 == 's' && c2 == 'r') {*c = 0xFB; return (2);} /* sq root */ if (c1 == '=' && c2 == '=') {*c = 0xF0; return (2);} /* == */ if (c1 == '>' && c2 == '=') {*c = 0xF2; return (2);} /* >= */ if (c1 == '<' && c2 == '=') {*c = 0xF3; return (2);} /* <= */ if (c1 == '+' && c2 == '-') {*c = 0xF1; return (2);} /* +- */ if (c1 == '~' && c2 == '=') {*c = 0xF7; return (2);} /* ~= */ if (c1 == 'a' && c2 == 'p') {*c = 0x7E; return (2);} /* approx */ if (c1 == 'n' && c2 == 'o') {*c = 0xAA; return (2);} /* not */ if (c1 == 'm' && c2 == 'o') {*c = 0xEE; return (2);} /* member */ if (c1 == 'c' && c2 == 'a') {*c = 0xEF; return (2);} /* intersect */ if (c1 == 'c' && c2 == 'u') {*c = 0x55; return (2);} /* union */ if (c1 == 'i' && c2 == '1') {*c = 0xF4; return (2);} /* integral1 */ if (c1 == 'i' && c2 == '2') {*c = 0xF5; return (2);} /* integral2 */ /* * greek */ if (c1 == '*' && c2 == 'a') {*c = 0xE0; return (2);} /* alpha */ if (c1 == '*' && c2 == 'b') {*c = 0xE1; return (2);} /* beta */ if (c1 == '*' && c2 == 'g') {*c = 0xE2; return (2);} /* gamma */ if (c1 == '*' && c2 == 'd') {*c = 0x7F; return (2);} /* delta */ if (c1 == '*' && c2 == 's') {*c = 0xE4; return (2);} /* sigma */ if (c1 == '*' && c2 == 'p') {*c = 0xE3; return (2);} /* pi */ if (c1 == '*' && c2 == 'm') {*c = 0xE6; return (2);} /* mu */ *c = ' '; return (0); } /*------------------------------*/ /* fontchange */ /*------------------------------*/ fontchange (fnt, s) char fnt; char *s; { /* * handles \fx font change escapes for R,B,I,S,P (atari-specific) * resets current and last font in dc struct (last used for .ft * with no args) */ int tmp; *s = '\0'; switch (fnt) { case 'R': /* Times Roman */ if (dc.dofnt == YES) { if (dc.thisfnt == 2) strcpy (s, e_italic); else if (dc.thisfnt == 3) strcpy (s, e_bold); } dc.lastfnt = dc.thisfnt; dc.thisfnt = 1; break; case 'I': /* Times italic */ if (dc.dofnt == YES) strcpy (s, s_italic); dc.lastfnt = dc.thisfnt; dc.thisfnt = 2; break; case 'B': /* Times bold */ if (dc.dofnt == YES) strcpy (s, s_bold); dc.lastfnt = dc.thisfnt; dc.thisfnt = 3; break; case 'S': /* math/special */ *s = '\0'; dc.lastfnt = dc.thisfnt; dc.thisfnt = 4; break; case 'P': /* previous (exchange) */ if (dc.dofnt == YES) { if (dc.lastfnt == 1) { if (dc.thisfnt == 2) strcpy (s, e_italic); else if (dc.thisfnt == 3) strcpy (s, e_bold); } else if (dc.lastfnt == 2) { strcpy (s, s_italic); /* to I */ } else if (dc.lastfnt == 3) { strcpy (s, s_bold); /* to B */ } else *s = '\0'; /* nothing */ } tmp = dc.thisfnt; /* swap this/last */ dc.thisfnt = dc.lastfnt; dc.lastfnt = tmp; break; default: *s = '\0'; break; } set_ireg (".f", dc.thisfnt, 0); } /*------------------------------*/ /* findreg */ /*------------------------------*/ findreg (name) register char *name; { /* * find register named 'name' in pool. return index into array or -1 * if not found. */ register int i; register char *prname; for (i = 0; i < MAXREGS; i++) { prname = rg[i].rname; if (*prname == *name && *(prname + 1) == *(name + 1)) break; } return ((i < MAXREGS) ? i : -1); }