8 typedef struct Tree Tree;
9 typedef struct Tnode Tnode;
23 // char *(*strfn)(Tnode*);
24 // uint (*draw)(Tnode*, Image*, Image*, Point);
25 void (*expand)(Tnode*);
26 void (*collapse)(Tnode*);
34 typedef struct Atree Atree;
41 Atree *atreeinit(char*);
44 Tnode *initxheader(void);
45 Tnode *initxcache(char *name);
46 Tnode *initxsuper(void);
47 Tnode *initxlocalroot(char *name, u32int addr);
48 Tnode *initxentry(Entry);
49 Tnode *initxsource(Entry, int);
50 Tnode *initxentryblock(Block*, Entry*);
51 Tnode *initxdatablock(Block*, uint);
52 Tnode *initxroot(char *name, uchar[VtScoreSize]);
55 int mainstacksize = STACK;
63 * dumbed down versions of fossil routines
75 sprint(s, "%x", state);
77 strcat(s, ",Free"); /* should not happen */
107 if(type < nelem(bttab))
117 b = mallocz(sizeof(Block)+h.blockSize, 1);
118 b->data = (void*)&b[1];
160 readBlock(int part, u32int addr)
168 start = partStart(part);
170 if(addr >= end-start){
171 werrstr("bad addr 0x%.8ux; wanted 0x%.8ux - 0x%.8ux", addr, start, end);
178 offset = ((u64int)(addr+start))*h.blockSize;
181 nn = pread(fd, buf, n, offset);
187 werrstr("short read");
198 int vtType[BtMax] = {
199 VtDataType, /* BtData | 0 */
200 VtDataType+1, /* BtData | 1 */
201 VtDataType+2, /* BtData | 2 */
202 VtDataType+3, /* BtData | 3 */
203 VtDataType+4, /* BtData | 4 */
204 VtDataType+5, /* BtData | 5 */
205 VtDataType+6, /* BtData | 6 */
206 VtDataType+7, /* BtData | 7 */
207 VtDirType, /* BtDir | 0 */
208 VtDirType+1, /* BtDir | 1 */
209 VtDirType+2, /* BtDir | 2 */
210 VtDirType+3, /* BtDir | 3 */
211 VtDirType+4, /* BtDir | 4 */
212 VtDirType+5, /* BtDir | 5 */
213 VtDirType+6, /* BtDir | 6 */
214 VtDirType+7, /* BtDir | 7 */
218 ventiBlock(uchar score[VtScoreSize], uint type)
224 memmove(b->score, score, VtScoreSize);
227 n = vtread(z, b->score, vtType[type], b->data, h.blockSize);
229 fprint(2, "vtread returns %d: %r\n", n);
233 vtzeroextend(vtType[type], b->data, n, h.blockSize);
242 dataBlock(uchar score[VtScoreSize], uint type, uint tag)
249 addr = globalToLocal(score);
251 return ventiBlock(score, type);
253 lpb = h.blockSize/LabelSize;
254 bl = readBlock(PartLabel, addr/lpb);
257 if(!labelUnpack(&l, bl->data, addr%lpb)){
264 werrstr("type mismatch; got %d (%s) wanted %d (%s)",
265 l.type, btStr(l.type), type, btStr(type));
268 if(tag && l.tag != tag){
269 werrstr("tag mismatch; got 0x%.8ux wanted 0x%.8ux",
273 b = readBlock(PartData, addr);
285 p = mallocz(sizeof *p, 1);
291 copyMetaBlock(MetaBlock mb)
295 p = mallocz(sizeof mb, 1);
304 #pragma varargck argpos stringnode 1
307 stringnode(char *fmt, ...)
312 t = mallocz(sizeof(Tnode), 1);
314 t->str = vsmprint(fmt, arg);
321 xcacheexpand(Tnode *t)
327 t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1);
328 t->kid[0] = initxheader();
332 initxcache(char *name)
336 if((fd = open(name, OREAD)) < 0)
337 sysfatal("cannot open %s: %r", name);
339 t = stringnode("%s", name);
340 t->expand = xcacheexpand;
345 xheaderexpand(Tnode *t)
351 t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1);
352 t->kid[0] = initxsuper();
353 //t->kid[1] = initxlabel(h.label);
354 //t->kid[2] = initxdata(h.data);
360 u8int buf[HeaderSize];
363 if(pread(fd, buf, HeaderSize, HeaderOffset) < HeaderSize)
364 return stringnode("error reading header: %r");
365 if(!headerUnpack(&h, buf))
366 return stringnode("error unpacking header: %r");
368 t = stringnode("header "
370 "blockSize=%#ux (%d) "
375 h.version, h.version, h.blockSize, h.blockSize,
377 h.label, h.label, h.data, h.data, h.end, h.end);
378 t->expand = xheaderexpand;
383 xsuperexpand(Tnode *t)
389 t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1);
390 t->kid[0] = initxlocalroot("active", super.active);
391 // t->kid[1] = initxlocalroot("next", super.next);
392 // t->kid[2] = initxlocalroot("current", super.current);
401 b = readBlock(PartSuper, 0);
403 return stringnode("reading super: %r");
404 if(!superUnpack(&super, b->data)){
406 return stringnode("unpacking super: %r");
409 t = stringnode("super "
418 super.version, super.epochLow, super.epochHigh,
419 super.qid, super.active, super.next, super.current,
420 super.last, super.name);
421 t->expand = xsuperexpand;
426 xvacrootexpand(Tnode *t)
432 t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1);
433 t->kid[0] = initxroot("root", vac.score);
437 initxvacroot(uchar score[VtScoreSize])
440 uchar buf[VtRootSize];
443 if((n = vtread(z, score, VtRootType, buf, VtRootSize)) < 0)
444 return stringnode("reading root %V: %r", score);
446 if(vtrootunpack(&vac, buf) < 0)
447 return stringnode("unpack %d-byte root: %r", n);
449 h.blockSize = vac.blocksize;
450 t = stringnode("vac version=%#ux name=%s type=%s blocksize=%lud score=%V prev=%V",
451 VtRootVersion, vac.name, vac.type, vac.blocksize, vac.score, vac.prev);
452 t->expand = xvacrootexpand;
459 return stringnode("label type=%s state=%s epoch=%#ux tag=%#ux",
460 btStr(l.type), bsStr(l.state), l.epoch, l.tag);
463 typedef struct Xblock Xblock;
468 int (*gen)(void*, Block*, int, Tnode**);
474 xblockexpand(Tnode *tt)
478 Xblock *t = (Xblock*)tt;
486 t->t.kid = mallocz(Q*sizeof(t->t.kid[0]), 1);
487 t->t.kid[0] = initxlabel(t->b->l);
492 switch((*t->gen)(t->arg, t->b, i, &nn)){
500 t->t.kid = realloc(t->t.kid, (j+Q)*sizeof(t->t.kid[0]));
508 nilgen(void *v, Block *b, int o, Tnode **tp)
514 initxblock(Block *b, char *s, int (*gen)(void *v, Block *b, int o, Tnode **tp), void *arg)
520 t = mallocz(sizeof(Xblock), 1);
524 if(b->addr == NilBlock)
525 t->t.str = smprint("Block %V: %s", b->score, s);
527 t->t.str = smprint("Block %#ux: %s", b->addr, s);
530 t->t.expand = xblockexpand;
535 xentrygen(void *v, Block *b, int o, Tnode **tp)
541 if(o >= ed->dsize/VtEntrySize)
544 entryUnpack(&e, b->data, o);
545 if(!showinactive && !(e.flags & VtEntryActive))
552 initxentryblock(Block *b, Entry *ed)
554 return initxblock(b, "entry", xentrygen, ed);
557 typedef struct Xentry Xentry;
565 xentryexpand(Tnode *tt)
567 Xentry *t = (Xentry*)tt;
573 t->t.kid = mallocz(sizeof(t->t.kid[0])*t->t.nkid, 1);
574 t->t.kid[0] = initxsource(t->e, 1);
582 t = mallocz(sizeof *t, 1);
584 t->t.str = smprint("Entry gen=%#ux psize=%d dsize=%d depth=%d flags=%#ux size=%lld score=%V",
585 e.gen, e.psize, e.dsize, e.depth, e.flags, e.size, e.score);
586 if(e.flags & VtEntryLocal)
587 t->t.str = smprint("%s archive=%d snap=%d tag=%#ux", t->t.str, e.archive, e.snap, e.tag);
588 t->t.expand = xentryexpand;
594 ptrgen(void *v, Block *b, int o, Tnode **tp)
600 if(o >= ed->psize/VtScoreSize)
605 memmove(e.score, b->data+o*VtScoreSize, VtScoreSize);
606 if(memcmp(e.score, vtzeroscore, VtScoreSize) == 0)
608 *tp = initxsource(e, 0);
613 etype(int flags, int depth)
617 if(flags&_VtEntryDir)
625 initxsource(Entry e, int dowrap)
630 b = dataBlock(e.score, etype(e.flags, e.depth), e.tag);
632 return stringnode("dataBlock: %r");
634 if((e.flags & VtEntryActive) == 0)
635 return stringnode("inactive Entry");
638 if(e.flags & _VtEntryDir)
639 tt = initxentryblock(b, copyEntry(e));
641 tt = initxdatablock(b, e.dsize);
643 tt = initxblock(b, smprint("%s+%d pointer", (e.flags & _VtEntryDir) ? "BtDir" : "BtData", e.depth),
644 ptrgen, copyEntry(e));
648 * wrap the contents of the Source in a Source node,
649 * just so it's closer to what you see in the code.
652 t = stringnode("Source");
654 t->kid = mallocz(sizeof(Tnode*)*1, 1);
662 xlocalrootgen(void *v, Block *b, int o, Tnode **tp)
668 entryUnpack(&e, b->data, o);
674 initxlocalroot(char *name, u32int addr)
676 uchar score[VtScoreSize];
679 localToGlobal(addr, score);
680 b = dataBlock(score, BtDir, RootTag);
682 return stringnode("read data block %#ux: %r", addr);
683 return initxblock(b, smprint("'%s' fs root", name), xlocalrootgen, nil);
687 xvacrootgen(void *v, Block *b, int o, Tnode **tp)
693 entryUnpack(&e, b->data, o);
699 initxroot(char *name, uchar score[VtScoreSize])
703 b = dataBlock(score, BtDir, RootTag);
705 return stringnode("read data block %V: %r", score);
706 return initxblock(b, smprint("'%s' fs root", name), xvacrootgen, nil);
709 initxdirentry(MetaEntry *me)
714 if(!deUnpack(&dir, me))
715 return stringnode("deUnpack: %r");
717 t = stringnode("dirEntry elem=%s size=%llud data=%#lux/%#lux meta=%#lux/%#lux", dir.elem, dir.size, dir.entry, dir.gen, dir.mentry, dir.mgen);
719 t->kid = mallocz(sizeof(t->kid[0])*1, 1);
720 t->kid[0] = stringnode(
722 "uid=%s gid=%s mid=%s\n"
723 "mtime=%lud mcount=%lud ctime=%lud atime=%lud\n"
725 "plan9 %d p9path %#llux p9version %lud\n"
726 "qidSpace %d offset %#llux max %#llux",
728 dir.uid, dir.gid, dir.mid,
729 dir.mtime, dir.mcount, dir.ctime, dir.atime,
731 dir.plan9, dir.p9path, dir.p9version,
732 dir.qidSpace, dir.qidOffset, dir.qidMax);
737 metaentrygen(void *v, Block *b, int o, Tnode **tp)
746 meUnpack(&me, mb, o);
748 t = stringnode("MetaEntry %d bytes", mb->size);
749 t->kid = mallocz(sizeof(t->kid[0])*1, 1);
750 t->kid[0] = initxdirentry(&me);
757 metablockgen(void *v, Block *b, int o, Tnode **tp)
765 /* hack: reuse initxblock as a generic iterator */
767 t = (Xblock*)initxblock(b, "", metaentrygen, mb);
768 t->t.str = smprint("MetaBlock %d/%d space used, %d add'l free %d/%d table used%s",
769 mb->size, mb->maxsize, mb->free, mb->nindex, mb->maxindex,
770 mb->botch ? " [BOTCH]" : "");
777 * attempt to guess at the type of data in the block.
778 * it could just be data from a file, but we're hoping it's MetaBlocks.
781 initxdatablock(Block *b, uint n)
788 if(mbUnpack(&mb, b->data, n))
789 return initxblock(b, "metadata", metablockgen, copyMetaBlock(mb));
791 return initxblock(b, "data", nil, nil);
795 parseScore(uchar *score, char *buf, int n)
799 memset(score, 0, VtScoreSize);
801 if(n < VtScoreSize*2)
803 for(i=0; i<VtScoreSize*2; i++){
804 if(buf[i] >= '0' && buf[i] <= '9')
806 else if(buf[i] >= 'a' && buf[i] <= 'f')
807 c = buf[i] - 'a' + 10;
808 else if(buf[i] >= 'A' && buf[i] <= 'F')
809 c = buf[i] - 'A' + 10;
829 v = va_arg(f->args, uchar*);
832 }else if((addr = globalToLocal(v)) != NilBlock)
833 fmtprint(f, "0x%.8ux", addr);
835 for(i = 0; i < VtScoreSize; i++)
836 fmtprint(f, "%2.2ux", v[i]);
846 uchar score[VtScoreSize];
848 fmtinstall('V', scoreFmt);
852 fprint(2, "warning: cannot dial venti: %r\n");
853 else if(vtconnect(z) < 0){
854 fprint(2, "warning: cannot connect to venti: %r\n");
857 a = mallocz(sizeof(Atree), 1);
858 if(strncmp(arg, "vac:", 4) == 0){
859 if(!parseScore(score, arg+4, strlen(arg+4))){
860 fprint(2, "cannot parse score\n");
863 a->root = initxvacroot(score);
865 a->root = initxcache(arg);
875 Linewidth = Nubwidth*2+4,
879 drawtext(char *s, Image *m, Image *clipr, Point o)
888 for(t=s; t&&*t; t=nt){
889 if(nt = strchr(t, '\n')){
895 _string(m, Pt(o.x, o.y+dy), display->black, ZP, display->defaultfont,
896 t, nil, e-t, clipr->clipr, nil, ZP, SoverD);
897 dy += display->defaultfont->height;
903 drawnub(Image *m, Image *clipr, Point o, Tnode *t)
909 if(t->nkid == -1 && t->expand == nil)
912 o.y += (display->defaultfont->height-Nubheight)/2;
913 draw(m, rectaddpt(Rect(0,0,1,Nubheight), o), display->black, clipr, ZP);
914 draw(m, rectaddpt(Rect(0,0,Nubwidth,1), o), display->black, clipr, o);
915 draw(m, rectaddpt(Rect(Nubwidth-1,0,Nubwidth,Nubheight), o),
916 display->black, clipr, addpt(o, Pt(Nubwidth-1, 0)));
917 draw(m, rectaddpt(Rect(0, Nubheight-1, Nubwidth, Nubheight), o),
918 display->black, clipr, addpt(o, Pt(0, Nubheight-1)));
920 draw(m, rectaddpt(Rect(0, Nubheight/2, Nubwidth, Nubheight/2+1), o),
921 display->black, clipr, addpt(o, Pt(0, Nubheight/2)));
923 draw(m, rectaddpt(Rect(Nubwidth/2, 0, Nubwidth/2+1, Nubheight), o),
924 display->black, clipr, addpt(o, Pt(Nubwidth/2, 0)));
929 drawnode(Tnode *t, Image *m, Image *clipr, Point o)
941 oo = Pt(o.x+Nubwidth+2, o.y);
943 // dy = (*t->draw)(t, m, clipr, oo);
949 // fs = s = (*t->strfn)(t);
952 dy = drawtext(s, m, clipr, oo);
957 if(t->nkid == -1 && t->expand)
959 oo = Pt(o.x+Nubwidth+(Linewidth-Nubwidth)/2, o.y+dy);
960 for(i=0; i<t->nkid; i++)
961 oo.y += drawnode(t->kid[i], m, clipr, oo);
964 drawnub(m, clipr, o, t);
969 drawtree(Tree *t, Image *m, Rectangle r)
973 draw(m, r, display->white, nil, ZP);
975 replclipr(t->clipr, 1, r);
976 p = addpt(t->offset, r.min);
977 drawnode(t->root, m, t->clipr, p);
981 findnode(Tnode *t, Point p)
986 if(ptinrect(p, rectaddpt(Rect(0,0,Nubwidth, Nubheight), t->offset)))
990 for(i=0; i<t->nkid; i++)
991 if(tt = findnode(t->kid[i], p))
999 fprint(2, "usage: fossil/view /dev/sdC0/fossil\n");
1000 threadexitsall("usage");
1008 if(new && getwindow(display, Refnone) < 0)
1009 fprint(2,"can't reattach to window");
1010 drawtree(&t, screen, screen->r);
1022 char *items[] = { "exit", 0 };
1028 threadmain(int argc, char **argv)
1055 fs = atreeinit(dir);
1057 initdraw(0, "/lib/font/bit/lucsans/unicode.8.font", "tree");
1059 initdraw(0, "/lib/font/bit/lucidasans/unicode.8.font", "tree");
1063 t.clipr = allocimage(display, Rect(0,0,1,1), GREY1, 1, DOpaque);
1066 flushimage(display, 1);
1073 if(fs->resizefd > 0){
1075 estart(Eready, fs->resizefd, 1);
1080 switch(n=eread(Emouse|Eready, &e)){
1082 if(Eready && n==Eready)
1092 t.offset = addpt(t.offset, subpt(m.xy, p));
1096 }while(m.buttons == Left);
1103 n = emenuhit(MMenu, &m, &menu);
1108 threadexitsall(nil);
1114 while(m.buttons == Right);
1117 tn = findnode(t.root, m.xy);
1119 tn->expanded = !tn->expanded;