#include #include #include #include #include #include #include <9p.h> #include "dat.h" char *mtpt = "/mnt/font"; char *service = "font"; Srv fs; Xfont *xfont; int nxfont; static char Enotfound[] = "file not found"; enum { Qtopdir = 0, Qfontdir, Qsizedir, Qfontfile, Qsubfontfile, }; #define QID(q,f,s,m,p) (vlong)((q)|((f)<<4)|((s)<<20)|((m)<<28)|((vlong)(p)<<32)) #define FILE(q) (int)((q).path & 0xF) #define FONT(q) (int)(((q).path>>4) & 0xFFFF) #define SIZE(q) (int)(((q).path>>20) & 0xFF) #define MONO(q) (int)(((q).path>>28) & 0x1) #define PAGE(q) (int)(((q).path>>32) & PageMask) static int sizes[] = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 28 }; void usage(void) { fprint(2, "usage: fontsrv [-m mtpt] [-s service]\n"); exits("usage"); } static char* fswalk1(Fid *f, char *name, Qid *qid) { int i, n, k1, sz; char *p, *err; Qid q; Xfont *font; q = f->qid; q.vers = 0; switch(FILE(f->qid)) { default: return Enotfound; case Qtopdir: if(strcmp(name, "..") == 0) break; for(i=0; iqid), sz, k1, 0); q.type = QTDIR; break; case Qsizedir: if(strcmp(name, "..") == 0){ q.path = QID(Qfontdir, FONT(f->qid), 0, 0, 0); q.type = QTDIR; break; } sz = SIZE(f->qid); k1 = MONO(f->qid); if(strcmp(name, "font") == 0){ q.path = QID(Qfontfile, FONT(f->qid), sz, k1, 0); q.type = 0; break; } font = &xfont[FONT(f->qid)]; err = xfload(font); if(err != nil) return err; p = name; if(*p != 'x') return Enotfound; p++; n = strtoul(p, &p, 16); i = (n/PageSize)&PageMask; if(p != name+7 || strcmp(p, ".bit") != 0 || n%PageSize != 0 || !font->page[i]) return Enotfound; q.path = QID(Qsubfontfile, FONT(f->qid), sz, k1, i); q.type = 0; break; } *qid = q; f->qid = q; return nil; } static void filldir(Dir *d) { Qid q; Xfont *font; char *err, buf[64]; q.path = d->qid.path; q.type = 0; q.vers = 0; memset(d, 0, sizeof *d); d->mode= 0444; d->muid = estrdup9p(""); d->uid = estrdup9p("font"); d->gid = estrdup9p("font"); switch(FILE(q)){ default: sysfatal("filldir %#llux", q.path); case Qtopdir: q.type = QTDIR; d->name = estrdup9p("/"); break; case Qfontdir: q.type = QTDIR; font = &xfont[FONT(q)]; d->name = estrdup9p(font->name); break; case Qsizedir: q.type = QTDIR; snprint(buf, sizeof buf, "%d%s", SIZE(q), MONO(q) ? "" : "a"); d->name = estrdup9p(buf); break; case Qfontfile: font = &xfont[FONT(q)]; err = xfload(font); if(err == nil) d->length = 11+1+11+1+font->npage*(8+1+8+1+11+1); d->name = estrdup9p("font"); break; case Qsubfontfile: snprint(buf, sizeof buf, "x%06x.bit", (int)PAGE(q)*PageSize); d->name = estrdup9p(buf); break; } d->qid = q; if(q.type == QTDIR) d->mode |= DMDIR | 0111; } int rootgen(int i, Dir *d, void *) { if(i >= nxfont) return -1; d->qid.path = QID(Qfontdir, i, 0, 0, 0); filldir(d); return 0; } int fontgen(int i, Dir *d, void *v) { Fid *f; f = v; if(i >= 2*nelem(sizes)) return -1; d->qid.path = QID(Qsizedir, FONT(f->qid), sizes[i/2], i&1, 0); filldir(d); return 0; } int sizegen(int i, Dir *d, void *v) { Qid q; Fid *f; Xfont *font; int sz, k1, j; char* err; f = v; q = f->qid; sz = SIZE(f->qid); k1 = MONO(f->qid); if(i == 0) { d->qid.path = QID(Qfontfile, FONT(f->qid), sz, k1, 0); filldir(d); return 0; } i--; font = &xfont[FONT(q)]; err = xfload(font); if(err != nil) return -1; for(j=0; jpage); j++){ if(font->page[j] == 0) continue; if(i == 0){ d->qid.path = QID(Qsubfontfile, FONT(f->qid), sz, k1, j); filldir(d); return 0; } i--; } return -1; } void fsattach(Req *r) { Qid q; q.path = Qtopdir; q.type = QTDIR; q.vers = 0; r->ofcall.qid = q; r->fid->qid = q; respond(r, nil); } void fsopen(Req *r) { if(r->ifcall.mode != OREAD) { respond(r, "permission denied"); return; } r->ofcall.qid = r->fid->qid; respond(r, nil); } void fsreadfont(Req *r) { int i, size, lo, hi; Fid* f; Xfont* font; char *data, *err; Fmt fmt; f = r->fid; font = &xfont[FONT(f->qid)]; if((err = xfload(font)) != nil){ respond(r, err); return; } size = SIZE(f->qid); xfscale(font, size); fmtstrinit(&fmt); fmtprint(&fmt, "%11d %11d\n", font->height, font->ascent); for(i=0; ipage); i++){ if(font->page[i] == 0) continue; lo = i*PageSize; hi = ((i+1)*PageSize) - 1; fmtprint(&fmt, "0x%06x 0x%06x x%06x.bit\n", lo, hi, lo); } data = fmtstrflush(&fmt); readstr(r, data); respond(r, nil); free(data); } static void packinfo(Fontchar *fc, uchar *p, int n) { int j; for(j=0; j<=n; j++){ p[0] = fc->x; p[1] = fc->x>>8; p[2] = fc->top; p[3] = fc->bottom; p[4] = fc->left; p[5] = fc->width; fc++; p += 6; } } void fsreadsubfont(Req *r) { int size, i, lo, hi; Fid* f; char *data, *err, cbuf[12]; Memsubfont *sf; Memimage *m; Xfont *font; f = r->fid; font = &xfont[FONT(f->qid)]; if((err = xfload(font)) != nil){ respond(r, err); return; } if(f->aux == nil) { i = PAGE(f->qid); lo = i*PageSize; hi = (i+1)*PageSize-1; f->aux = mksubfont(font, nil, lo, hi, SIZE(f->qid), MONO(f->qid)); if(f->aux == nil){ responderror(r); return; } } sf = f->aux; m = sf->bits; if(r->ifcall.offset < 5*12){ data = smprint("%11s %11d %11d %11d %11d ", chantostr(cbuf, m->chan), m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y); readstr(r, data); respond(r, nil); free(data); return; } r->ifcall.offset -= 5*12; size = bytesperline(m->r, chantodepth(m->chan)) * Dy(m->r); if(r->ifcall.offset < size) { readbuf(r, byteaddr(m, m->r.min), size); respond(r, nil); return; } r->ifcall.offset -= size; data = emalloc9p(3*12+6*(sf->n+1)); sprint(data, "%11d %11d %11d ", sf->n, sf->height, sf->ascent); packinfo(sf->info, (uchar*)data+3*12, sf->n); readbuf(r, data, 3*12+6*(sf->n+1)); respond(r, nil); free(data); } void fsread(Req *r) { Fid* f; f = r->fid; switch(FILE(f->qid)){ default: respond(r, "internal error"); return; case Qtopdir: dirread9p(r, rootgen, nil); break; case Qfontdir: dirread9p(r, fontgen, f); break; case Qsizedir: dirread9p(r, sizegen, f); break; case Qfontfile: fsreadfont(r); return; case Qsubfontfile: fsreadsubfont(r); return; } respond(r, nil); } void fsdestroyfid(Fid *fid) { Memsubfont *sf; sf = fid->aux; freememsubfont(sf); fid->aux = nil; } void fsstat(Req *r) { r->d.qid.path = r->fid->qid.path; filldir(&r->d); respond(r, nil); } void threadmain(int argc, char **argv) { ARGBEGIN{ case 'D': chatty9p++; break; case 'm': mtpt = EARGF(usage()); break; case 's': service = EARGF(usage()); break; default: usage(); }ARGEND if(argc != 0) usage(); fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); xfontinit(); fs.attach = fsattach; fs.open = fsopen; fs.read = fsread; fs.stat = fsstat; fs.walk1 = fswalk1; fs.destroyfid = fsdestroyfid; threadpostmountsrv(&fs, service, mtpt, MREPL); threadexits(nil); }