text.c (6741B)
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, (int)yyval, p, ebase[yyval], eht[yyval], lfont[yyval], rfont[yyval], ps); 112 printf(".ds %d \"%s\n", (int)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 int 126 trans(int c, char *p1) 127 { 128 int f; 129 130 if (isalpharune(c) && ft == ITAL && c != 'f' && c != 'j') { /* italic letter */ 131 shim(pclass, nclass = ILET); 132 cadd(c); 133 return ITAL; 134 } 135 if (isalpharune(c) && ft != ITAL) { /* other letter */ 136 shim(pclass, nclass = OLET); 137 cadd(c); 138 return ROM; 139 } 140 if (isdigitrune(c)) { 141 shim(pclass, nclass = DIG); 142 roman(c); 143 return ROM; /* this is the right side font of this object */ 144 } 145 f = ROM; 146 nclass = OTHER; 147 switch (c) { 148 case ':': case ';': case '!': case '%': case '?': 149 shim(pclass, nclass); 150 roman(c); 151 return f; 152 case '(': case '[': 153 shim(pclass, nclass = LPAR); 154 roman(c); 155 return f; 156 case ')': case ']': 157 shim(pclass, nclass = RPAR); 158 roman(c); 159 return f; 160 case ',': 161 shim(pclass, nclass = OTHER); 162 roman(c); 163 return f; 164 case '.': 165 if (rf == ROM) 166 roman(c); 167 else 168 cadd(c); 169 return f; 170 case '|': /* postscript needs help with default width! */ 171 shim(pclass, nclass = VBAR); 172 sadd("\\v'.17m'\\z|\\v'-.17m'\\|"); /* and height */ 173 return f; 174 case '=': 175 shim(pclass, nclass = PLUS); 176 sadd("\\(eq"); 177 return f; 178 case '+': 179 shim(pclass, nclass = PLUS); 180 sadd("\\(pl"); 181 return f; 182 case '>': 183 case '<': /* >, >=, >>, <, <-, <=, << */ 184 shim(pclass, nclass = PLUS); 185 if (*psp == '=') { 186 sadd(c == '<' ? "\\(<=" : "\\(>="); 187 psp++; 188 } else if (c == '<' && *psp == '-') { /* <- only */ 189 sadd("\\(<-"); 190 psp++; 191 } else if (*psp == c) { /* << or >> */ 192 cadd(c); 193 cadd(c); 194 psp++; 195 } else { 196 cadd(c); 197 } 198 return f; 199 case '-': 200 shim(pclass, nclass = PLUS); /* probably too big for ->'s */ 201 if (*psp == '>') { 202 sadd("\\(->"); 203 psp++; 204 } else { 205 sadd("\\(mi"); 206 } 207 return f; 208 case '/': 209 shim(pclass, nclass = SLASH); 210 cadd('/'); 211 return f; 212 case '~': 213 case ' ': 214 sadd("\\|\\|"); 215 return f; 216 case '^': 217 sadd("\\|"); 218 return f; 219 case '\\': /* troff - pass only \(xx without comment */ 220 shim(pclass, nclass); 221 cadd('\\'); 222 cadd(c = *psp++); 223 if (c == '(' && *psp && *(psp+1)) { 224 cadd(*psp++); 225 cadd(*psp++); 226 } else 227 fprintf(stderr, "eqn warning: unquoted troff command \\%c, file %s:%d\n", 228 c, curfile->fname, curfile->lineno); 229 return f; 230 case '\'': 231 shim(pclass, nclass); 232 sadd("\\(fm"); 233 return f; 234 235 case 'f': 236 if (ft == ITAL) { 237 shim(pclass, nclass = ILETF); 238 cadd('f'); 239 f = ITAL; 240 } else 241 cadd('f'); 242 return f; 243 case 'j': 244 if (ft == ITAL) { 245 shim(pclass, nclass = ILETJ); 246 cadd('j'); 247 f = ITAL; 248 } else 249 cadd('j'); 250 return f; 251 default: 252 shim(pclass, nclass); 253 cadd(c); 254 return ft==ITAL ? ITAL : ROM; 255 } 256 } 257 258 char *pad(int n) /* return the padding as a string */ 259 { 260 static char buf[30]; 261 262 buf[0] = 0; 263 if (n < 0) { 264 sprintf(buf, "\\h'-%du*\\w'\\^'u'", -n); 265 return buf; 266 } 267 for ( ; n > 1; n -= 2) 268 strcat(buf, "\\|"); 269 if (n > 0) 270 strcat(buf, "\\^"); 271 return buf; 272 } 273 274 void shim(int lc, int rc) /* add padding space suitable to left and right classes */ 275 { 276 sadd(pad(class[lc][rc])); 277 } 278 279 void roman(int c) /* add char c in "roman" font */ 280 { 281 nextft = ROM; 282 cadd(c); 283 } 284 285 void sadd(char *s) /* add string s to cs */ 286 { 287 while (*s) 288 cadd(*s++); 289 } 290 291 void cadd(int c) /* add character c to end of cs */ 292 { 293 char *p; 294 int w; 295 296 if (lastft != nextft) { 297 if (lastft != 0) { 298 *csp++ = '\\'; 299 *csp++ = 'f'; 300 *csp++ = 'P'; 301 } 302 *csp++ = '\\'; 303 *csp++ = 'f'; 304 if (ftp == ftstack) { /* bottom level */ 305 if (ftp->ft == ITAL) /* usual case */ 306 *csp++ = nextft; 307 else /* gfont set, use it */ 308 for (p = ftp->name; (*csp = *p++); ) 309 csp++; 310 } else { /* inside some kind of font ... */ 311 for (p = ftp->name; (*csp = *p++); ) 312 csp++; 313 } 314 lastft = nextft; 315 } 316 w = wctomb(csp, c); 317 if(w > 0) /* ignore bad characters */ 318 csp += w; 319 }