tmerge - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 9b4a2324d39a8c952c8184249d2b06b9349205a2
 (DIR) parent 4a18fa68b01bf8121a8660d3f5214e5927763251
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Wed,  8 Jul 2009 21:43:14 -0700
       
       merge
       
       Diffstat:
         M include/9p.h                        |       1 +
         M man/man1/9term.1                    |       2 +-
         A man/man4/fontsrv.4                  |     126 +++++++++++++++++++++++++++++++
         A src/cmd/fontsrv/a.h                 |      23 +++++++++++++++++++++++
         A src/cmd/fontsrv/main.c              |     594 +++++++++++++++++++++++++++++++
         A src/cmd/fontsrv/mkfile              |      14 ++++++++++++++
         A src/cmd/fontsrv/nowsys.c            |      21 +++++++++++++++++++++
         A src/cmd/fontsrv/osx.c               |     292 +++++++++++++++++++++++++++++++
         A src/cmd/fontsrv/x11.c               |       2 ++
         M src/lib9p/srv.c                     |       3 +++
         M src/libdraw/getsubfont.c            |       6 +++++-
         M src/libdraw/openfont.c              |      61 +++++++++++++++++++++++++++++--
         M src/libdraw/subfontname.c           |       2 +-
       
       13 files changed, 1140 insertions(+), 7 deletions(-)
       ---
 (DIR) diff --git a/include/9p.h b/include/9p.h
       t@@ -206,6 +206,7 @@ struct Srv {
                int                leavefdsopen;        /* magic for acme win */
                int                dotu;
                int                foreground;        /* run in foreground */
       +        int                fake;
        
        /* below is implementation-specific; don't use */
                Fidpool*        fpool;
 (DIR) diff --git a/man/man1/9term.1 b/man/man1/9term.1
       t@@ -158,7 +158,7 @@ for the preceding string (see
        .PP
        Text may be moved vertically within the window.
        A scroll bar on the left of the window shows in its clear portion what fragment of the
       -total output text is visible on the screen, and in its gray part what
       +total output text is visible on the screen, and in its grey part what
        is above or below view;
        it measures characters, not lines.
        Mousing inside the scroll bar moves text:
 (DIR) diff --git a/man/man4/fontsrv.4 b/man/man4/fontsrv.4
       t@@ -0,0 +1,126 @@
       +.TH FONTSRV 4
       +.SH NAME
       +fontsrv \- file system access to host fonts
       +.SH SYNOPSIS
       +.B fontsrv
       +[
       +.B -m
       +.I mtpt
       +]
       +.PP
       +.B fontsrv
       +.B -p
       +.I path
       +.SH DESCRIPTION
       +.I Fontsrv
       +presents the host window system's fonts
       +in the standard Plan 9 format
       +(see
       +.IR font (7)).
       +It serves a virtual directory tree mounted at
       +.I mtpt
       +(if the
       +.B -m
       +option is given)
       +and posted at
       +.I srvname 
       +(default
       +.IR font ).
       +.PP
       +The 
       +.B -p
       +option changes 
       +.I fontsrv 's
       +behavior: rather than serve a file system,
       +.I fontsrv
       +prints to standard output the contents of the named 
       +.IR path .
       +If
       +.I path
       +names a directory in the served file system,
       +.I fontsrv
       +lists the directory's contents.
       +.PP
       +The fonts are arranged in a two-level tree.
       +The root contains directories named for each system font.
       +Each font directory contains subdirectories named for
       +a point size and whether the subfonts are anti-aliased:
       +.B 10
       +(bitmap)
       +.BR 10a
       +(anti-aliased greyscale)
       +.BR 12 ,
       +.BR 12a ,
       +and so on.
       +The font directory will synthesize additional sizes on
       +demand: looking up
       +.B 19a
       +will synthesize the 19-point anti-aliased size
       +if possible.
       +Each size directory contains a
       +.B font
       +file and subfont files
       +named
       +.BR x0000.bit ,
       +.BR x0100.bit ,
       +and so on
       +representing 256-character Unicode ranges.
       +.PP
       +.I Openfont
       +(see
       +.IR graphics (3))
       +recognizes font paths beginning with 
       +.B /mnt/font
       +and implements them by invoking
       +.IR fontsrv ;
       +it need not be running already.
       +.SH EXAMPLES
       +List the fonts on the system:
       +.IP
       +.EX
       +% fontsrv &
       +% 9p ls font
       +.EE
       +.LP
       +or:
       +.IP
       +.EX
       +% fontsrv -p .
       +.EE
       +.LP
       +Run 
       +.IR acme (1)
       +using the operating system's Monaco as the fixed-width font:
       +.IP
       +.EX
       +% acme -F /mnt/font/Monaco/13a/font
       +.EE
       +.LP
       +Run
       +.IR sam (1)
       +using the same font:
       +.IP
       +.EX
       +font=/mnt/font/Monaco/13a/font sam
       +.EE
       +.SH SOURCE
       +.B \*9/src/cmd/fontsrv
       +.SH SEE ALSO
       +.IR font (7)
       +.SH BUGS
       +.PP
       +Due to OS X restrictions,
       +.I fontsrv
       +does not fork itself into the background
       +when serving a user-level file system.
       +.PP
       +.I Fontsrv
       +has no support for X11 fonts;
       +on X11 systems, it will serve an empty top-level directory.
       +.PP
       +On OS X, the anti-aliased bitmaps are not perfect.
       +For example, the lower case r in the subfont
       +.B Times-Roman/14a/x0000.bit
       +appears truncated on the right and
       +too light overall.
       +
 (DIR) diff --git a/src/cmd/fontsrv/a.h b/src/cmd/fontsrv/a.h
       t@@ -0,0 +1,23 @@
       +typedef struct XFont XFont;
       +XFont *xfont;
       +int nxfont;
       +
       +struct XFont
       +{
       +        char *name;
       +        int loaded;
       +        uchar range[256];        // range[i] == whether to have subfont i<<8 to (i+1)<<8.
       +        int nrange;
       +        int unit;
       +        double height;
       +        double originy;
       +};
       +
       +void        loadfonts(void);
       +void        load(XFont*);
       +Memsubfont*        mksubfont(char*, int, int, int, int);
       +
       +extern XFont *xfont;
       +extern int nxfont;
       +void *emalloc9p(ulong);
       +extern Memsubfont *defont;
 (DIR) diff --git a/src/cmd/fontsrv/main.c b/src/cmd/fontsrv/main.c
       t@@ -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;
       +}
       +
 (DIR) diff --git a/src/cmd/fontsrv/mkfile b/src/cmd/fontsrv/mkfile
       t@@ -0,0 +1,14 @@
       +<|sh ../devdraw/mkwsysrules.sh
       +<$PLAN9/src/mkhdr
       +
       +TARG=fontsrv
       +
       +HFILES=a.h
       +
       +OFILES=\
       +        main.$O\
       +        $WSYSTYPE.$O\
       +
       +<$PLAN9/src/mkone
       +
       +
 (DIR) diff --git a/src/cmd/fontsrv/nowsys.c b/src/cmd/fontsrv/nowsys.c
       t@@ -0,0 +1,21 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <draw.h>
       +#include <memdraw.h>
       +#include "a.h"
       +
       +void
       +loadfonts(void)
       +{
       +}
       +
       +void
       +load(XFont *f)
       +{
       +}
       +
       +Memsubfont*
       +mksubfont(char *name, int lo, int hi, int size, int antialias)
       +{
       +        return nil;
       +}
 (DIR) diff --git a/src/cmd/fontsrv/osx.c b/src/cmd/fontsrv/osx.c
       t@@ -0,0 +1,292 @@
       +#include <u.h>
       +
       +#define Point OSXPoint
       +#define Rect OSXRect
       +#define Cursor OSXCursor
       +#include <Carbon/Carbon.h>
       +#undef Rect
       +#undef Point
       +#undef Cursor
       +#undef offsetof
       +#undef nil
       +
       +#include <libc.h>
       +#include <draw.h>
       +#include <memdraw.h>
       +#include "a.h"
       +
       +
       +extern void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], const CGGlyph[], size_t);
       +
       +char*
       +mac2c(CFStringRef s)
       +{
       +        char *p;
       +        int n;
       +
       +        n = CFStringGetLength(s)*8;        
       +        p = malloc(n);
       +        CFStringGetCString(s, p, n, kCFStringEncodingUTF8);
       +        return p;
       +}
       +
       +CFStringRef
       +c2mac(char *p)
       +{
       +        return CFStringCreateWithBytes(nil, (uchar*)p, strlen(p), kCFStringEncodingUTF8, false);
       +}
       +
       +Rectangle
       +mac2r(CGRect r, int size, int unit)
       +{
       +        Rectangle rr;
       +
       +        rr.min.x = r.origin.x*size/unit;
       +        rr.min.y = r.origin.y*size/unit;
       +        rr.max.x = (r.origin.x+r.size.width)*size/unit + 0.99999999;
       +        rr.max.y = (r.origin.x+r.size.width)*size/unit + 0.99999999;
       +        return rr;
       +}
       +
       +void
       +loadfonts(void)
       +{
       +        int i, n;
       +        CTFontCollectionRef allc;
       +        CFArrayRef array;
       +        CFStringRef s;
       +        CTFontDescriptorRef f;
       +
       +        allc = CTFontCollectionCreateFromAvailableFonts(0);
       +        array = CTFontCollectionCreateMatchingFontDescriptors(allc);
       +        n = CFArrayGetCount(array);
       +        xfont = emalloc9p(n*sizeof xfont[0]);
       +        for(i=0; i<n; i++) {
       +                f = (void*)CFArrayGetValueAtIndex(array, i);
       +                if(f == nil)
       +                        continue;
       +                s = CTFontDescriptorCopyAttribute(f, kCTFontNameAttribute);
       +                xfont[nxfont].name = mac2c(s);                
       +                CFRelease(s);
       +                nxfont++;
       +        }
       +}
       +
       +CGRect
       +subfontbbox(CGFontRef font, int lo, int hi)
       +{
       +        int i, first;
       +        CGRect bbox;
       +
       +        bbox.origin.x = 0;
       +        bbox.origin.y = 0;
       +        bbox.size.height = 0;
       +        bbox.size.width = 0;
       +
       +        first = 1;
       +        for(i=lo; i<=hi; i++) {
       +                UniChar u;
       +                CGGlyph g;
       +                CGRect r;
       +
       +                u = i;
       +                CGFontGetGlyphsForUnichars(font, &u, &g, 1);
       +                if(g == 0 || !CGFontGetGlyphBBoxes(font, &g, 1, &r))
       +                        continue;
       +
       +                r.size.width += r.origin.x;
       +                r.size.height += r.origin.y;
       +                if(first) {
       +                        bbox = r;
       +                        first = 0;
       +                        continue;
       +                }
       +                if(bbox.origin.x > r.origin.x)
       +                        bbox.origin.x = r.origin.x;        
       +                if(bbox.origin.y > r.origin.y)
       +                        bbox.origin.y = r.origin.y;        
       +                if(bbox.size.width < r.size.width)
       +                        bbox.size.width = r.size.width;
       +                if(bbox.size.height < r.size.height)
       +                        bbox.size.height = r.size.height;
       +        }
       +        
       +        bbox.size.width -= bbox.origin.x;
       +        bbox.size.height -= bbox.origin.y;
       +        return bbox;
       +}
       +
       +void
       +load(XFont *f)
       +{
       +        int i, j;
       +        CGFontRef font;
       +        CFStringRef s;
       +        UniChar u[256];
       +        CGGlyph g[256];
       +        CGRect bbox;
       +
       +        if(f->loaded)
       +                return;
       +        f->loaded = 1;
       +        s = c2mac(f->name);
       +        font = CGFontCreateWithFontName(s);
       +        CFRelease(s);
       +        if(font == nil)
       +                return;
       +        
       +        // assume bbox gives latin1 is height/ascent for all
       +        bbox = subfontbbox(font, 0x00, 0xff);
       +        f->unit = CGFontGetUnitsPerEm(font);
       +        f->height = bbox.size.height;
       +        f->originy = bbox.origin.y;
       +
       +        // figure out where the letters are
       +        for(i=0; i<0xffff; i+=0x100) {
       +                for(j=0; j<0x100; j++) {
       +                        u[j] = i+j;
       +                        g[j] = 0;
       +                }
       +                CGFontGetGlyphsForUnichars(font, u, g, 256);
       +                for(j=0; j<0x100; j++) {
       +                        if(g[j] != 0) {
       +                                f->range[i>>8] = 1;
       +                                f->nrange++;
       +                                break;
       +                        }
       +                }
       +        }
       +        CFRelease(font);
       +}
       +
       +Memsubfont*
       +mksubfont(char *name, int lo, int hi, int size, int antialias)
       +{
       +        CFStringRef s;
       +        CGColorSpaceRef color;
       +        CGContextRef ctxt;
       +        CGFontRef font;
       +        CGRect bbox;
       +        Memimage *m, *mc, *m1;
       +        int x, y, y0;
       +        int i, unit;
       +        Fontchar *fc, *fc0;
       +        Memsubfont *sf;
       +
       +        s = c2mac(name);
       +        font = CGFontCreateWithFontName(s);
       +        CFRelease(s);
       +        if(font == nil)
       +                return nil;
       +        bbox = subfontbbox(font, lo, hi);
       +        unit = CGFontGetUnitsPerEm(font);
       +        x = (int)(bbox.size.width * size / unit + 0.99999999);
       +        y = bbox.size.height * size/unit + 0.99999999;
       +        y0 = (int)(-bbox.origin.y * size/unit + 0.99999999);
       +        m = allocmemimage(Rect(0, 0, x*(hi+1-lo), y), GREY8);
       +        if(m == nil)
       +                return nil;
       +        mc = allocmemimage(Rect(0, 0, x, y), GREY8);
       +        if(mc == nil)
       +                return nil;
       +        memfillcolor(m, DBlack);
       +        memfillcolor(mc, DBlack);
       +        fc = malloc((hi+2 - lo) * sizeof fc[0]);
       +        sf = malloc(sizeof *sf);
       +        if(fc == nil || sf == nil) {
       +                freememimage(m);
       +                freememimage(mc);
       +                free(fc);
       +                free(sf);
       +                return nil;
       +        }
       +        fc0 = fc;
       +
       +        color = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
       +        ctxt = CGBitmapContextCreate(byteaddr(mc, mc->r.min), Dx(mc->r), Dy(mc->r), 8,
       +                mc->width*sizeof(u32int), color, kCGImageAlphaNone);
       +        CGColorSpaceRelease(color);
       +        if(ctxt == nil) {
       +                freememimage(m);
       +                freememimage(mc);
       +                free(fc);
       +                free(sf);
       +                return nil;
       +        }
       +
       +        CGContextSetFont(ctxt, font);
       +        CGContextSetFontSize(ctxt, size);
       +        CGContextSetAllowsAntialiasing(ctxt, antialias);
       +        CGContextSetRGBFillColor(ctxt, 1, 1, 1, 1);
       +        CGContextSetTextPosition(ctxt, 0, 0);        // XXX
       +
       +        x = 0;
       +        for(i=lo; i<=hi; i++, fc++) {
       +                UniChar u[2];
       +                CGGlyph g[2];
       +                CGRect r[2];
       +                CGPoint p1;
       +                int n;
       +
       +                fc->x = x;
       +                fc->top = 0;
       +                fc->bottom = Dy(m->r);
       +
       +                n = 0;
       +                u[n++] = i;
       +                if(0)        // debugging
       +                        u[n++] = '|';
       +                g[0] = 0;
       +                CGFontGetGlyphsForUnichars(font, u, g, n);
       +                if(g[0] == 0 || !CGFontGetGlyphBBoxes(font, g, n, r)) {
       +                None:
       +                        fc->width = 0;
       +                        if(i == 0) {
       +                                Point p;
       +                                Fontchar *i;
       +                                p = Pt(x, y0);
       +                                // memimagestring(m, p, memwhite, ZP, defont, peterface);
       +                                i = defont->info + 0;
       +                                memdraw(m, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom),
       +                                        memwhite, ZP, defont->bits, Pt(i->x, i->top), S);
       +                                p.x += i->width;
       +                                fc->left = i->left;
       +                                fc->width = i->width;
       +                                x = p.x;
       +                        }        
       +                        continue;
       +                }
       +                memfillcolor(mc, DBlack);
       +                CGContextSetTextPosition(ctxt, 0, y0);
       +                CGContextShowGlyphs(ctxt, g, n);
       +                p1 = CGContextGetTextPosition(ctxt);
       +                if(p1.x <= 0)
       +                        goto None;
       +                memimagedraw(m, Rect(x, 0, x + p1.x, y), mc, ZP, memopaque, ZP, S);
       +                fc->width = p1.x;
       +                fc->left = 0;
       +                x += p1.x;
       +        }
       +        fc->x = x;
       +
       +        // round up to 32-bit boundary
       +        // so that in-memory data is same
       +        // layout as in-file data.
       +        if(antialias)
       +                x += -x & 3;
       +        else
       +                x += -x & 31;
       +        m1 = allocmemimage(Rect(0, 0, x, y), antialias ? GREY8 : GREY1);
       +        memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
       +        freememimage(m);
       +
       +        sf->name = nil;
       +        sf->n = hi+1 - lo;
       +        sf->height = Dy(m1->r);
       +        sf->ascent = Dy(m1->r) - y0;
       +        sf->info = fc0;
       +        sf->bits = m1;
       +        
       +        return sf;
       +}
       +
 (DIR) diff --git a/src/cmd/fontsrv/x11.c b/src/cmd/fontsrv/x11.c
       t@@ -0,0 +1,2 @@
       +/* maybe someday */
       +#include "nowsys.c"
 (DIR) diff --git a/src/lib9p/srv.c b/src/lib9p/srv.c
       t@@ -794,6 +794,9 @@ respond(Req *r, char *error)
                if(r->error)
                        setfcallerror(&r->ofcall, r->error);
        
       +        if(srv->fake)
       +                return;
       +
        if(chatty9p)
                fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);
        
 (DIR) diff --git a/src/libdraw/getsubfont.c b/src/libdraw/getsubfont.c
       t@@ -6,6 +6,8 @@
         * Default version: treat as file name
         */
        
       +int _fontpipe(char*);
       +
        Subfont*
        _getsubfont(Display *d, char *name)
        {
       t@@ -13,7 +15,9 @@ _getsubfont(Display *d, char *name)
                Subfont *f;
        
                fd = open(name, OREAD);
       -                
       +        if(fd < 0 && strncmp(name, "/mnt/font/", 10) == 0)
       +                fd = _fontpipe(name+10);
       +
                if(fd < 0){
                        fprint(2, "getsubfont: can't open %s: %r\n", name);
                        return 0;
 (DIR) diff --git a/src/libdraw/openfont.c b/src/libdraw/openfont.c
       t@@ -3,6 +3,7 @@
        #include <draw.h>
        
        extern vlong _drawflength(int);
       +int _fontpipe(char*);
        
        Font*
        openfont(Display *d, char *name)
       t@@ -27,26 +28,78 @@ openfont(Display *d, char *name)
                        }
                        name = nambuf;
                }
       +        if(fd >= 0)
       +                n = _drawflength(fd);
       +        if(fd < 0 && strncmp(name, "/mnt/font/", 10) == 0) {
       +                fd = _fontpipe(name+10);
       +                n = 8192;
       +        }
                if(fd < 0)
                        return 0;
        
       -        n = _drawflength(fd);
                buf = malloc(n+1);
                if(buf == 0){
                        close(fd);
                        free(nambuf);
                        return 0;
                }
       -        buf[n] = 0;
       -        i = read(fd, buf, n);
       +        i = readn(fd, buf, n);
                close(fd);
       -        if(i != n){
       +        if(i <= 0){
                        free(buf);
                        free(nambuf);
                        return 0;
                }
       +        buf[i] = 0;
                fnt = buildfont(d, buf, name);
                free(buf);
                free(nambuf);
                return fnt;
        }
       +
       +int
       +_fontpipe(char *name)
       +{
       +        int p[2];
       +        char c;
       +        char buf[1024], *argv[10];
       +        int nbuf, pid;
       +        
       +        if(pipe(p) < 0)
       +                return -1;
       +        pid = rfork(RFNOWAIT|RFFDG|RFPROC);
       +        if(pid < 0) {
       +                close(p[0]);
       +                close(p[1]);
       +                return -1;
       +        }
       +        if(pid == 0) {
       +                close(p[0]);
       +                dup(p[1], 1);
       +                dup(p[1], 2);
       +                if(p[1] > 2)
       +                        close(p[1]);
       +                argv[0] = "fontsrv";
       +                argv[1] = "-pp";
       +                argv[2] = name;
       +                argv[3] = nil;
       +                execvp("fontsrv", argv);
       +                print("exec fontsrv: %r\n");
       +                _exit(0);
       +        }
       +        close(p[1]);
       +        
       +        // success marked with leading \001.
       +        // otherwise an error happened.
       +        for(nbuf=0; nbuf<sizeof buf-1; nbuf++) {
       +                if(read(p[0], &c, 1) < 1 || c == '\n') {
       +                        buf[nbuf] = '\0';
       +                        werrstr(buf);
       +                        close(p[0]);
       +                        return -1;
       +                }
       +                if(c == '\001')
       +                        break;
       +        }
       +        return p[0];
       +}
 (DIR) diff --git a/src/libdraw/subfontname.c b/src/libdraw/subfontname.c
       t@@ -43,7 +43,7 @@ subfontname(char *cfname, char *fname, int maxdepth)
                }
        
                /* try default */
       -        if(access(t, AREAD) == 0)
       +        if(strncmp(t, "/mnt/font/", 10) == 0 || access(t, AREAD) == 0)
                        return t;
        
                return nil;