xref: /plan9/sys/src/ape/cmd/pdksh/path.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier #include "sh.h"
2*7dd7cddfSDavid du Colombier #include "ksh_stat.h"
3*7dd7cddfSDavid du Colombier 
4*7dd7cddfSDavid du Colombier /*
5*7dd7cddfSDavid du Colombier  *	Contains a routine to search a : separated list of
6*7dd7cddfSDavid du Colombier  *	paths (a la CDPATH) and make appropiate file names.
7*7dd7cddfSDavid du Colombier  *	Also contains a routine to simplify .'s and ..'s out of
8*7dd7cddfSDavid du Colombier  *	a path name.
9*7dd7cddfSDavid du Colombier  *
10*7dd7cddfSDavid du Colombier  *	Larry Bouzane (larry@cs.mun.ca)
11*7dd7cddfSDavid du Colombier  */
12*7dd7cddfSDavid du Colombier 
13*7dd7cddfSDavid du Colombier /*
14*7dd7cddfSDavid du Colombier  * $Log: path.c,v $
15*7dd7cddfSDavid du Colombier  * Revision 1.2  1994/05/19  18:32:40  michael
16*7dd7cddfSDavid du Colombier  * Merge complete, stdio replaced, various fixes. (pre autoconf)
17*7dd7cddfSDavid du Colombier  *
18*7dd7cddfSDavid du Colombier  * Revision 1.1  1994/04/06  13:14:03  michael
19*7dd7cddfSDavid du Colombier  * Initial revision
20*7dd7cddfSDavid du Colombier  *
21*7dd7cddfSDavid du Colombier  * Revision 4.2  1990/12/06  18:05:24  larry
22*7dd7cddfSDavid du Colombier  * Updated test code to reflect parameter change.
23*7dd7cddfSDavid du Colombier  * Fixed problem with /a/./.dir being simplified to /a and not /a/.dir due
24*7dd7cddfSDavid du Colombier  * to *(cur+2) == *f test instead of the correct cur+2 == f
25*7dd7cddfSDavid du Colombier  *
26*7dd7cddfSDavid du Colombier  * Revision 4.1  90/10/29  14:42:19  larry
27*7dd7cddfSDavid du Colombier  * base MUN version
28*7dd7cddfSDavid du Colombier  *
29*7dd7cddfSDavid du Colombier  * Revision 3.1.0.4  89/02/16  20:28:36  larry
30*7dd7cddfSDavid du Colombier  * Forgot to set *pathlist to NULL when last changed make_path().
31*7dd7cddfSDavid du Colombier  *
32*7dd7cddfSDavid du Colombier  * Revision 3.1.0.3  89/02/13  20:29:55  larry
33*7dd7cddfSDavid du Colombier  * Fixed up cd so that it knew when a node from CDPATH was used and would
34*7dd7cddfSDavid du Colombier  * print a message only when really necessary.
35*7dd7cddfSDavid du Colombier  *
36*7dd7cddfSDavid du Colombier  * Revision 3.1.0.2  89/02/13  17:51:22  larry
37*7dd7cddfSDavid du Colombier  * Merged with Eric Gisin's version.
38*7dd7cddfSDavid du Colombier  *
39*7dd7cddfSDavid du Colombier  * Revision 3.1.0.1  89/02/13  17:50:58  larry
40*7dd7cddfSDavid du Colombier  * *** empty log message ***
41*7dd7cddfSDavid du Colombier  *
42*7dd7cddfSDavid du Colombier  * Revision 3.1  89/02/13  17:49:28  larry
43*7dd7cddfSDavid du Colombier  * *** empty log message ***
44*7dd7cddfSDavid du Colombier  *
45*7dd7cddfSDavid du Colombier  */
46*7dd7cddfSDavid du Colombier 
47*7dd7cddfSDavid du Colombier #ifdef S_ISLNK
48*7dd7cddfSDavid du Colombier static char	*do_phys_path ARGS((XString *xsp, char *xp, const char *path));
49*7dd7cddfSDavid du Colombier #endif /* S_ISLNK */
50*7dd7cddfSDavid du Colombier 
51*7dd7cddfSDavid du Colombier /*
52*7dd7cddfSDavid du Colombier  *	Makes a filename into result using the following algorithm.
53*7dd7cddfSDavid du Colombier  *	- make result NULL
54*7dd7cddfSDavid du Colombier  *	- if file starts with '/', append file to result & set cdpathp to NULL
55*7dd7cddfSDavid du Colombier  *	- if file starts with ./ or ../ append cwd and file to result
56*7dd7cddfSDavid du Colombier  *	  and set cdpathp to NULL
57*7dd7cddfSDavid du Colombier  *	- if the first element of cdpathp doesnt start with a '/' xx or '.' xx
58*7dd7cddfSDavid du Colombier  *	  then cwd is appended to result.
59*7dd7cddfSDavid du Colombier  *	- the first element of cdpathp is appended to result
60*7dd7cddfSDavid du Colombier  *	- file is appended to result
61*7dd7cddfSDavid du Colombier  *	- cdpathp is set to the start of the next element in cdpathp (or NULL
62*7dd7cddfSDavid du Colombier  *	  if there are no more elements.
63*7dd7cddfSDavid du Colombier  *	The return value indicates whether a non-null element from cdpathp
64*7dd7cddfSDavid du Colombier  *	was appened to result.
65*7dd7cddfSDavid du Colombier  */
66*7dd7cddfSDavid du Colombier int
make_path(cwd,file,cdpathp,xsp,phys_pathp)67*7dd7cddfSDavid du Colombier make_path(cwd, file, cdpathp, xsp, phys_pathp)
68*7dd7cddfSDavid du Colombier 	const char *cwd;
69*7dd7cddfSDavid du Colombier 	const char *file;
70*7dd7cddfSDavid du Colombier 	char	**cdpathp;	/* & of : separated list */
71*7dd7cddfSDavid du Colombier 	XString	*xsp;
72*7dd7cddfSDavid du Colombier 	int	*phys_pathp;
73*7dd7cddfSDavid du Colombier {
74*7dd7cddfSDavid du Colombier 	int	rval = 0;
75*7dd7cddfSDavid du Colombier 	int	use_cdpath = 1;
76*7dd7cddfSDavid du Colombier 	char	*plist;
77*7dd7cddfSDavid du Colombier 	int	len;
78*7dd7cddfSDavid du Colombier 	int	plen = 0;
79*7dd7cddfSDavid du Colombier 	char	*xp = Xstring(*xsp, xp);
80*7dd7cddfSDavid du Colombier 
81*7dd7cddfSDavid du Colombier 	if (!file)
82*7dd7cddfSDavid du Colombier 		file = null;
83*7dd7cddfSDavid du Colombier 
84*7dd7cddfSDavid du Colombier 	if (!ISRELPATH(file)) {
85*7dd7cddfSDavid du Colombier 		*phys_pathp = 0;
86*7dd7cddfSDavid du Colombier 		use_cdpath = 0;
87*7dd7cddfSDavid du Colombier 	} else {
88*7dd7cddfSDavid du Colombier 		if (file[0] == '.') {
89*7dd7cddfSDavid du Colombier 			char c = file[1];
90*7dd7cddfSDavid du Colombier 
91*7dd7cddfSDavid du Colombier 			if (c == '.')
92*7dd7cddfSDavid du Colombier 				c = file[2];
93*7dd7cddfSDavid du Colombier 			if (ISDIRSEP(c) || c == '\0')
94*7dd7cddfSDavid du Colombier 				use_cdpath = 0;
95*7dd7cddfSDavid du Colombier 		}
96*7dd7cddfSDavid du Colombier 
97*7dd7cddfSDavid du Colombier 		plist = *cdpathp;
98*7dd7cddfSDavid du Colombier 		if (!plist)
99*7dd7cddfSDavid du Colombier 			use_cdpath = 0;
100*7dd7cddfSDavid du Colombier 		else if (use_cdpath) {
101*7dd7cddfSDavid du Colombier 			char *pend;
102*7dd7cddfSDavid du Colombier 
103*7dd7cddfSDavid du Colombier 			for (pend = plist; *pend && *pend != PATHSEP; pend++)
104*7dd7cddfSDavid du Colombier 				;
105*7dd7cddfSDavid du Colombier 			plen = pend - plist;
106*7dd7cddfSDavid du Colombier 			*cdpathp = *pend ? ++pend : (char *) 0;
107*7dd7cddfSDavid du Colombier 		}
108*7dd7cddfSDavid du Colombier 
109*7dd7cddfSDavid du Colombier 		if ((use_cdpath == 0 || !plen || ISRELPATH(plist))
110*7dd7cddfSDavid du Colombier 		    && (cwd && *cwd))
111*7dd7cddfSDavid du Colombier 		{
112*7dd7cddfSDavid du Colombier 			len = strlen(cwd);
113*7dd7cddfSDavid du Colombier 			XcheckN(*xsp, xp, len);
114*7dd7cddfSDavid du Colombier 			memcpy(xp, cwd, len);
115*7dd7cddfSDavid du Colombier 			xp += len;
116*7dd7cddfSDavid du Colombier 			if (!ISDIRSEP(cwd[len - 1]))
117*7dd7cddfSDavid du Colombier 				Xput(*xsp, xp, DIRSEP);
118*7dd7cddfSDavid du Colombier 		}
119*7dd7cddfSDavid du Colombier 		*phys_pathp = Xlength(*xsp, xp);
120*7dd7cddfSDavid du Colombier 		if (use_cdpath && plen) {
121*7dd7cddfSDavid du Colombier 			XcheckN(*xsp, xp, plen);
122*7dd7cddfSDavid du Colombier 			memcpy(xp, plist, plen);
123*7dd7cddfSDavid du Colombier 			xp += plen;
124*7dd7cddfSDavid du Colombier 			if (!ISDIRSEP(plist[plen - 1]))
125*7dd7cddfSDavid du Colombier 				Xput(*xsp, xp, DIRSEP);
126*7dd7cddfSDavid du Colombier 			rval = 1;
127*7dd7cddfSDavid du Colombier 		}
128*7dd7cddfSDavid du Colombier 	}
129*7dd7cddfSDavid du Colombier 
130*7dd7cddfSDavid du Colombier 	len = strlen(file) + 1;
131*7dd7cddfSDavid du Colombier 	XcheckN(*xsp, xp, len);
132*7dd7cddfSDavid du Colombier 	memcpy(xp, file, len);
133*7dd7cddfSDavid du Colombier 
134*7dd7cddfSDavid du Colombier 	if (!use_cdpath)
135*7dd7cddfSDavid du Colombier 		*cdpathp = (char *) 0;
136*7dd7cddfSDavid du Colombier 
137*7dd7cddfSDavid du Colombier 	return rval;
138*7dd7cddfSDavid du Colombier }
139*7dd7cddfSDavid du Colombier 
140*7dd7cddfSDavid du Colombier /*
141*7dd7cddfSDavid du Colombier  * Simplify pathnames containing "." and ".." entries.
142*7dd7cddfSDavid du Colombier  * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
143*7dd7cddfSDavid du Colombier  */
144*7dd7cddfSDavid du Colombier void
simplify_path(path)145*7dd7cddfSDavid du Colombier simplify_path(path)
146*7dd7cddfSDavid du Colombier 	char	*path;
147*7dd7cddfSDavid du Colombier {
148*7dd7cddfSDavid du Colombier 	char	*cur;
149*7dd7cddfSDavid du Colombier 	char	*t;
150*7dd7cddfSDavid du Colombier 	int	isrooted;
151*7dd7cddfSDavid du Colombier 	char	*very_start = path;
152*7dd7cddfSDavid du Colombier 	char	*start;
153*7dd7cddfSDavid du Colombier 
154*7dd7cddfSDavid du Colombier 	if (!*path)
155*7dd7cddfSDavid du Colombier 		return;
156*7dd7cddfSDavid du Colombier 
157*7dd7cddfSDavid du Colombier 	if ((isrooted = ISROOTEDPATH(path)))
158*7dd7cddfSDavid du Colombier 		very_start++;
159*7dd7cddfSDavid du Colombier #if defined (OS2) || defined (__CYGWIN__)
160*7dd7cddfSDavid du Colombier 	if (path[0] && path[1] == ':')	/* skip a: */
161*7dd7cddfSDavid du Colombier 		very_start += 2;
162*7dd7cddfSDavid du Colombier #endif /* OS2 || __CYGWIN__ */
163*7dd7cddfSDavid du Colombier 
164*7dd7cddfSDavid du Colombier 	/* Before			After
165*7dd7cddfSDavid du Colombier 	 *  /foo/			/foo
166*7dd7cddfSDavid du Colombier 	 *  /foo/../../bar		/bar
167*7dd7cddfSDavid du Colombier 	 *  /foo/./blah/..		/foo
168*7dd7cddfSDavid du Colombier 	 *  .				.
169*7dd7cddfSDavid du Colombier 	 *  ..				..
170*7dd7cddfSDavid du Colombier 	 *  ./foo			foo
171*7dd7cddfSDavid du Colombier 	 *  foo/../../../bar		../../bar
172*7dd7cddfSDavid du Colombier 	 * OS2 and CYGWIN:
173*7dd7cddfSDavid du Colombier 	 *  a:/foo/../..		a:/
174*7dd7cddfSDavid du Colombier 	 *  a:.				a:
175*7dd7cddfSDavid du Colombier 	 *  a:..			a:..
176*7dd7cddfSDavid du Colombier 	 *  a:foo/../../blah		a:../blah
177*7dd7cddfSDavid du Colombier 	 */
178*7dd7cddfSDavid du Colombier 
179*7dd7cddfSDavid du Colombier #ifdef __CYGWIN__
180*7dd7cddfSDavid du Colombier        /* preserve leading double-slash on pathnames (for UNC paths) */
181*7dd7cddfSDavid du Colombier        if (path[0] && ISDIRSEP(path[0]) && path[1] && ISDIRSEP(path[1]))
182*7dd7cddfSDavid du Colombier                very_start++;
183*7dd7cddfSDavid du Colombier #endif /* __CYGWIN__ */
184*7dd7cddfSDavid du Colombier 
185*7dd7cddfSDavid du Colombier 	for (cur = t = start = very_start; ; ) {
186*7dd7cddfSDavid du Colombier 		/* treat multiple '/'s as one '/' */
187*7dd7cddfSDavid du Colombier 		while (ISDIRSEP(*t))
188*7dd7cddfSDavid du Colombier 			t++;
189*7dd7cddfSDavid du Colombier 
190*7dd7cddfSDavid du Colombier 		if (*t == '\0') {
191*7dd7cddfSDavid du Colombier 			if (cur == path)
192*7dd7cddfSDavid du Colombier 				/* convert empty path to dot */
193*7dd7cddfSDavid du Colombier 				*cur++ = '.';
194*7dd7cddfSDavid du Colombier 			*cur = '\0';
195*7dd7cddfSDavid du Colombier 			break;
196*7dd7cddfSDavid du Colombier 		}
197*7dd7cddfSDavid du Colombier 
198*7dd7cddfSDavid du Colombier 		if (t[0] == '.') {
199*7dd7cddfSDavid du Colombier 			if (!t[1] || ISDIRSEP(t[1])) {
200*7dd7cddfSDavid du Colombier 				t += 1;
201*7dd7cddfSDavid du Colombier 				continue;
202*7dd7cddfSDavid du Colombier 			} else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
203*7dd7cddfSDavid du Colombier 				if (!isrooted && cur == start) {
204*7dd7cddfSDavid du Colombier 					if (cur != very_start)
205*7dd7cddfSDavid du Colombier 						*cur++ = DIRSEP;
206*7dd7cddfSDavid du Colombier 					*cur++ = '.';
207*7dd7cddfSDavid du Colombier 					*cur++ = '.';
208*7dd7cddfSDavid du Colombier 					start = cur;
209*7dd7cddfSDavid du Colombier 				} else if (cur != start)
210*7dd7cddfSDavid du Colombier 					while (--cur > start && !ISDIRSEP(*cur))
211*7dd7cddfSDavid du Colombier 						;
212*7dd7cddfSDavid du Colombier 				t += 2;
213*7dd7cddfSDavid du Colombier 				continue;
214*7dd7cddfSDavid du Colombier 			}
215*7dd7cddfSDavid du Colombier 		}
216*7dd7cddfSDavid du Colombier 
217*7dd7cddfSDavid du Colombier 		if (cur != very_start)
218*7dd7cddfSDavid du Colombier 			*cur++ = DIRSEP;
219*7dd7cddfSDavid du Colombier 
220*7dd7cddfSDavid du Colombier 		/* find/copy next component of pathname */
221*7dd7cddfSDavid du Colombier 		while (*t && !ISDIRSEP(*t))
222*7dd7cddfSDavid du Colombier 			*cur++ = *t++;
223*7dd7cddfSDavid du Colombier 	}
224*7dd7cddfSDavid du Colombier }
225*7dd7cddfSDavid du Colombier 
226*7dd7cddfSDavid du Colombier 
227*7dd7cddfSDavid du Colombier void
set_current_wd(path)228*7dd7cddfSDavid du Colombier set_current_wd(path)
229*7dd7cddfSDavid du Colombier 	char *path;
230*7dd7cddfSDavid du Colombier {
231*7dd7cddfSDavid du Colombier 	int len;
232*7dd7cddfSDavid du Colombier 	char *p = path;
233*7dd7cddfSDavid du Colombier 
234*7dd7cddfSDavid du Colombier 	if (!p && !(p = ksh_get_wd((char *) 0, 0)))
235*7dd7cddfSDavid du Colombier 		p = null;
236*7dd7cddfSDavid du Colombier 
237*7dd7cddfSDavid du Colombier 	len = strlen(p) + 1;
238*7dd7cddfSDavid du Colombier 
239*7dd7cddfSDavid du Colombier 	if (len > current_wd_size)
240*7dd7cddfSDavid du Colombier 		current_wd = aresize(current_wd, current_wd_size = len, APERM);
241*7dd7cddfSDavid du Colombier 	memcpy(current_wd, p, len);
242*7dd7cddfSDavid du Colombier 	if (p != path && p != null)
243*7dd7cddfSDavid du Colombier 		afree(p, ATEMP);
244*7dd7cddfSDavid du Colombier }
245*7dd7cddfSDavid du Colombier 
246*7dd7cddfSDavid du Colombier #ifdef S_ISLNK
247*7dd7cddfSDavid du Colombier char *
get_phys_path(path)248*7dd7cddfSDavid du Colombier get_phys_path(path)
249*7dd7cddfSDavid du Colombier 	const char *path;
250*7dd7cddfSDavid du Colombier {
251*7dd7cddfSDavid du Colombier 	XString xs;
252*7dd7cddfSDavid du Colombier 	char *xp;
253*7dd7cddfSDavid du Colombier 
254*7dd7cddfSDavid du Colombier 	Xinit(xs, xp, strlen(path) + 1, ATEMP);
255*7dd7cddfSDavid du Colombier 
256*7dd7cddfSDavid du Colombier 	xp = do_phys_path(&xs, xp, path);
257*7dd7cddfSDavid du Colombier 
258*7dd7cddfSDavid du Colombier 	if (!xp)
259*7dd7cddfSDavid du Colombier 		return (char *) 0;
260*7dd7cddfSDavid du Colombier 
261*7dd7cddfSDavid du Colombier 	if (Xlength(xs, xp) == 0)
262*7dd7cddfSDavid du Colombier 		Xput(xs, xp, DIRSEP);
263*7dd7cddfSDavid du Colombier 	Xput(xs, xp, '\0');
264*7dd7cddfSDavid du Colombier 
265*7dd7cddfSDavid du Colombier 	return Xclose(xs, xp);
266*7dd7cddfSDavid du Colombier }
267*7dd7cddfSDavid du Colombier 
268*7dd7cddfSDavid du Colombier static char *
do_phys_path(xsp,xp,path)269*7dd7cddfSDavid du Colombier do_phys_path(xsp, xp, path)
270*7dd7cddfSDavid du Colombier 	XString *xsp;
271*7dd7cddfSDavid du Colombier 	char *xp;
272*7dd7cddfSDavid du Colombier 	const char *path;
273*7dd7cddfSDavid du Colombier {
274*7dd7cddfSDavid du Colombier 	const char *p, *q;
275*7dd7cddfSDavid du Colombier 	int len, llen;
276*7dd7cddfSDavid du Colombier 	int savepos;
277*7dd7cddfSDavid du Colombier 	char lbuf[PATH];
278*7dd7cddfSDavid du Colombier 
279*7dd7cddfSDavid du Colombier 	Xcheck(*xsp, xp);
280*7dd7cddfSDavid du Colombier 	for (p = path; p; p = q) {
281*7dd7cddfSDavid du Colombier 		while (ISDIRSEP(*p))
282*7dd7cddfSDavid du Colombier 			p++;
283*7dd7cddfSDavid du Colombier 		if (!*p)
284*7dd7cddfSDavid du Colombier 			break;
285*7dd7cddfSDavid du Colombier 		len = (q = ksh_strchr_dirsep(p)) ? q - p : strlen(p);
286*7dd7cddfSDavid du Colombier 		if (len == 1 && p[0] == '.')
287*7dd7cddfSDavid du Colombier 			continue;
288*7dd7cddfSDavid du Colombier 		if (len == 2 && p[0] == '.' && p[1] == '.') {
289*7dd7cddfSDavid du Colombier 			while (xp > Xstring(*xsp, xp)) {
290*7dd7cddfSDavid du Colombier 				xp--;
291*7dd7cddfSDavid du Colombier 				if (ISDIRSEP(*xp))
292*7dd7cddfSDavid du Colombier 					break;
293*7dd7cddfSDavid du Colombier 			}
294*7dd7cddfSDavid du Colombier 			continue;
295*7dd7cddfSDavid du Colombier 		}
296*7dd7cddfSDavid du Colombier 
297*7dd7cddfSDavid du Colombier 		savepos = Xsavepos(*xsp, xp);
298*7dd7cddfSDavid du Colombier 		Xput(*xsp, xp, DIRSEP);
299*7dd7cddfSDavid du Colombier 		XcheckN(*xsp, xp, len + 1);
300*7dd7cddfSDavid du Colombier 		memcpy(xp, p, len);
301*7dd7cddfSDavid du Colombier 		xp += len;
302*7dd7cddfSDavid du Colombier 		*xp = '\0';
303*7dd7cddfSDavid du Colombier 
304*7dd7cddfSDavid du Colombier 		llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
305*7dd7cddfSDavid du Colombier 		if (llen < 0) {
306*7dd7cddfSDavid du Colombier 			/* EINVAL means it wasn't a symlink... */
307*7dd7cddfSDavid du Colombier 			if (errno != EINVAL)
308*7dd7cddfSDavid du Colombier 				return (char *) 0;
309*7dd7cddfSDavid du Colombier 			continue;
310*7dd7cddfSDavid du Colombier 		}
311*7dd7cddfSDavid du Colombier 		lbuf[llen] = '\0';
312*7dd7cddfSDavid du Colombier 
313*7dd7cddfSDavid du Colombier 		/* If absolute path, start from scratch.. */
314*7dd7cddfSDavid du Colombier 		xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp)
315*7dd7cddfSDavid du Colombier 				     : Xrestpos(*xsp, xp, savepos);
316*7dd7cddfSDavid du Colombier 		if (!(xp = do_phys_path(xsp, xp, lbuf)))
317*7dd7cddfSDavid du Colombier 			return (char *) 0;
318*7dd7cddfSDavid du Colombier 	}
319*7dd7cddfSDavid du Colombier 	return xp;
320*7dd7cddfSDavid du Colombier }
321*7dd7cddfSDavid du Colombier #endif /* S_ISLNK */
322*7dd7cddfSDavid du Colombier 
323*7dd7cddfSDavid du Colombier #ifdef	TEST
324*7dd7cddfSDavid du Colombier 
main(argc,argv)325*7dd7cddfSDavid du Colombier main(argc, argv)
326*7dd7cddfSDavid du Colombier {
327*7dd7cddfSDavid du Colombier 	int	rv;
328*7dd7cddfSDavid du Colombier 	char	*cp, cdpath[256], pwd[256], file[256], result[256];
329*7dd7cddfSDavid du Colombier 
330*7dd7cddfSDavid du Colombier 	printf("enter CDPATH: "); gets(cdpath);
331*7dd7cddfSDavid du Colombier 	printf("enter PWD: "); gets(pwd);
332*7dd7cddfSDavid du Colombier 	while (1) {
333*7dd7cddfSDavid du Colombier 		if (printf("Enter file: "), gets(file) == 0)
334*7dd7cddfSDavid du Colombier 			return 0;
335*7dd7cddfSDavid du Colombier 		cp = cdpath;
336*7dd7cddfSDavid du Colombier 		do {
337*7dd7cddfSDavid du Colombier 			rv = make_path(pwd, file, &cp, result, sizeof(result));
338*7dd7cddfSDavid du Colombier 			printf("make_path returns (%d), \"%s\" ", rv, result);
339*7dd7cddfSDavid du Colombier 			simplify_path(result);
340*7dd7cddfSDavid du Colombier 			printf("(simpifies to \"%s\")\n", result);
341*7dd7cddfSDavid du Colombier 		} while (cp);
342*7dd7cddfSDavid du Colombier 	}
343*7dd7cddfSDavid du Colombier }
344*7dd7cddfSDavid du Colombier #endif	/* TEST */
345