master hovercats/oakiss / pkg / rc / patch / 0004-keep-PATH-and-path-in-sync.patch
  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