#include #include #include #include #include #include #include #include typedef struct { char **s; int n; }Lines; typedef struct { char *name; char *user; Lines detail[4]; }Pkg; typedef struct { char *cmd; int p[2]; /* p[1] is write to program; p[0] set to prog fd 0*/ int q[2]; /* q[0] is read from program; q[1] set to prog fd 1 */ Channel *sync; /* chan(ulong) */ }Exec; char *action[] = { "Install", "Exit", }; enum { Info, Files, Depends, Changes, }; char *detail[] = { "Info", "Files", "Depends", "Changes", }; #define STACK 1024*16 int mainstacksize = STACK; int ctldeletequits = 1; Controlset *cs; Channel *cevent, *cstatus; Pkg *pkg; int npkg; int nlog; Pkg *curpkg; void status(char *fmt, ...) { va_list arg; char *p; va_start(arg, fmt); p = vsmprint(fmt, arg); va_end(arg); chanprint(cs->ctl, "log_text add %q", p); chanprint(cs->ctl, "log_text scroll 1"); chanprint(cs->ctl, "log_scroll max %d", ++nlog); free(p); } void addline(Lines *l, char *s) { if(l->n%16 == 0) l->s = ctlrealloc(l->s, (l->n+16)*sizeof(char*)); l->s[l->n++] = ctlstrdup(s); } void execproc(void *v) { Channel *sync; Exec *e; int p[2], q[2]; char *cmd; threadsetname("execproc"); e = v; p[0] = e->p[0]; p[1] = e->p[1]; q[0] = e->q[0]; q[1] = e->q[1]; cmd = e->cmd; sync = e->sync; rfork(RFFDG); free(e); dup(p[0], 0); close(p[0]); close(p[1]); if(q[0]){ dup(q[1], 1); close(q[0]); close(q[1]); } if(1) close(2); procexecl(sync, "/bin/rc", "rc", "-c", cmd, 0); sysfatal("can't exec"); } void procruncmd(void *v) { Exec *e; Channel *sync, *chan; Biobuf bi; char *s, *cmd; int p[2], q[2]; void **a; a = v; cmd = a[0]; chan = a[1]; free(a); if(pipe(p)<0 || pipe(q)<0) sysfatal("can't create pipe: %r"); sync = chancreate(sizeof(ulong), 0); if(sync == nil) sysfatal("can't create channel: %r"); e = ctlmalloc(sizeof(Exec)); e->p[0] = p[0]; e->p[1] = p[1]; e->q[0] = q[0]; e->q[1] = q[1]; e->cmd = cmd; e->sync = sync; proccreate(execproc, e, STACK); recvul(sync); chanfree(sync); close(p[0]); close(p[1]); close(q[1]); Binit(&bi, q[0], OREAD); while((s=Brdstr(&bi, '\n', 1)) != nil) sendp(chan, s); Bterm(&bi); sendp(chan, nil); close(q[0]); free(s); } void runcmd(char *cmd, Channel* chan) { void **a; a = ctlmalloc(sizeof(void*)*2); a[0] = cmd; a[1] = chan; proccreate(procruncmd, a, STACK); } void getfile(int f) { Lines *l; char *cmd, *s; Channel *c; assert(curpkg != nil); l = &curpkg->detail[f]; if(l->n != 0) return; status("fetching %s for packages %s/%s", detail[f], curpkg->user, curpkg->name); cmd = nil; switch(f){ case Info: cmd = smprint("contrib/cat /n/sources/contrib/%s/replica/%s/inf | fmt", curpkg->user, curpkg->name); break; case Files: cmd = smprint("contrib/cat /n/sources/contrib/%s/replica/%s/db", curpkg->user, curpkg->name); break; case Depends: cmd = smprint("contrib/cat /n/sources/contrib/%s/replica/%s/dep", curpkg->user, curpkg->name); break; case Changes: cmd = smprint("contrib/cat /n/sources/contrib/%s/replica/%s/chg", curpkg->user, curpkg->name); break; } c = chancreate(sizeof(char *), 0); runcmd(cmd, c); while((s=recvp(c)) != nil) addline(l, s); chanfree(c); } void setdetail(int d) { Lines *l; int i; chanprint(cs->ctl, "detail_text clear"); for(i=0; ictl, "%s value %d", detail[i], i==d? 1: 0); if(curpkg == nil) return; getfile(d); l = &curpkg->detail[d]; if(l->n == -1) return; for(i=0; in; i++) chanprint(cs->ctl, "detail_text add %q", l->s[i]); chanprint(cs->ctl, "detail_scroll max %d", l->n); } int pkgcmp(void *a, void *b) { return strcmp(((Pkg*)a)->name, ((Pkg*)b)->name); } void mkpkgs(void) { Channel *c; char *cmd, *s, *p; int i, w, h, mw; status("fetching package list..."); c = chancreate(sizeof(char *), 0); cmd = smprint("contrib/listall"); runcmd(cmd, c); npkg = 0; pkg = nil; while((s=recvp(c)) != nil) { pkg = ctlrealloc(pkg, sizeof(Pkg)*(npkg+1)); p = strchr(s, '/'); if(p == nil) sysfatal("bad list file: %r"); *p = '\0'; pkg[npkg].user = ctlstrdup(s); pkg[npkg].name = ctlstrdup(p+1); memset(pkg[npkg].detail, 0, sizeof(Lines)*4); npkg++; free(s); } chanfree(c); qsort(pkg, npkg, sizeof(Pkg), pkgcmp); mw = 0; for(i=0; ictl, "list_text add %q", pkg[i].name); w = stringwidth(font, pkg[i].name); if(w > mw) mw = w; } w = mw+4; h = font->height+4; chanprint(cs->ctl, "list_text size %d %d %d %d\n", w, h, w, 2048); chanprint(cs->ctl, "list_scroll max %d", npkg); status("done."); resizecontrolset(cs); } void install(void) { char *s; if(curpkg != nil){ status("trying to install %s/%s", curpkg->user, curpkg->name); s = smprint("contrib/install %s/%s", curpkg->user, curpkg->name); runcmd(s, cstatus); } chanprint(cs->ctl, "Install value 0"); } void initcolors(void) { Image *i; i = allocimagemix(display, DPaleyellow, DWhite); namectlimage(i, "textbg"); i = allocimagemix(display, DPalebluegreen, DWhite); namectlimage(i, "butbg"); i = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellowgreen); namectlimage(i, "scrollbg"); i = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow); namectlimage(i, "selbg"); i = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlue); namectlimage(i, "pressbg"); } void mkbutton(char *s) { int w, h; createtextbutton(cs, s); chanprint(cs->ctl, "%s text %s", s, s); chanprint(cs->ctl, "%s pressedtextcolor pressbg", s); chanprint(cs->ctl, "%s image butbg", s); chanprint(cs->ctl, "%s mask transparent", s); chanprint(cs->ctl, "%s align center", s); chanprint(cs->ctl, "%s border 1", s); w = stringwidth(font, s)+4; h = font->height + 4; chanprint(cs->ctl, "%s size %d %d %d %d", s, w, h, 1024, h); controlwire(controlcalled(s), "event", cevent); } void mktext(char *s, char *sbg) { createtext(cs, s); chanprint(cs->ctl, "%s border 1", s); chanprint(cs->ctl, "%s image textbg", s); chanprint(cs->ctl, "%s selectcolor %s", s, sbg); } void mkscroll(char *s, char *text) { createslider(cs, s); chanprint(cs->ctl, "%s border 1", s); chanprint(cs->ctl, "%s image scrollbg", s); chanprint(cs->ctl, "%s indicatorcolor textbg", s); chanprint(cs->ctl, "%s size 12 10 12 2048", s); chanprint(cs->ctl, "%s absolute 0", s); chanprint(cs->ctl, "%s format '%%q: %s topline %%d'", s, text); controlwire(controlcalled(s), "event", cs->ctl); } void mklabel(char *s) { int w, h; createlabel(cs, s); chanprint(cs->ctl, "%s align center", s); chanprint(cs->ctl, "%s border 1", s); chanprint(cs->ctl, "%s image paleyellow", s); chanprint(cs->ctl, "%s value %q", s, s); w = stringwidth(font, s)+4; h = font->height+4; chanprint(cs->ctl, "%s size %d %d %d %d", s, w, h, 1024, h); } void mkcontrols(void) { int i; createcolumn(cs, "window"); createrow(cs, "browser"); chanprint(cs->ctl, "browser separation %d", 1); createrow(cs, "log"); createrow(cs, "buttons"); chanprint(cs->ctl, "window add browser log buttons"); createcolumn(cs, "list"); mklabel("Packages"); mktext("list_text", "selbg"); controlwire(controlcalled("list_text"), "event", cevent); mkscroll("list_scroll", "list_text"); chanprint(cs->ctl, "list add Packages list_text"); createrow(cs, "detail"); createcolumn(cs, "detail_content"); createrow(cs, "detail_buttons"); for(i=0; ictl, "detail_buttons add %s", detail[i]); } mktext("detail_text", "textbg"); mkscroll("detail_scroll", "detail_text"); chanprint(cs->ctl, "detail_content add detail_buttons detail_text"); chanprint(cs->ctl, "detail add detail_scroll detail_content"); mktext("log_text", "white"); chanprint(cs->ctl, "log_text size %d %d %d %d\n", 10, (font->height*4)+4, 2048, (font->height*4)+4); mkscroll("log_scroll", "log_text"); chanprint(cs->ctl, "log add log_scroll log_text"); for(i=0; ictl, "buttons add %s", action[i]); } chanprint(cs->ctl, "browser add list_scroll list detail"); activate(controlcalled("window")); } void resizecontrolset(Controlset *) { if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); chanprint(cs->ctl, "window size"); chanprint(cs->ctl, "window rect %R", screen->r); chanprint(cs->ctl, "log_scroll vis '%d'", Dy(controlcalled("log_scroll")->rect)/font->height); chanprint(cs->ctl, "list_scroll vis '%d'", Dy(controlcalled("list_scroll")->rect)/font->height); chanprint(cs->ctl, "detail_scroll vis '%d'", Dy(controlcalled("detail_scroll")->rect)/font->height); chanprint(cs->ctl, "window show"); } void work(void) { char *s, *args[8]; int n, i; enum { AEvent, AStatus, NALT}; static Alt alts[NALT]; alts[AEvent].c = cevent; alts[AEvent].v = &s; alts[AEvent].op = CHANRCV; alts[AStatus].c = cstatus; alts[AStatus].v = &s; alts[AStatus].op = CHANRCV; alts[NALT].op = CHANEND; for(;;){ switch(alt(alts)){ case AStatus: if(s){ status(s); free(s); } break; case AEvent: n = tokenize(s, args, nelem(args)); if(n == 3){ if(strcmp(args[0], "Exit:")==0) threadexitsall(nil); if(strcmp(args[0], "Install:")==0){ install(); }else{ for(i=0; i=0 && iclicktotype = 1; cevent = chancreate(sizeof(char *), 0); cstatus = chancreate(sizeof(char *), 0); if(cevent==nil || cstatus==nil) sysfatal("can't create channels. %r"); initcolors(); mkcontrols(); resizecontrolset(cs); mkpkgs(); work(); }