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 }