Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include "e.h"
#include "y.tab.h"
#include <ctype.h>
#include <utf.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, UTFmax);
        if(w == 0){
                psp++;
                return 0;
        }
        if(w < 0){
                psp += 1;
                return Runeerror;       /* 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 isdigitrune(int c)
{
        return ('0'<=c && c<='9');
}

int
trans(int c, char *)
{
        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;
}