1 #include "e.h" 2 #include "y.tab.h" 3 #include <ctype.h> 4 5 #define CSSIZE 1000 6 char cs[CSSIZE+20]; /* text string converted into this */ 7 char *csp; /* next spot in cs[] */ 8 char *psp; /* next character in input token */ 9 10 int lf, rf; /* temporary spots for left and right fonts */ 11 int lastft; /* last \f added */ 12 int nextft; /* next \f to be added */ 13 14 int pclass; /* class of previous character */ 15 int nclass; /* class of next character */ 16 17 int class[LAST][LAST] ={ /* guesswork, tuned to times roman postscript */ 18 19 /*OT OL IL DG LP RP SL PL IF IJ VB */ 20 /*OT*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OTHER */ 21 /*OL*/ { 1, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0 }, /* OLET */ 22 /*IL*/ { 1, 1, 0, 1, 1, 1, 1, 3, 2, 1, 0 }, /* ILET */ 23 /*DG*/ { 1, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0 }, /* DIG */ 24 /*LP*/ { 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 0 }, /* LPAR */ 25 /*RP*/ { 2, 2, 2, 1, 1, 1, 1, 2, 3, 3, 0 }, /* RPAR */ 26 /*SL*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0 }, /* SLASH */ 27 /*PL*/ { 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 0 }, /* PLUS */ 28 /*IF*/ { 3, 3, 1, 2, 2, 3, 2, 3, 0, 1, 1 }, /* ILETF */ 29 /*IJ*/ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0 }, /* ILETJ */ 30 /*VB*/ { 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1 }, /* VBAR */ 31 32 }; 33 34 extern void shim(int, int); 35 extern void roman(int); 36 extern void sadd(char *); 37 extern void cadd(int); 38 extern int trans(int, char *); 39 40 int textc(void) /* read next UTF rune from psp */ 41 { 42 wchar_t r; 43 int w; 44 45 w = mbtowc(&r, psp, 3); 46 if(w == 0){ 47 psp++; 48 return 0; 49 } 50 if(w < 0){ 51 psp += 1; 52 return 0x80; /* Plan 9-ism */ 53 } 54 psp += w; 55 return r; 56 } 57 58 void text(int t, char *p1) /* convert text string p1 of type t */ 59 { 60 int c; 61 char *p; 62 tbl *tp; 63 64 yyval = salloc(); 65 ebase[yyval] = 0; 66 eht[yyval] = EM(1.0, ps); /* ht in ems of orig size */ 67 lfont[yyval] = rfont[yyval] = ROM; 68 lclass[yyval] = rclass[yyval] = OTHER; 69 if (t == QTEXT) { 70 for (p = p1; *p; p++) /* scan for embedded \f's */ 71 if (*p == '\\' && *(p+1) == 'f') 72 break; 73 if (*p) /* if found \f, leave it alone and hope */ 74 p = p1; 75 else { 76 sprintf(cs, "\\f%s%s\\fP", ftp->name, p1); 77 p = cs; 78 } 79 } else if (t == SPACE) 80 p = "\\ "; 81 else if (t == THIN) 82 p = "\\|"; 83 else if (t == TAB) 84 p = "\\t"; 85 else if ((tp = lookup(restbl, p1)) != NULL) { 86 p = tp->cval; 87 } else { 88 lf = rf = 0; 89 lastft = 0; 90 nclass = NONE; /* get started with no class == no pad */ 91 csp = cs; 92 for (psp = p1; (c = textc()) != '\0'; ) { 93 nextft = ft; 94 pclass = nclass; 95 rf = trans(c, p1); 96 if (lf == 0) { 97 lf = rf; /* left stuff is first found */ 98 lclass[yyval] = nclass; 99 } 100 if (csp-cs > CSSIZE) 101 ERROR "converted token %.25s... too long", p1 FATAL ; 102 } 103 sadd("\\fP"); 104 *csp = '\0'; 105 p = cs; 106 lfont[yyval] = lf; 107 rfont[yyval] = rf; 108 rclass[yyval] = nclass; 109 } 110 dprintf(".\t%dtext: S%d <- %s; b=%g,h=%g,lf=%c,rf=%c,ps=%d\n", 111 t, yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps); 112 printf(".ds %d \"%s\n", yyval, p); 113 } 114 115 int isalpharune(int c) 116 { 117 return ('a'<=c && c<='z') || ('A'<=c && c<='Z'); 118 } 119 120 int isdigitrune(int c) 121 { 122 return ('0'<=c && c<='9'); 123 } 124 125 trans(int c, char *p1) 126 { 127 int f; 128 129 if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') { /* italic letter */ 130 shim(pclass, nclass = ILET); 131 cadd(c); 132 return ITAL; 133 } 134 if (isalpharune(c) && ft != ITAL) { /* other letter */ 135 shim(pclass, nclass = OLET); 136 cadd(c); 137 return ROM; 138 } 139 if (isdigitrune(c)) { 140 shim(pclass, nclass = DIG); 141 roman(c); 142 return ROM; /* this is the right side font of this object */ 143 } 144 f = ROM; 145 nclass = OTHER; 146 switch (c) { 147 case ':': case ';': case '!': case '%': case '?': 148 shim(pclass, nclass); 149 roman(c); 150 return f; 151 case '(': case '[': 152 shim(pclass, nclass = LPAR); 153 roman(c); 154 return f; 155 case ')': case ']': 156 shim(pclass, nclass = RPAR); 157 roman(c); 158 return f; 159 case ',': 160 shim(pclass, nclass = OTHER); 161 roman(c); 162 return f; 163 case '.': 164 if (rf == ROM) 165 roman(c); 166 else 167 cadd(c); 168 return f; 169 case '|': /* postscript needs help with default width! */ 170 shim(pclass, nclass = VBAR); 171 sadd("\\v'.17m'\\z|\\v'-.17m'\\|"); /* and height */ 172 return f; 173 case '=': 174 shim(pclass, nclass = PLUS); 175 sadd("\\(eq"); 176 return f; 177 case '+': 178 shim(pclass, nclass = PLUS); 179 sadd("\\(pl"); 180 return f; 181 case '>': 182 case '<': /* >, >=, >>, <, <-, <=, << */ 183 shim(pclass, nclass = PLUS); 184 if (*psp == '=') { 185 sadd(c == '<' ? "\\(<=" : "\\(>="); 186 psp++; 187 } else if (c == '<' && *psp == '-') { /* <- only */ 188 sadd("\\(<-"); 189 psp++; 190 } else if (*psp == c) { /* << or >> */ 191 cadd(c); 192 cadd(c); 193 psp++; 194 } else { 195 cadd(c); 196 } 197 return f; 198 case '-': 199 shim(pclass, nclass = PLUS); /* probably too big for ->'s */ 200 if (*psp == '>') { 201 sadd("\\(->"); 202 psp++; 203 } else { 204 sadd("\\(mi"); 205 } 206 return f; 207 case '/': 208 shim(pclass, nclass = SLASH); 209 cadd('/'); 210 return f; 211 case '~': 212 case ' ': 213 sadd("\\|\\|"); 214 return f; 215 case '^': 216 sadd("\\|"); 217 return f; 218 case '\\': /* troff - pass only \(xx without comment */ 219 shim(pclass, nclass); 220 cadd('\\'); 221 cadd(c = *psp++); 222 if (c == '(' && *psp && *(psp+1)) { 223 cadd(*psp++); 224 cadd(*psp++); 225 } else 226 fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n", 227 c, curfile->fname, curfile->lineno); 228 return f; 229 case '\'': 230 shim(pclass, nclass); 231 sadd("\\(fm"); 232 return f; 233 234 case 'f': 235 if (ft == ITAL) { 236 shim(pclass, nclass = ILETF); 237 cadd('f'); 238 f = ITAL; 239 } else 240 cadd('f'); 241 return f; 242 case 'j': 243 if (ft == ITAL) { 244 shim(pclass, nclass = ILETJ); 245 cadd('j'); 246 f = ITAL; 247 } else 248 cadd('j'); 249 return f; 250 default: 251 shim(pclass, nclass); 252 cadd(c); 253 return ft==ITAL ? ITAL : ROM; 254 } 255 } 256 257 char *pad(int n) /* return the padding as a string */ 258 { 259 static char buf[20]; 260 261 buf[0] = 0; 262 if (n < 0) { 263 sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n); 264 return buf; 265 } 266 for ( ; n > 1; n -= 2) 267 strcat(buf, "\\|"); 268 if (n > 0) 269 strcat(buf, "\\^"); 270 return buf; 271 } 272 273 void shim(int lc, int rc) /* add padding space suitable to left and right classes */ 274 { 275 sadd(pad(class[lc][rc])); 276 } 277 278 void roman(int c) /* add char c in "roman" font */ 279 { 280 nextft = ROM; 281 cadd(c); 282 } 283 284 void sadd(char *s) /* add string s to cs */ 285 { 286 while (*s) 287 cadd(*s++); 288 } 289 290 void cadd(int c) /* add character c to end of cs */ 291 { 292 char *p; 293 int w; 294 295 if (lastft != nextft) { 296 if (lastft != 0) { 297 *csp++ = '\\'; 298 *csp++ = 'f'; 299 *csp++ = 'P'; 300 } 301 *csp++ = '\\'; 302 *csp++ = 'f'; 303 if (ftp == ftstack) { /* bottom level */ 304 if (ftp->ft == ITAL) /* usual case */ 305 *csp++ = nextft; 306 else /* gfont set, use it */ 307 for (p = ftp->name; *csp = *p++; ) 308 csp++; 309 } else { /* inside some kind of font ... */ 310 for (p = ftp->name; *csp = *p++; ) 311 csp++; 312 } 313 lastft = nextft; 314 } 315 w = wctomb(csp, c); 316 if(w > 0) /* ignore bad characters */ 317 csp += w; 318 } 319