diff options
Diffstat (limited to 'src/cmd/eqn/text.c')
-rw-r--r-- | src/cmd/eqn/text.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/cmd/eqn/text.c b/src/cmd/eqn/text.c new file mode 100644 index 00000000..261c7fbf --- /dev/null +++ b/src/cmd/eqn/text.c @@ -0,0 +1,318 @@ +#include "e.h" +#include "y.tab.h" +#include <ctype.h> + +#define CSSIZE 1000 +char cs[CSSIZE+20]; /* text string converted into this */ +char *csp; /* next spot in cs[] */ +char *psp; /* next character in input token */ + +int lf, rf; /* temporary spots for left and right fonts */ +int lastft; /* last \f added */ +int nextft; /* next \f to be added */ + +int pclass; /* class of previous character */ +int nclass; /* class of next character */ + +int class[LAST][LAST] ={ /* guesswork, tuned to times roman postscript */ + + /*OT OL IL DG LP RP SL PL IF IJ VB */ +/*OT*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OTHER */ +/*OL*/ { 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OLET */ +/*IL*/ { 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 }, /* ILET */ +/*DG*/ { 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 }, /* DIG */ +/*LP*/ { 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 }, /* LPAR */ +/*RP*/ { 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 }, /* RPAR */ +/*SL*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 }, /* SLASH */ +/*PL*/ { 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 }, /* PLUS */ +/*IF*/ { 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 }, /* ILETF */ +/*IJ*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 }, /* ILETJ */ +/*VB*/ { 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 }, /* VBAR */ + +}; + +extern void shim(int, int); +extern void roman(int); +extern void sadd(char *); +extern void cadd(int); +extern int trans(int, char *); + +int textc(void) /* read next UTF rune from psp */ +{ + wchar_t r; + int w; + + w = mbtowc(&r, psp, 3); + if(w == 0){ + psp++; + return 0; + } + if(w < 0){ + psp += 1; + return 0x80; /* Plan 9-ism */ + } + psp += w; + return r; +} + +void text(int t, char *p1) /* convert text string p1 of type t */ +{ + int c; + char *p; + tbl *tp; + + yyval = salloc(); + ebase[yyval] = 0; + eht[yyval] = EM(1.0, ps); /* ht in ems of orig size */ + lfont[yyval] = rfont[yyval] = ROM; + lclass[yyval] = rclass[yyval] = OTHER; + if (t == QTEXT) { + for (p = p1; *p; p++) /* scan for embedded \f's */ + if (*p == '\\' && *(p+1) == 'f') + break; + if (*p) /* if found \f, leave it alone and hope */ + p = p1; + else { + sprintf(cs, "\\f%s%s\\fP", ftp->name, p1); + p = cs; + } + } else if (t == SPACE) + p = "\\ "; + else if (t == THIN) + p = "\\|"; + else if (t == TAB) + p = "\\t"; + else if ((tp = lookup(restbl, p1)) != NULL) { + p = tp->cval; + } else { + lf = rf = 0; + lastft = 0; + nclass = NONE; /* get started with no class == no pad */ + csp = cs; + for (psp = p1; (c = textc()) != '\0'; ) { + nextft = ft; + pclass = nclass; + rf = trans(c, p1); + if (lf == 0) { + lf = rf; /* left stuff is first found */ + lclass[yyval] = nclass; + } + if (csp-cs > CSSIZE) + ERROR "converted token %.25s... too long", p1 FATAL ; + } + sadd("\\fP"); + *csp = '\0'; + p = cs; + lfont[yyval] = lf; + rfont[yyval] = rf; + rclass[yyval] = nclass; + } + dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n", + t, yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps); + printf(".ds %d \"%s\n", yyval, p); +} + +int isalpharune(int c) +{ + return ('a'<=c && c<='z') || ('A'<=c && c<='Z'); +} + +int isdigitrune(int c) +{ + return ('0'<=c && c<='9'); +} + +trans(int c, char *p1) +{ + int f; + + if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') { /* italic letter */ + shim(pclass, nclass = ILET); + cadd(c); + return ITAL; + } + if (isalpharune(c) && ft != ITAL) { /* other letter */ + shim(pclass, nclass = OLET); + cadd(c); + return ROM; + } + if (isdigitrune(c)) { + shim(pclass, nclass = DIG); + roman(c); + return ROM; /* this is the right side font of this object */ + } + f = ROM; + nclass = OTHER; + switch (c) { + case ':': case ';': case '!': case '%': case '?': + shim(pclass, nclass); + roman(c); + return f; + case '(': case '[': + shim(pclass, nclass = LPAR); + roman(c); + return f; + case ')': case ']': + shim(pclass, nclass = RPAR); + roman(c); + return f; + case ',': + shim(pclass, nclass = OTHER); + roman(c); + return f; + case '.': + if (rf == ROM) + roman(c); + else + cadd(c); + return f; + case '|': /* postscript needs help with default width! */ + shim(pclass, nclass = VBAR); + sadd("\\v'.17m'\\z|\\v'-.17m'\\|"); /* and height */ + return f; + case '=': + shim(pclass, nclass = PLUS); + sadd("\\(eq"); + return f; + case '+': + shim(pclass, nclass = PLUS); + sadd("\\(pl"); + return f; + case '>': + case '<': /* >, >=, >>, <, <-, <=, << */ + shim(pclass, nclass = PLUS); + if (*psp == '=') { + sadd(c == '<' ? "\\(<=" : "\\(>="); + psp++; + } else if (c == '<' && *psp == '-') { /* <- only */ + sadd("\\(<-"); + psp++; + } else if (*psp == c) { /* << or >> */ + cadd(c); + cadd(c); + psp++; + } else { + cadd(c); + } + return f; + case '-': + shim(pclass, nclass = PLUS); /* probably too big for ->'s */ + if (*psp == '>') { + sadd("\\(->"); + psp++; + } else { + sadd("\\(mi"); + } + return f; + case '/': + shim(pclass, nclass = SLASH); + cadd('/'); + return f; + case '~': + case ' ': + sadd("\\|\\|"); + return f; + case '^': + sadd("\\|"); + return f; + case '\\': /* troff - pass only \(xx without comment */ + shim(pclass, nclass); + cadd('\\'); + cadd(c = *psp++); + if (c == '(' && *psp && *(psp+1)) { + cadd(*psp++); + cadd(*psp++); + } else + fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n", + c, curfile->fname, curfile->lineno); + return f; + case '\'': + shim(pclass, nclass); + sadd("\\(fm"); + return f; + + case 'f': + if (ft == ITAL) { + shim(pclass, nclass = ILETF); + cadd('f'); + f = ITAL; + } else + cadd('f'); + return f; + case 'j': + if (ft == ITAL) { + shim(pclass, nclass = ILETJ); + cadd('j'); + f = ITAL; + } else + cadd('j'); + return f; + default: + shim(pclass, nclass); + cadd(c); + return ft==ITAL ? ITAL : ROM; + } +} + +char *pad(int n) /* return the padding as a string */ +{ + static char buf[20]; + + buf[0] = 0; + if (n < 0) { + sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n); + return buf; + } + for ( ; n > 1; n -= 2) + strcat(buf, "\\|"); + if (n > 0) + strcat(buf, "\\^"); + return buf; +} + +void shim(int lc, int rc) /* add padding space suitable to left and right classes */ +{ + sadd(pad(class[lc][rc])); +} + +void roman(int c) /* add char c in "roman" font */ +{ + nextft = ROM; + cadd(c); +} + +void sadd(char *s) /* add string s to cs */ +{ + while (*s) + cadd(*s++); +} + +void cadd(int c) /* add character c to end of cs */ +{ + char *p; + int w; + + if (lastft != nextft) { + if (lastft != 0) { + *csp++ = '\\'; + *csp++ = 'f'; + *csp++ = 'P'; + } + *csp++ = '\\'; + *csp++ = 'f'; + if (ftp == ftstack) { /* bottom level */ + if (ftp->ft == ITAL) /* usual case */ + *csp++ = nextft; + else /* gfont set, use it */ + for (p = ftp->name; *csp = *p++; ) + csp++; + } else { /* inside some kind of font ... */ + for (p = ftp->name; *csp = *p++; ) + csp++; + } + lastft = nextft; + } + w = wctomb(csp, c); + if(w > 0) /* ignore bad characters */ + csp += w; +} |