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 Memsubfont *defont;
18 void
19 usage(void)
20 {
21 fprint(2, "usage: fontsrv [-m mtpt]\n");
22 fprint(2, "or fontsrv -p path\n");
23 exits("usage");
24 }
26 static
27 void
28 packinfo(Fontchar *fc, uchar *p, int n)
29 {
30 int j;
32 for(j=0; j<=n; j++){
33 p[0] = fc->x;
34 p[1] = fc->x>>8;
35 p[2] = fc->top;
36 p[3] = fc->bottom;
37 p[4] = fc->left;
38 p[5] = fc->width;
39 fc++;
40 p += 6;
41 }
42 }
44 enum
45 {
46 Qroot = 0,
47 Qfontdir,
48 Qsizedir,
49 Qfontfile,
50 Qsubfontfile,
51 };
53 #define QTYPE(p) ((p) & 0xF)
54 #define QFONT(p) (((p) >> 4) & 0xFFFF)
55 #define QSIZE(p) (((p) >> 20) & 0xFF)
56 #define QANTIALIAS(p) (((p) >> 28) & 0x1)
57 #define QRANGE(p) (((p) >> 29) & 0xFF)
58 static int sizes[] = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 28 };
60 static vlong
61 qpath(int type, int font, int size, int antialias, int range)
62 {
63 return type | (font << 4) | (size << 20) | (antialias << 28) | ((vlong)range << 29);
64 }
66 static void
67 dostat(vlong path, Qid *qid, Dir *dir)
68 {
69 char *name;
70 Qid q;
71 ulong mode;
72 vlong length;
73 XFont *f;
74 char buf[100];
76 q.type = 0;
77 q.vers = 0;
78 q.path = path;
79 mode = 0444;
80 length = 0;
81 name = "???";
83 switch(QTYPE(path)) {
84 default:
85 sysfatal("dostat %#llux", path);
87 case Qroot:
88 q.type = QTDIR;
89 name = "/";
90 break;
92 case Qfontdir:
93 q.type = QTDIR;
94 f = &xfont[QFONT(path)];
95 name = f->name;
96 break;
98 case Qsizedir:
99 q.type = QTDIR;
100 snprint(buf, sizeof buf, "%lld%s", QSIZE(path), QANTIALIAS(path) ? "a" : "");
101 name = buf;
102 break;
104 case Qfontfile:
105 f = &xfont[QFONT(path)];
106 load(f);
107 length = 11+1+11+1+f->nrange*(6+1+6+1+9+1);
108 name = "font";
109 break;
111 case Qsubfontfile:
112 snprint(buf, sizeof buf, "x%02llx00.bit", QRANGE(path));
113 name = buf;
114 break;
117 if(qid)
118 *qid = q;
119 if(dir) {
120 memset(dir, 0, sizeof *dir);
121 dir->name = estrdup9p(name);
122 dir->muid = estrdup9p("");
123 dir->uid = estrdup9p("font");
124 dir->gid = estrdup9p("font");
125 dir->qid = q;
126 if(q.type == QTDIR)
127 mode |= DMDIR | 0111;
128 dir->mode = mode;
129 dir->length = length;
133 static char*
134 xwalk1(Fid *fid, char *name, Qid *qid)
136 int i, dotdot;
137 vlong path;
138 char *p;
139 int a, n;
140 XFont *f;
142 path = fid->qid.path;
143 dotdot = strcmp(name, "..") == 0;
144 switch(QTYPE(path)) {
145 default:
146 NotFound:
147 return "file not found";
149 case Qroot:
150 if(dotdot)
151 break;
152 for(i=0; i<nxfont; i++) {
153 if(strcmp(xfont[i].name, name) == 0) {
154 path = qpath(Qfontdir, i, 0, 0, 0);
155 goto Found;
158 goto NotFound;
160 case Qfontdir:
161 if(dotdot) {
162 path = Qroot;
163 break;
165 n = strtol(name, &p, 10);
166 if(n == 0)
167 goto NotFound;
168 a = 0;
169 if(*p == 'a') {
170 a = 1;
171 p++;
173 if(*p != 0)
174 goto NotFound;
175 path += Qsizedir - Qfontdir + qpath(0, 0, n, a, 0);
176 break;
178 case Qsizedir:
179 if(dotdot) {
180 path = qpath(Qfontdir, QFONT(path), 0, 0, 0);
181 break;
183 if(strcmp(name, "font") == 0) {
184 path += Qfontfile - Qsizedir;
185 break;
187 f = &xfont[QFONT(path)];
188 load(f);
189 p = name;
190 if(*p != 'x')
191 goto NotFound;
192 p++;
193 n = strtoul(p, &p, 16);
194 if(p != name+5 || (n&0xFF) != 0 || strcmp(p, ".bit") != 0 || !f->range[(n>>8) & 0xFF])
195 goto NotFound;
196 path += Qsubfontfile - Qsizedir + qpath(0, 0, 0, 0, (n>>8) & 0xFF);
197 break;
199 Found:
200 dostat(path, qid, nil);
201 fid->qid = *qid;
202 return nil;
205 static int
206 rootgen(int i, Dir *d, void *v)
208 if(i >= nxfont)
209 return -1;
210 dostat(qpath(Qfontdir, i, 0, 0, 0), nil, d);
211 return 0;
214 static int
215 fontgen(int i, Dir *d, void *v)
217 vlong path;
218 Fid *f;
220 f = v;
221 path = f->qid.path;
222 if(i >= 2*nelem(sizes))
223 return -1;
224 dostat(qpath(Qsizedir, QFONT(path), sizes[i/2], i&1, 0), nil, d);
225 return 0;
228 static int
229 sizegen(int i, Dir *d, void *v)
231 vlong path;
232 Fid *fid;
233 XFont *f;
234 int j;
236 fid = v;
237 path = fid->qid.path;
238 if(i == 0) {
239 path += Qfontfile - Qsizedir;
240 goto Done;
242 i--;
243 f = &xfont[QFONT(path)];
244 load(f);
245 for(j=0; j<nelem(f->range); j++) {
246 if(f->range[j] == 0)
247 continue;
248 if(i == 0) {
249 path += Qsubfontfile - Qsizedir;
250 path += qpath(0, 0, 0, 0, j);
251 goto Done;
253 i--;
255 return -1;
257 Done:
258 dostat(path, nil, d);
259 return 0;
262 static void
263 xattach(Req *r)
265 dostat(0, &r->ofcall.qid, nil);
266 r->fid->qid = r->ofcall.qid;
267 respond(r, nil);
270 static void
271 xopen(Req *r)
273 if(r->ifcall.mode != OREAD) {
274 respond(r, "permission denied");
275 return;
277 r->ofcall.qid = r->fid->qid;
278 respond(r, nil);
281 void
282 responderrstr(Req *r)
284 char err[ERRMAX];
286 rerrstr(err, sizeof err);
287 respond(r, err);
290 static void
291 xread(Req *r)
293 int i, size, height, ascent;
294 vlong path;
295 Fmt fmt;
296 XFont *f;
297 char *data;
298 Memsubfont *sf;
299 Memimage *m;
301 path = r->fid->qid.path;
302 switch(QTYPE(path)) {
303 case Qroot:
304 dirread9p(r, rootgen, nil);
305 break;
306 case Qfontdir:
307 dirread9p(r, fontgen, r->fid);
308 break;
309 case Qsizedir:
310 dirread9p(r, sizegen, r->fid);
311 break;
312 case Qfontfile:
313 fmtstrinit(&fmt);
314 f = &xfont[QFONT(path)];
315 load(f);
316 if(f->unit == 0)
317 break;
318 height = f->height * (int)QSIZE(path)/f->unit + 0.99999999;
319 ascent = height - (int)(-f->originy * (int)QSIZE(path)/f->unit + 0.99999999);
320 fmtprint(&fmt, "%11d %11d\n", height, ascent);
321 for(i=0; i<nelem(f->range); i++) {
322 if(f->range[i] == 0)
323 continue;
324 fmtprint(&fmt, "0x%04x 0x%04x x%04x.bit\n", i<<8, (i<<8) + 0xFF, i<<8);
326 data = fmtstrflush(&fmt);
327 readstr(r, data);
328 free(data);
329 break;
330 case Qsubfontfile:
331 f = &xfont[QFONT(path)];
332 load(f);
333 if(r->fid->aux == nil) {
334 r->fid->aux = mksubfont(f->name, QRANGE(path)<<8, (QRANGE(path)<<8)+0xFF, QSIZE(path), QANTIALIAS(path));
335 if(r->fid->aux == nil) {
336 responderrstr(r);
337 return;
340 sf = r->fid->aux;
341 m = sf->bits;
342 if(r->ifcall.offset < 5*12) {
343 char *chan;
344 if(QANTIALIAS(path))
345 chan = "k8";
346 else
347 chan = "k1";
348 data = smprint("%11s %11d %11d %11d %11d ", chan, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y);
349 readstr(r, data);
350 free(data);
351 break;
353 r->ifcall.offset -= 5*12;
354 size = bytesperline(m->r, chantodepth(m->chan)) * Dy(m->r);
355 if(r->ifcall.offset < size) {
356 readbuf(r, byteaddr(m, m->r.min), size);
357 break;
359 r->ifcall.offset -= size;
360 data = emalloc9p(3*12+6*(sf->n+1));
361 sprint(data, "%11d %11d %11d ", sf->n, sf->height, sf->ascent);
362 packinfo(sf->info, (uchar*)data+3*12, sf->n);
363 readbuf(r, data, 3*12+6*(sf->n+1));
364 free(data);
365 break;
367 respond(r, nil);
370 static void
371 xdestroyfid(Fid *fid)
373 Memsubfont *sf;
375 sf = fid->aux;
376 if(sf == nil)
377 return;
379 freememimage(sf->bits);
380 free(sf->info);
381 free(sf);
382 fid->aux = nil;
385 static void
386 xstat(Req *r)
388 dostat(r->fid->qid.path, nil, &r->d);
389 respond(r, nil);
392 Srv xsrv;
394 int
395 proccreate(void (*f)(void*), void *a, unsigned i)
397 abort();
400 int pflag;
402 static long dirpackage(uchar*, long, Dir**);
404 void
405 dump(char *path)
407 char *elem, *p, *path0, *err;
408 uchar buf[4096];
409 Fid fid;
410 Qid qid;
411 Dir *d;
412 Req r;
413 int off, i, n;
415 // root
416 memset(&fid, 0, sizeof fid);
417 dostat(0, &fid.qid, nil);
418 qid = fid.qid;
420 path0 = path;
421 while(path != nil) {
422 p = strchr(path, '/');
423 if(p != nil)
424 *p = '\0';
425 elem = path;
426 if(strcmp(elem, "") != 0 && strcmp(elem, ".") != 0) {
427 err = xwalk1(&fid, elem, &qid);
428 if(err != nil) {
429 fprint(2, "%s: %s\n", path0, err);
430 exits(err);
433 if(p)
434 *p++ = '/';
435 path = p;
438 memset(&r, 0, sizeof r);
439 xsrv.fake = 1;
441 // read and display
442 off = 0;
443 for(;;) {
444 r.srv = &xsrv;
445 r.fid = &fid;
446 r.ifcall.type = Tread;
447 r.ifcall.count = sizeof buf;
448 r.ifcall.offset = off;
449 r.ofcall.data = (char*)buf;
450 r.ofcall.count = 0;
451 xread(&r);
452 if(r.ofcall.type != Rread) {
453 fprint(2, "reading %s: %s\n", path0, r.ofcall.ename);
454 exits(r.ofcall.ename);
456 n = r.ofcall.count;
457 if(n == 0)
458 break;
459 if(off == 0 && pflag > 1) {
460 print("\001");
462 off += n;
463 if(qid.type & QTDIR) {
464 n = dirpackage(buf, n, &d);
465 for(i=0; i<n; i++)
466 print("%s%s\n", d[i].name, (d[i].mode&DMDIR) ? "/" : "");
467 free(d);
468 } else
469 write(1, buf, n);
473 int
474 fontcmp(const void *va, const void *vb)
476 XFont *a, *b;
478 a = (XFont*)va;
479 b = (XFont*)vb;
480 return strcmp(a->name, b->name);
483 void
484 main(int argc, char **argv)
486 char *mtpt, *srvname;
488 mtpt = nil;
489 srvname = "font";
491 ARGBEGIN{
492 case 'D':
493 chatty9p++;
494 break;
495 case 'F':
496 chattyfuse++;
497 break;
498 case 'm':
499 mtpt = EARGF(usage());
500 break;
501 case 's':
502 srvname = EARGF(usage());
503 break;
504 case 'p':
505 pflag++;
506 break;
507 default:
508 usage();
509 }ARGEND
511 xsrv.attach = xattach;
512 xsrv.open = xopen;
513 xsrv.read = xread;
514 xsrv.stat = xstat;
515 xsrv.walk1 = xwalk1;
516 xsrv.destroyfid = xdestroyfid;
518 fmtinstall('R', Rfmt);
519 fmtinstall('P', Pfmt);
520 memimageinit();
521 defont = getmemdefont();
522 loadfonts();
523 qsort(xfont, nxfont, sizeof xfont[0], fontcmp);
525 if(pflag) {
526 if(argc != 1 || chatty9p || chattyfuse)
527 usage();
528 dump(argv[0]);
529 exits(0);
532 if(pflag || argc != 0)
533 usage();
535 /*
536 * Check twice -- if there is an exited instance
537 * mounted there, the first access will fail but unmount it.
538 */
539 if(mtpt && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0)
540 sysfatal("mountpoint %s does not exist", mtpt);
542 xsrv.foreground = 1;
543 threadpostmountsrv(&xsrv, srvname, mtpt, 0);
546 /*
547 /sys/src/libc/9sys/dirread.c
548 */
549 static
550 long
551 dirpackage(uchar *buf, long ts, Dir **d)
553 char *s;
554 long ss, i, n, nn, m;
556 *d = nil;
557 if(ts <= 0)
558 return 0;
560 /*
561 * first find number of all stats, check they look like stats, & size all associated strings
562 */
563 ss = 0;
564 n = 0;
565 for(i = 0; i < ts; i += m){
566 m = BIT16SZ + GBIT16(&buf[i]);
567 if(statcheck(&buf[i], m) < 0)
568 break;
569 ss += m;
570 n++;
573 if(i != ts)
574 return -1;
576 *d = malloc(n * sizeof(Dir) + ss);
577 if(*d == nil)
578 return -1;
580 /*
581 * then convert all buffers
582 */
583 s = (char*)*d + n * sizeof(Dir);
584 nn = 0;
585 for(i = 0; i < ts; i += m){
586 m = BIT16SZ + GBIT16((uchar*)&buf[i]);
587 if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
588 free(*d);
589 *d = nil;
590 return -1;
592 nn++;
593 s += m;
596 return nn;