/* * 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 * - Heavily modified by Devin Reade to avoid memory trashing bugs. * * $Id: escape.c,v 1.2 1997/03/20 06:40:50 gdr Exp $ */ #ifdef __ORCAC__ segment "escape____"; #pragma noroot #pragma optimize 79 #endif #define INVERSE '\xF' #define NORMAL '\xE' #include #include #include #ifdef __GNO__ #include #else #include "unix/err.h" #endif #ifdef sparc #include "unix/sunos.h" #endif #include "nroff.h" #include "escape.h" #include "macros.h" static int specialchar (char *s, char *c); /* * expesc * * Expand escape sequences in the buffer , placing the results * in buffer . If the number of characters written into * would be more than characters, then abort with an error * message. */ void expesc (char *src, char *dest, size_t len) { 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; const char *percent = "%"; char *scratch; s = src; t = dest; /* * if escape parsing is not on, just copy string */ if (dc.escon == NO) { if (strlen(src) > len-1) { errx(-1, "buffer overflow at %s:%d", __FILE__, __LINE__); } strcpy (dest, src); 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 { switch(*(s+1)) { case '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 */ FINDREG(percent, nreg, scratch); if (nreg < 0) { errx(-1, "no register match"); } /* * 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'; FINDREG(name, nreg, scratch); if (nreg < 0) { errx(-1, "no register match"); } /* * 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; } break; case '"': /* \" comment */ *s = EOS; *t = *s; return; case '*': /* \*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) { errx(-1,"string not found"); } while (*pstr) { *t++ = *pstr++; } s += 2; } else { /* * \*x form */ name[0] = *s; name[1] = '\0'; pstr = getstr (name); if (!pstr) { errx(-1, "string not found"); } while (*pstr) { *t++ = *pstr++; } s += 1; } break; case '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 */ break; case '(': /* \(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; } break; case 'e': /* \e printable version of escape */ *t++ = dc.escchr; s += 2; break; case '-': /* \- minus */ case '`': /* \` grave, like \(ga */ case '\'': /* \' accute, like \(aa */ case '.': /* \. period */ case ' ': /* \(space) space */ /* verbatim */ *t++ = *(s+1); s += 2; break; case '0': /* \0 digital width space */ *t++ = ' '; s += 2; break; case '|': /* \| narrow width char (0 in nroff) */ case '^': /* \^ narrow width char (0 in nroff) */ case '&': /* \& non-printing zero width */ case '!': /* \! transparent copy line */ case '$': /* \$N interpolate arg 1<=N<=9 */ case 'a': /* \a */ case 'b': /* \b'abc...' */ case 'c': /* \c */ case 'd': /* \d */ case 'k': /* \kx */ case 'l': /* \l'Nc' */ case 'L': /* \L'Nc' */ case 'p': /* \p */ case 'r': /* \r */ case 's': /* \sN,\s+-N */ case 'u': /* \u */ case 'w': /* \w'str' */ case 'x': /* \x'N' */ case '{': /* \{ */ case '}': /* \} */ case '\n': /* \(newline) ignore newline */ case '\r': /* \(newline) ignore newline */ s += 2; /* currently ignored */ break; case '%': /* \% hyphen */ *t++ = '-'; *t++ = '-'; s += 2; break; case '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++; } break; case 'o': /* \o'abc...' overstrike*/ s += 2; delim = *s++; while (*s != EOS && *s != delim) { *t++ = *s++; *t++ = 0x08; } s++; break; case 't': /* \t horizontal tab*/ *t++ = '\t'; s += 2; break; case '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++; } break; case 'z': /* \zc print c w/o spacing*/ s += 2; *t++ = *s++; *t++ = 0x08; break; default: /* \X any other character not above*/ s += 1; *t++ = *s++; break; } } } /* * end the string and return it in original buf */ *t = EOS; /* gdr: this seems to defeat the expansion we just did. */ strcpy (src, dest); } /* * specialchar * handles \(xx escape sequences for special characters (atari-specific) */ static int specialchar (register char *s, register char *c) { register char c1; register char c2; c1 = *s; c2 = *(s+1); /* * symbols (std font) */ if (c1 == 'e' && c2 == 'm') {*c = 0x2D; return 2;} /* dash */ if (c1 == 'h' && c2 == 'y') {*c = 0x2D; return 2;} /* hyphen */ if (c1 == 'b' && c2 == 'u') {*c = 0xF9; return 2;} /* bullet */ if (c1 == 's' && c2 == 'q') {*c = 0xF9; return 2;} /* square */ if (c1 == 'r' && c2 == 'u') {*c = 0x5F; return 2;} /* rule */ if (c1 == '1' && c2 == '2') {*c = 0xAB; return 2;} /* 1/2 */ if (c1 == '1' && c2 == '4') {*c = 0xAC; return 2;} /* 1/4 */ if (c1 == 'd' && c2 == 'e') {*c = 0xF8; return 2;} /* degree */ if (c1 == 'd' && c2 == 'g') {*c = 0xBB; return 2;} /* dagger */ if (c1 == 'f' && c2 == 'm') {*c = 0xBA; return 2;} /* dagger */ if (c1 == 'c' && c2 == 't') {*c = 0x9B; return 2;} /* cent */ 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 == '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 == '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 */ if (c1 == 'b' && c2 == 'r') {*c = 0x7C; return 2;} /* box v rule */ if (c1 == 'b' && c2 == 'v') {*c = 0x7C; return 2;} /* bold vert */ if (c1 == 'p' && c2 == 'l') {*c = 0x2B; return 2;} /* math plus */ if (c1 == 'm' && c2 == 'i') {*c = 0x2D; return 2;} /* math minus */ if (c1 == 'e' && c2 == 'q') {*c = 0x3D; return 2;} /* math equal */ if (c1 == '*' && c2 == '*') {*c = 0x2A; return 2;} /* math star */ if (c1 == 's' && c2 == 'l') {*c = 0x2F; return 2;} /* slash */ if (c1 == 'u' && c2 == 'l') {*c = 0x5F; return 2;} /* underrule */ if (c1 == 's' && c2 == 'c') {*c = 0xDD; return 2;} /* section */ /* * 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 * 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) */ #undef SHORT_STANDOUT void fontchange (char fnt, char *s) { int tmp; *s = '\0'; switch (fnt) { case 'R': /* Times Roman */ if (dc.dofnt == YES) { #ifdef SHORT_STANDOUT s[0] = E_STANDOUT; s[1] = 0; #else strcpy (s, e_standout); #endif } dc.lastfnt = dc.thisfnt; dc.thisfnt = 1; break; case 'I': /* Times italic */ if (dc.dofnt == YES) { #ifdef SHORT_STANDOUT s[0] = S_STANDOUT; s[1] = 0; #else strcpy (s, s_standout); #endif } dc.lastfnt = dc.thisfnt; dc.thisfnt = 2; break; case 'B': /* Times bold */ if (dc.dofnt == YES) { #ifdef SHORT_STANDOUT s[0] = S_STANDOUT; s[1] = 0; #else strcpy (s, s_standout); #endif } 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) { #ifdef SHORT_STANDOUT s[0] = E_STANDOUT; s[1] = 0; #else strcpy (s, e_standout); /* to R */ #endif } else if (dc.lastfnt == 2) { #ifdef SHORT_STANDOUT s[0] = S_STANDOUT; s[1] = 0; #else strcpy (s, s_standout); /* to I */ #endif } else if (dc.lastfnt == 3) { #ifdef SHORT_STANDOUT s[0] = S_STANDOUT; s[1] = 0; #else strcpy (s, s_standout); /* to B */ #endif } 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); } #if 0 /* using macro version */ /* * findreg * * find register named 'name' in pool. return index into array or -1 * if not found. */ int findreg (register char *name) { 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); } #endif