Window* lookfile(Rune *s, int n) { int i, j, k; Window *w; Column *c; Text *t; /* avoid terminal slash on directories */ if(n>1 && s[n-1] == '/') --n; for(j=0; j<row.ncol; j++){ c = row.col[j]; for(i=0; i<c->nw; i++){ w = c->w[i]; t = &w->body; k = t->file->nname; if(k>1 && t->file->name[k-1] == '/') k--; if(runeeq(t->file->name, k, s, n)){ w = w->body.file->curtext->w; if(w->col != nil) /* protect against race deleting w */ return w; } } } return nil; }
void waitthread(void *v) { Waitmsg *w; Command *c, *lc; uint pid; int found, ncmd; Rune *cmd; char *err; Text *t; Pid *pids, *p, *lastp; enum { WErr, WKill, WWait, WCmd, NWALT }; Alt alts[NWALT+1]; USED(v); threadsetname("waitthread"); pids = nil; alts[WErr].c = cerr; alts[WErr].v = &err; alts[WErr].op = CHANRCV; alts[WKill].c = ckill; alts[WKill].v = &cmd; alts[WKill].op = CHANRCV; alts[WWait].c = cwait; alts[WWait].v = &w; alts[WWait].op = CHANRCV; alts[WCmd].c = ccommand; alts[WCmd].v = &c; alts[WCmd].op = CHANRCV; alts[NWALT].op = CHANEND; command = nil; for(;;){ switch(alt(alts)){ case WErr: qlock(&row.lk); warning(nil, "%s", err); free(err); flushimage(display, 1); qunlock(&row.lk); break; case WKill: found = FALSE; ncmd = runestrlen(cmd); for(c=command; c; c=c->next){ /* -1 for blank */ if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE){ if(postnote(PNGROUP, c->pid, "kill") < 0) warning(nil, "kill %S: %r\n", cmd); found = TRUE; } } if(!found) warning(nil, "Kill: no process %S\n", cmd); free(cmd); break; case WWait: pid = w->pid; lc = nil; for(c=command; c; c=c->next){ if(c->pid == pid){ if(lc) lc->next = c->next; else command = c->next; break; } lc = c; } qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); if(c == nil){ /* helper processes use this exit status */ if(strncmp(w->msg, "libthread", 9) != 0){ p = emalloc(sizeof(Pid)); p->pid = pid; strncpy(p->msg, w->msg, sizeof(p->msg)); p->next = pids; pids = p; } }else{ if(search(t, c->name, c->nname)){ textdelete(t, t->q0, t->q1, TRUE); textsetselect(t, 0, 0); } if(w->msg[0]) warning(c->md, "%.*S: exit %s\n", c->nname-1, c->name, w->msg); flushimage(display, 1); } qunlock(&row.lk); free(w); Freecmd: if(c){ if(c->iseditcmd) sendul(cedit, 0); free(c->text); free(c->name); fsysdelid(c->md); free(c); } break; case WCmd: /* has this command already exited? */ lastp = nil; for(p=pids; p!=nil; p=p->next){ if(p->pid == c->pid){ if(p->msg[0]) warning(c->md, "%s\n", p->msg); if(lastp == nil) pids = p->next; else lastp->next = p->next; free(p); goto Freecmd; } lastp = p; } c->next = command; command = c; qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); textinsert(t, 0, c->name, c->nname, TRUE); textsetselect(t, 0, 0); flushimage(display, 1); qunlock(&row.lk); break; } } }
int runestreq(Runestr a, Runestr b) { return runeeq(a.r, a.nr, b.r, b.nr); }
int search(Text *ct, Rune *r, uint n) { uint q, nb, maxn; int around; Rune *s, *b, *c; if(n==0 || n>ct->file->b.nc) return FALSE; if(2*n > RBUFSIZE){ warning(nil, "string too long\n"); return FALSE; } maxn = max(2*n, RBUFSIZE); s = fbufalloc(); b = s; nb = 0; b[nb] = 0; around = 0; q = ct->q1; for(;;){ if(q >= ct->file->b.nc){ q = 0; around = 1; nb = 0; b[nb] = 0; } if(nb > 0){ c = runestrchr(b, r[0]); if(c == nil){ q += nb; nb = 0; b[nb] = 0; if(around && q>=ct->q1) break; continue; } q += (c-b); nb -= (c-b); b = c; } /* reload if buffer covers neither string nor rest of file */ if(nb<n && nb!=ct->file->b.nc-q){ nb = ct->file->b.nc-q; if(nb >= maxn) nb = maxn-1; bufread(&ct->file->b, q, s, nb); b = s; b[nb] = '\0'; } /* this runeeq is fishy but the null at b[nb] makes it safe */ if(runeeq(b, n, r, n)==TRUE){ if(ct->w){ textshow(ct, q, q+n, 1); winsettag(ct->w); }else{ ct->q0 = q; ct->q1 = q+n; } seltext = ct; fbuffree(s); return TRUE; } --nb; b++; q++; if(around && q>=ct->q1) break; } fbuffree(s); return FALSE; }