13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <libg.h> 43e12c5d1SDavid du Colombier #include <bio.h> 53e12c5d1SDavid du Colombier #include "proof.h" 63e12c5d1SDavid du Colombier 73e12c5d1SDavid du Colombier char fname[NFONT][20]; /* font names */ 83e12c5d1SDavid du Colombier Font *fonttab[NFONT][NSIZE]; /* pointers to fonts */ 93e12c5d1SDavid du Colombier int fmap[NFONT]; /* what map to use with this font */ 103e12c5d1SDavid du Colombier 113e12c5d1SDavid du Colombier static void bufchar(Point, Subfont *, uchar *); 123e12c5d1SDavid du Colombier static void loadfont(int, int); 133e12c5d1SDavid du Colombier static void fontlookup(int, char *); 14*219b2ee8SDavid du Colombier static void buildxheight(Biobuf*); 153e12c5d1SDavid du Colombier static void buildmap(Biobuf*); 163e12c5d1SDavid du Colombier static void buildtroff(char *); 173e12c5d1SDavid du Colombier static void addmap(int, char *, int); 18*219b2ee8SDavid du Colombier static char *map(Rune*, int); 193e12c5d1SDavid du Colombier static void scanstr(char *, char *, char **); 203e12c5d1SDavid du Colombier 213e12c5d1SDavid du Colombier int specfont; /* somehow, number of special font */ 223e12c5d1SDavid du Colombier 23*219b2ee8SDavid du Colombier #define NMAP 5 24*219b2ee8SDavid du Colombier #define QUICK 2048 /* char values less than this are quick to look up */ 25*219b2ee8SDavid du Colombier #define eq(s,t) strcmp((char *) s, (char *) t) == 0 26*219b2ee8SDavid du Colombier 27*219b2ee8SDavid du Colombier int curmap = -1; /* what map are we working on */ 28*219b2ee8SDavid du Colombier 29*219b2ee8SDavid du Colombier typedef struct Link Link; 30*219b2ee8SDavid du Colombier struct Link /* link names together */ 313e12c5d1SDavid du Colombier { 32*219b2ee8SDavid du Colombier uchar *name; 33*219b2ee8SDavid du Colombier int val; 34*219b2ee8SDavid du Colombier Link *next; 35*219b2ee8SDavid du Colombier }; 36*219b2ee8SDavid du Colombier 37*219b2ee8SDavid du Colombier typedef struct Map Map; 38*219b2ee8SDavid du Colombier struct Map /* holds a mapping from uchar name to index */ 39*219b2ee8SDavid du Colombier { 40*219b2ee8SDavid du Colombier double xheight; 41*219b2ee8SDavid du Colombier Rune quick[QUICK]; /* low values get special treatment */ 42*219b2ee8SDavid du Colombier Link *slow; /* other stuff goes into a link list */ 43*219b2ee8SDavid du Colombier }; 44*219b2ee8SDavid du Colombier 45*219b2ee8SDavid du Colombier Map charmap[5]; 46*219b2ee8SDavid du Colombier 47*219b2ee8SDavid du Colombier typedef struct Fontmap Fontmap; 48*219b2ee8SDavid du Colombier struct Fontmap /* mapping from troff name to filename */ 49*219b2ee8SDavid du Colombier { 50*219b2ee8SDavid du Colombier char *troffname; 51*219b2ee8SDavid du Colombier char *prefix; 52*219b2ee8SDavid du Colombier int map; /* which charmap to use for this font */ 53*219b2ee8SDavid du Colombier char *fallback; /* font to look in if can't find char here */ 54*219b2ee8SDavid du Colombier }; 55*219b2ee8SDavid du Colombier 56*219b2ee8SDavid du Colombier Fontmap fontmap[100]; 57*219b2ee8SDavid du Colombier int pos2fontmap[NFONT]; /* indexed by troff font position, gives Fontmap */ 58*219b2ee8SDavid du Colombier int nfontmap = 0; /* how many are there */ 59*219b2ee8SDavid du Colombier 60*219b2ee8SDavid du Colombier 61*219b2ee8SDavid du Colombier void 62*219b2ee8SDavid du Colombier dochar(Rune r[]) 63*219b2ee8SDavid du Colombier { 64*219b2ee8SDavid du Colombier char *s, *fb; 653e12c5d1SDavid du Colombier Font *f; 663e12c5d1SDavid du Colombier Point p; 67*219b2ee8SDavid du Colombier int fontno, fm, i; 68*219b2ee8SDavid du Colombier char buf[10]; 693e12c5d1SDavid du Colombier 703e12c5d1SDavid du Colombier fontno = curfont; 71*219b2ee8SDavid du Colombier if((s = map(r, curfont)) == 0){ /* not on current font */ 72*219b2ee8SDavid du Colombier if ((s = map(r, specfont)) != 0) /* on special font */ 733e12c5d1SDavid du Colombier fontno = specfont; 74*219b2ee8SDavid du Colombier else{ 75*219b2ee8SDavid du Colombier /* look for fallback */ 76*219b2ee8SDavid du Colombier fm = pos2fontmap[curfont]; 77*219b2ee8SDavid du Colombier fb = fontmap[fm].fallback; 78*219b2ee8SDavid du Colombier if(fb){ 79*219b2ee8SDavid du Colombier /* see if fallback is mounted */ 80*219b2ee8SDavid du Colombier for(i = 0; i < NFONT; i++){ 81*219b2ee8SDavid du Colombier if(eq(fb, fontmap[pos2fontmap[i]].troffname)){ 82*219b2ee8SDavid du Colombier s = map(r, i); 83*219b2ee8SDavid du Colombier if(s){ 84*219b2ee8SDavid du Colombier fontno = i; 85*219b2ee8SDavid du Colombier goto found; 86*219b2ee8SDavid du Colombier } 87*219b2ee8SDavid du Colombier } 88*219b2ee8SDavid du Colombier } 89*219b2ee8SDavid du Colombier } 903e12c5d1SDavid du Colombier /* no such char; use name itself on defont */ 91*219b2ee8SDavid du Colombier /* this is not a general solution */ 923e12c5d1SDavid du Colombier p.x = hpos/DIV + xyoffset.x + offset.x; 933e12c5d1SDavid du Colombier p.y = vpos/DIV + xyoffset.y + offset.y; 943e12c5d1SDavid du Colombier p.y -= font->ascent; 95*219b2ee8SDavid du Colombier sprint(buf, "%S", r); 96*219b2ee8SDavid du Colombier string(&screen, p, font, buf, S|D); 973e12c5d1SDavid du Colombier return; 983e12c5d1SDavid du Colombier } 993e12c5d1SDavid du Colombier } 100*219b2ee8SDavid du Colombier found: 1013e12c5d1SDavid du Colombier p.x = hpos/DIV + xyoffset.x + offset.x; 1023e12c5d1SDavid du Colombier p.y = vpos/DIV + xyoffset.y + offset.y; 1033e12c5d1SDavid du Colombier while ((f = fonttab[fontno][cursize]) == 0) 1043e12c5d1SDavid du Colombier loadfont(fontno, cursize); 1053e12c5d1SDavid du Colombier p.y -= f->ascent; 106*219b2ee8SDavid du Colombier dprint(2, "putting %S at %d,%d font %d, size %d\n", r, p.x, p.y, fontno, cursize); 107*219b2ee8SDavid du Colombier string(&screen, p, f, s, S|D); 1083e12c5d1SDavid du Colombier } 1093e12c5d1SDavid du Colombier 1103e12c5d1SDavid du Colombier 1113e12c5d1SDavid du Colombier static void 1123e12c5d1SDavid du Colombier loadfont(int n, int s) 1133e12c5d1SDavid du Colombier { 1143e12c5d1SDavid du Colombier char file[100]; 1153e12c5d1SDavid du Colombier int i, t, fd, deep; 1163e12c5d1SDavid du Colombier static char *try[3] = {"", "times/R.", "pelm/"}; 1173e12c5d1SDavid du Colombier Subfont *f; 1183e12c5d1SDavid du Colombier Font *ff; 1193e12c5d1SDavid du Colombier 1203e12c5d1SDavid du Colombier try[0] = fname[n]; 1213e12c5d1SDavid du Colombier for (t = 0; t < 3; t++){ 122*219b2ee8SDavid du Colombier i = s * mag * charmap[fmap[n]].xheight/0.72; /* a pixel is 0.72 points */ 1233e12c5d1SDavid du Colombier if (i < MINSIZE) 1243e12c5d1SDavid du Colombier i = MINSIZE; 1253e12c5d1SDavid du Colombier dprint(2, "size %d, i %d, mag %g\n", s, i, mag); 126*219b2ee8SDavid du Colombier for(; i >= MINSIZE; i--){ 127*219b2ee8SDavid du Colombier /* if .font file exists, take that */ 128*219b2ee8SDavid du Colombier sprint(file, "%s/%s%d.font", libfont, try[t], i); 129*219b2ee8SDavid du Colombier ff = rdfontfile(file, screen.ldepth); 130*219b2ee8SDavid du Colombier if(ff != 0){ 131*219b2ee8SDavid du Colombier fonttab[n][s] = ff; 132*219b2ee8SDavid du Colombier dprint(2, "using %s for font %d %d\n", file, n, s); 133*219b2ee8SDavid du Colombier return; 134*219b2ee8SDavid du Colombier } 135*219b2ee8SDavid du Colombier /* else look for a subfont file */ 1363e12c5d1SDavid du Colombier for (deep = screen.ldepth; deep >= 0; deep--){ 1373e12c5d1SDavid du Colombier sprint(file, "%s/%s%d.%d", libfont, try[t], i, 1 /*deep*/); 1383e12c5d1SDavid du Colombier dprint(2, "trying %s for %d\n", file, i); 1393e12c5d1SDavid du Colombier if ((fd = open(file, 0)) >= 0){ 1403e12c5d1SDavid du Colombier f = rdsubfontfile(fd, 0); 1413e12c5d1SDavid du Colombier if (f == 0) { 1423e12c5d1SDavid du Colombier fprint(2, "can't rdsubfontfile %s: %r\n", file); 1433e12c5d1SDavid du Colombier exits("rdsubfont"); 1443e12c5d1SDavid du Colombier } 1453e12c5d1SDavid du Colombier close(fd); 1463e12c5d1SDavid du Colombier ff = mkfont(f, 0); 1473e12c5d1SDavid du Colombier if(ff == 0){ 1483e12c5d1SDavid du Colombier fprint(2, "can't mkfont %s: %r\n", file); 1493e12c5d1SDavid du Colombier exits("rdsubfont"); 1503e12c5d1SDavid du Colombier } 1513e12c5d1SDavid du Colombier fonttab[n][s] = ff; 1523e12c5d1SDavid du Colombier dprint(2, "using %s for font %d %d\n", file, n, s); 1533e12c5d1SDavid du Colombier return; 1543e12c5d1SDavid du Colombier } 1553e12c5d1SDavid du Colombier } 1563e12c5d1SDavid du Colombier } 157*219b2ee8SDavid du Colombier } 1583e12c5d1SDavid du Colombier fprint(2, "can't find font %s.%d or substitute, quitting\n", fname[n], s); 1593e12c5d1SDavid du Colombier exits("no font"); 1603e12c5d1SDavid du Colombier } 1613e12c5d1SDavid du Colombier 1623e12c5d1SDavid du Colombier void 1633e12c5d1SDavid du Colombier loadfontname(int n, char *s) 1643e12c5d1SDavid du Colombier { 1653e12c5d1SDavid du Colombier int i; 1663e12c5d1SDavid du Colombier Font *f, *g = 0; 1673e12c5d1SDavid du Colombier 1683e12c5d1SDavid du Colombier if (strcmp(s, fname[n]) == 0) 1693e12c5d1SDavid du Colombier return; 1703e12c5d1SDavid du Colombier fontlookup(n, s); 1713e12c5d1SDavid du Colombier for (i = 0; i < NSIZE; i++) 1723e12c5d1SDavid du Colombier if (f = fonttab[n][i]){ 1733e12c5d1SDavid du Colombier if (f != g) { 1743e12c5d1SDavid du Colombier ffree(f); 1753e12c5d1SDavid du Colombier g = f; 1763e12c5d1SDavid du Colombier } 1773e12c5d1SDavid du Colombier fonttab[n][i] = 0; 1783e12c5d1SDavid du Colombier } 1793e12c5d1SDavid du Colombier } 1803e12c5d1SDavid du Colombier 1813e12c5d1SDavid du Colombier void 1823e12c5d1SDavid du Colombier allfree(void) 1833e12c5d1SDavid du Colombier { 1843e12c5d1SDavid du Colombier int i; 1853e12c5d1SDavid du Colombier 1863e12c5d1SDavid du Colombier for (i=0; i<NFONT; i++) 1873e12c5d1SDavid du Colombier loadfontname(i, "??"); 1883e12c5d1SDavid du Colombier } 1893e12c5d1SDavid du Colombier 1903e12c5d1SDavid du Colombier 1913e12c5d1SDavid du Colombier void 1923e12c5d1SDavid du Colombier readmapfile(char *file) 1933e12c5d1SDavid du Colombier { 1943e12c5d1SDavid du Colombier Biobuf *fp; 1953e12c5d1SDavid du Colombier char *p, cmd[100]; 1963e12c5d1SDavid du Colombier 1973e12c5d1SDavid du Colombier if ((fp=Bopen(file, OREAD)) == 0){ 1983e12c5d1SDavid du Colombier fprint(2, "proof: can't open map file %s\n", file); 1993e12c5d1SDavid du Colombier exits("urk"); 2003e12c5d1SDavid du Colombier } 2013e12c5d1SDavid du Colombier while((p=Brdline(fp, '\n')) != 0) { 2023e12c5d1SDavid du Colombier p[Blinelen(fp)-1] = 0; 2033e12c5d1SDavid du Colombier scanstr(p, cmd, 0); 2043e12c5d1SDavid du Colombier if(p[0]=='\0' || eq(cmd, "#")) /* skip comments, empty */ 2053e12c5d1SDavid du Colombier continue; 206*219b2ee8SDavid du Colombier else if(eq(cmd, "xheight")) 207*219b2ee8SDavid du Colombier buildxheight(fp); 2083e12c5d1SDavid du Colombier else if(eq(cmd, "map")) 2093e12c5d1SDavid du Colombier buildmap(fp); 2103e12c5d1SDavid du Colombier else if(eq(cmd, "special")) 2113e12c5d1SDavid du Colombier buildtroff(p); 2123e12c5d1SDavid du Colombier else if(eq(cmd, "troff")) 2133e12c5d1SDavid du Colombier buildtroff(p); 2143e12c5d1SDavid du Colombier else 2153e12c5d1SDavid du Colombier fprint(2, "weird map line %s\n", p); 2163e12c5d1SDavid du Colombier } 217*219b2ee8SDavid du Colombier Bterm(fp); 218*219b2ee8SDavid du Colombier } 219*219b2ee8SDavid du Colombier 220*219b2ee8SDavid du Colombier static void 221*219b2ee8SDavid du Colombier buildxheight(Biobuf *fp) /* map goes from char name to value to print via *string() */ 222*219b2ee8SDavid du Colombier { 223*219b2ee8SDavid du Colombier char *line; 224*219b2ee8SDavid du Colombier 225*219b2ee8SDavid du Colombier line = Brdline(fp, '\n'); 226*219b2ee8SDavid du Colombier if(line == 0){ 227*219b2ee8SDavid du Colombier fprint(2, "proof: bad map file\n"); 228*219b2ee8SDavid du Colombier exits("map"); 229*219b2ee8SDavid du Colombier } 230*219b2ee8SDavid du Colombier charmap[curmap].xheight = atof(line); 2313e12c5d1SDavid du Colombier } 2323e12c5d1SDavid du Colombier 2333e12c5d1SDavid du Colombier static void 2343e12c5d1SDavid du Colombier buildmap(Biobuf *fp) /* map goes from char name to value to print via *string() */ 2353e12c5d1SDavid du Colombier { 2363e12c5d1SDavid du Colombier uchar *p, *line, ch[100]; 2373e12c5d1SDavid du Colombier int val; 238*219b2ee8SDavid du Colombier Rune r; 2393e12c5d1SDavid du Colombier 2403e12c5d1SDavid du Colombier curmap++; 241*219b2ee8SDavid du Colombier if(curmap >= NMAP){ 242*219b2ee8SDavid du Colombier fprint(2, "proof: out of char maps; recompile\n"); 243*219b2ee8SDavid du Colombier exits("charmap"); 244*219b2ee8SDavid du Colombier } 2453e12c5d1SDavid du Colombier while ((line = Brdline(fp, '\n'))!= 0){ 2463e12c5d1SDavid du Colombier if (line[0] == '\n') 2473e12c5d1SDavid du Colombier return; 2483e12c5d1SDavid du Colombier line[Blinelen(fp)-1] = 0; 2493e12c5d1SDavid du Colombier scanstr((char *) line, (char *) ch, (char **) &p); 2503e12c5d1SDavid du Colombier if (ch[0] == '\0') { 2513e12c5d1SDavid du Colombier fprint(2, "bad map file line '%s'\n", line); 2523e12c5d1SDavid du Colombier continue; 2533e12c5d1SDavid du Colombier } 2543e12c5d1SDavid du Colombier val = strtol((char *) p, 0, 10); 2553e12c5d1SDavid du Colombier dprint(2, "buildmap %s (%x %x) %s %d\n", ch, ch[0], ch[1], p, val); 256*219b2ee8SDavid du Colombier chartorune(&r, (char*)ch); 257*219b2ee8SDavid du Colombier if(utflen((char*)ch)==1 && r<QUICK) 258*219b2ee8SDavid du Colombier charmap[curmap].quick[r] = val; 259*219b2ee8SDavid du Colombier else 2603e12c5d1SDavid du Colombier addmap(curmap, strdup((char *) ch), val); /* put somewhere else */ 2613e12c5d1SDavid du Colombier } 2623e12c5d1SDavid du Colombier } 2633e12c5d1SDavid du Colombier 2643e12c5d1SDavid du Colombier static void 2653e12c5d1SDavid du Colombier addmap(int n, char *s, int val) /* stick a new link on */ 2663e12c5d1SDavid du Colombier { 2673e12c5d1SDavid du Colombier Link *p = (Link *) malloc(sizeof(Link)); 268*219b2ee8SDavid du Colombier Link *prev = charmap[n].slow; 2693e12c5d1SDavid du Colombier 2703e12c5d1SDavid du Colombier if(p == 0) 2713e12c5d1SDavid du Colombier exits("out of memory in addmap"); 2723e12c5d1SDavid du Colombier p->name = (uchar *) s; 2733e12c5d1SDavid du Colombier p->val = val; 274*219b2ee8SDavid du Colombier p->next = prev; 275*219b2ee8SDavid du Colombier charmap[n].slow = p; 2763e12c5d1SDavid du Colombier } 2773e12c5d1SDavid du Colombier 2783e12c5d1SDavid du Colombier static void 2793e12c5d1SDavid du Colombier buildtroff(char *buf) /* map troff names into bitmap filenames */ 2803e12c5d1SDavid du Colombier { /* e.g., R -> times/R., I -> times/I., etc. */ 281*219b2ee8SDavid du Colombier char *p, cmd[100], name[200], prefix[400], fallback[100]; 2823e12c5d1SDavid du Colombier 2833e12c5d1SDavid du Colombier scanstr(buf, cmd, &p); 2843e12c5d1SDavid du Colombier scanstr(p, name, &p); 2853e12c5d1SDavid du Colombier scanstr(p, prefix, &p); 286*219b2ee8SDavid du Colombier while(*p!=0 && isspace(*p)) 287*219b2ee8SDavid du Colombier p++; 288*219b2ee8SDavid du Colombier if(*p != 0){ 289*219b2ee8SDavid du Colombier scanstr(p, fallback, &p); 290*219b2ee8SDavid du Colombier fontmap[nfontmap].fallback = strdup(fallback); 291*219b2ee8SDavid du Colombier }else 292*219b2ee8SDavid du Colombier fontmap[nfontmap].fallback = 0; 2933e12c5d1SDavid du Colombier fontmap[nfontmap].troffname = strdup(name); 2943e12c5d1SDavid du Colombier fontmap[nfontmap].prefix = strdup(prefix); 2953e12c5d1SDavid du Colombier fontmap[nfontmap].map = curmap; 296*219b2ee8SDavid du Colombier 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>"); 2973e12c5d1SDavid du Colombier nfontmap++; 2983e12c5d1SDavid du Colombier } 2993e12c5d1SDavid du Colombier 3003e12c5d1SDavid du Colombier static void 3013e12c5d1SDavid du Colombier fontlookup(int n, char *s) /* map troff name of s into position n */ 3023e12c5d1SDavid du Colombier { 3033e12c5d1SDavid du Colombier int i; 3043e12c5d1SDavid du Colombier 3053e12c5d1SDavid du Colombier for(i = 0; i < nfontmap; i++) 3063e12c5d1SDavid du Colombier if (eq(s, fontmap[i].troffname)) { 3073e12c5d1SDavid du Colombier strcpy(fname[n], fontmap[i].prefix); 3083e12c5d1SDavid du Colombier fmap[n] = fontmap[i].map; 309*219b2ee8SDavid du Colombier pos2fontmap[n] = i; 3103e12c5d1SDavid du Colombier if (eq(s, "S")) 3113e12c5d1SDavid du Colombier specfont = n; 3123e12c5d1SDavid du Colombier dprint(2, "font %d %s is %s\n", n, s, fname[n]); 3133e12c5d1SDavid du Colombier return; 3143e12c5d1SDavid du Colombier } 3153e12c5d1SDavid du Colombier /* god help us if this font isn't there */ 3163e12c5d1SDavid du Colombier } 3173e12c5d1SDavid du Colombier 3183e12c5d1SDavid du Colombier 319*219b2ee8SDavid du Colombier static char * 320*219b2ee8SDavid du Colombier map(Rune rp[], int font) /* figure out mapping for char in this font */ 3213e12c5d1SDavid du Colombier { 322*219b2ee8SDavid du Colombier static char s[100]; 323*219b2ee8SDavid du Colombier char c[10]; 3243e12c5d1SDavid du Colombier Link *p; 325*219b2ee8SDavid du Colombier Rune r; 3263e12c5d1SDavid du Colombier 327*219b2ee8SDavid du Colombier if(rp[1]==0 && rp[0]<QUICK) /* fast lookup */ 328*219b2ee8SDavid du Colombier r = charmap[fmap[font]].quick[rp[0]]; 329*219b2ee8SDavid du Colombier else { /* high-valued or compound character name */ 330*219b2ee8SDavid du Colombier sprint(c, "%S", rp); 331*219b2ee8SDavid du Colombier r = 0; 332*219b2ee8SDavid du Colombier for (p = charmap[fmap[font]].slow; p; p = p->next) 333*219b2ee8SDavid du Colombier if(eq(c, p->name)){ 334*219b2ee8SDavid du Colombier r = p->val; 335*219b2ee8SDavid du Colombier break; 336*219b2ee8SDavid du Colombier } 337*219b2ee8SDavid du Colombier } 338*219b2ee8SDavid du Colombier if(r == 0){ /* not there */ 339*219b2ee8SDavid du Colombier dprint(2, "didn't find %S font# %d\n", rp, font); 3403e12c5d1SDavid du Colombier return 0; 3413e12c5d1SDavid du Colombier } 342*219b2ee8SDavid du Colombier dprint(2, "map %S to %s font# %d\n", rp, s, font); 343*219b2ee8SDavid du Colombier s[runetochar(s, &r)] = 0; 3443e12c5d1SDavid du Colombier return s; 3453e12c5d1SDavid du Colombier } 3463e12c5d1SDavid du Colombier 3473e12c5d1SDavid du Colombier static void 3483e12c5d1SDavid du Colombier scanstr(char *s, char *ans, char **ep) 3493e12c5d1SDavid du Colombier { 3503e12c5d1SDavid du Colombier for (; isspace((uchar) *s); s++) 3513e12c5d1SDavid du Colombier ; 352*219b2ee8SDavid du Colombier for (; *s!=0 && !isspace((uchar) *s); ) 3533e12c5d1SDavid du Colombier *ans++ = *s++; 3543e12c5d1SDavid du Colombier *ans = 0; 3553e12c5d1SDavid du Colombier if (ep) 3563e12c5d1SDavid du Colombier *ep = s; 3573e12c5d1SDavid du Colombier } 358