Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <thread.h>
6 #include <fcall.h>
7 #include <9p.h>
8 /*
9 * we included thread.h in order to include 9p.h,
10 * but we don't use threads, so exits is ok.
11 */
12 #undef exits
14 #include "a.h"
16 void
17 usage(void)
18 {
19 fprint(2, "usage: fontsrv [-m mtpt]\n");
20 fprint(2, "or fontsrv -p path\n");
21 exits("usage");
22 }
24 static
25 void
26 packinfo(Fontchar *fc, uchar *p, int n)
27 {
28 int j;
30 for(j=0; j<=n; j++){
31 p[0] = fc->x;
32 p[1] = fc->x>>8;
33 p[2] = fc->top;
34 p[3] = fc->bottom;
35 p[4] = fc->left;
36 p[5] = fc->width;
37 fc++;
38 p += 6;
39 }
40 }
42 enum
43 {
44 Qroot = 0,
45 Qfontdir,
46 Qsizedir,
47 Qfontfile,
48 Qsubfontfile,
49 };
51 #define QTYPE(p) ((p) & 0xF)
52 #define QFONT(p) (((p) >> 4) & 0xFFFF)
53 #define QSIZE(p) (((p) >> 20) & 0xFF)
54 #define QANTIALIAS(p) (((p) >> 28) & 0x1)
55 #define QRANGE(p) (((p) >> 29) & 0xFFFFFF)
56 static int sizes[] = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 28 };
58 static vlong
59 qpath(int type, int font, int size, int antialias, int range)
60 {
61 return type | (font << 4) | (size << 20) | (antialias << 28) | ((vlong)range << 29);
62 }
64 static void
65 dostat(vlong path, Qid *qid, Dir *dir)
66 {
67 char *name;
68 Qid q;
69 ulong mode;
70 vlong length;
71 XFont *f;
72 char buf[100];
74 q.type = 0;
75 q.vers = 0;
76 q.path = path;
77 mode = 0444;
78 length = 0;
79 name = "???";
81 switch(QTYPE(path)) {
82 default:
83 sysfatal("dostat %#llux", path);
85 case Qroot:
86 q.type = QTDIR;
87 name = "/";
88 break;
90 case Qfontdir:
91 q.type = QTDIR;
92 f = &xfont[QFONT(path)];
93 name = f->name;
94 break;
96 case Qsizedir:
97 q.type = QTDIR;
98 snprint(buf, sizeof buf, "%lld%s", QSIZE(path), QANTIALIAS(path) ? "a" : "");
99 name = buf;
100 break;
102 case Qfontfile:
103 f = &xfont[QFONT(path)];
104 load(f);
105 length = 11+1+11+1+f->nfile*(6+1+6+1+9+1);
106 name = "font";
107 break;
109 case Qsubfontfile:
110 snprint(buf, sizeof buf, "x%04x.bit", (int)QRANGE(path)*SubfontSize);
111 name = buf;
112 break;
115 if(qid)
116 *qid = q;
117 if(dir) {
118 memset(dir, 0, sizeof *dir);
119 dir->name = estrdup9p(name);
120 dir->muid = estrdup9p("");
121 dir->uid = estrdup9p("font");
122 dir->gid = estrdup9p("font");
123 dir->qid = q;
124 if(q.type == QTDIR)
125 mode |= DMDIR | 0111;
126 dir->mode = mode;
127 dir->length = length;
131 static char*
132 xwalk1(Fid *fid, char *name, Qid *qid)
134 int i, dotdot;
135 vlong path;
136 char *p;
137 int a, n;
138 XFont *f;
140 path = fid->qid.path;
141 dotdot = strcmp(name, "..") == 0;
142 switch(QTYPE(path)) {
143 default:
144 NotFound:
145 return "file not found";
147 case Qroot:
148 if(dotdot)
149 break;
150 for(i=0; i<nxfont; i++) {
151 if(strcmp(xfont[i].name, name) == 0) {
152 path = qpath(Qfontdir, i, 0, 0, 0);
153 goto Found;
156 goto NotFound;
158 case Qfontdir:
159 if(dotdot) {
160 path = Qroot;
161 break;
163 n = strtol(name, &p, 10);
164 if(n == 0)
165 goto NotFound;
166 a = 0;
167 if(*p == 'a') {
168 a = 1;
169 p++;
171 if(*p != 0)
172 goto NotFound;
173 path += Qsizedir - Qfontdir + qpath(0, 0, n, a, 0);
174 break;
176 case Qsizedir:
177 if(dotdot) {
178 path = qpath(Qfontdir, QFONT(path), 0, 0, 0);
179 break;
181 if(strcmp(name, "font") == 0) {
182 path += Qfontfile - Qsizedir;
183 break;
185 f = &xfont[QFONT(path)];
186 load(f);
187 p = name;
188 if(*p != 'x')
189 goto NotFound;
190 p++;
191 n = strtoul(p, &p, 16);
192 if(p < name+5 || p > name+5 && name[1] == '0' || n%SubfontSize != 0 || n/SubfontSize >= MaxSubfont || strcmp(p, ".bit") != 0 || !f->range[n/SubfontSize])
193 goto NotFound;
194 path += Qsubfontfile - Qsizedir + qpath(0, 0, 0, 0, n/SubfontSize);
195 break;
197 Found:
198 dostat(path, qid, nil);
199 fid->qid = *qid;
200 return nil;
203 static int
204 rootgen(int i, Dir *d, void *v)
206 if(i >= nxfont)
207 return -1;
208 dostat(qpath(Qfontdir, i, 0, 0, 0), nil, d);
209 return 0;
212 static int
213 fontgen(int i, Dir *d, void *v)
215 vlong path;
216 Fid *f;
218 f = v;
219 path = f->qid.path;
220 if(i >= 2*nelem(sizes))
221 return -1;
222 dostat(qpath(Qsizedir, QFONT(path), sizes[i/2], i&1, 0), nil, d);
223 return 0;
226 static int
227 sizegen(int i, Dir *d, void *v)
229 vlong path;
230 Fid *fid;
231 XFont *f;
233 fid = v;
234 path = fid->qid.path;
235 if(i == 0) {
236 path += Qfontfile - Qsizedir;
237 goto Done;
239 i--;
240 f = &xfont[QFONT(path)];
241 load(f);
242 if(i < f->nfile) {
243 path += Qsubfontfile - Qsizedir;
244 path += qpath(0, 0, 0, 0, f->file[i]);
245 goto Done;
247 return -1;
249 Done:
250 dostat(path, nil, d);
251 return 0;
254 static void
255 xattach(Req *r)
257 dostat(0, &r->ofcall.qid, nil);
258 r->fid->qid = r->ofcall.qid;
259 respond(r, nil);
262 static void
263 xopen(Req *r)
265 if(r->ifcall.mode != OREAD) {
266 respond(r, "permission denied");
267 return;
269 r->ofcall.qid = r->fid->qid;
270 respond(r, nil);
273 void
274 responderrstr(Req *r)
276 char err[ERRMAX];
278 rerrstr(err, sizeof err);
279 respond(r, err);
282 static void
283 xread(Req *r)
285 int i, size, height, ascent;
286 vlong path;
287 Fmt fmt;
288 XFont *f;
289 char *data;
290 Memsubfont *sf;
291 Memimage *m;
293 path = r->fid->qid.path;
294 switch(QTYPE(path)) {
295 case Qroot:
296 dirread9p(r, rootgen, nil);
297 break;
298 case Qfontdir:
299 dirread9p(r, fontgen, r->fid);
300 break;
301 case Qsizedir:
302 dirread9p(r, sizegen, r->fid);
303 break;
304 case Qfontfile:
305 fmtstrinit(&fmt);
306 f = &xfont[QFONT(path)];
307 load(f);
308 if(f->unit == 0 && f->loadheight == nil) {
309 readstr(r, "font missing\n");
310 break;
312 if(f->fonttext == nil) {
313 height = 0;
314 ascent = 0;
315 if(f->unit > 0) {
316 height = f->height * (int)QSIZE(path)/f->unit + 0.99999999;
317 ascent = height - (int)(-f->originy * (int)QSIZE(path)/f->unit + 0.99999999);
319 if(f->loadheight != nil)
320 f->loadheight(f, QSIZE(path), &height, &ascent);
321 fmtprint(&fmt, "%11d %11d\n", height, ascent);
322 for(i=0; i<f->nfile; i++)
323 fmtprint(&fmt, "0x%04x 0x%04x x%04x.bit\n", f->file[i]*SubfontSize, ((f->file[i]+1)*SubfontSize) - 1, f->file[i]*SubfontSize);
324 f->fonttext = fmtstrflush(&fmt);
325 f->nfonttext = strlen(f->fonttext);
327 readbuf(r, f->fonttext, f->nfonttext);
328 break;
329 case Qsubfontfile:
330 f = &xfont[QFONT(path)];
331 load(f);
332 if(r->fid->aux == nil) {
333 r->fid->aux = mksubfont(f, f->name, QRANGE(path)*SubfontSize, ((QRANGE(path)+1)*SubfontSize)-1, QSIZE(path), QANTIALIAS(path));
334 if(r->fid->aux == nil) {
335 responderrstr(r);
336 return;
339 sf = r->fid->aux;
340 m = sf->bits;
341 if(r->ifcall.offset < 5*12) {
342 char *chan;
343 if(QANTIALIAS(path))
344 chan = "k8";
345 else
346 chan = "k1";
347 data = smprint("%11s %11d %11d %11d %11d ", chan, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y);
348 readstr(r, data);
349 free(data);
350 break;
352 r->ifcall.offset -= 5*12;
353 size = bytesperline(m->r, chantodepth(m->chan)) * Dy(m->r);
354 if(r->ifcall.offset < size) {
355 readbuf(r, byteaddr(m, m->r.min), size);
356 break;
358 r->ifcall.offset -= size;
359 data = emalloc9p(3*12+6*(sf->n+1));
360 sprint(data, "%11d %11d %11d ", sf->n, sf->height, sf->ascent);
361 packinfo(sf->info, (uchar*)data+3*12, sf->n);
362 readbuf(r, data, 3*12+6*(sf->n+1));
363 free(data);
364 break;
366 respond(r, nil);
369 static void
370 xdestroyfid(Fid *fid)
372 Memsubfont *sf;
374 sf = fid->aux;
375 if(sf == nil)
376 return;
378 freememimage(sf->bits);
379 free(sf->info);
380 free(sf);
381 fid->aux = nil;
384 static void
385 xstat(Req *r)
387 dostat(r->fid->qid.path, nil, &r->d);
388 respond(r, nil);
391 Srv xsrv;
393 int
394 proccreate(void (*f)(void*), void *a, unsigned i)
396 abort();
399 int pflag;
401 static long dirpackage(uchar*, long, Dir**);
403 void
404 dump(char *path)
406 char *elem, *p, *path0, *err;
407 uchar buf[4096];
408 Fid fid;
409 Qid qid;
410 Dir *d;
411 Req r;
412 int off, i, n;
414 // root
415 memset(&fid, 0, sizeof fid);
416 dostat(0, &fid.qid, nil);
417 qid = fid.qid;
419 path0 = path;
420 while(path != nil) {
421 p = strchr(path, '/');
422 if(p != nil)
423 *p = '\0';
424 elem = path;
425 if(strcmp(elem, "") != 0 && strcmp(elem, ".") != 0) {
426 err = xwalk1(&fid, elem, &qid);
427 if(err != nil) {
428 fprint(2, "%s: %s\n", path0, err);
429 exits(err);
432 if(p)
433 *p++ = '/';
434 path = p;
437 memset(&r, 0, sizeof r);
438 xsrv.fake = 1;
440 // read and display
441 off = 0;
442 for(;;) {
443 r.srv = &xsrv;
444 r.fid = &fid;
445 r.ifcall.type = Tread;
446 r.ifcall.count = sizeof buf;
447 r.ifcall.offset = off;
448 r.ofcall.data = (char*)buf;
449 r.ofcall.count = 0;
450 xread(&r);
451 if(r.ofcall.type != Rread) {
452 fprint(2, "reading %s: %s\n", path0, r.ofcall.ename);
453 exits(r.ofcall.ename);
455 n = r.ofcall.count;
456 if(n == 0)
457 break;
458 if(off == 0 && pflag > 1) {
459 print("\001");
461 off += n;
462 if(qid.type & QTDIR) {
463 n = dirpackage(buf, n, &d);
464 for(i=0; i<n; i++)
465 print("%s%s\n", d[i].name, (d[i].mode&DMDIR) ? "/" : "");
466 free(d);
467 } else
468 write(1, buf, n);
472 int
473 fontcmp(const void *va, const void *vb)
475 XFont *a, *b;
477 a = (XFont*)va;
478 b = (XFont*)vb;
479 return strcmp(a->name, b->name);
482 void
483 main(int argc, char **argv)
485 char *mtpt, *srvname;
487 mtpt = nil;
488 srvname = "font";
490 ARGBEGIN{
491 case 'D':
492 chatty9p++;
493 break;
494 case 'F':
495 chattyfuse++;
496 break;
497 case 'm':
498 mtpt = EARGF(usage());
499 break;
500 case 's':
501 srvname = EARGF(usage());
502 break;
503 case 'p':
504 pflag++;
505 break;
506 default:
507 usage();
508 }ARGEND
510 xsrv.attach = xattach;
511 xsrv.open = xopen;
512 xsrv.read = xread;
513 xsrv.stat = xstat;
514 xsrv.walk1 = xwalk1;
515 xsrv.destroyfid = xdestroyfid;
517 fmtinstall('R', Rfmt);
518 fmtinstall('P', Pfmt);
519 memimageinit();
520 loadfonts();
521 qsort(xfont, nxfont, sizeof xfont[0], fontcmp);
523 if(pflag) {
524 if(argc != 1 || chatty9p || chattyfuse)
525 usage();
526 dump(argv[0]);
527 exits(0);
530 if(pflag || argc != 0)
531 usage();
533 /*
534 * Check twice -- if there is an exited instance
535 * mounted there, the first access will fail but unmount it.
536 */
537 if(mtpt && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0)
538 sysfatal("mountpoint %s does not exist", mtpt);
540 xsrv.foreground = 1;
541 threadpostmountsrv(&xsrv, srvname, mtpt, 0);
544 /*
545 /sys/src/libc/9sys/dirread.c
546 */
547 static
548 long
549 dirpackage(uchar *buf, long ts, Dir **d)
551 char *s;
552 long ss, i, n, nn, m;
554 *d = nil;
555 if(ts <= 0)
556 return 0;
558 /*
559 * first find number of all stats, check they look like stats, & size all associated strings
560 */
561 ss = 0;
562 n = 0;
563 for(i = 0; i < ts; i += m){
564 m = BIT16SZ + GBIT16(&buf[i]);
565 if(statcheck(&buf[i], m) < 0)
566 break;
567 ss += m;
568 n++;
571 if(i != ts)
572 return -1;
574 *d = malloc(n * sizeof(Dir) + ss);
575 if(*d == nil)
576 return -1;
578 /*
579 * then convert all buffers
580 */
581 s = (char*)*d + n * sizeof(Dir);
582 nn = 0;
583 for(i = 0; i < ts; i += m){
584 m = BIT16SZ + GBIT16((uchar*)&buf[i]);
585 if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
586 free(*d);
587 *d = nil;
588 return -1;
590 nn++;
591 s += m;
594 return nn;