merge
This commit is contained in:
commit
9b4a2324d3
13 changed files with 1140 additions and 7 deletions
594
src/cmd/fontsrv/main.c
Normal file
594
src/cmd/fontsrv/main.c
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <thread.h>
|
||||
#include <fcall.h>
|
||||
#include <9p.h>
|
||||
/*
|
||||
* we included thread.h in order to include 9p.h,
|
||||
* but we don't use threads, so exits is ok.
|
||||
*/
|
||||
#undef exits
|
||||
|
||||
#include "a.h"
|
||||
|
||||
Memsubfont *defont;
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: fontsrv [-m mtpt]\n");
|
||||
fprint(2, "or fontsrv -p path\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
Qroot = 0,
|
||||
Qfontdir,
|
||||
Qsizedir,
|
||||
Qfontfile,
|
||||
Qsubfontfile,
|
||||
};
|
||||
|
||||
#define QTYPE(p) ((p) & 0xF)
|
||||
#define QFONT(p) (((p) >> 4) & 0xFFFF)
|
||||
#define QSIZE(p) (((p) >> 20) & 0xFF)
|
||||
#define QANTIALIAS(p) (((p) >> 28) & 0x1)
|
||||
#define QRANGE(p) (((p) >> 29) & 0xFF)
|
||||
static int sizes[] = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 24, 28 };
|
||||
|
||||
static vlong
|
||||
qpath(int type, int font, int size, int antialias, int range)
|
||||
{
|
||||
return type | (font << 4) | (size << 20) | (antialias << 28) | ((vlong)range << 29);
|
||||
}
|
||||
|
||||
static void
|
||||
dostat(vlong path, Qid *qid, Dir *dir)
|
||||
{
|
||||
char *name;
|
||||
Qid q;
|
||||
ulong mode;
|
||||
vlong length;
|
||||
XFont *f;
|
||||
char buf[100];
|
||||
|
||||
q.type = 0;
|
||||
q.vers = 0;
|
||||
q.path = path;
|
||||
mode = 0444;
|
||||
length = 0;
|
||||
name = "???";
|
||||
|
||||
switch(QTYPE(path)) {
|
||||
default:
|
||||
sysfatal("dostat %#llux", path);
|
||||
|
||||
case Qroot:
|
||||
q.type = QTDIR;
|
||||
name = "/";
|
||||
break;
|
||||
|
||||
case Qfontdir:
|
||||
q.type = QTDIR;
|
||||
f = &xfont[QFONT(path)];
|
||||
name = f->name;
|
||||
break;
|
||||
|
||||
case Qsizedir:
|
||||
q.type = QTDIR;
|
||||
snprint(buf, sizeof buf, "%lld%s", QSIZE(path), QANTIALIAS(path) ? "a" : "");
|
||||
name = buf;
|
||||
break;
|
||||
|
||||
case Qfontfile:
|
||||
f = &xfont[QFONT(path)];
|
||||
load(f);
|
||||
length = 11+1+11+1+f->nrange*(6+1+6+1+9+1);
|
||||
name = "font";
|
||||
break;
|
||||
|
||||
case Qsubfontfile:
|
||||
snprint(buf, sizeof buf, "x%02llx00.bit", QRANGE(path));
|
||||
name = buf;
|
||||
break;
|
||||
}
|
||||
|
||||
if(qid)
|
||||
*qid = q;
|
||||
if(dir) {
|
||||
memset(dir, 0, sizeof *dir);
|
||||
dir->name = estrdup9p(name);
|
||||
dir->muid = estrdup9p("");
|
||||
dir->uid = estrdup9p("font");
|
||||
dir->gid = estrdup9p("font");
|
||||
dir->qid = q;
|
||||
if(q.type == QTDIR)
|
||||
mode |= DMDIR | 0111;
|
||||
dir->mode = mode;
|
||||
dir->length = length;
|
||||
}
|
||||
}
|
||||
|
||||
static char*
|
||||
xwalk1(Fid *fid, char *name, Qid *qid)
|
||||
{
|
||||
int i, dotdot;
|
||||
vlong path;
|
||||
char *p;
|
||||
int a, n;
|
||||
XFont *f;
|
||||
|
||||
path = fid->qid.path;
|
||||
dotdot = strcmp(name, "..") == 0;
|
||||
switch(QTYPE(path)) {
|
||||
default:
|
||||
NotFound:
|
||||
return "file not found";
|
||||
|
||||
case Qroot:
|
||||
if(dotdot)
|
||||
break;
|
||||
for(i=0; i<nxfont; i++) {
|
||||
if(strcmp(xfont[i].name, name) == 0) {
|
||||
path = qpath(Qfontdir, i, 0, 0, 0);
|
||||
goto Found;
|
||||
}
|
||||
}
|
||||
goto NotFound;
|
||||
|
||||
case Qfontdir:
|
||||
if(dotdot) {
|
||||
path = Qroot;
|
||||
break;
|
||||
}
|
||||
n = strtol(name, &p, 10);
|
||||
if(n == 0)
|
||||
goto NotFound;
|
||||
a = 0;
|
||||
if(*p == 'a') {
|
||||
a = 1;
|
||||
p++;
|
||||
}
|
||||
if(*p != 0)
|
||||
goto NotFound;
|
||||
path += Qsizedir - Qfontdir + qpath(0, 0, n, a, 0);
|
||||
break;
|
||||
|
||||
case Qsizedir:
|
||||
if(dotdot) {
|
||||
path = qpath(Qfontdir, QFONT(path), 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
if(strcmp(name, "font") == 0) {
|
||||
path += Qfontfile - Qsizedir;
|
||||
break;
|
||||
}
|
||||
f = &xfont[QFONT(path)];
|
||||
load(f);
|
||||
p = name;
|
||||
if(*p != 'x')
|
||||
goto NotFound;
|
||||
p++;
|
||||
n = strtoul(p, &p, 16);
|
||||
if(p != name+5 || (n&0xFF) != 0 || strcmp(p, ".bit") != 0 || !f->range[(n>>8) & 0xFF])
|
||||
goto NotFound;
|
||||
path += Qsubfontfile - Qsizedir + qpath(0, 0, 0, 0, (n>>8) & 0xFF);
|
||||
break;
|
||||
}
|
||||
Found:
|
||||
dostat(path, qid, nil);
|
||||
fid->qid = *qid;
|
||||
return nil;
|
||||
}
|
||||
|
||||
static int
|
||||
rootgen(int i, Dir *d, void *v)
|
||||
{
|
||||
if(i >= nxfont)
|
||||
return -1;
|
||||
dostat(qpath(Qfontdir, i, 0, 0, 0), nil, d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fontgen(int i, Dir *d, void *v)
|
||||
{
|
||||
vlong path;
|
||||
Fid *f;
|
||||
|
||||
f = v;
|
||||
path = f->qid.path;
|
||||
if(i >= 2*nelem(sizes))
|
||||
return -1;
|
||||
dostat(qpath(Qsizedir, QFONT(path), sizes[i/2], i&1, 0), nil, d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sizegen(int i, Dir *d, void *v)
|
||||
{
|
||||
vlong path;
|
||||
Fid *fid;
|
||||
XFont *f;
|
||||
int j;
|
||||
|
||||
fid = v;
|
||||
path = fid->qid.path;
|
||||
if(i == 0) {
|
||||
path += Qfontfile - Qsizedir;
|
||||
goto Done;
|
||||
}
|
||||
i--;
|
||||
f = &xfont[QFONT(path)];
|
||||
load(f);
|
||||
for(j=0; j<nelem(f->range); j++) {
|
||||
if(f->range[j] == 0)
|
||||
continue;
|
||||
if(i == 0) {
|
||||
path += Qsubfontfile - Qsizedir;
|
||||
path += qpath(0, 0, 0, 0, j);
|
||||
goto Done;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
return -1;
|
||||
|
||||
Done:
|
||||
dostat(path, nil, d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xattach(Req *r)
|
||||
{
|
||||
dostat(0, &r->ofcall.qid, nil);
|
||||
r->fid->qid = r->ofcall.qid;
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
xopen(Req *r)
|
||||
{
|
||||
if(r->ifcall.mode != OREAD) {
|
||||
respond(r, "permission denied");
|
||||
return;
|
||||
}
|
||||
r->ofcall.qid = r->fid->qid;
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
void
|
||||
responderrstr(Req *r)
|
||||
{
|
||||
char err[ERRMAX];
|
||||
|
||||
rerrstr(err, sizeof err);
|
||||
respond(r, err);
|
||||
}
|
||||
|
||||
static void
|
||||
xread(Req *r)
|
||||
{
|
||||
int i, size, height, ascent;
|
||||
vlong path;
|
||||
Fmt fmt;
|
||||
XFont *f;
|
||||
char *data;
|
||||
Memsubfont *sf;
|
||||
Memimage *m;
|
||||
|
||||
path = r->fid->qid.path;
|
||||
switch(QTYPE(path)) {
|
||||
case Qroot:
|
||||
dirread9p(r, rootgen, nil);
|
||||
break;
|
||||
case Qfontdir:
|
||||
dirread9p(r, fontgen, r->fid);
|
||||
break;
|
||||
case Qsizedir:
|
||||
dirread9p(r, sizegen, r->fid);
|
||||
break;
|
||||
case Qfontfile:
|
||||
fmtstrinit(&fmt);
|
||||
f = &xfont[QFONT(path)];
|
||||
load(f);
|
||||
if(f->unit == 0)
|
||||
break;
|
||||
height = f->height * (int)QSIZE(path)/f->unit + 0.99999999;
|
||||
ascent = height - (int)(-f->originy * (int)QSIZE(path)/f->unit + 0.99999999);
|
||||
fmtprint(&fmt, "%11d %11d\n", height, ascent);
|
||||
for(i=0; i<nelem(f->range); i++) {
|
||||
if(f->range[i] == 0)
|
||||
continue;
|
||||
fmtprint(&fmt, "0x%04x 0x%04x x%04x.bit\n", i<<8, (i<<8) + 0xFF, i<<8);
|
||||
}
|
||||
data = fmtstrflush(&fmt);
|
||||
readstr(r, data);
|
||||
free(data);
|
||||
break;
|
||||
case Qsubfontfile:
|
||||
f = &xfont[QFONT(path)];
|
||||
load(f);
|
||||
if(r->fid->aux == nil) {
|
||||
r->fid->aux = mksubfont(f->name, QRANGE(path)<<8, (QRANGE(path)<<8)+0xFF, QSIZE(path), QANTIALIAS(path));
|
||||
if(r->fid->aux == nil) {
|
||||
responderrstr(r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
sf = r->fid->aux;
|
||||
m = sf->bits;
|
||||
if(r->ifcall.offset < 5*12) {
|
||||
char *chan;
|
||||
if(QANTIALIAS(path))
|
||||
chan = "k8";
|
||||
else
|
||||
chan = "k1";
|
||||
data = smprint("%11s %11d %11d %11d %11d ", chan, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y);
|
||||
readstr(r, data);
|
||||
free(data);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
}
|
||||
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));
|
||||
free(data);
|
||||
break;
|
||||
}
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
xdestroyfid(Fid *fid)
|
||||
{
|
||||
Memsubfont *sf;
|
||||
|
||||
sf = fid->aux;
|
||||
if(sf == nil)
|
||||
return;
|
||||
|
||||
freememimage(sf->bits);
|
||||
free(sf->info);
|
||||
free(sf);
|
||||
fid->aux = nil;
|
||||
}
|
||||
|
||||
static void
|
||||
xstat(Req *r)
|
||||
{
|
||||
dostat(r->fid->qid.path, nil, &r->d);
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
Srv xsrv;
|
||||
|
||||
int
|
||||
proccreate(void (*f)(void*), void *a, unsigned i)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
int pflag;
|
||||
|
||||
static long dirpackage(uchar*, long, Dir**);
|
||||
|
||||
void
|
||||
dump(char *path)
|
||||
{
|
||||
char *elem, *p, *path0, *err;
|
||||
uchar buf[4096];
|
||||
Fid fid;
|
||||
Qid qid;
|
||||
Dir *d;
|
||||
Req r;
|
||||
int off, i, n;
|
||||
|
||||
// root
|
||||
memset(&fid, 0, sizeof fid);
|
||||
dostat(0, &fid.qid, nil);
|
||||
qid = fid.qid;
|
||||
|
||||
path0 = path;
|
||||
while(path != nil) {
|
||||
p = strchr(path, '/');
|
||||
if(p != nil)
|
||||
*p = '\0';
|
||||
elem = path;
|
||||
if(strcmp(elem, "") != 0 && strcmp(elem, ".") != 0) {
|
||||
err = xwalk1(&fid, elem, &qid);
|
||||
if(err != nil) {
|
||||
fprint(2, "%s: %s\n", path0, err);
|
||||
exits(err);
|
||||
}
|
||||
}
|
||||
if(p)
|
||||
*p++ = '/';
|
||||
path = p;
|
||||
}
|
||||
|
||||
memset(&r, 0, sizeof r);
|
||||
xsrv.fake = 1;
|
||||
|
||||
// read and display
|
||||
off = 0;
|
||||
for(;;) {
|
||||
r.srv = &xsrv;
|
||||
r.fid = &fid;
|
||||
r.ifcall.type = Tread;
|
||||
r.ifcall.count = sizeof buf;
|
||||
r.ifcall.offset = off;
|
||||
r.ofcall.data = (char*)buf;
|
||||
r.ofcall.count = 0;
|
||||
xread(&r);
|
||||
if(r.ofcall.type != Rread) {
|
||||
fprint(2, "reading %s: %s\n", path0, r.ofcall.ename);
|
||||
exits(r.ofcall.ename);
|
||||
}
|
||||
n = r.ofcall.count;
|
||||
if(n == 0)
|
||||
break;
|
||||
if(off == 0 && pflag > 1) {
|
||||
print("\001");
|
||||
}
|
||||
off += n;
|
||||
if(qid.type & QTDIR) {
|
||||
n = dirpackage(buf, n, &d);
|
||||
for(i=0; i<n; i++)
|
||||
print("%s%s\n", d[i].name, (d[i].mode&DMDIR) ? "/" : "");
|
||||
free(d);
|
||||
} else
|
||||
write(1, buf, n);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
fontcmp(const void *va, const void *vb)
|
||||
{
|
||||
XFont *a, *b;
|
||||
|
||||
a = (XFont*)va;
|
||||
b = (XFont*)vb;
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *mtpt;
|
||||
|
||||
mtpt = unsharp("#9/font/mnt");
|
||||
|
||||
ARGBEGIN{
|
||||
case 'D':
|
||||
chatty9p++;
|
||||
break;
|
||||
case 'F':
|
||||
chattyfuse++;
|
||||
break;
|
||||
case 'm':
|
||||
mtpt = EARGF(usage());
|
||||
break;
|
||||
case 'p':
|
||||
pflag++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
xsrv.attach = xattach;
|
||||
xsrv.open = xopen;
|
||||
xsrv.read = xread;
|
||||
xsrv.stat = xstat;
|
||||
xsrv.walk1 = xwalk1;
|
||||
xsrv.destroyfid = xdestroyfid;
|
||||
|
||||
fmtinstall('R', Rfmt);
|
||||
fmtinstall('P', Pfmt);
|
||||
memimageinit();
|
||||
defont = getmemdefont();
|
||||
loadfonts();
|
||||
qsort(xfont, nxfont, sizeof xfont[0], fontcmp);
|
||||
|
||||
if(pflag) {
|
||||
if(argc != 1 || chatty9p || chattyfuse)
|
||||
usage();
|
||||
dump(argv[0]);
|
||||
exits(0);
|
||||
}
|
||||
|
||||
if(pflag || argc != 0)
|
||||
usage();
|
||||
|
||||
/*
|
||||
* Check twice -- if there is an exited instance
|
||||
* mounted there, the first access will fail but unmount it.
|
||||
*/
|
||||
if(mtpt && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0)
|
||||
sysfatal("mountpoint %s does not exist", mtpt);
|
||||
|
||||
xsrv.foreground = 1;
|
||||
threadpostmountsrv(&xsrv, "font", mtpt, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
/sys/src/libc/9sys/dirread.c
|
||||
*/
|
||||
static
|
||||
long
|
||||
dirpackage(uchar *buf, long ts, Dir **d)
|
||||
{
|
||||
char *s;
|
||||
long ss, i, n, nn, m;
|
||||
|
||||
*d = nil;
|
||||
if(ts <= 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* first find number of all stats, check they look like stats, & size all associated strings
|
||||
*/
|
||||
ss = 0;
|
||||
n = 0;
|
||||
for(i = 0; i < ts; i += m){
|
||||
m = BIT16SZ + GBIT16(&buf[i]);
|
||||
if(statcheck(&buf[i], m) < 0)
|
||||
break;
|
||||
ss += m;
|
||||
n++;
|
||||
}
|
||||
|
||||
if(i != ts)
|
||||
return -1;
|
||||
|
||||
*d = malloc(n * sizeof(Dir) + ss);
|
||||
if(*d == nil)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* then convert all buffers
|
||||
*/
|
||||
s = (char*)*d + n * sizeof(Dir);
|
||||
nn = 0;
|
||||
for(i = 0; i < ts; i += m){
|
||||
m = BIT16SZ + GBIT16((uchar*)&buf[i]);
|
||||
if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
|
||||
free(*d);
|
||||
*d = nil;
|
||||
return -1;
|
||||
}
|
||||
nn++;
|
||||
s += m;
|
||||
}
|
||||
|
||||
return nn;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue