1 /* $NetBSD: path.c,v 1.7 2005/06/26 19:09:00 christos Exp $ */
5 __RCSID("$NetBSD: path.c,v 1.7 2005/06/26 19:09:00 christos Exp $");
13 * Contains a routine to search a : separated list of
14 * paths (a la CDPATH) and make appropriate file names.
15 * Also contains a routine to simplify .'s and ..'s out of
18 * Larry Bouzane (larry@cs.mun.ca)
22 static char *do_phys_path
ARGS((XString
*, char *, const char *));
26 * Makes a filename into result using the following algorithm.
28 * - if file starts with '/', append file to result & set cdpathp to NULL
29 * - if file starts with ./ or ../ append cwd and file to result
30 * and set cdpathp to NULL
31 * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx
32 * then cwd is appended to result.
33 * - the first element of cdpathp is appended to result
34 * - file is appended to result
35 * - cdpathp is set to the start of the next element in cdpathp (or NULL
36 * if there are no more elements.
37 * The return value indicates whether a non-null element from cdpathp
38 * was appended to result.
41 make_path(cwd
, file
, cdpathp
, xsp
, phys_pathp
)
44 char **cdpathp
; /* & of : separated list */
53 char *xp
= Xstring(*xsp
, xp
);
58 if (!ISRELPATH(file
)) {
67 if (ISDIRSEP(c
) || c
== '\0')
74 else if (use_cdpath
) {
77 for (pend
= plist
; *pend
&& *pend
!= PATHSEP
; pend
++)
80 *cdpathp
= *pend
? ++pend
: (char *) 0;
83 if ((use_cdpath
== 0 || !plen
|| ISRELPATH(plist
))
87 XcheckN(*xsp
, xp
, len
);
90 if (!ISDIRSEP(cwd
[len
- 1]))
91 Xput(*xsp
, xp
, DIRSEP
);
93 *phys_pathp
= Xlength(*xsp
, xp
);
94 if (use_cdpath
&& plen
) {
95 XcheckN(*xsp
, xp
, plen
);
96 memcpy(xp
, plist
, plen
);
98 if (!ISDIRSEP(plist
[plen
- 1]))
99 Xput(*xsp
, xp
, DIRSEP
);
104 len
= strlen(file
) + 1;
105 XcheckN(*xsp
, xp
, len
);
106 memcpy(xp
, file
, len
);
109 *cdpathp
= (char *) 0;
115 * Simplify pathnames containing "." and ".." entries.
116 * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
125 char *very_start
= pathx
;
131 if ((isrooted
= ISROOTEDPATH(pathx
)))
133 #if defined (OS2) || defined (__CYGWIN__)
134 if (pathx
[0] && pathx
[1] == ':') /* skip a: */
136 #endif /* OS2 || __CYGWIN__ */
140 * /foo/../../bar /bar
141 * /foo/./blah/.. /foo
145 * foo/../../../bar ../../bar
150 * a:foo/../../blah a:../blah
154 /* preserve leading double-slash on pathnames (for UNC paths) */
155 if (pathx
[0] && ISDIRSEP(pathx
[0]) && pathx
[1] && ISDIRSEP(pathx
[1]))
157 #endif /* __CYGWIN__ */
159 for (cur
= t
= start
= very_start
; ; ) {
160 /* treat multiple '/'s as one '/' */
166 /* convert empty path to dot */
173 if (!t
[1] || ISDIRSEP(t
[1])) {
176 } else if (t
[1] == '.' && (!t
[2] || ISDIRSEP(t
[2]))) {
177 if (!isrooted
&& cur
== start
) {
178 if (cur
!= very_start
)
183 } else if (cur
!= start
)
184 while (--cur
> start
&& !ISDIRSEP(*cur
))
191 if (cur
!= very_start
)
194 /* find/copy next component of pathname */
195 while (*t
&& !ISDIRSEP(*t
))
202 set_current_wd(pathx
)
208 if (!p
&& !(p
= ksh_get_wd((char *) 0, 0)))
213 if (len
> current_wd_size
)
214 current_wd
= aresize(current_wd
, current_wd_size
= len
, APERM
);
215 memcpy(current_wd
, p
, len
);
216 if (p
!= pathx
&& p
!= null
)
228 Xinit(xs
, xp
, strlen(pathx
) + 1, ATEMP
);
230 xp
= do_phys_path(&xs
, xp
, pathx
);
235 if (Xlength(xs
, xp
) == 0)
236 Xput(xs
, xp
, DIRSEP
);
239 return Xclose(xs
, xp
);
243 do_phys_path(xsp
, xp
, pathx
)
254 for (p
= pathx
; p
; p
= q
) {
259 len
= (q
= ksh_strchr_dirsep(p
)) ? q
- p
: (int)strlen(p
);
260 if (len
== 1 && p
[0] == '.')
262 if (len
== 2 && p
[0] == '.' && p
[1] == '.') {
263 while (xp
> Xstring(*xsp
, xp
)) {
271 savepos
= Xsavepos(*xsp
, xp
);
272 Xput(*xsp
, xp
, DIRSEP
);
273 XcheckN(*xsp
, xp
, len
+ 1);
278 llen
= readlink(Xstring(*xsp
, xp
), lbuf
, sizeof(lbuf
) - 1);
280 /* EINVAL means it wasn't a symlink... */
287 /* If absolute path, start from scratch.. */
288 xp
= ISABSPATH(lbuf
) ? Xstring(*xsp
, xp
)
289 : Xrestpos(*xsp
, xp
, savepos
);
290 if (!(xp
= do_phys_path(xsp
, xp
, lbuf
)))
302 char *cp
, cdpath
[256], pwd
[256], file
[256], result
[256];
304 printf("enter CDPATH: "); gets(cdpath
);
305 printf("enter PWD: "); gets(pwd
);
307 if (printf("Enter file: "), gets(file
) == 0)
311 rv
= make_path(pwd
, file
, &cp
, result
, sizeof(result
));
312 printf("make_path returns (%d), \"%s\" ", rv
, result
);
313 simplify_path(result
);
314 printf("(simpifies to \"%s\")\n", result
);