koreth@panarthea.ebay.sun.com (Steven Grimm) (11/15/89)
Submitted-by: rosenkra@hall.cray.com (Bill Rosenkranz) Posting-number: Volume 3, Issue 10 Archive-name: nroff/part03 part03/03 -bill rosenkra@hall.cray.com rosenkra@boston.cray.com -------------cut here 0---------------------cut here----------------------- #!/bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by hall!rosenkra on Sun Nov 12 16:35:37 CST 1989 # Contents: escape.c low.c macros.c strings.c echo x - escape.c sed 's/^@//' > "escape.c" <<'@//E*O*F escape.c//' /* * 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) strcpy (s, "\33q"); dc.lastfnt = dc.thisfnt; dc.thisfnt = 1; break; case 'I': /* Times italic */ if (dc.dofnt == YES) strcpy (s, "\33p"); dc.lastfnt = dc.thisfnt; dc.thisfnt = 2; break; case 'B': /* Times bold */ if (dc.dofnt == YES) strcpy (s, "\33p"); 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) strcpy (s, "\33q"); /* to R */ else if (dc.lastfnt == 2) strcpy (s, "\33p"); /* to I */ else if (dc.lastfnt == 3) strcpy (s, "\33p"); /* 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); } @//E*O*F escape.c// chmod u=rw,g=r,o=r escape.c echo x - low.c sed 's/^@//' > "low.c" <<'@//E*O*F low.c//' /* * low.c - misc low-level functions for 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" /*------------------------------*/ /* atod */ /*------------------------------*/ atod (c) char c; { /* * convert ascii character to decimal. */ return (((c < '0') || (c > '9')) ? -1 : c - '0'); } /*------------------------------*/ /* robrk */ /*------------------------------*/ robrk () { /* * end current filled line */ if (co.outp > 0) { co.outbuf[co.outp] = '\r'; co.outbuf[co.outp+1] = '\n'; co.outbuf[co.outp+2] = EOS; put (co.outbuf); } co.outp = 0; co.outw = 0; co.outwds = 0; co.outesc = 0; } /*------------------------------*/ /* ctod */ /*------------------------------*/ ctod (p) register char *p; { /* * convert string to decimal. * processes only positive values. */ register int val; register int d; val = 0; while (*p != EOS) { d = atod (*p++); if (d == -1) return (val); val = 10 * val + d; } return (val); } /*------------------------------*/ /* skipbl */ /*------------------------------*/ char *skipbl (p) register char *p; { /* * skip blanks and tabs in character buffer. return ptr to first * non-space or non-tab char. this could mean EOS or \r or \n. * also increments the arg ptr (side effect). */ while (*p == ' ' || *p == '\t') ++p; return (p); } /*------------------------------*/ /* skipwd */ /*------------------------------*/ char *skipwd (p) register char *p; { /* * skip over word and punctuation. anything but space,\t,\r,\n, and EOS * is skipped. return ptr to the first of these found. also increments * the arg ptr (side effect). */ while (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != EOS) ++p; return (p); } /*------------------------------*/ /* space */ /*------------------------------*/ space (n) int n; { /* * space vertically n lines. this does header and footer also. */ robrk (); if (pg.lineno > pg.bottom) return; if (pg.lineno == 0) phead (); skip (min (n, pg.bottom + 1 - pg.lineno)); pg.lineno += n; set_ireg ("ln", pg.lineno, 0); if (pg.lineno > pg.bottom) pfoot (); } /*------------------------------*/ /* getfield */ /*------------------------------*/ char *getfield (p, q, delim) register char *p; register char *q; char delim; { /* * get field from title */ while (*p != delim && *p != '\r' && *p != '\n' && *p != EOS) { *q++ = *p++; } *q = EOS; if (*p == delim) ++p; return (p); } /*------------------------------*/ /* getwrd */ /*------------------------------*/ getwrd (p0, p1) register char *p0; register char *p1; { /* * get non-blank word from p0 into p1. * return number of characters processed. */ register int i; register char *p; char c; /* * init counter... */ i = 0; /* * skip leading whitespace */ while (*p0 && (*p0 == ' ' || *p0 == '\t')) { ++i; ++p0; } /* * set ptr and start to look for end of word */ p = p0; while (*p0 != ' ' && *p0 != EOS && *p0 != '\t') { if (*p0 == '\n' || *p0 == '\r') break; *p1 = *p0++; ++p1; ++i; } c = *(p1 - 1); if (c == '"') c = *(p1 - 2); if (c == '?' || c == '!') { *p1++ = ' '; ++i; } if (c == '.' && (*p0 == '\n' || *p0 == '\r' || islower (*p))) { *p1++ = ' '; ++i; } *p1 = EOS; return (i); } /*------------------------------*/ /* countesc */ /*------------------------------*/ #define ESC 27 countesc (p) register char *p; { /* * count atari escape sequence characters in given null-terminated * string */ register char *pp; register int num; pp = p; num = 0; while (*pp != EOS) { if (*pp == ESC) { /* * count escape char (atari-specific, vt52) * generally only p,q,b,and c will show up... */ switch (*(pp+1)) { case 'A': /* ESC-a */ case 'B': case 'C': case 'D': case 'E': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'd': case 'e': case 'f': case 'j': case 'k': case 'l': case 'o': case 'p': case 'q': case 'v': case 'w': num += 2; break; case 'b': /* ESC-a-b */ case 'c': num += 3; break; case 'Y': /* ESC-a-b-c */ num += 4; break; default: num += 1; break; } } pp++; } return (num); } /*------------------------------*/ /* itoda */ /*------------------------------*/ itoda (value, p, size) int value; register char *p; register int size; { /* * convert integer to decimal ascii string */ register int i; register int j; register int k; register int aval; char c[20]; aval = abs (value); c[0] = EOS; i = 1; do { c[i++] = (aval % 10) + '0'; aval /= 10; } while (aval > 0 && i <= size); if (value < 0 && i <= size) c[i++] = '-'; for (j = 0; j < i; ++j) *p++ = c[i - j - 1]; return (i); } /*------------------------------*/ /* itoROMAN */ /*------------------------------*/ itoROMAN (value, p, size) int value; register char *p; register int size; { /* * convert integer to upper roman. must be positive */ register int i; register int j; register int k; register int aval; char c[100]; int rem; aval = abs (value); c[0] = EOS; i = 1; /* * trivial case: */ if (aval == 0) { c[i++] = '0'; goto done_100; } /* * temporarily mod 100... */ aval = aval % 100; if (aval > 0) { /* * build backward * * | I| 1 * | II| 2 * | III| 3 * | VI| 4 * | V| 5 * | IV| 6 * | IIV| 7 * | IIIV| 8 * | XI| 9 * | X| 0 * | IX| 11 * | IIX| 12 */ if ((aval % 5 == 0) && (aval % 10 != 0))/* 5 */ c[i++] = 'V'; else { rem = aval % 10; if (rem == 9) /* 9 */ { c[i++] = 'X'; c[i++] = 'I'; } else if (rem == 8) /* 8 */ { c[i++] = 'I'; c[i++] = 'I'; c[i++] = 'I'; c[i++] = 'V'; } else if (rem == 7) /* 7 */ { c[i++] = 'I'; c[i++] = 'I'; c[i++] = 'V'; } else if (rem == 6) /* 6 */ { c[i++] = 'I'; c[i++] = 'V'; } else if (rem == 4) /* 4 */ { c[i++] = 'V'; c[i++] = 'I'; } else /* 3,2,1 */ { for (j = 0; j < rem; j++) c[i++] = 'I'; } } aval /= 10; if (aval == 0) goto done_100; rem = aval % 10; if (rem == 4) { c[i++] = 'L'; c[i++] = 'X'; } else if (rem == 5) { c[i++] = 'L'; } else if (rem < 4) { for (j = 0; j < rem; j++) c[i++] = 'X'; } else { for (j = 0; j < rem - 5; j++) c[i++] = 'X'; c[i++] = 'L'; } } done_100: /* * divide by 100 (they are done) and temp mod by another 10 */ aval = abs (value); aval /= 100; if (aval > 0) { rem = aval % 10; if (rem == 4) { c[i++] = 'D'; c[i++] = 'C'; } if (rem == 5) { c[i++] = 'D'; } else if (rem < 4) { for (j = 0; j < rem; j++) c[i++] = 'C'; } else if (rem == 9) { c[i++] = 'M'; c[i++] = 'C'; } else if (rem < 9) { for (j = 0; j < rem - 5; j++) c[i++] = 'C'; c[i++] = 'D'; } } aval /= 10; if (aval > 0) { rem = aval % 10; if (rem < 4) { for (j = 0; j < rem; j++) c[i++] = 'M'; } } if (value < 0) c[i++] = '-'; for (j = 0; j < i; ++j) *p++ = c[i - j - 1]; return (i); } /*------------------------------*/ /* itoroman */ /*------------------------------*/ itoroman (value, p, size) int value; char *p; int size; { /* * convert integer to lower roman */ register int i; register int len; register int aval; char c[100]; c[0] = EOS; len = itoROMAN (value, c, size); for (i = 0; i < len; i++) { p[i] = c[i]; if (isalpha (p[i])) p[i] = tolower (c[i]); } return (len); } /*------------------------------*/ /* itoLETTER */ /*------------------------------*/ itoLETTER (value, p, size) int value; register char *p; register int size; { /* * convert integer to upper letter value: 0,A,B,C,...,AA,AB,AC,... */ register int i; register int j; register int k; register int aval; int rem; char c[20]; aval = abs (value); c[0] = EOS; i = 1; /* * 1 based: * * 0 0 * 1 A * 25 Z * 26 AA * 51 AZ * 52 AAA * ... */ if (aval == 0) c[i++] = '0'; else if (aval < 27) { c[i++] = aval - 1 + 'A'; } else { do { c[i++] = ((aval - 1) % 26) + 'A'; aval = (aval - 1) / 26; } while (aval > 0 && i <= size); } if (value < 0 && i <= size) c[i++] = '-'; for (j = 0; j < i; ++j) *p++ = c[i - j - 1]; return (i); } /*------------------------------*/ /* itoletter */ /*------------------------------*/ itoletter (value, p, size) int value; register char *p; register int size; { /* * convert integer to upper letter value: 0,a,b,c,...,aa,ab,ac,... */ register int i; register int j; register int k; register int aval; char c[20]; int rem; aval = abs (value); c[0] = EOS; i = 1; /* * 1 based: * * 0 0 * 1 A * 25 Z * 26 AA * 51 AZ * 52 AAA * ... */ if (aval == 0) c[i++] = '0'; else if (aval < 27) { c[i++] = aval - 1 + 'a'; } else { do { c[i++] = ((aval - 1) % 26) + 'a'; aval = (aval - 1) / 26; } while (aval > 0 && i <= size); } if (value < 0 && i <= size) c[i++] = '-'; for (j = 0; j < i; ++j) *p++ = c[i - j - 1]; return (i); } /*------------------------------*/ /* min */ /*------------------------------*/ #ifdef min #undef min #endif min (v1, v2) register int v1; register int v2; { /* * find minimum of two integer ONLY */ return ((v1 < v2) ? v1 : v2); } /*------------------------------*/ /* max */ /*------------------------------*/ #ifdef max #undef max #endif max (v1, v2) register int v1; register int v2; { /* * find maximum of two integers ONLY */ return ((v1 > v2) ? v1 : v2); } /*------------------------------*/ /* err_exit */ /*------------------------------*/ #ifdef ALCYON #include <osbind.h> #endif err_exit (code) { /* * exit cleanly on fatal error (close files, etc). also handles normal * exit. */ if (err_stream != stderr && err_stream != (FILE *) 0) fclose (err_stream); if (dbg_stream != stderr && dbg_stream != (FILE *) 0) fclose (dbg_stream); #ifdef ALCYON if (hold_screen) { printf ("enter any key..."); Cconin (); } #endif exit (code); } @//E*O*F low.c// chmod u=rw,g=r,o=r low.c echo x - macros.c sed 's/^@//' > "macros.c" <<'@//E*O*F macros.c//' /* * macros.c - macro input/output processing for 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" /*------------------------------*/ /* defmac */ /*------------------------------*/ defmac (p, infp) register char *p; FILE *infp; { /* * Define a macro. top level, read from stream. * * we should read macro without interpretation EXCEPT: * * 1) number registers are interpolated * 2) strings indicated by \* are interpolated * 3) arguments indicated by \$ are interpolated * 4) concealed newlines indicated by \(newline) are eliminated * 5) comments indicated by \" are eliminated * 6) \t and \a are interpreted as ASCII h tab and SOH. * 7) \\ is interpreted as backslash and \. is interpreted as a period. * * currently, we do only 3. a good place to do it would be here before * putmac, after colmac... */ register char *q; register int i; char name[MNLEN]; char defn[MXMLEN]; char newend[10]; /* * skip the .de and get to the name... */ q = skipwd (p); q = skipbl (q); /* * ok, name now holds the name. make sure it is valid (i.e. first * char is alpha...). getwrd returns the length of the word. */ i = getwrd (q, name); if (!isalpha (*name)) { fprintf (err_stream, "***%s: missing or illegal macro definition name\n", myname); err_exit (-1); } /* * truncate to 2 char max name. */ if (i > 2) name[2] = EOS; /* * skip the name and see if we have a new end defined... */ q = skipwd (p); q = skipbl (q); for (i = 0; i < 10; i++) newend[i] = EOS; for (i = 0; (i < 10) && ( isalpha (q[i]) || isdigit (q[i]) ); i++) { newend[i] = q[i]; } /* * read a line from input stream until we get the end of macro * command (.en or ..). actually. we should have read the next * field just above here to get the .de NA . or .de NA en string * to be new end of macro. */ i = 0; while (getlin (p, infp) != EOF) { if (p[0] == dc.cmdchr && newend[0] != EOS && p[1] == newend[0] && p[2] == newend[1]) { /* * replacement end found */ break; } if (p[0] == dc.cmdchr && p[1] == 'e' && p[2] == 'n') { /* * .en found */ break; } if (p[0] == dc.cmdchr && p[1] == dc.cmdchr) { /* * .. found */ break; } /* * collect macro from the line we just read. all this does * is put it in the string defn. */ if ((i = colmac (p, defn, i)) == ERR) { fprintf (err_stream, "***%s: macro definition too long\n", myname); err_exit (-1); } } /* * store the macro */ if (putmac (name, defn) == ERR) { fprintf (err_stream, "***%s: macro definition table full\n", myname); err_exit (-1); } } /*------------------------------*/ /* colmac */ /*------------------------------*/ colmac (p, d, i) register char *p; char d[]; register int i; { /* * Collect macro definition from input stream */ while (*p != EOS) { if (i >= MXMLEN - 1) { d[i - 1] = EOS; return (ERR); } d[i++] = *p++; } d[i] = EOS; return (i); } /*------------------------------*/ /* putmac */ /*------------------------------*/ putmac (name, p) char *name; char *p; { /* * Put macro definition into table * * NOTE: any expansions of things like number registers SHOULD * have been done already. */ /* * any room left? (did we exceed max number of possible macros) */ if (mac.lastp >= MXMDEF) return (ERR); /* * will new one fit in big buffer? */ if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF]) { return (ERR); } /* * add it... * * bump counter, set ptr to name, copy name, copy def. * finally increment end of macro buffer ptr (emb). * * macro looks like this in mb: * * mac.mb[MACBUF] size of total buf * lastp < MXMDEF number of macros possible * *mnames[MXMDEF] -> names, each max length * ..._____________________________...____________________... * / / /|X|X|0|macro definition |0| / / / / / / / * .../_/_/_|_|_|_|________________...___|_|/_/_/_/_/_/_/_... * ^ * | * \----- mac.mnames[mac.lastp] points here * * both the 2 char name (XX) and the descripton are null term and * follow one after the other. */ ++mac.lastp; mac.mnames[mac.lastp] = mac.emb; strcpy (mac.emb, name); strcpy (mac.emb + strlen (name) + 1, p); mac.emb += strlen (name) + strlen (p) + 2; return (OK); } /*------------------------------*/ /* getmac */ /*------------------------------*/ char *getmac (name) register char *name; { /* * Get (lookup) macro definition from namespace */ register int i; /* * loop for all macros, starting with last one */ for (i = mac.lastp; i >= 0; --i) { /* * is this REALLY a macro? */ if (mac.mnames[i]) { /* * if it compares, return a ptr to it */ if (!strcmp (name, mac.mnames[i])) { /*!!!debug puts (mac.mnames[i]);*/ if (mac.mnames[i][1] == EOS) return (mac.mnames[i] + 2); else return (mac.mnames[i] + 3); } } } /* * none found, return null */ return (NULL); } /*------------------------------*/ /* maceval */ /*------------------------------*/ maceval (p, m) register char *p; char m[]; { /* * Evaluate macro expansion */ register int i; register int j; char *argp[10]; char c; /* * replace command char with EOS */ *p++ = EOS; /* * initialize argp array to substitute command * string for any undefined argument * * NO!!! this is fixed... */ for (i = 0; i < 10; ++i) argp[i] = p; /* * skip the command name */ p = skipwd (p); *p++ = EOS; /* * loop for all $n variables... */ for (i = 0; i < 10; ++i) { /* * get to substituted param and if no more, reset remaining * args to NULL and stop... */ p = skipbl (p); if (*p == '\r' || *p == '\n' || *p == EOS) { for ( ; i < 10; i++) *argp[i] = '\0'; break; } /* * ...otherwise, see if this param is quoted. if it is, * it is all one parameter, even with blanks (but not * newlines...). look for another "c" (which is the quote). * * if no quote, just read the arg as a single word and null * terminate it. */ if (*p == '\'' || *p == '"') { c = *p++; argp[i] = p; while (*p != c && *p != '\r' && *p != '\n' && *p != EOS) ++p; *p++ = EOS; } else { argp[i] = p; p = skipwd (p); *p++ = EOS; } } /* * m contains text of the macro. p contained the input line. * here we start at the end of the macro def and see if there * are any $n thingies. go backwards. */ for (i = strlen (m) - 1; i >= 0; --i) { /* * found a $. */ if (i > 0 && m[i - 1] == '$') { if (!isdigit (m[i])) { /* * it wasn't a numeric replacement arg so * push this char back onto input stream */ putbak (m[i]); } else { /* * it WAS a numeric replacement arg. so we * want to push back the appropriate macro * invocation arg. m[i]-'0' is the numerical * value of the $0 thru $9. if the arg is * not there, argp[n] will be (char *) 0 * and pbstr will do nothing. */ pbstr (argp[m[i] - '0']); --i; } } else { /* * no $ so push back the char... */ putbak (m[i]); } } /* * at this point, the iobuf will hold the new macro command, full * expanded for $n things. the return gets us right back to the * main loop in main() and we parse the (new) command just as if * it were read from a file. */ } /*------------------------------*/ /* printmac */ /*------------------------------*/ printmac (opt) int opt; /* 0=name&size,1=total size,2=full */ { /* * print all macros and strings and tabulate sizes */ register long i; register long space; register long totalspace; register char *pname; register char *pdef; space = 0L; totalspace = 0L; fflush (pout); fflush (err_stream); for (i = (long) mac.lastp; i >= 0; --i) { /* * is this REALLY a macro? */ if (mac.mnames[i]) { pname = (char *) (mac.mnames[i]); pdef = pname + 3; if (*(pname + 1) == '\0') pdef = pname + 2; space = (long) strlen (pdef); totalspace += space; switch (opt) { case 0: fprintf (err_stream, "%s %ld\n", pname, space); break; case 2: fprintf (err_stream, "%s %ld\n", pname, space); fprintf (err_stream, "%s\n", pdef); break; case 1: default: break; } } } fprintf (err_stream, "Total space: %ld\n", totalspace); } @//E*O*F macros.c// chmod u=rw,g=r,o=r macros.c echo x - strings.c sed 's/^@//' > "strings.c" <<'@//E*O*F strings.c//' /* * strings.c - String input/output processing for 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" /*------------------------------*/ /* defstr */ /*------------------------------*/ defstr (p) register char *p; { /* * Define a string. top level, read from command line. * * we should read string without interpretation EXCEPT: * * 1) number registers are interpolated * 2) strings indicated by \* are interpolated * 3) arguments indicated by \$ are interpolated * 4) concealed newlines indicated by \(newline) are eliminated * 5) comments indicated by \" are eliminated * 6) \t and \a are interpreted as ASCII h tab and SOH. * 7) \\ is interpreted as backslash and \. is interpreted as a period. * * currently, we do only 3. a good place to do it would be here before * putstr, after colstr... */ register char *q; register int i; char name[MNLEN]; char defn[MXMLEN]; name[0] = '\0'; defn[0] = '\0'; /* * skip the .ds and get to the name... */ q = skipwd (p); q = skipbl (q); /* * ok, name now holds the name. make sure it is valid (i.e. first * char is alpha...). getwrd returns the length of the word. */ i = getwrd (q, name); if (!name[0]) { fprintf (err_stream, "***%s: missing or illegal string definition name\n", myname); err_exit (-1); } /* * truncate to 2 char max name. */ if (i > 2) name[2] = EOS; /* * skip the name to get to the string. it CAN start with a " to * have leading blanks... */ q = skipwd (q); q = skipbl (q); /* * read rest of line from input stream and collect string into * temp buffer defn */ if ((i = colstr (q, defn)) == ERR) { fprintf (err_stream, "***%s: string definition too long\n", myname); err_exit (-1); } /* * store the string */ if (putstr (name, defn) == ERR) { fprintf (err_stream, "***%s: string definition table full\n", myname); err_exit (-1); } } /*------------------------------*/ /* colstr */ /*------------------------------*/ colstr (p, d) register char *p; char d[]; { /* * Collect string definition from input stream */ register int i = 0; if (*p == '\"') p++; while (*p != EOS) { if (i >= MXMLEN - 1) { d[i - 1] = EOS; return (ERR); } d[i++] = *p++; } d[i] = EOS; return (i); } /*------------------------------*/ /* putstr */ /*------------------------------*/ putstr (name, p) register char *name; register char *p; { /* * Put string definition into (macro) table * * NOTE: any expansions of things like number registers SHOULD * have been done already. strings and macros share mb buffer */ /* * any room left? (did we exceed max number of possible macros) */ if (mac.lastp >= MXMDEF) return (ERR); /* * will new one fit in big buffer? */ if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF]) { return (ERR); } /* * add it... * * bump counter, set ptr to name, copy name, copy def. * finally increment end of macro buffer ptr (emb). * * string looks like this in mb: * * mac.mb[MACBUF] size of total buf * lastp < MXMDEF number of macros/strings possible * *mnames[MXMDEF] -> names, each max length * ...______________________________...____________________... * / / /|X|X|0|string definition |0| / / / / / / / * .../_/_/_|_|_|_|_________________...___|_|/_/_/_/_/_/_/_... * ^ * | * \----- mac.mnames[mac.lastp] points here * * both the 2 char name (XX) and the descripton are null term and * follow one after the other. */ ++mac.lastp; mac.mnames[mac.lastp] = mac.emb; strcpy (mac.emb, name); strcpy (mac.emb + strlen (name) + 1, p); mac.emb += strlen (name) + strlen (p) + 2; return (OK); } /*------------------------------*/ /* getstr */ /*------------------------------*/ char *getstr (name) register char *name; { /* * Get (lookup) string definition from namespace */ register int i; /* * loop for all macros, starting with last one */ for (i = mac.lastp; i >= 0; --i) { /* * is this REALLY a macro? */ if (mac.mnames[i]) { /* * if it compares, return a ptr to it */ if (!strcmp (name, mac.mnames[i])) { /*!!!debug puts (mac.mnames[i]);*/ if (mac.mnames[i][1] == EOS) return (mac.mnames[i] + 2); else return (mac.mnames[i] + 3); } } } /* * none found, return null */ return (NULL); } @//E*O*F strings.c// chmod u=rw,g=r,o=r strings.c exit 0