t$foo in tags - here only for reference. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 99f40290902d69956f7ef57b33599c4092021d01
 (DIR) parent b9403fe70a539ab5a6d174e5a800082c542ea06b
 (HTM) Author: rsc <devnull@localhost>
       Date:   Wed, 21 Apr 2004 22:39:37 +0000
       
       $foo in tags - here only for reference.
       
       Diffstat:
         M src/cmd/acme/exec.c                 |       2 ++
         M src/cmd/acme/fns.h                  |       3 +++
         M src/cmd/acme/fsys.c                 |       2 ++
         M src/cmd/acme/look.c                 |      37 ++++++++++++++++++++++++-------
         M src/cmd/acme/util.c                 |       1 +
         M src/cmd/acme/wind.c                 |     179 +++++++++++++++++++++++++++++--
       
       6 files changed, 209 insertions(+), 15 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c
       t@@ -159,6 +159,8 @@ execute(Text *t, uint aq0, uint aq1, int external, Text *argt)
                                        q1++;
                                while(q0>0 && isexecc(c=textreadc(t, q0-1)) && c!=':')
                                        q0--;
       +                        if(q0>0 && textreadc(t, q0-1)=='$')
       +                                q0--;
                                if(q1 == q0)
                                        return;
                        }
 (DIR) diff --git a/src/cmd/acme/fns.h b/src/cmd/acme/fns.h
       t@@ -92,6 +92,9 @@ char*        edittext(Window*, int, Rune*, int);
        void                flushwarnings(void);
        void                startplumbing(void);
        
       +int                expandenv(Rune**, uint*);
       +int                abbrevenv(Rune**, uint*);
       +
        Runestr        runestr(Rune*, uint);
        Range range(int, int);
        
 (DIR) diff --git a/src/cmd/acme/fsys.c b/src/cmd/acme/fsys.c
       t@@ -145,6 +145,8 @@ fsysproc(void *v)
                        if(n <= 0){
                                if(closing)
                                        break;
       +                        if(n == 0)
       +                                werrstr("short read");
                                error("i/o error on server channel");
                        }
                        if(x == nil){
 (DIR) diff --git a/src/cmd/acme/look.c b/src/cmd/acme/look.c
       t@@ -15,6 +15,8 @@
        #include "dat.h"
        #include "fns.h"
        
       +#define debug 0
       +
        FsFid *plumbsendfid;
        FsFid *plumbeditfid;
        
       t@@ -456,10 +458,12 @@ dirname(Text *t, Rune *r, int n)
                b = nil;
                if(t==nil || t->w==nil)
                        goto Rescue;
       +        if(n>=1 && r[0]=='$')
       +                expandenv(&r, &n);
                nt = t->w->tag.file->b.nc;
                if(nt == 0)
                        goto Rescue;
       -        if(n>=1 &&  r[0]=='/')
       +        if(n>=1 && r[0]=='/')
                        goto Rescue;
                b = runemalloc(nt+n+1);
                bufread(&t->w->tag.file->b, 0, b, nt);
       t@@ -473,9 +477,12 @@ dirname(Text *t, Rune *r, int n)
                }
                if(slash < 0)
                        goto Rescue;
       -        runemove(b+slash+1, r, n);
       +        slash++;
       +        if(expandenv(&b, &slash))
       +                b = runerealloc(b, slash+n);
       +        runemove(b+slash, r, n);
                free(r);
       -        return cleanrname(runestr(b, slash+1+n));
       +        return cleanrname(runestr(b, slash+n));
        
            Rescue:
                free(b);
       t@@ -535,9 +542,11 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
                n = q1-q0;
                if(n == 0)
                        return FALSE;
       +
                /* see if it's a file name */
       -        r = runemalloc(n);
       +        r = runemalloc(n+1);        /* +1 for $ below */
                bufread(&t->file->b, q0, r, n);
       +
                /* first, does it have bad chars? */
                nname = -1;
                for(i=0; i<n; i++){
       t@@ -552,9 +561,13 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
                }
                if(nname == -1)
                        nname = n;
       -        for(i=0; i<nname; i++)
       +        for(i=0; i<nname; i++){
       +                if(i==0 && r[0]=='$')
       +                        continue;
                        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
       t@@ -569,10 +582,18 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
                else if(amin == q0)
                        goto Isfile;
                else{
       -                rs = dirname(t, r, nname);
       -                r = rs.r;
       -                nname = rs.nr;
       +                if(debug) fprint(2, "x1 %.*S\n", nname, r);
       +                if(r[0] != '$'){
       +                        rs = dirname(t, r, nname);
       +                        r = rs.r;
       +                        nname = rs.nr;
       +                        if(debug) fprint(2, "x1.5 %.*S\n", nname, r);
       +                }
       +                if(r[0]=='$')
       +                        expandenv(&r, &nname);
       +                if(debug) fprint(2, "x2 %.*S\n", nname, r);
                }
       +
                e->bname = runetobyte(r, nname);
                /* if it's already a window name, it's a file */
                w = lookfile(r, nname);
 (DIR) diff --git a/src/cmd/acme/util.c b/src/cmd/acme/util.c
       t@@ -454,3 +454,4 @@ makenewwindow(Text *t)
                        colgrow(w->col, w, 1);
                return w;
        }
       +
 (DIR) diff --git a/src/cmd/acme/wind.c b/src/cmd/acme/wind.c
       t@@ -258,6 +258,7 @@ winsetname(Window *w, Rune *name, int n)
                int i;
                static Rune Lslashguide[] = { '/', 'g', 'u', 'i', 'd', 'e', 0 };
                static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
       +
                t = &w->body;
                if(runeeq(t->file->name, t->file->nname, name, n) == TRUE)
                        return;
       t@@ -318,8 +319,8 @@ wincleartag(Window *w)
        void
        winsettag1(Window *w)
        {
       -        int i, j, k, n, bar, dirty;
       -        Rune *new, *old, *r;
       +        int i, j, k, n, ntagname, bar, dirty;
       +        Rune *new, *old, *tagname, *r;
                Image *b;
                uint q0, q1;
                Rectangle br;
       t@@ -331,6 +332,7 @@ winsettag1(Window *w)
                static Rune Lput[] = { ' ', 'P', 'u', 't', 0 };
                static Rune Llook[] = { ' ', 'L', 'o', 'o', 'k', ' ', 0 };
                static Rune Lpipe[] = { ' ', '|', 0 };
       +
                /* there are races that get us here with stuff in the tag cache, so we take extra care to sync it */
                if(w->tag.ncache!=0 || w->tag.file->mod)
                        wincommit(w, &w->tag);        /* check file name; also guarantees we can modify tag contents */
       t@@ -340,18 +342,27 @@ winsettag1(Window *w)
                for(i=0; i<w->tag.file->b.nc; i++)
                        if(old[i]==' ' || old[i]=='\t')
                                break;
       -        if(runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE){
       +
       +        /* make sure the file name is set correctly in the tag */
       +        ntagname = w->body.file->nname;
       +        tagname = runemalloc(ntagname);
       +        runemove(tagname, w->body.file->name, ntagname);
       +        abbrevenv(&tagname, &ntagname);
       +
       +        if(runeeq(old, i, tagname, ntagname) == FALSE){
                        textdelete(&w->tag, 0, i, TRUE);
       -                textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE);
       +                textinsert(&w->tag, 0, tagname, ntagname, TRUE);
                        free(old);
                        old = runemalloc(w->tag.file->b.nc+1);
                        bufread(&w->tag.file->b, 0, old, w->tag.file->b.nc);
                        old[w->tag.file->b.nc] = '\0';
                }
       -        new = runemalloc(w->body.file->nname+100);
       +
       +        /* compute the text for the whole tag, replacing current only if it differs */
       +        new = runemalloc(ntagname+100);
                i = 0;
       -        runemove(new+i, w->body.file->name, w->body.file->nname);
       -        i += w->body.file->nname;
       +        runemove(new+i, tagname, ntagname);
       +        i += ntagname;
                runemove(new+i, Ldelsnarf, 10);
                i += 10;
                if(w->filemenu){
       t@@ -389,6 +400,8 @@ winsettag1(Window *w)
                if(runestrlen(new) != i)
                        fprint(2, "s '%S' len not %d\n", new, i);
                assert(i==runestrlen(new));
       +
       +        /* replace tag if the new one is different */
                if(runeeq(new, i, old, k) == FALSE){
                        n = k;
                        if(n > i)
       t@@ -411,6 +424,7 @@ winsettag1(Window *w)
                                }
                        }
                }
       +        free(tagname);
                free(old);
                free(new);
                w->tag.file->mod = FALSE;
       t@@ -463,6 +477,7 @@ wincommit(Window *w, Text *t)
                for(i=0; i<w->tag.file->b.nc; i++)
                        if(r[i]==' ' || r[i]=='\t')
                                break;
       +        expandenv(&r, &i);
                if(runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE){
                        seq++;
                        filemark(w->body.file);
       t@@ -581,3 +596,153 @@ winevent(Window *w, char *fmt, ...)
                        sendp(x->c, nil);
                }
        }
       +
       +int
       +expandenv(Rune **rp, uint *np)
       +{
       +        char *s, *t;
       +        Rune *p, *r, *q;
       +        uint n, pref;
       +        int nb, nr, slash;
       +        Runestr rs;
       +
       +        r = *rp;
       +        n = *np;
       +        if(n == 0 || r[0] != '$')
       +                return FALSE;
       +        for(p=r+1; *p && *p != '/'; p++)
       +                ;
       +        pref = p-r;
       +        s = runetobyte(r+1, pref-1);
       +        if((t = getenv(s)) == nil){
       +                free(s);
       +                return FALSE;
       +        }
       +
       +        q = runemalloc(utflen(t)+(n-pref));
       +        cvttorunes(t, strlen(t), q, &nb, &nr, nil);
       +        assert(nr==utflen(t));
       +        runemove(q+nr, p, n-pref);
       +        free(r);
       +        rs = runestr(q, nr+(n-pref));
       +        slash = rs.nr>0 && q[rs.nr-1] == '/';
       +        rs = cleanrname(rs);
       +        if(slash){
       +                rs.r = runerealloc(rs.r, rs.nr+1);
       +                rs.r[rs.nr++] = '/';
       +        }
       +        *rp = rs.r;
       +        *np = rs.nr;
       +        return TRUE;
       +}
       +
       +extern char **environ;
       +Rune **runeenv;
       +
       +/*
       + * Weird sort order -- shorter names first, 
       + * prefer lowercase over uppercase ($home over $HOME),
       + * then do normal string comparison.
       + */
       +int
       +runeenvcmp(const void *va, const void *vb)
       +{
       +        Rune *a, *b;
       +        int na, nb;
       +
       +        a = *(Rune**)va;
       +        b = *(Rune**)vb;
       +        na = runestrchr(a, '=') - a;
       +        nb = runestrchr(b, '=') -  b;
       +        if(na < nb)
       +                return -1;
       +        if(nb > na)
       +                return 1;
       +        if(na == 0)
       +                return 0;
       +        if(islowerrune(a[0]) && !islowerrune(b[0]))
       +                return -1;
       +        if(islowerrune(b[0]) && !islowerrune(a[0]))
       +                return 1;
       +        return runestrncmp(a, b, na);
       +}
       +
       +void
       +mkruneenv(void)
       +{
       +        int i, bad, n, nr;
       +        char *p;
       +        Rune *r, *q;
       +
       +        n = 0;
       +        for(i=0; environ[i]; i++){
       +                /*
       +                 * Ignore some pollution.
       +                 */
       +                if(environ[i][0] == '_')
       +                        continue;
       +                if(strncmp(environ[i], "PWD=", 4) == 0)
       +                        continue;
       +                if(strncmp(environ[i], "OLDPWD=", 7) == 0)
       +                        continue;
       +
       +                /*
       +                 * Must be a rooted path.
       +                 */
       +                if((p = strchr(environ[i], '=')) == nil || *(p+1) != '/')
       +                        continue;
       +
       +                /*
       +                 * Only use the ones that we accept in look - all isfilec
       +                 */
       +                bad = 0;
       +                r = bytetorune(environ[i], &nr);
       +                for(q=r; *q != '='; q++)
       +                        if(!isfilec(*q)){
       +                                free(r);
       +                                bad = 1;
       +                                break;
       +                        }
       +                if(!bad){
       +                        runeenv = erealloc(runeenv, (n+1)*sizeof(runeenv[0]));
       +                        runeenv[n++] = r;
       +                }
       +        }
       +        runeenv = erealloc(runeenv, (n+1)*sizeof(runeenv[0]));
       +        runeenv[n] = nil;
       +        qsort(runeenv, n, sizeof(runeenv[0]), runeenvcmp);
       +}
       +
       +int
       +abbrevenv(Rune **rp, uint *np)
       +{
       +        int i, len, alen;
       +        Rune *r, *p, *q;
       +        uint n;
       +
       +        r = *rp;
       +        n = *np;
       +        if(n == 0 || r[0] != '/')
       +                return FALSE;
       +
       +        if(runeenv == nil)
       +                mkruneenv();
       +
       +        for(i=0; runeenv[i]; i++){
       +                p = runestrchr(runeenv[i], '=')+1;
       +                len = runestrlen(p);
       +                if(len <= n && (r[len]==0 || r[len]=='/') && runeeq(r, len, p, len)==TRUE){
       +                        alen = (p-1) - runeenv[i];
       +                        q = runemalloc(1+alen+n-len);
       +                        q[0] = '$';
       +                        runemove(q+1, runeenv[i], alen);
       +                        runemove(q+1+alen, r+len, n-len);
       +                        free(r);
       +                        *rp = q;
       +                        *np = 1+alen+n-len;
       +                        return TRUE;
       +                }
       +        }
       +        return FALSE;
       +}
       +