aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/eqn/text.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/eqn/text.c')
-rw-r--r--src/cmd/eqn/text.c318
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;
+}