plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

main.c (10560B)


      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
     13 
     14 #include "a.h"
     15 
     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 }
     23 
     24 static
     25 void
     26 packinfo(Fontchar *fc, uchar *p, int n)
     27 {
     28 	int j;
     29 
     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 }
     41 
     42 enum
     43 {
     44 	Qroot = 0,
     45 	Qfontdir,
     46 	Qsizedir,
     47 	Qfontfile,
     48 	Qsubfontfile,
     49 };
     50 
     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 };
     57 
     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 }
     63 
     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];
     73 
     74 	q.type = 0;
     75 	q.vers = 0;
     76 	q.path = path;
     77 	mode = 0444;
     78 	length = 0;
     79 	name = "???";
     80 
     81 	switch(QTYPE(path)) {
     82 	default:
     83 		sysfatal("dostat %#llux", path);
     84 
     85 	case Qroot:
     86 		q.type = QTDIR;
     87 		name = "/";
     88 		break;
     89 
     90 	case Qfontdir:
     91 		q.type = QTDIR;
     92 		f = &xfont[QFONT(path)];
     93 		name = f->name;
     94 		break;
     95 
     96 	case Qsizedir:
     97 		q.type = QTDIR;
     98 		snprint(buf, sizeof buf, "%lld%s", QSIZE(path), QANTIALIAS(path) ? "a" : "");
     99 		name = buf;
    100 		break;
    101 
    102 	case Qfontfile:
    103 		f = &xfont[QFONT(path)];
    104 		load(f);
    105 		length = 11+1+11+1+f->nfile*(8+1+8+1+11+1);
    106 		name = "font";
    107 		break;
    108 
    109 	case Qsubfontfile:
    110 		snprint(buf, sizeof buf, "x%06x.bit", (int)QRANGE(path)*SubfontSize);
    111 		name = buf;
    112 		break;
    113 	}
    114 
    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;
    128 	}
    129 }
    130 
    131 static char*
    132 xwalk1(Fid *fid, char *name, Qid *qid)
    133 {
    134 	int i, dotdot;
    135 	vlong path;
    136 	char *p;
    137 	int a, n;
    138 	XFont *f;
    139 
    140 	path = fid->qid.path;
    141 	dotdot = strcmp(name, "..") == 0;
    142 	switch(QTYPE(path)) {
    143 	default:
    144 	NotFound:
    145 		return "file not found";
    146 
    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;
    154 			}
    155 		}
    156 		goto NotFound;
    157 
    158 	case Qfontdir:
    159 		if(dotdot) {
    160 			path = Qroot;
    161 			break;
    162 		}
    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++;
    170 		}
    171 		if(*p != 0)
    172 			goto NotFound;
    173 		path += Qsizedir - Qfontdir + qpath(0, 0, n, a, 0);
    174 		break;
    175 
    176 	case Qsizedir:
    177 		if(dotdot) {
    178 			path = qpath(Qfontdir, QFONT(path), 0, 0, 0);
    179 			break;
    180 		}
    181 		if(strcmp(name, "font") == 0) {
    182 			path += Qfontfile - Qsizedir;
    183 			break;
    184 		}
    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+7 || p > name+7 && 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;
    196 	}
    197 Found:
    198 	dostat(path, qid, nil);
    199 	fid->qid = *qid;
    200 	return nil;
    201 }
    202 
    203 static int
    204 rootgen(int i, Dir *d, void *v)
    205 {
    206 	if(i >= nxfont)
    207 		return -1;
    208 	dostat(qpath(Qfontdir, i, 0, 0, 0), nil, d);
    209 	return 0;
    210 }
    211 
    212 static int
    213 fontgen(int i, Dir *d, void *v)
    214 {
    215 	vlong path;
    216 	Fid *f;
    217 
    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;
    224 }
    225 
    226 static int
    227 sizegen(int i, Dir *d, void *v)
    228 {
    229 	vlong path;
    230 	Fid *fid;
    231 	XFont *f;
    232 
    233 	fid = v;
    234 	path = fid->qid.path;
    235 	if(i == 0) {
    236 		path += Qfontfile - Qsizedir;
    237 		goto Done;
    238 	}
    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;
    246 	}
    247 	return -1;
    248 
    249 Done:
    250 	dostat(path, nil, d);
    251 	return 0;
    252 }
    253 
    254 static void
    255 xattach(Req *r)
    256 {
    257 	dostat(0, &r->ofcall.qid, nil);
    258 	r->fid->qid = r->ofcall.qid;
    259 	respond(r, nil);
    260 }
    261 
    262 static void
    263 xopen(Req *r)
    264 {
    265 	if(r->ifcall.mode != OREAD) {
    266 		respond(r, "permission denied");
    267 		return;
    268 	}
    269 	r->ofcall.qid = r->fid->qid;
    270 	respond(r, nil);
    271 }
    272 
    273 void
    274 responderrstr(Req *r)
    275 {
    276 	char err[ERRMAX];
    277 
    278 	rerrstr(err, sizeof err);
    279 	respond(r, err);
    280 }
    281 
    282 static void
    283 xread(Req *r)
    284 {
    285 	int i, size, height, ascent;
    286 	vlong path;
    287 	Fmt fmt;
    288 	XFont *f;
    289 	char *data;
    290 	char *buf;
    291 	Memsubfont *sf;
    292 	Memimage *m;
    293 
    294 	path = r->fid->qid.path;
    295 	switch(QTYPE(path)) {
    296 	case Qroot:
    297 		dirread9p(r, rootgen, nil);
    298 		break;
    299 	case Qfontdir:
    300 		dirread9p(r, fontgen, r->fid);
    301 		break;
    302 	case Qsizedir:
    303 		dirread9p(r, sizegen, r->fid);
    304 		break;
    305 	case Qfontfile:
    306 		fmtstrinit(&fmt);
    307 		f = &xfont[QFONT(path)];
    308 		load(f);
    309 		if(f->unit == 0 && f->loadheight == nil) {
    310 			readstr(r, "font missing\n");
    311 			break;
    312 		}
    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);
    318 		}
    319 		if(f->loadheight != nil)
    320 			f->loadheight(f, QSIZE(path), &height, &ascent);
    321 		fmtprint(&fmt, "%11d %11d\n", height, ascent);
    322 		if(f->fonttext == nil) {
    323 			for(i=0; i<f->nfile; i++)
    324 				fmtprint(&fmt, "0x%06x 0x%06x x%06x.bit\n", f->file[i]*SubfontSize, ((f->file[i]+1)*SubfontSize) - 1, f->file[i]*SubfontSize);
    325 			f->fonttext = fmtstrflush(&fmt);
    326 			f->nfonttext = strlen(f->fonttext);
    327 		} else {
    328 			buf = fmtstrflush(&fmt);
    329 			strncpy(f->fonttext, buf, strlen(buf));  // Do not copy the null byte.
    330 			free(buf);
    331 		}
    332 		readbuf(r, f->fonttext, f->nfonttext);
    333 		break;
    334 	case Qsubfontfile:
    335 		f = &xfont[QFONT(path)];
    336 		load(f);
    337 		if(r->fid->aux == nil) {
    338 			r->fid->aux = mksubfont(f, f->name, QRANGE(path)*SubfontSize, ((QRANGE(path)+1)*SubfontSize)-1, QSIZE(path), QANTIALIAS(path));
    339 			if(r->fid->aux == nil) {
    340 				responderrstr(r);
    341 				return;
    342 			}
    343 		}
    344 		sf = r->fid->aux;
    345 		m = sf->bits;
    346 		if(r->ifcall.offset < 5*12) {
    347 			char *chan;
    348 			if(QANTIALIAS(path))
    349 				chan = "k8";
    350 			else
    351 				chan = "k1";
    352 			data = smprint("%11s %11d %11d %11d %11d ", chan, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y);
    353 			readstr(r, data);
    354 			free(data);
    355 			break;
    356 		}
    357 		r->ifcall.offset -= 5*12;
    358 		size = bytesperline(m->r, chantodepth(m->chan)) * Dy(m->r);
    359 		if(r->ifcall.offset < size) {
    360 			readbuf(r, byteaddr(m, m->r.min), size);
    361 			break;
    362 		}
    363 		r->ifcall.offset -= size;
    364 		data = emalloc9p(3*12+6*(sf->n+1));
    365 		sprint(data, "%11d %11d %11d ", sf->n, sf->height, sf->ascent);
    366 		packinfo(sf->info, (uchar*)data+3*12, sf->n);
    367 		readbuf(r, data, 3*12+6*(sf->n+1));
    368 		free(data);
    369 		break;
    370 	}
    371 	respond(r, nil);
    372 }
    373 
    374 static void
    375 xdestroyfid(Fid *fid)
    376 {
    377 	Memsubfont *sf;
    378 
    379 	sf = fid->aux;
    380 	if(sf == nil)
    381 		return;
    382 
    383 	freememimage(sf->bits);
    384 	free(sf->info);
    385 	free(sf);
    386 	fid->aux = nil;
    387 }
    388 
    389 static void
    390 xstat(Req *r)
    391 {
    392 	dostat(r->fid->qid.path, nil, &r->d);
    393 	respond(r, nil);
    394 }
    395 
    396 Srv xsrv;
    397 
    398 int
    399 proccreate(void (*f)(void*), void *a, unsigned i)
    400 {
    401 	abort();
    402 }
    403 
    404 int pflag;
    405 
    406 static long dirpackage(uchar*, long, Dir**);
    407 
    408 void
    409 dump(char *path)
    410 {
    411 	char *elem, *p, *path0, *err;
    412 	uchar buf[4096];
    413 	Fid fid;
    414 	Qid qid;
    415 	Dir *d;
    416 	Req r;
    417 	int off, i, n;
    418 
    419 	// root
    420 	memset(&fid, 0, sizeof fid);
    421 	dostat(0, &fid.qid, nil);
    422 	qid = fid.qid;
    423 
    424 	path0 = path;
    425 	while(path != nil) {
    426 		p = strchr(path, '/');
    427 		if(p != nil)
    428 			*p = '\0';
    429 		elem = path;
    430 		if(strcmp(elem, "") != 0 && strcmp(elem, ".") != 0) {
    431 			err = xwalk1(&fid, elem, &qid);
    432 			if(err != nil) {
    433 				fprint(2, "%s: %s\n", path0, err);
    434 				exits(err);
    435 			}
    436 		}
    437 		if(p)
    438 			*p++ = '/';
    439 		path = p;
    440 	}
    441 
    442 	memset(&r, 0, sizeof r);
    443 	xsrv.fake = 1;
    444 
    445 	// read and display
    446 	off = 0;
    447 	for(;;) {
    448 		r.srv = &xsrv;
    449 		r.fid = &fid;
    450 		r.ifcall.type = Tread;
    451 		r.ifcall.count = sizeof buf;
    452 		r.ifcall.offset = off;
    453 		r.ofcall.data = (char*)buf;
    454 		r.ofcall.count = 0;
    455 		xread(&r);
    456 		if(r.ofcall.type != Rread) {
    457 			fprint(2, "reading %s: %s\n", path0, r.ofcall.ename);
    458 			exits(r.ofcall.ename);
    459 		}
    460 		n = r.ofcall.count;
    461 		if(n == 0)
    462 			break;
    463 		if(off == 0 && pflag > 1) {
    464 			print("\001");
    465 		}
    466 		off += n;
    467 		if(qid.type & QTDIR) {
    468 			n = dirpackage(buf, n, &d);
    469 			for(i=0; i<n; i++)
    470 				print("%s%s\n", d[i].name, (d[i].mode&DMDIR) ? "/" : "");
    471 			free(d);
    472 		} else
    473 			write(1, buf, n);
    474 	}
    475 }
    476 
    477 int
    478 fontcmp(const void *va, const void *vb)
    479 {
    480 	XFont *a, *b;
    481 
    482 	a = (XFont*)va;
    483 	b = (XFont*)vb;
    484 	return strcmp(a->name, b->name);
    485 }
    486 
    487 void
    488 main(int argc, char **argv)
    489 {
    490 	char *mtpt, *srvname;
    491 
    492 	mtpt = nil;
    493 	srvname = "font";
    494 
    495 	ARGBEGIN{
    496 	case 'D':
    497 		chatty9p++;
    498 		break;
    499 	case 'F':
    500 		chattyfuse++;
    501 		break;
    502 	case 'm':
    503 		mtpt = EARGF(usage());
    504 		break;
    505 	case 's':
    506 		srvname = EARGF(usage());
    507 		break;
    508 	case 'p':
    509 		pflag++;
    510 		break;
    511 	default:
    512 		usage();
    513 	}ARGEND
    514 
    515 	xsrv.attach = xattach;
    516 	xsrv.open = xopen;
    517 	xsrv.read = xread;
    518 	xsrv.stat = xstat;
    519 	xsrv.walk1 = xwalk1;
    520 	xsrv.destroyfid = xdestroyfid;
    521 
    522 	fmtinstall('R', Rfmt);
    523 	fmtinstall('P', Pfmt);
    524 	memimageinit();
    525 	loadfonts();
    526 	qsort(xfont, nxfont, sizeof xfont[0], fontcmp);
    527 
    528 	if(pflag) {
    529 		if(argc != 1 || chatty9p || chattyfuse)
    530 			usage();
    531 		dump(argv[0]);
    532 		exits(0);
    533 	}
    534 
    535 	if(pflag || argc != 0)
    536 		usage();
    537 
    538 	/*
    539 	 * Check twice -- if there is an exited instance
    540 	 * mounted there, the first access will fail but unmount it.
    541 	 */
    542 	if(mtpt && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0)
    543 		sysfatal("mountpoint %s does not exist", mtpt);
    544 
    545 	xsrv.foreground = 1;
    546 	threadpostmountsrv(&xsrv, srvname, mtpt, 0);
    547 }
    548 
    549 /*
    550 	/sys/src/libc/9sys/dirread.c
    551 */
    552 static
    553 long
    554 dirpackage(uchar *buf, long ts, Dir **d)
    555 {
    556 	char *s;
    557 	long ss, i, n, nn, m;
    558 
    559 	*d = nil;
    560 	if(ts <= 0)
    561 		return 0;
    562 
    563 	/*
    564 	 * first find number of all stats, check they look like stats, & size all associated strings
    565 	 */
    566 	ss = 0;
    567 	n = 0;
    568 	for(i = 0; i < ts; i += m){
    569 		m = BIT16SZ + GBIT16(&buf[i]);
    570 		if(statcheck(&buf[i], m) < 0)
    571 			break;
    572 		ss += m;
    573 		n++;
    574 	}
    575 
    576 	if(i != ts)
    577 		return -1;
    578 
    579 	*d = malloc(n * sizeof(Dir) + ss);
    580 	if(*d == nil)
    581 		return -1;
    582 
    583 	/*
    584 	 * then convert all buffers
    585 	 */
    586 	s = (char*)*d + n * sizeof(Dir);
    587 	nn = 0;
    588 	for(i = 0; i < ts; i += m){
    589 		m = BIT16SZ + GBIT16((uchar*)&buf[i]);
    590 		if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
    591 			free(*d);
    592 			*d = nil;
    593 			return -1;
    594 		}
    595 		nn++;
    596 		s += m;
    597 	}
    598 
    599 	return nn;
    600 }