1From bc1444426b57c30af71af6a26fa1674984d414a4 Mon Sep 17 00:00:00 2001
2From: hovercats <hovercatswithlasereyes@protonmail.com>
3Date: Sat, 25 Apr 2026 16:54:31 +0200
4Subject: [PATCH] keep $PATH and $path in sync
5
6---
7 exec.c | 12 ++++----
8 fns.h | 1 +
9 rc.h | 1 +
10 var.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
11 4 files changed, 99 insertions(+), 8 deletions(-)
12
13diff --git a/exec.c b/exec.c
14index ce9872a..987960d 100644
15--- a/exec.c
16+++ b/exec.c
17@@ -265,6 +265,7 @@ main(int argc, char *argv[])
18 Trapinit();
19 Vinit();
20 inttoascii(num, mypid = getpid());
21+ pathinit();
22 setvar("pid", newword(num, (word *)0));
23 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
24 :(word *)0);
25@@ -758,16 +759,15 @@ void
26 Xassign(void)
27 {
28 var *v;
29+ word *w;
30
31- if(count(runq->argv->words)!=1){
32+ w = Poplist();
33+ if(count(w)!=1){
34 Xerror1("= variable name not singleton!");
35 return;
36 }
37- v = vlook(runq->argv->words->word);
38- poplist();
39- freewords(v->val);
40- v->val = Poplist();
41- v->changed = 1;
42+ setvar(w->word, Poplist());
43+ freewords(w);
44 }
45
46 /*
47diff --git a/fns.h b/fns.h
48index 1644d1e..a99f6fa 100644
49--- a/fns.h
50+++ b/fns.h
51@@ -49,6 +49,7 @@ int mapfd(int);
52 int match(char*, char*, int);
53 char* makepath(char*, char*);
54 void panic(char*, int);
55+void pathinit(void);
56 void pfln(io*, char*, int);
57 void poplist(void);
58 void popword(void);
59diff --git a/rc.h b/rc.h
60index a688663..3f48cce 100644
61--- a/rc.h
62+++ b/rc.h
63@@ -117,6 +117,7 @@ struct var{
64 int pc; /* pc of start of function */
65 char fnchanged;
66 char changed;
67+ void (*changefn)(var*);
68 char name[];
69 };
70 var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
71diff --git a/var.c b/var.c
72index 73b01fa..e132a7b 100644
73--- a/var.c
74+++ b/var.c
75@@ -70,6 +70,7 @@ newvar(char *name, var *next)
76 v->fn = 0;
77 v->changed = 0;
78 v->fnchanged = 0;
79+ v->changefn = 0;
80 return v;
81 }
82
83@@ -92,13 +93,21 @@ vlook(char *name)
84 return gvlook(name);
85 }
86
87-void
88-setvar(char *name, word *val)
89+static void
90+setvar_(char *name, word *val, int callfn)
91 {
92 var *v = vlook(name);
93 freewords(v->val);
94 v->val = val;
95 v->changed = 1;
96+ if(callfn && v->changefn)
97+ v->changefn(v);
98+}
99+
100+void
101+setvar(char *name, word *val)
102+{
103+ setvar_(name, val, 1);
104 }
105
106 void
107@@ -107,3 +116,83 @@ freevar(var *v)
108 freewords(v->val);
109 free(v);
110 }
111+
112+static void
113+bigpath(var *v)
114+{
115+ /* convert $PATH to $path */
116+ char *p, *q;
117+ word **l, *w;
118+
119+ if(v->val == 0){
120+ setvar_("path", 0, 0);
121+ return;
122+ }
123+ p = v->val->word;
124+ w = 0;
125+ l = &w;
126+ /*
127+ * Doesn't handle escaped colon nonsense.
128+ */
129+ if(p[0] == 0)
130+ p = 0;
131+ while(p){
132+ q = strchr(p, ':');
133+ if(q)
134+ *q = 0;
135+ *l = newword(p[0] ? p : ".", 0);
136+ l = &(*l)->next;
137+ if(q){
138+ *q = ':';
139+ p = q+1;
140+ }else
141+ p = 0;
142+ }
143+ setvar_("path", w, 0);
144+}
145+
146+static char *
147+list2strcolon(word *words)
148+{
149+ char *value, *s, *t;
150+ int len = 0;
151+ word *ap;
152+ for(ap = words;ap;ap = ap->next)
153+ len+=1+strlen(ap->word);
154+ value = emalloc(len+1);
155+ s = value;
156+ for(ap = words;ap;ap = ap->next){
157+ for(t = ap->word;*t;) *s++=*t++;
158+ *s++=':';
159+ }
160+ if(s==value)
161+ *s='\0';
162+ else s[-1]='\0';
163+ return value;
164+}
165+
166+static void
167+littlepath(var *v)
168+{
169+ /* convert $path to $PATH */
170+ char *p;
171+ word *w;
172+
173+ p = list2strcolon(v->val);
174+ w = new(word);
175+ w->word = p;
176+ w->next = 0;
177+ setvar_("PATH", w, 1); /* 1: recompute $path to expose colon problems */
178+}
179+
180+void
181+pathinit(void)
182+{
183+ var *v;
184+
185+ v = gvlook("path");
186+ v->changefn = littlepath;
187+ v = gvlook("PATH");
188+ v->changefn = bigpath;
189+ bigpath(v);
190+}
191--
1922.49.0
193