int expandfile(Text *t, uint q0, uint q1, Expand *e) { int i, n, nname, colon, eval; uint amin, amax; Rune *r, c; Window *w; Runestr rs; amax = q1; if(q1 == q0){ colon = -1; while(q1<t->file->b.nc && isfilec(c=textreadc(t, q1))){ if(c == ':'){ colon = q1; break; } q1++; } while(q0>0 && (isfilec(c=textreadc(t, q0-1)) || isaddrc(c) || isregexc(c))){ q0--; if(colon<0 && c==':') colon = q0; } /* * if it looks like it might begin file: , consume address chars after : * otherwise terminate expansion at : */ if(colon >= 0){ q1 = colon; if(colon<t->file->b.nc-1 && isaddrc(textreadc(t, colon+1))){ q1 = colon+1; while(q1<t->file->b.nc && isaddrc(textreadc(t, q1))) q1++; } } if(q1 > q0) if(colon >= 0){ /* stop at white space */ for(amax=colon+1; amax<t->file->b.nc; amax++) if((c=textreadc(t, amax))==' ' || c=='\t' || c=='\n') break; }else amax = t->file->b.nc; } amin = amax; e->q0 = q0; e->q1 = q1; n = q1-q0; if(n == 0) return FALSE; /* see if it's a file name */ r = runemalloc(n); bufread(&t->file->b, q0, r, n); /* first, does it have bad chars? */ nname = -1; for(i=0; i<n; i++){ c = r[i]; if(c==':' && nname<0){ if(q0+i+1<t->file->b.nc && (i==n-1 || isaddrc(textreadc(t, q0+i+1)))) amin = q0+i; else goto Isntfile; nname = i; } } if(nname == -1) nname = n; for(i=0; i<nname; i++) if(!isfilec(r[i])) goto Isntfile; /* * See if it's a file name in <>, and turn that into an include * file name if so. Should probably do it for "" too, but that's not * restrictive enough syntax and checking for a #include earlier on the * line would be silly. */ if(q0>0 && textreadc(t, q0-1)=='<' && q1<t->file->b.nc && textreadc(t, q1)=='>'){ rs = includename(t, r, nname); r = rs.r; nname = rs.nr; } else if(amin == q0) goto Isfile; else{ rs = dirname(t, r, nname); r = rs.r; nname = rs.nr; } e->bname = runetobyte(r, nname); /* if it's already a window name, it's a file */ w = lookfile(r, nname); if(w != nil) goto Isfile; /* if it's the name of a file, it's a file */ if(ismtpt(e->bname) || access(e->bname, 0) < 0){ free(e->bname); e->bname = nil; goto Isntfile; } Isfile: e->name = r; e->nname = nname; e->u.at = t; e->a0 = amin+1; eval = FALSE; address(TRUE, nil, range(-1,-1), range(0,0), t, e->a0, amax, tgetc, &eval, (uint*)&e->a1); return TRUE; Isntfile: free(r); return FALSE; }
int textload(Text *t, uint q0, char *file, int setqid) { Rune *rp; Dirlist *dl, **dlp; int fd, i, j, n, ndl, nulls; uint q, q1; Dir *d, *dbuf; char *tmp; Text *u; if(t->ncache!=0 || t->file->b.nc || t->w==nil || t!=&t->w->body) error("text.load"); if(t->w->isdir && t->file->nname==0){ warning(nil, "empty directory name"); return -1; } if(ismtpt(file)){ warning(nil, "will not open self mount point %s\n", file); return -1; } fd = open(file, OREAD); if(fd < 0){ warning(nil, "can't open %s: %r\n", file); return -1; } d = dirfstat(fd); if(d == nil){ warning(nil, "can't fstat %s: %r\n", file); goto Rescue; } nulls = FALSE; if(d->qid.type & QTDIR){ /* this is checked in get() but it's possible the file changed underfoot */ if(t->file->ntext > 1){ warning(nil, "%s is a directory; can't read with multiple windows on it\n", file); goto Rescue; } t->w->isdir = TRUE; t->w->filemenu = FALSE; if(t->file->nname > 0 && t->file->name[t->file->nname-1] != '/'){ rp = runemalloc(t->file->nname+1); runemove(rp, t->file->name, t->file->nname); rp[t->file->nname] = '/'; winsetname(t->w, rp, t->file->nname+1); free(rp); } dlp = nil; ndl = 0; dbuf = nil; while((n=dirread(fd, &dbuf)) > 0){ for(i=0; i<n; i++){ dl = emalloc(sizeof(Dirlist)); j = strlen(dbuf[i].name); tmp = emalloc(j+1+1); memmove(tmp, dbuf[i].name, j); if(dbuf[i].qid.type & QTDIR) tmp[j++] = '/'; tmp[j] = '\0'; dl->r = bytetorune(tmp, &dl->nr); dl->wid = stringwidth(t->fr.font, tmp); free(tmp); ndl++; dlp = realloc(dlp, ndl*sizeof(Dirlist*)); dlp[ndl-1] = dl; } free(dbuf); } qsort(dlp, ndl, sizeof(Dirlist*), dircmp); t->w->dlp = dlp; t->w->ndl = ndl; textcolumnate(t, dlp, ndl); q1 = t->file->b.nc; }else{ t->w->isdir = FALSE; t->w->filemenu = TRUE; q1 = q0 + fileload(t->file, q0, fd, &nulls); } if(setqid){ t->file->dev = d->dev; t->file->mtime = d->mtime; t->file->qidpath = d->qid.path; } close(fd); rp = fbufalloc(); for(q=q0; q<q1; q+=n){ n = q1-q; if(n > RBUFSIZE) n = RBUFSIZE; bufread(&t->file->b, q, rp, n); if(q < t->org) t->org += n; else if(q <= t->org+t->fr.nchars) frinsert(&t->fr, rp, rp+n, q-t->org); if(t->fr.lastlinefull) break; } fbuffree(rp); for(i=0; i<t->file->ntext; i++){ u = t->file->text[i]; if(u != t){ if(u->org > u->file->b.nc) /* will be 0 because of reset(), but safety first */ u->org = 0; textresize(u, u->all, TRUE); textbacknl(u, u->org, 0); /* go to beginning of line */ } textsetselect(u, q0, q0); } if(nulls) warning(nil, "%s: NUL bytes elided\n", file); free(d); return q1-q0; Rescue: close(fd); return -1; }