5 * Contains a routine to search a : separated list of
6 * paths (a la CDPATH) and make appropriate file names.
7 * Also contains a routine to simplify .'s and ..'s out of
10 * Larry Bouzane (larry@cs.mun.ca)
13 static char *do_phys_path(XString
*, char *, const char *);
16 * Makes a filename into result using the following algorithm.
18 * - if file starts with '/', append file to result & set cdpathp to NULL
19 * - if file starts with ./ or ../ append cwd and file to result
20 * and set cdpathp to NULL
21 * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx
22 * then cwd is appended to result.
23 * - the first element of cdpathp is appended to result
24 * - file is appended to result
25 * - cdpathp is set to the start of the next element in cdpathp (or NULL
26 * if there are no more elements.
27 * The return value indicates whether a non-null element from cdpathp
28 * was appended to result.
31 make_path(const char *cwd
, const char *file
,
32 char **cdpathp
, /* & of : separated list */
42 char *xp
= Xstring(*xsp
, xp
);
47 if (!ISRELPATH(file
)) {
56 if (ISDIRSEP(c
) || c
== '\0')
63 else if (use_cdpath
) {
66 for (pend
= plist
; *pend
&& *pend
!= PATHSEP
; pend
++)
69 *cdpathp
= *pend
? ++pend
: (char *) 0;
72 if ((use_cdpath
== 0 || !plen
|| ISRELPATH(plist
)) &&
76 XcheckN(*xsp
, xp
, len
);
79 if (!ISDIRSEP(cwd
[len
- 1]))
80 Xput(*xsp
, xp
, DIRSEP
);
82 *phys_pathp
= Xlength(*xsp
, xp
);
83 if (use_cdpath
&& plen
) {
84 XcheckN(*xsp
, xp
, plen
);
85 memcpy(xp
, plist
, plen
);
87 if (!ISDIRSEP(plist
[plen
- 1]))
88 Xput(*xsp
, xp
, DIRSEP
);
93 len
= strlen(file
) + 1;
94 XcheckN(*xsp
, xp
, len
);
95 memcpy(xp
, file
, len
);
98 *cdpathp
= (char *) 0;
104 * Simplify pathnames containing "." and ".." entries.
105 * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
108 simplify_path(char *path
)
114 char *very_start
= path
;
121 if ((isrooted
= ISROOTEDPATH(path
)))
126 * /foo/../../bar /bar
127 * /foo/./blah/.. /foo
131 * foo/../../../bar ../../bar
134 for (cur
= t
= start
= very_start
; ; ) {
135 /* treat multiple '/'s as one '/' */
141 /* convert empty path to dot */
148 if (!t
[1] || ISDIRSEP(t
[1])) {
151 } else if (t
[1] == '.' && (!t
[2] || ISDIRSEP(t
[2]))) {
152 if (!isrooted
&& cur
== start
) {
153 if (cur
!= very_start
)
158 } else if (cur
!= start
)
159 while (--cur
> start
&& !ISDIRSEP(*cur
))
168 if (cur
!= very_start
)
171 /* find/copy next component of pathname */
172 while (*t
&& !ISDIRSEP(*t
))
180 set_current_wd(char *path
)
185 if (!p
&& !(p
= ksh_get_wd((char *) 0, 0)))
190 if (len
> current_wd_size
)
191 current_wd
= aresize(current_wd
, current_wd_size
= len
, APERM
);
192 memcpy(current_wd
, p
, len
);
193 if (p
!= path
&& p
!= null
)
198 get_phys_path(const char *path
)
203 Xinit(xs
, xp
, strlen(path
) + 1, ATEMP
);
205 xp
= do_phys_path(&xs
, xp
, path
);
210 if (Xlength(xs
, xp
) == 0)
211 Xput(xs
, xp
, DIRSEP
);
214 return Xclose(xs
, xp
);
218 do_phys_path(XString
*xsp
, char *xp
, const char *path
)
226 for (p
= path
; p
; p
= q
) {
231 len
= (q
= ksh_strchr_dirsep(p
)) ? q
- p
: strlen(p
);
232 if (len
== 1 && p
[0] == '.')
234 if (len
== 2 && p
[0] == '.' && p
[1] == '.') {
235 while (xp
> Xstring(*xsp
, xp
)) {
243 savepos
= Xsavepos(*xsp
, xp
);
244 Xput(*xsp
, xp
, DIRSEP
);
245 XcheckN(*xsp
, xp
, len
+ 1);
250 llen
= readlink(Xstring(*xsp
, xp
), lbuf
, sizeof(lbuf
) - 1);
252 /* EINVAL means it wasn't a symlink... */
259 /* If absolute path, start from scratch.. */
260 xp
= ISABSPATH(lbuf
) ? Xstring(*xsp
, xp
)
261 : Xrestpos(*xsp
, xp
, savepos
);
262 if (!(xp
= do_phys_path(xsp
, xp
, lbuf
)))
274 char *cp
, cdpath
[256], pwd
[256], file
[256], result
[256];
276 printf("enter CDPATH: "); gets(cdpath
);
277 printf("enter PWD: "); gets(pwd
);
279 if (printf("Enter file: "), gets(file
) == 0)
283 rv
= make_path(pwd
, file
, &cp
, result
, sizeof(result
));
284 printf("make_path returns (%d), \"%s\" ", rv
, result
);
285 simplify_path(result
);
286 printf("(simpifies to \"%s\")\n", result
);