Plan 9 from Bell Labs’s /usr/web/sources/contrib/yk/root/sys/src/cmd/fontsrv/fontsrv.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <thread.h>
#include <fcall.h>
#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; i<nxfont; i++){
			if(strcmp(xfont[i].name, name) == 0){
				q.path = QID(Qfontdir, i, 0, 0, 0);
				q.type = QTDIR;
				break;
			}
		}
		if(i == nxfont)
			return Enotfound;
		break;
	case Qfontdir:
		if(strcmp(name, "..") == 0){
			q.path = Qtopdir;
			q.type = QTDIR;
			break;
		}
		sz = strtol(name, &p, 10);
		if(sz == 0)
			return Enotfound;
		k1 = 1;
		if(*p == 'a'){
			k1 = 0;
			p++;
		}
		if(*p != 0)
			return Enotfound;
		q.path = QID(Qsizedir, FONT(f->qid), 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+5 || 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; j<nelem(font->page); 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, 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;
	}
	xfscale(font, SIZE(f->qid));

	fmtstrinit(&fmt);
	fmtprint(&fmt, "%11d %11d\n", font->height, font->ascent);
	for(i=0; i<nelem(font->page); 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;
	Fid* f;
	char *data, *err, cbuf[12];
	Memsubfont *sf;
	Memimage *m;
	Xfont *xf;

	f = r->fid;
	xf = &xfont[FONT(f->qid)];
	if((err = xfload(xf)) != nil){
		respond(r, err);
		return;
	}
	if(f->aux == nil) {
		i = PAGE(f->qid);
		xfscale(xf, SIZE(f->qid));
		f->aux = xfsubfont(xf, nil, i*PageSize, PageSize, 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);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.