/* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ /* @(#)picasso:troffgen.c 1.0 */ #include <string.h> #include <ctype.h> #include "font.h" #include "picasso.h" #include "y.tab.h" char esc = '\\'; char eqn_delim[] = "\0"; /* the following table of troff names for special characters is in ASCII */ /* order of their names, so that a binary search could be done if desired. */ /* the font field MUST conform to the font initialization in fonts.c, with */ /* the "standard" Times Roman in position 0 and the symbol font as font 1. */ struct trcode {char name[2]; char font; unsigned char value;} trcode[] = {'\0','\0','\0','\0', /* null entry, never matched. */ '!','=', 1, 0271, /* not equal */ '!','b', 1, 0313, /* not subset */ '!','m', 1, 0317, /* not member */ '"','a', 0, 0315, /* hungarumlaut accent */ '\'','\'',0,0272, /* right double quote */ '*','*', 1, '*', /* math star */ '*','A', 1, 'A', '*','B', 1, 'B', '*','C', 1, 'X', /* greek */ '*','D', 1, 'D', '*','E', 1, 'E', '*','F', 1, 'F', /* alpha-*/ '*','G', 1, 'G', '*','H', 1, 'Q', '*','I', 1, 'I', /* bet. */ '*','K', 1, 'K', '*','L', 1, 'L', '*','M', 1, 'M', '*','N', 1, 'N', '*','O', 1, 'O', '*','P', 1, 'P', '*','Q', 1, 'Y', '*','R', 1, 'R', '*','S', 1, 'S', '*','T', 1, 'T', '*','U', 1, 'U', '*','W', 1, 'W', '*','X', 1, 'C', '*','Y', 1, 'H', '*','Z', 1, 'Z', '*','a', 1, 'a', '*','b', 1, 'b', '*','c', 1, 'x', '*','d', 1, 'd', '*','e', 1, 'e', '*','f', 1, 'f', '*','g', 1, 'g', '*','h', 1, 'q', '*','i', 1, 'i', '*','k', 1, 'k', '*','l', 1, 'l', '*','m', 1, 'm', '*','n', 1, 'n', '*','o', 1, 'o', '*','p', 1, 'p', '*','q', 1, 'y', '*','r', 1, 'r', '*','s', 1, 's', '*','t', 1, 't', '*','u', 1, 'u', '*','w', 1, 'w', '*','x', 1, 'c', '*','y', 1, 'h', '*','z', 1, 'z', '+','-', 1, 0261, /* plus-minus */ ',','a', 0, 0313, /* cedilla accent */ '-','>', 1, 0256, /* right arrow */ '-','a', 0, 0305, /* macron accent */ '.','a', 0, 0307, /* dot accent */ ':','a', 0, 0310, /* dieresis accent */ '<','-', 1, 0254, /* left arrow */ '<','=', 1, 0243, /* less than or equal */ '=','=', 1, 0272, /* identically equal */ '>','=', 1, 0263, /* greater than or equal */ 'C','O', 1, 0343, /* copyright (sanserif) */ 'C','R', 1, 0277, /* carriage return */ 'C','a', 0, 0316, /* ogonek accent */ 'I','f', 1, 0301, /* I (fraktur) */ 'L','B', 1, 0350, /* paren, left bottom */ 'L','T', 1, 0346, /* paren, left top */ 'O','+', 1, 0305, /* circled plus */ 'O','x', 1, 0304, /* circled times */ 'R','B', 1, 0370, /* paren, right bottom */ 'R','G', 1, 0342, /* registered (sanserif) */ 'R','T', 1, 0366, /* paren, right top */ 'R','f', 1, 0302, /* R (fraktur) */ 'T','M', 1, 0344, /* trademark (sanserif) */ 'U','a', 0, 0306, /* breve accent */ '^','a', 0, 0303, /* circumflex accent */ '`','`', 0, 0252, /* left double quote */ 'a','a', 0, 0302, /* circumflex accent */ 'a','b', 1, 0253, /* arrow both (left & right) */ 'a','f', 1, 0300, /* aleph */ 'a','h', 1, 0276, /* arrow horizontal extender */ 'a','n', 1, 0320, /* angle */ 'a','p', 1, '~', /* approximates */ 'a','v', 1, 0275, /* arrow vertical extender */ 'b','<', 1, 0341, /* left angle bracket */ 'b','>', 1, 0361, /* right angle bracket */ 'b','u', 0, 0267, /* bullet */ 'b','v', 1, 0352, /* bold vertical (extender) */ 'c','.', 1, 0327, /* centered dot */ 'c','a', 1, 0307, /* cap */ 'c','g', 1, '@', /* congruent to */ 'c','o', 1, 0323, /* copyright (serif) */ 'c','r', 0, 0250, /* currency */ 'c','t', 0, 0242, /* cent */ 'c','u', 1, 0310, /* cup */ 'd','a', 1, 0257, /* down arrow */ 'd','d', 0, 0263, /* double dagger */ 'd','e', 1, 0260, /* degree */ 'd','g', 0, 0262, /* dagger */ 'd','i', 1, 0270, /* divide */ 'e','l', 0, 0274, /* ellipsis */ 'e','m', 0, 0320, /* emdash */ 'e','n', 0, 0261, /* endash */ 'e','q', 1, '=', /* equals */ 'e','s', 1, 0306, /* empty set */ 'f','a', 1, '"', /* for all */ 'f','i', 0, 0256, /* fi ligature */ 'f','l', 0, 0257, /* fl ligature */ 'f','m', 1, 0242, /* minute (footmark) */ 'f','n', 0, 0246, /* florin */ 'f','r', 0, 0244, /* fraction bar */ 'g','a', 0, 0301, /* circumflex accent */ 'g','r', 1, 0321, /* gradient */ 'h','y', 0, '-', /* hyphen */ 'i','b', 1, 0315, /* improper subset */ 'i','f', 1, 0245, /* infinity */ 'i','p', 1, 0312, /* improper superset */ 'i','s', 1, 0362, /* integral sign */ 'l','&', 1, 0331, /* logical and */ 'l','b', 1, 0356, /* brace, left bottom */ 'l','c', 1, 0351, /* square bracket l. ceiling */ 'l','f', 1, 0353, /* square bracket l. floor */ 'l','k', 1, 0355, /* brace, left middle */ 'l','t', 1, 0354, /* brace, left top */ 'l','z', 1, 0340, /* lozenge */ 'l','|', 1, 0332, /* logical or */ 'm','i', 1, '-', /* minus */ 'm','o', 1, 0316, /* member of */ 'm','u', 1, 0264, /* multiply */ 'n','o', 1, 0330, /* logical not */ 'o','a', 0, 0312, /* ring accent */ 'o','r', 1, '|', /* or (vertical bar) */ 'p','d', 1, 0266, /* partial derivative */ 'p','g', 0, 0266, /* paragraph */ 'p','l', 1, '+', /* plus */ 'p','p', 1, '^', /* perpendicular */ 'p','s', 0, 0243, /* pound sterling */ 'p','t', 1, 0265, /* proportional to */ 'r','b', 1, 0376, /* brace, right bottom */ 'r','c', 1, 0371, /* square bracket r. ceiling */ 'r','f', 1, 0373, /* square bracket r. floor */ 'r','g', 1, 0322, /* registered (serif) */ 'r','k', 1, 0375, /* brace, right middle */ 'r','n', 1, '\'', /* root extender (en) */ 'r','t', 1, 0374, /* brace, right top */ 's','b', 1, 0314, /* subset */ 's','c', 0, 0247, /* section */ 's','l', 1, '/', /* slash */ 's','p', 1, 0311, /* superset */ 's','r', 1, 0326, /* square root */ 's','t', 1, '`', /* such that */ 't','e', 1, '$', /* there exists */ 't','f', 1, '\\', /* therefore */ 't','m', 1, 0324, /* trademark (serif) */ 't','s', 1, 'V', /* terminal sigma */ 'u','a', 1, 0255, /* up arrow */ 'u','l', 1, '_', /* underscore */ 'v','a', 0, 0317, /* caron accent */ 'w','s', 1, 0303, /* Weierstrass P */ 'y','n', 0, 0245, /* yen */ '~','a', 0, 0304, /* tilde accent */ '~','~', 1, 0273, /* approximately */ '\0','\0','\0','\0', /* sentinel; loop terminus */ }; int troffcode(str) char *str; { int n; for (n = 1; trcode[n].name[0] != '\0'; n++) if (str[0] == trcode[n].name[0] && str[1] == trcode[n].name[1]) return n; return 0; } static troffparm(name, parm, prev) char *name, *parm; int *prev; /* the previous value */ { extern double atof(); double r, s=0, t; while (isspace(*parm)) ++parm; t = getfval(name); if (*parm == '\0') r = *prev; else { r = atof(parm); if (*parm == '+' || *parm == '-') s = t; while (*parm && !isspace(*parm)) parm++; switch (parm[-1]) { case 'i': r *= 72; break; case 'c': r *= (72.*50./127.); break; case 'P': r *= 12; break; case 'u': r /= 6; break; } } *prev = t; setfval(name, r+s); } /* The following should be regarded as a kludge, since these values don't get set by textsize = , etc. There is confusion between picasso's ideas of these variables and troff's. */ static int ft; /* save previous font for \fP and .ft */ static int psize = 10, /* ditto previous point size */ vsize = 12; /* and vertical spacing */ troff(s) char *s; { int i, fp; if (s[1] == 'f' && s[2] == 't') { for (s += 3; isspace(*s); ++s) ; i = getfval("textfont"); /* save current font */ if (s == '\0') /* reset previous */ fp = ft; else if (isdigit(*s)) /* allow multi-digit nums */ fp = checkfont((double)atoi(s)); else fp = setfont(tostring(s)); ft = i; setfval("textfont", fp); } else if (s[1] == 'p' && s[2] == 's') troffparm("textsize", s+3, &psize); else if (s[1] == 'v' && s[2] == 's') troffparm("textspace", s+3, &vsize); else if (s[1] == 'e') if (s[2] == 'o') esc = '\0'; else if (s[2] == 'c') { for (s += 3; isspace(*s); ++s) ; esc = *s ? *s : '\\'; } } obj *troffgen(s) YYSTYPE s; { troff(s.p); save_one(CENTER, 0, 0, 0, s.p); free(s.p); return makenode(TROFF, 0, (int)getfval("curlayer")); } char *parse_text (txt, fp, sp) /* split txt into substrings with */ char *txt; /* uniform font and pointsize; */ int *fp, *sp; /* some '\0' chars are put in txt.*/ { extern int parsing; static char buf[256]; static int n = 0, lim = 0; int i, j; char *bp; if (n == 0) { /* new string; initialize */ lim = strlen(txt); ft = *fp; } else if (n == lim) { n = 0; return NULL; } for (bp = buf; n < lim; ) { if (txt[n] != esc && txt[n] != *eqn_delim) *bp++ = txt[n++]; else if (txt[n] == *eqn_delim) { if (!parsing) { do n++; while (txt[n] != eqn_delim[1] && n < lim); n++; continue; } if (bp > buf) { *bp = '\0'; return buf; } eqn_save(".EQ"); while (txt[++n] != eqn_delim[1] && n < lim) *bp++ = txt[n]; if (n < lim) ++n; strcpy(bp, "\n.EN"); eqn_save(buf); eqn_gen(TEXT); bp = buf; *bp++ = '\0'; /* fudge, to prevent a 2nd save_one() */ } else { /* fonts, sizes, troff codes */ switch (txt[n+1]) { default: *bp++ = txt[n++]; break; case '&': /* zero-width char */ n += 2; /* discard it */ break; case '(': if ((i = troffcode(txt+n+2)) == 0) *bp++ = txt[n++]; /* unknown */ else { if (bp > buf && *fp != trcode[i].font) { *bp = '\0'; return buf; } *bp++ = trcode[i].value; ft = *fp; *fp = trcode[i].font; txt[++n] = '\\'; txt[n+1] = 'f'; txt[n+2] = 'P'; /* restore old font */ } break; case 'N': n += 3; *bp++ = atoi(txt+n); while (isdigit(txt[n])) n++; break; case 'f': if (bp > buf) { *bp = '\0'; return buf; } n += 2; i = *fp; /* save current font */ if (txt[n] == 'P') { /* reset previous */ *fp = ft; ++n; } else if (isdigit(txt[n])) *fp = checkfont((double)(txt[n++]-'0')); else { if (txt[n] != '(') *bp++ = txt[n++]; else { *bp++ = txt[++n]; *bp++ = txt[++n]; ++n; } *bp = '\0'; *fp = setfont(tostring(bp=buf)); } ft = i; break; case 's': if (bp > buf) { *bp = '\0'; return buf; } n += 2; if (txt[n] == '+' || txt[n] == '-') { if ((i = *sp) == 0) i = getfval("textsize"); if (txt[n] == '-') i = -i; ++n; } else i = 0; j = 0; if (i == 0 && txt[n] == '0'){/* use previous */ i = psize; ++n; } else { if (isdigit(txt[n])) j = txt[n++] - '0'; if (j && isdigit(txt[n])) j = j * 10 + txt[n++] - '0'; } psize = *sp = (i < 0 ? -(i+j) : i+j); break; } } } *bp = '\0'; if (bp != buf) return buf; else { n = 0; return NULL; } } int eqn_count = 0; char psfname[L_tmpnam] = ""; char dpost[] = "dpost"; FILE *eqnfp = NULL, *pipefp = NULL; int no_eqn = 0; eqn_save(s) char *s; { extern char *gwblib; char *dp, private[64], buf[BUFSIZ]; if (pipefp == NULL && !no_eqn){/* open up eqn|troff|dpost subprocess */ if (access("/usr/bin/eqn", 1)) /* kludge! */ no_eqn = 1; else { sprintf(private, "%s/%s", gwblib, dpost); dp = access(private,1) ? dpost : private; tmpnam(psfname); sprintf(buf, "eqn|troff -Tpost|%s -B>%s", dp, psfname); if ((pipefp = popen(buf, "w")) == NULL) fatal("cannot pipe through eqn"); } } if (no_eqn) { if (strncmp(s, ".EQ", 3) == 0 || strncmp(s, ".EN", 3) == 0 || strncmp(s, "delim", 5) == 0) ; else savetext(CENTER, s); return; } if (s[0] == '.' && s[1] == 'E' && s[2] == 'Q') { double f = getfval("textfont"); sprintf(buf,".ft %s\n.ps %d\n.vs %d\n", mount[(int)f]->name, (int)getfval("textsize"), (int)getfval("textspace")); fputs(buf, pipefp); } fputs(s, pipefp); fputc('\n', pipefp); scan_delim(s); } scan_delim(s) char *s; { while (isspace(*s)) ++s; /* probably eqn's syntax is less restrictive than the following */ if (strncmp(s,"delim",5)==0) { for (s += 5; isspace(*s); ++s) ; if (strcmp(s,"off")==0) eqn_delim[1] = eqn_delim[0] = '\0'; else { eqn_delim[1] = eqn_delim[0] = *s; if (*s++) if (*s) eqn_delim[1] = *s; } } } eqn_gen(type) int type; { extern int ntextlines; obj *p; char buf[8]; if (!no_eqn) { fputs(".bp\n", pipefp); sprintf(buf, "%d", ++eqn_count); save_one(EQNTXT, 0, 0, ntextlines, buf); } if (type == TROFF) { p = makenode(TROFF, 0, (int)getfval("curlayer")); checktextcolor(p); codegen = 1; } }