1 #include <u.h> 2 #include <libc.h> 3 #include <libg.h> 4 #include <bio.h> 5 #include "proof.h" 6 7 char fname[NFONT][20]; /* font names */ 8 Font *fonttab[NFONT][NSIZE]; /* pointers to fonts */ 9 int fmap[NFONT]; /* what map to use with this font */ 10 11 static void bufchar(Point, Subfont *, uchar *); 12 static void loadfont(int, int); 13 static void fontlookup(int, char *); 14 static void buildxheight(Biobuf*); 15 static void buildmap(Biobuf*); 16 static void buildtroff(char *); 17 static void addmap(int, char *, int); 18 static char *map(Rune*, int); 19 static void scanstr(char *, char *, char **); 20 21 int specfont; /* somehow, number of special font */ 22 23 #define NMAP 5 24 #define QUICK 2048 /* char values less than this are quick to look up */ 25 #define eq(s,t) strcmp((char *) s, (char *) t) == 0 26 27 int curmap = -1; /* what map are we working on */ 28 29 typedef struct Link Link; 30 struct Link /* link names together */ 31 { 32 uchar *name; 33 int val; 34 Link *next; 35 }; 36 37 typedef struct Map Map; 38 struct Map /* holds a mapping from uchar name to index */ 39 { 40 double xheight; 41 Rune quick[QUICK]; /* low values get special treatment */ 42 Link *slow; /* other stuff goes into a link list */ 43 }; 44 45 Map charmap[5]; 46 47 typedef struct Fontmap Fontmap; 48 struct Fontmap /* mapping from troff name to filename */ 49 { 50 char *troffname; 51 char *prefix; 52 int map; /* which charmap to use for this font */ 53 char *fallback; /* font to look in if can't find char here */ 54 }; 55 56 Fontmap fontmap[100]; 57 int pos2fontmap[NFONT]; /* indexed by troff font position, gives Fontmap */ 58 int nfontmap = 0; /* how many are there */ 59 60 61 void 62 dochar(Rune r[]) 63 { 64 char *s, *fb; 65 Font *f; 66 Point p; 67 int fontno, fm, i; 68 char buf[10]; 69 70 fontno = curfont; 71 if((s = map(r, curfont)) == 0){ /* not on current font */ 72 if ((s = map(r, specfont)) != 0) /* on special font */ 73 fontno = specfont; 74 else{ 75 /* look for fallback */ 76 fm = pos2fontmap[curfont]; 77 fb = fontmap[fm].fallback; 78 if(fb){ 79 /* see if fallback is mounted */ 80 for(i = 0; i < NFONT; i++){ 81 if(eq(fb, fontmap[pos2fontmap[i]].troffname)){ 82 s = map(r, i); 83 if(s){ 84 fontno = i; 85 goto found; 86 } 87 } 88 } 89 } 90 /* no such char; use name itself on defont */ 91 /* this is not a general solution */ 92 p.x = hpos/DIV + xyoffset.x + offset.x; 93 p.y = vpos/DIV + xyoffset.y + offset.y; 94 p.y -= font->ascent; 95 sprint(buf, "%S", r); 96 string(&screen, p, font, buf, S|D); 97 return; 98 } 99 } 100 found: 101 p.x = hpos/DIV + xyoffset.x + offset.x; 102 p.y = vpos/DIV + xyoffset.y + offset.y; 103 while ((f = fonttab[fontno][cursize]) == 0) 104 loadfont(fontno, cursize); 105 p.y -= f->ascent; 106 dprint(2, "putting %S at %d,%d font %d, size %d\n", r, p.x, p.y, fontno, cursize); 107 string(&screen, p, f, s, S|D); 108 } 109 110 111 static void 112 loadfont(int n, int s) 113 { 114 char file[100]; 115 int i, t, fd, deep; 116 static char *try[3] = {"", "times/R.", "pelm/"}; 117 Subfont *f; 118 Font *ff; 119 120 try[0] = fname[n]; 121 for (t = 0; t < 3; t++){ 122 i = s * mag * charmap[fmap[n]].xheight/0.72; /* a pixel is 0.72 points */ 123 if (i < MINSIZE) 124 i = MINSIZE; 125 dprint(2, "size %d, i %d, mag %g\n", s, i, mag); 126 for(; i >= MINSIZE; i--){ 127 /* if .font file exists, take that */ 128 sprint(file, "%s/%s%d.font", libfont, try[t], i); 129 ff = rdfontfile(file, screen.ldepth); 130 if(ff != 0){ 131 fonttab[n][s] = ff; 132 dprint(2, "using %s for font %d %d\n", file, n, s); 133 return; 134 } 135 /* else look for a subfont file */ 136 for (deep = screen.ldepth; deep >= 0; deep--){ 137 sprint(file, "%s/%s%d.%d", libfont, try[t], i, 1 /*deep*/); 138 dprint(2, "trying %s for %d\n", file, i); 139 if ((fd = open(file, 0)) >= 0){ 140 f = rdsubfontfile(fd, 0); 141 if (f == 0) { 142 fprint(2, "can't rdsubfontfile %s: %r\n", file); 143 exits("rdsubfont"); 144 } 145 close(fd); 146 ff = mkfont(f, 0); 147 if(ff == 0){ 148 fprint(2, "can't mkfont %s: %r\n", file); 149 exits("rdsubfont"); 150 } 151 fonttab[n][s] = ff; 152 dprint(2, "using %s for font %d %d\n", file, n, s); 153 return; 154 } 155 } 156 } 157 } 158 fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n], s); 159 exits("no font"); 160 } 161 162 void 163 loadfontname(int n, char *s) 164 { 165 int i; 166 Font *f, *g = 0; 167 168 if (strcmp(s, fname[n]) == 0) 169 return; 170 fontlookup(n, s); 171 for (i = 0; i < NSIZE; i++) 172 if (f = fonttab[n][i]){ 173 if (f != g) { 174 ffree(f); 175 g = f; 176 } 177 fonttab[n][i] = 0; 178 } 179 } 180 181 void 182 allfree(void) 183 { 184 int i; 185 186 for (i=0; i<NFONT; i++) 187 loadfontname(i, "??"); 188 } 189 190 191 void 192 readmapfile(char *file) 193 { 194 Biobuf *fp; 195 char *p, cmd[100]; 196 197 if ((fp=Bopen(file, OREAD)) == 0){ 198 fprint(2, "proof: can't open map file %s\n", file); 199 exits("urk"); 200 } 201 while((p=Brdline(fp, '\n')) != 0) { 202 p[Blinelen(fp)-1] = 0; 203 scanstr(p, cmd, 0); 204 if(p[0]=='\0' || eq(cmd, "#")) /* skip comments, empty */ 205 continue; 206 else if(eq(cmd, "xheight")) 207 buildxheight(fp); 208 else if(eq(cmd, "map")) 209 buildmap(fp); 210 else if(eq(cmd, "special")) 211 buildtroff(p); 212 else if(eq(cmd, "troff")) 213 buildtroff(p); 214 else 215 fprint(2, "weird map line %s\n", p); 216 } 217 Bterm(fp); 218 } 219 220 static void 221 buildxheight(Biobuf *fp) /* map goes from char name to value to print via *string() */ 222 { 223 char *line; 224 225 line = Brdline(fp, '\n'); 226 if(line == 0){ 227 fprint(2, "proof: bad map file\n"); 228 exits("map"); 229 } 230 charmap[curmap].xheight = atof(line); 231 } 232 233 static void 234 buildmap(Biobuf *fp) /* map goes from char name to value to print via *string() */ 235 { 236 uchar *p, *line, ch[100]; 237 int val; 238 Rune r; 239 240 curmap++; 241 if(curmap >= NMAP){ 242 fprint(2, "proof: out of char maps; recompile\n"); 243 exits("charmap"); 244 } 245 while ((line = Brdline(fp, '\n'))!= 0){ 246 if (line[0] == '\n') 247 return; 248 line[Blinelen(fp)-1] = 0; 249 scanstr((char *) line, (char *) ch, (char **) &p); 250 if (ch[0] == '\0') { 251 fprint(2, "bad map file line '%s'\n", line); 252 continue; 253 } 254 val = strtol((char *) p, 0, 10); 255 dprint(2, "buildmap %s (%x %x) %s %d\n", ch, ch[0], ch[1], p, val); 256 chartorune(&r, (char*)ch); 257 if(utflen((char*)ch)==1 && r<QUICK) 258 charmap[curmap].quick[r] = val; 259 else 260 addmap(curmap, strdup((char *) ch), val); /* put somewhere else */ 261 } 262 } 263 264 static void 265 addmap(int n, char *s, int val) /* stick a new link on */ 266 { 267 Link *p = (Link *) malloc(sizeof(Link)); 268 Link *prev = charmap[n].slow; 269 270 if(p == 0) 271 exits("out of memory in addmap"); 272 p->name = (uchar *) s; 273 p->val = val; 274 p->next = prev; 275 charmap[n].slow = p; 276 } 277 278 static void 279 buildtroff(char *buf) /* map troff names into bitmap filenames */ 280 { /* e.g., R -> times/R., I -> times/I., etc. */ 281 char *p, cmd[100], name[200], prefix[400], fallback[100]; 282 283 scanstr(buf, cmd, &p); 284 scanstr(p, name, &p); 285 scanstr(p, prefix, &p); 286 while(*p!=0 && isspace(*p)) 287 p++; 288 if(*p != 0){ 289 scanstr(p, fallback, &p); 290 fontmap[nfontmap].fallback = strdup(fallback); 291 }else 292 fontmap[nfontmap].fallback = 0; 293 fontmap[nfontmap].troffname = strdup(name); 294 fontmap[nfontmap].prefix = strdup(prefix); 295 fontmap[nfontmap].map = curmap; 296 dprint(2, "troff name %s is bitmap %s map %d in slot %d fallback %s\n", name, prefix, curmap, nfontmap, fontmap[nfontmap].fallback? fontmap[nfontmap].fallback : "<null>"); 297 nfontmap++; 298 } 299 300 static void 301 fontlookup(int n, char *s) /* map troff name of s into position n */ 302 { 303 int i; 304 305 for(i = 0; i < nfontmap; i++) 306 if (eq(s, fontmap[i].troffname)) { 307 strcpy(fname[n], fontmap[i].prefix); 308 fmap[n] = fontmap[i].map; 309 pos2fontmap[n] = i; 310 if (eq(s, "S")) 311 specfont = n; 312 dprint(2, "font %d %s is %s\n", n, s, fname[n]); 313 return; 314 } 315 /* god help us if this font isn't there */ 316 } 317 318 319 static char * 320 map(Rune rp[], int font) /* figure out mapping for char in this font */ 321 { 322 static char s[100]; 323 char c[10]; 324 Link *p; 325 Rune r; 326 327 if(rp[1]==0 && rp[0]<QUICK) /* fast lookup */ 328 r = charmap[fmap[font]].quick[rp[0]]; 329 else { /* high-valued or compound character name */ 330 sprint(c, "%S", rp); 331 r = 0; 332 for (p = charmap[fmap[font]].slow; p; p = p->next) 333 if(eq(c, p->name)){ 334 r = p->val; 335 break; 336 } 337 } 338 if(r == 0){ /* not there */ 339 dprint(2, "didn't find %S font# %d\n", rp, font); 340 return 0; 341 } 342 dprint(2, "map %S to %s font# %d\n", rp, s, font); 343 s[runetochar(s, &r)] = 0; 344 return s; 345 } 346 347 static void 348 scanstr(char *s, char *ans, char **ep) 349 { 350 for (; isspace((uchar) *s); s++) 351 ; 352 for (; *s!=0 && !isspace((uchar) *s); ) 353 *ans++ = *s++; 354 *ans = 0; 355 if (ep) 356 *ep = s; 357 } 358