13e12c5d1SDavid du Colombier #include "e.h"
23e12c5d1SDavid du Colombier #include "y.tab.h"
33e12c5d1SDavid du Colombier #include <ctype.h>
4*2651f6bbSDavid du Colombier #include <utf.h>
53e12c5d1SDavid du Colombier
63e12c5d1SDavid du Colombier #define CSSIZE 1000
73e12c5d1SDavid du Colombier char cs[CSSIZE+20]; /* text string converted into this */
83e12c5d1SDavid du Colombier char *csp; /* next spot in cs[] */
93e12c5d1SDavid du Colombier char *psp; /* next character in input token */
103e12c5d1SDavid du Colombier
113e12c5d1SDavid du Colombier int lf, rf; /* temporary spots for left and right fonts */
123e12c5d1SDavid du Colombier int lastft; /* last \f added */
133e12c5d1SDavid du Colombier int nextft; /* next \f to be added */
143e12c5d1SDavid du Colombier
153e12c5d1SDavid du Colombier int pclass; /* class of previous character */
163e12c5d1SDavid du Colombier int nclass; /* class of next character */
173e12c5d1SDavid du Colombier
183e12c5d1SDavid du Colombier int class[LAST][LAST] ={ /* guesswork, tuned to times roman postscript */
193e12c5d1SDavid du Colombier
203e12c5d1SDavid du Colombier /*OT OL IL DG LP RP SL PL IF IJ VB */
213e12c5d1SDavid du Colombier /*OT*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OTHER */
223e12c5d1SDavid du Colombier /*OL*/ { 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OLET */
233e12c5d1SDavid du Colombier /*IL*/ { 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 }, /* ILET */
243e12c5d1SDavid du Colombier /*DG*/ { 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 }, /* DIG */
253e12c5d1SDavid du Colombier /*LP*/ { 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 }, /* LPAR */
263e12c5d1SDavid du Colombier /*RP*/ { 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 }, /* RPAR */
273e12c5d1SDavid du Colombier /*SL*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 }, /* SLASH */
283e12c5d1SDavid du Colombier /*PL*/ { 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 }, /* PLUS */
293e12c5d1SDavid du Colombier /*IF*/ { 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 }, /* ILETF */
303e12c5d1SDavid du Colombier /*IJ*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 }, /* ILETJ */
313e12c5d1SDavid du Colombier /*VB*/ { 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 }, /* VBAR */
323e12c5d1SDavid du Colombier
333e12c5d1SDavid du Colombier };
343e12c5d1SDavid du Colombier
353e12c5d1SDavid du Colombier extern void shim(int, int);
363e12c5d1SDavid du Colombier extern void roman(int);
373e12c5d1SDavid du Colombier extern void sadd(char *);
383e12c5d1SDavid du Colombier extern void cadd(int);
393e12c5d1SDavid du Colombier extern int trans(int, char *);
403e12c5d1SDavid du Colombier
textc(void)417dd7cddfSDavid du Colombier int textc(void) /* read next UTF rune from psp */
427dd7cddfSDavid du Colombier {
437dd7cddfSDavid du Colombier wchar_t r;
447dd7cddfSDavid du Colombier int w;
457dd7cddfSDavid du Colombier
46*2651f6bbSDavid du Colombier w = mbtowc(&r, psp, UTFmax);
477dd7cddfSDavid du Colombier if(w == 0){
487dd7cddfSDavid du Colombier psp++;
497dd7cddfSDavid du Colombier return 0;
507dd7cddfSDavid du Colombier }
517dd7cddfSDavid du Colombier if(w < 0){
527dd7cddfSDavid du Colombier psp += 1;
53*2651f6bbSDavid du Colombier return Runeerror; /* Plan 9-ism */
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier psp += w;
567dd7cddfSDavid du Colombier return r;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier
text(int t,char * p1)593e12c5d1SDavid du Colombier void text(int t, char *p1) /* convert text string p1 of type t */
603e12c5d1SDavid du Colombier {
613e12c5d1SDavid du Colombier int c;
623e12c5d1SDavid du Colombier char *p;
633e12c5d1SDavid du Colombier tbl *tp;
643e12c5d1SDavid du Colombier
653e12c5d1SDavid du Colombier yyval = salloc();
663e12c5d1SDavid du Colombier ebase[yyval] = 0;
673e12c5d1SDavid du Colombier eht[yyval] = EM(1.0, ps); /* ht in ems of orig size */
683e12c5d1SDavid du Colombier lfont[yyval] = rfont[yyval] = ROM;
693e12c5d1SDavid du Colombier lclass[yyval] = rclass[yyval] = OTHER;
703e12c5d1SDavid du Colombier if (t == QTEXT) {
713e12c5d1SDavid du Colombier for (p = p1; *p; p++) /* scan for embedded \f's */
723e12c5d1SDavid du Colombier if (*p == '\\' && *(p+1) == 'f')
733e12c5d1SDavid du Colombier break;
743e12c5d1SDavid du Colombier if (*p) /* if found \f, leave it alone and hope */
753e12c5d1SDavid du Colombier p = p1;
763e12c5d1SDavid du Colombier else {
773e12c5d1SDavid du Colombier sprintf(cs, "\\f%s%s\\fP", ftp->name, p1);
783e12c5d1SDavid du Colombier p = cs;
793e12c5d1SDavid du Colombier }
803e12c5d1SDavid du Colombier } else if (t == SPACE)
813e12c5d1SDavid du Colombier p = "\\ ";
823e12c5d1SDavid du Colombier else if (t == THIN)
833e12c5d1SDavid du Colombier p = "\\|";
843e12c5d1SDavid du Colombier else if (t == TAB)
853e12c5d1SDavid du Colombier p = "\\t";
863e12c5d1SDavid du Colombier else if ((tp = lookup(restbl, p1)) != NULL) {
873e12c5d1SDavid du Colombier p = tp->cval;
883e12c5d1SDavid du Colombier } else {
893e12c5d1SDavid du Colombier lf = rf = 0;
903e12c5d1SDavid du Colombier lastft = 0;
913e12c5d1SDavid du Colombier nclass = NONE; /* get started with no class == no pad */
923e12c5d1SDavid du Colombier csp = cs;
937dd7cddfSDavid du Colombier for (psp = p1; (c = textc()) != '\0'; ) {
943e12c5d1SDavid du Colombier nextft = ft;
953e12c5d1SDavid du Colombier pclass = nclass;
963e12c5d1SDavid du Colombier rf = trans(c, p1);
973e12c5d1SDavid du Colombier if (lf == 0) {
983e12c5d1SDavid du Colombier lf = rf; /* left stuff is first found */
993e12c5d1SDavid du Colombier lclass[yyval] = nclass;
1003e12c5d1SDavid du Colombier }
1013e12c5d1SDavid du Colombier if (csp-cs > CSSIZE)
1023e12c5d1SDavid du Colombier ERROR "converted token %.25s... too long", p1 FATAL ;
1033e12c5d1SDavid du Colombier }
1043e12c5d1SDavid du Colombier sadd("\\fP");
1053e12c5d1SDavid du Colombier *csp = '\0';
1063e12c5d1SDavid du Colombier p = cs;
1073e12c5d1SDavid du Colombier lfont[yyval] = lf;
1083e12c5d1SDavid du Colombier rfont[yyval] = rf;
1093e12c5d1SDavid du Colombier rclass[yyval] = nclass;
1103e12c5d1SDavid du Colombier }
1113e12c5d1SDavid du Colombier dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n",
1123e12c5d1SDavid du Colombier t, yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps);
1133e12c5d1SDavid du Colombier printf(".ds %d \"%s\n", yyval, p);
1143e12c5d1SDavid du Colombier }
1153e12c5d1SDavid du Colombier
isdigitrune(int c)1167dd7cddfSDavid du Colombier int isdigitrune(int c)
1177dd7cddfSDavid du Colombier {
1187dd7cddfSDavid du Colombier return ('0'<=c && c<='9');
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier
121*2651f6bbSDavid du Colombier int
trans(int c,char *)122*2651f6bbSDavid du Colombier trans(int c, char *)
1233e12c5d1SDavid du Colombier {
1243e12c5d1SDavid du Colombier int f;
1253e12c5d1SDavid du Colombier
1267dd7cddfSDavid du Colombier if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') { /* italic letter */
1273e12c5d1SDavid du Colombier shim(pclass, nclass = ILET);
1283e12c5d1SDavid du Colombier cadd(c);
1293e12c5d1SDavid du Colombier return ITAL;
1303e12c5d1SDavid du Colombier }
1317dd7cddfSDavid du Colombier if (isalpharune(c) && ft != ITAL) { /* other letter */
1323e12c5d1SDavid du Colombier shim(pclass, nclass = OLET);
1333e12c5d1SDavid du Colombier cadd(c);
1343e12c5d1SDavid du Colombier return ROM;
1353e12c5d1SDavid du Colombier }
1367dd7cddfSDavid du Colombier if (isdigitrune(c)) {
1373e12c5d1SDavid du Colombier shim(pclass, nclass = DIG);
1383e12c5d1SDavid du Colombier roman(c);
1393e12c5d1SDavid du Colombier return ROM; /* this is the right side font of this object */
1403e12c5d1SDavid du Colombier }
1413e12c5d1SDavid du Colombier f = ROM;
1423e12c5d1SDavid du Colombier nclass = OTHER;
1433e12c5d1SDavid du Colombier switch (c) {
1443e12c5d1SDavid du Colombier case ':': case ';': case '!': case '%': case '?':
1453e12c5d1SDavid du Colombier shim(pclass, nclass);
1463e12c5d1SDavid du Colombier roman(c);
1473e12c5d1SDavid du Colombier return f;
1483e12c5d1SDavid du Colombier case '(': case '[':
1493e12c5d1SDavid du Colombier shim(pclass, nclass = LPAR);
1503e12c5d1SDavid du Colombier roman(c);
1513e12c5d1SDavid du Colombier return f;
1523e12c5d1SDavid du Colombier case ')': case ']':
1533e12c5d1SDavid du Colombier shim(pclass, nclass = RPAR);
1543e12c5d1SDavid du Colombier roman(c);
1553e12c5d1SDavid du Colombier return f;
1563e12c5d1SDavid du Colombier case ',':
1573e12c5d1SDavid du Colombier shim(pclass, nclass = OTHER);
1583e12c5d1SDavid du Colombier roman(c);
1593e12c5d1SDavid du Colombier return f;
1603e12c5d1SDavid du Colombier case '.':
1613e12c5d1SDavid du Colombier if (rf == ROM)
1623e12c5d1SDavid du Colombier roman(c);
1633e12c5d1SDavid du Colombier else
1643e12c5d1SDavid du Colombier cadd(c);
1653e12c5d1SDavid du Colombier return f;
1663e12c5d1SDavid du Colombier case '|': /* postscript needs help with default width! */
1673e12c5d1SDavid du Colombier shim(pclass, nclass = VBAR);
1683e12c5d1SDavid du Colombier sadd("\\v'.17m'\\z|\\v'-.17m'\\|"); /* and height */
1693e12c5d1SDavid du Colombier return f;
1703e12c5d1SDavid du Colombier case '=':
1713e12c5d1SDavid du Colombier shim(pclass, nclass = PLUS);
1723e12c5d1SDavid du Colombier sadd("\\(eq");
1733e12c5d1SDavid du Colombier return f;
1743e12c5d1SDavid du Colombier case '+':
1753e12c5d1SDavid du Colombier shim(pclass, nclass = PLUS);
1763e12c5d1SDavid du Colombier sadd("\\(pl");
1773e12c5d1SDavid du Colombier return f;
1783e12c5d1SDavid du Colombier case '>':
1793e12c5d1SDavid du Colombier case '<': /* >, >=, >>, <, <-, <=, << */
1803e12c5d1SDavid du Colombier shim(pclass, nclass = PLUS);
1813e12c5d1SDavid du Colombier if (*psp == '=') {
1823e12c5d1SDavid du Colombier sadd(c == '<' ? "\\(<=" : "\\(>=");
1833e12c5d1SDavid du Colombier psp++;
1843e12c5d1SDavid du Colombier } else if (c == '<' && *psp == '-') { /* <- only */
1853e12c5d1SDavid du Colombier sadd("\\(<-");
1863e12c5d1SDavid du Colombier psp++;
1873e12c5d1SDavid du Colombier } else if (*psp == c) { /* << or >> */
1883e12c5d1SDavid du Colombier cadd(c);
1893e12c5d1SDavid du Colombier cadd(c);
1903e12c5d1SDavid du Colombier psp++;
1913e12c5d1SDavid du Colombier } else {
1923e12c5d1SDavid du Colombier cadd(c);
1933e12c5d1SDavid du Colombier }
1943e12c5d1SDavid du Colombier return f;
1953e12c5d1SDavid du Colombier case '-':
1963e12c5d1SDavid du Colombier shim(pclass, nclass = PLUS); /* probably too big for ->'s */
1973e12c5d1SDavid du Colombier if (*psp == '>') {
1983e12c5d1SDavid du Colombier sadd("\\(->");
1993e12c5d1SDavid du Colombier psp++;
2003e12c5d1SDavid du Colombier } else {
2013e12c5d1SDavid du Colombier sadd("\\(mi");
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier return f;
2043e12c5d1SDavid du Colombier case '/':
2053e12c5d1SDavid du Colombier shim(pclass, nclass = SLASH);
2063e12c5d1SDavid du Colombier cadd('/');
2073e12c5d1SDavid du Colombier return f;
2083e12c5d1SDavid du Colombier case '~':
2093e12c5d1SDavid du Colombier case ' ':
2103e12c5d1SDavid du Colombier sadd("\\|\\|");
2113e12c5d1SDavid du Colombier return f;
2123e12c5d1SDavid du Colombier case '^':
2133e12c5d1SDavid du Colombier sadd("\\|");
2143e12c5d1SDavid du Colombier return f;
2153e12c5d1SDavid du Colombier case '\\': /* troff - pass only \(xx without comment */
2163e12c5d1SDavid du Colombier shim(pclass, nclass);
2173e12c5d1SDavid du Colombier cadd('\\');
2183e12c5d1SDavid du Colombier cadd(c = *psp++);
2193e12c5d1SDavid du Colombier if (c == '(' && *psp && *(psp+1)) {
2203e12c5d1SDavid du Colombier cadd(*psp++);
2213e12c5d1SDavid du Colombier cadd(*psp++);
2223e12c5d1SDavid du Colombier } else
2237dd7cddfSDavid du Colombier fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n",
2247dd7cddfSDavid du Colombier c, curfile->fname, curfile->lineno);
2253e12c5d1SDavid du Colombier return f;
2263e12c5d1SDavid du Colombier case '\'':
2273e12c5d1SDavid du Colombier shim(pclass, nclass);
2283e12c5d1SDavid du Colombier sadd("\\(fm");
2293e12c5d1SDavid du Colombier return f;
2303e12c5d1SDavid du Colombier
2313e12c5d1SDavid du Colombier case 'f':
2323e12c5d1SDavid du Colombier if (ft == ITAL) {
2333e12c5d1SDavid du Colombier shim(pclass, nclass = ILETF);
2343e12c5d1SDavid du Colombier cadd('f');
2353e12c5d1SDavid du Colombier f = ITAL;
2363e12c5d1SDavid du Colombier } else
2373e12c5d1SDavid du Colombier cadd('f');
2383e12c5d1SDavid du Colombier return f;
2393e12c5d1SDavid du Colombier case 'j':
2403e12c5d1SDavid du Colombier if (ft == ITAL) {
2413e12c5d1SDavid du Colombier shim(pclass, nclass = ILETJ);
2423e12c5d1SDavid du Colombier cadd('j');
2433e12c5d1SDavid du Colombier f = ITAL;
2443e12c5d1SDavid du Colombier } else
2453e12c5d1SDavid du Colombier cadd('j');
2463e12c5d1SDavid du Colombier return f;
2473e12c5d1SDavid du Colombier default:
2483e12c5d1SDavid du Colombier shim(pclass, nclass);
2493e12c5d1SDavid du Colombier cadd(c);
2503e12c5d1SDavid du Colombier return ft==ITAL ? ITAL : ROM;
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier }
2533e12c5d1SDavid du Colombier
pad(int n)2543e12c5d1SDavid du Colombier char *pad(int n) /* return the padding as a string */
2553e12c5d1SDavid du Colombier {
2563e12c5d1SDavid du Colombier static char buf[20];
2573e12c5d1SDavid du Colombier
2583e12c5d1SDavid du Colombier buf[0] = 0;
2593e12c5d1SDavid du Colombier if (n < 0) {
2603e12c5d1SDavid du Colombier sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n);
2613e12c5d1SDavid du Colombier return buf;
2623e12c5d1SDavid du Colombier }
2633e12c5d1SDavid du Colombier for ( ; n > 1; n -= 2)
2643e12c5d1SDavid du Colombier strcat(buf, "\\|");
2653e12c5d1SDavid du Colombier if (n > 0)
2663e12c5d1SDavid du Colombier strcat(buf, "\\^");
2673e12c5d1SDavid du Colombier return buf;
2683e12c5d1SDavid du Colombier }
2693e12c5d1SDavid du Colombier
shim(int lc,int rc)2703e12c5d1SDavid du Colombier void shim(int lc, int rc) /* add padding space suitable to left and right classes */
2713e12c5d1SDavid du Colombier {
2723e12c5d1SDavid du Colombier sadd(pad(class[lc][rc]));
2733e12c5d1SDavid du Colombier }
2743e12c5d1SDavid du Colombier
roman(int c)2753e12c5d1SDavid du Colombier void roman(int c) /* add char c in "roman" font */
2763e12c5d1SDavid du Colombier {
2773e12c5d1SDavid du Colombier nextft = ROM;
2783e12c5d1SDavid du Colombier cadd(c);
2793e12c5d1SDavid du Colombier }
2803e12c5d1SDavid du Colombier
sadd(char * s)2813e12c5d1SDavid du Colombier void sadd(char *s) /* add string s to cs */
2823e12c5d1SDavid du Colombier {
2833e12c5d1SDavid du Colombier while (*s)
2843e12c5d1SDavid du Colombier cadd(*s++);
2853e12c5d1SDavid du Colombier }
2863e12c5d1SDavid du Colombier
cadd(int c)2877dd7cddfSDavid du Colombier void cadd(int c) /* add character c to end of cs */
2883e12c5d1SDavid du Colombier {
2893e12c5d1SDavid du Colombier char *p;
2907dd7cddfSDavid du Colombier int w;
2913e12c5d1SDavid du Colombier
2923e12c5d1SDavid du Colombier if (lastft != nextft) {
2933e12c5d1SDavid du Colombier if (lastft != 0) {
2943e12c5d1SDavid du Colombier *csp++ = '\\';
2953e12c5d1SDavid du Colombier *csp++ = 'f';
2963e12c5d1SDavid du Colombier *csp++ = 'P';
2973e12c5d1SDavid du Colombier }
2983e12c5d1SDavid du Colombier *csp++ = '\\';
2993e12c5d1SDavid du Colombier *csp++ = 'f';
3003e12c5d1SDavid du Colombier if (ftp == ftstack) { /* bottom level */
3013e12c5d1SDavid du Colombier if (ftp->ft == ITAL) /* usual case */
3023e12c5d1SDavid du Colombier *csp++ = nextft;
3033e12c5d1SDavid du Colombier else /* gfont set, use it */
3043e12c5d1SDavid du Colombier for (p = ftp->name; *csp = *p++; )
3053e12c5d1SDavid du Colombier csp++;
3063e12c5d1SDavid du Colombier } else { /* inside some kind of font ... */
3073e12c5d1SDavid du Colombier for (p = ftp->name; *csp = *p++; )
3083e12c5d1SDavid du Colombier csp++;
3093e12c5d1SDavid du Colombier }
3103e12c5d1SDavid du Colombier lastft = nextft;
3113e12c5d1SDavid du Colombier }
3127dd7cddfSDavid du Colombier w = wctomb(csp, c);
3137dd7cddfSDavid du Colombier if(w > 0) /* ignore bad characters */
3147dd7cddfSDavid du Colombier csp += w;
3153e12c5d1SDavid du Colombier }
316