URI:
       tmain.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tmain.c (10429B)
       ---
            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*(6+1+6+1+9+1);
          106                 name = "font";
          107                 break;
          108 
          109         case Qsubfontfile:
          110                 snprint(buf, sizeof buf, "x%04x.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+5 || p > name+5 && 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         Memsubfont *sf;
          291         Memimage *m;
          292 
          293         path = r->fid->qid.path;
          294         switch(QTYPE(path)) {
          295         case Qroot:
          296                 dirread9p(r, rootgen, nil);
          297                 break;
          298         case Qfontdir:
          299                 dirread9p(r, fontgen, r->fid);
          300                 break;
          301         case Qsizedir:
          302                 dirread9p(r, sizegen, r->fid);
          303                 break;
          304         case Qfontfile:
          305                 fmtstrinit(&fmt);
          306                 f = &xfont[QFONT(path)];
          307                 load(f);
          308                 if(f->unit == 0 && f->loadheight == nil) {
          309                         readstr(r, "font missing\n");
          310                         break;
          311                 }
          312                 if(f->fonttext == nil) {
          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                         for(i=0; i<f->nfile; i++)
          323                                 fmtprint(&fmt, "0x%04x 0x%04x x%04x.bit\n", f->file[i]*SubfontSize, ((f->file[i]+1)*SubfontSize) - 1, f->file[i]*SubfontSize);
          324                         f->fonttext = fmtstrflush(&fmt);
          325                         f->nfonttext = strlen(f->fonttext);
          326                 }
          327                 readbuf(r, f->fonttext, f->nfonttext);
          328                 break;
          329         case Qsubfontfile:
          330                 f = &xfont[QFONT(path)];
          331                 load(f);
          332                 if(r->fid->aux == nil) {
          333                         r->fid->aux = mksubfont(f, f->name, QRANGE(path)*SubfontSize, ((QRANGE(path)+1)*SubfontSize)-1, QSIZE(path), QANTIALIAS(path));
          334                         if(r->fid->aux == nil) {
          335                                 responderrstr(r);
          336                                 return;
          337                         }
          338                 }
          339                 sf = r->fid->aux;
          340                 m = sf->bits;
          341                 if(r->ifcall.offset < 5*12) {
          342                         char *chan;
          343                         if(QANTIALIAS(path))
          344                                 chan = "k8";
          345                         else
          346                                 chan = "k1";
          347                         data = smprint("%11s %11d %11d %11d %11d ", chan, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y);
          348                         readstr(r, data);
          349                         free(data);
          350                         break;
          351                 }
          352                 r->ifcall.offset -= 5*12;
          353                 size = bytesperline(m->r, chantodepth(m->chan)) * Dy(m->r);
          354                 if(r->ifcall.offset < size) {
          355                         readbuf(r, byteaddr(m, m->r.min), size);
          356                         break;
          357                 }
          358                 r->ifcall.offset -= size;
          359                 data = emalloc9p(3*12+6*(sf->n+1));
          360                 sprint(data, "%11d %11d %11d ", sf->n, sf->height, sf->ascent);
          361                 packinfo(sf->info, (uchar*)data+3*12, sf->n);
          362                 readbuf(r, data, 3*12+6*(sf->n+1));
          363                 free(data);
          364                 break;
          365         }
          366         respond(r, nil);
          367 }
          368 
          369 static void
          370 xdestroyfid(Fid *fid)
          371 {
          372         Memsubfont *sf;
          373 
          374         sf = fid->aux;
          375         if(sf == nil)
          376                 return;
          377 
          378         freememimage(sf->bits);
          379         free(sf->info);
          380         free(sf);
          381         fid->aux = nil;
          382 }
          383 
          384 static void
          385 xstat(Req *r)
          386 {
          387         dostat(r->fid->qid.path, nil, &r->d);
          388         respond(r, nil);
          389 }
          390 
          391 Srv xsrv;
          392 
          393 int
          394 proccreate(void (*f)(void*), void *a, unsigned i)
          395 {
          396         abort();
          397 }
          398 
          399 int pflag;
          400 
          401 static long dirpackage(uchar*, long, Dir**);
          402 
          403 void
          404 dump(char *path)
          405 {
          406         char *elem, *p, *path0, *err;
          407         uchar buf[4096];
          408         Fid fid;
          409         Qid qid;
          410         Dir *d;
          411         Req r;
          412         int off, i, n;
          413 
          414         // root
          415         memset(&fid, 0, sizeof fid);
          416         dostat(0, &fid.qid, nil);
          417         qid = fid.qid;
          418 
          419         path0 = path;
          420         while(path != nil) {
          421                 p = strchr(path, '/');
          422                 if(p != nil)
          423                         *p = '\0';
          424                 elem = path;
          425                 if(strcmp(elem, "") != 0 && strcmp(elem, ".") != 0) {
          426                         err = xwalk1(&fid, elem, &qid);
          427                         if(err != nil) {
          428                                 fprint(2, "%s: %s\n", path0, err);
          429                                 exits(err);
          430                         }
          431                 }
          432                 if(p)
          433                         *p++ = '/';
          434                 path = p;
          435         }
          436 
          437         memset(&r, 0, sizeof r);
          438         xsrv.fake = 1;
          439 
          440         // read and display
          441         off = 0;
          442         for(;;) {
          443                 r.srv = &xsrv;
          444                 r.fid = &fid;
          445                 r.ifcall.type = Tread;
          446                 r.ifcall.count = sizeof buf;
          447                 r.ifcall.offset = off;
          448                 r.ofcall.data = (char*)buf;
          449                 r.ofcall.count = 0;
          450                 xread(&r);
          451                 if(r.ofcall.type != Rread) {
          452                         fprint(2, "reading %s: %s\n", path0, r.ofcall.ename);
          453                         exits(r.ofcall.ename);
          454                 }
          455                 n = r.ofcall.count;
          456                 if(n == 0)
          457                         break;
          458                 if(off == 0 && pflag > 1) {
          459                         print("\001");
          460                 }
          461                 off += n;
          462                 if(qid.type & QTDIR) {
          463                         n = dirpackage(buf, n, &d);
          464                         for(i=0; i<n; i++)
          465                                 print("%s%s\n", d[i].name, (d[i].mode&DMDIR) ? "/" : "");
          466                         free(d);
          467                 } else
          468                         write(1, buf, n);
          469         }
          470 }
          471 
          472 int
          473 fontcmp(const void *va, const void *vb)
          474 {
          475         XFont *a, *b;
          476 
          477         a = (XFont*)va;
          478         b = (XFont*)vb;
          479         return strcmp(a->name, b->name);
          480 }
          481 
          482 void
          483 main(int argc, char **argv)
          484 {
          485         char *mtpt, *srvname;
          486 
          487         mtpt = nil;
          488         srvname = "font";
          489 
          490         ARGBEGIN{
          491         case 'D':
          492                 chatty9p++;
          493                 break;
          494         case 'F':
          495                 chattyfuse++;
          496                 break;
          497         case 'm':
          498                 mtpt = EARGF(usage());
          499                 break;
          500         case 's':
          501                 srvname = EARGF(usage());
          502                 break;
          503         case 'p':
          504                 pflag++;
          505                 break;
          506         default:
          507                 usage();
          508         }ARGEND
          509 
          510         xsrv.attach = xattach;
          511         xsrv.open = xopen;
          512         xsrv.read = xread;
          513         xsrv.stat = xstat;
          514         xsrv.walk1 = xwalk1;
          515         xsrv.destroyfid = xdestroyfid;
          516 
          517         fmtinstall('R', Rfmt);
          518         fmtinstall('P', Pfmt);
          519         memimageinit();
          520         loadfonts();
          521         qsort(xfont, nxfont, sizeof xfont[0], fontcmp);
          522 
          523         if(pflag) {
          524                 if(argc != 1 || chatty9p || chattyfuse)
          525                         usage();
          526                 dump(argv[0]);
          527                 exits(0);
          528         }
          529 
          530         if(pflag || argc != 0)
          531                 usage();
          532 
          533         /*
          534          * Check twice -- if there is an exited instance
          535          * mounted there, the first access will fail but unmount it.
          536          */
          537         if(mtpt && access(mtpt, AEXIST) < 0 && access(mtpt, AEXIST) < 0)
          538                 sysfatal("mountpoint %s does not exist", mtpt);
          539 
          540         xsrv.foreground = 1;
          541         threadpostmountsrv(&xsrv, srvname, mtpt, 0);
          542 }
          543 
          544 /*
          545         /sys/src/libc/9sys/dirread.c
          546 */
          547 static
          548 long
          549 dirpackage(uchar *buf, long ts, Dir **d)
          550 {
          551         char *s;
          552         long ss, i, n, nn, m;
          553 
          554         *d = nil;
          555         if(ts <= 0)
          556                 return 0;
          557 
          558         /*
          559          * first find number of all stats, check they look like stats, & size all associated strings
          560          */
          561         ss = 0;
          562         n = 0;
          563         for(i = 0; i < ts; i += m){
          564                 m = BIT16SZ + GBIT16(&buf[i]);
          565                 if(statcheck(&buf[i], m) < 0)
          566                         break;
          567                 ss += m;
          568                 n++;
          569         }
          570 
          571         if(i != ts)
          572                 return -1;
          573 
          574         *d = malloc(n * sizeof(Dir) + ss);
          575         if(*d == nil)
          576                 return -1;
          577 
          578         /*
          579          * then convert all buffers
          580          */
          581         s = (char*)*d + n * sizeof(Dir);
          582         nn = 0;
          583         for(i = 0; i < ts; i += m){
          584                 m = BIT16SZ + GBIT16((uchar*)&buf[i]);
          585                 if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
          586                         free(*d);
          587                         *d = nil;
          588                         return -1;
          589                 }
          590                 nn++;
          591                 s += m;
          592         }
          593 
          594         return nn;
          595 }