changelog for 0.9
[posh.git] / path.c
blobd52034fe54d276235be96e5264c7050d85fbfe22
1 #include "sh.h"
2 #include "ksh_stat.h"
4 #include "src/compat.h"
6 /*
7 * Contains a routine to search a : separated list of
8 * paths (a la CDPATH) and make appropiate file names.
9 * Also contains a routine to simplify .'s and ..'s out of
10 * a path name.
12 * Larry Bouzane (larry@cs.mun.ca)
16 * $Log: path.c,v $
17 * Revision 1.2 1994/05/19 18:32:40 michael
18 * Merge complete, stdio replaced, various fixes. (pre autoconf)
20 * Revision 1.1 1994/04/06 13:14:03 michael
21 * Initial revision
23 * Revision 4.2 1990/12/06 18:05:24 larry
24 * Updated test code to reflect parameter change.
25 * Fixed problem with /a/./.dir being simplified to /a and not /a/.dir due
26 * to *(cur+2) == *f test instead of the correct cur+2 == f
28 * Revision 4.1 90/10/29 14:42:19 larry
29 * base MUN version
31 * Revision 3.1.0.4 89/02/16 20:28:36 larry
32 * Forgot to set *pathlist to NULL when last changed make_path().
34 * Revision 3.1.0.3 89/02/13 20:29:55 larry
35 * Fixed up cd so that it knew when a node from CDPATH was used and would
36 * print a message only when really necessary.
38 * Revision 3.1.0.2 89/02/13 17:51:22 larry
39 * Merged with Eric Gisin's version.
41 * Revision 3.1.0.1 89/02/13 17:50:58 larry
42 * *** empty log message ***
44 * Revision 3.1 89/02/13 17:49:28 larry
45 * *** empty log message ***
50 * Makes a filename into result using the following algorithm.
51 * - make result NULL
52 * - if file starts with '/', append file to result & set cdpathp to NULL
53 * - if file starts with ./ or ../ append cwd and file to result
54 * and set cdpathp to NULL
55 * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx
56 * then cwd is appended to result.
57 * - the first element of cdpathp is appended to result
58 * - file is appended to result
59 * - cdpathp is set to the start of the next element in cdpathp (or NULL
60 * if there are no more elements.
61 * The return value indicates whether a non-null element from cdpathp
62 * was appened to result.
65 int
66 make_path(cwd, file, cdpathp, xsp, phys_pathp)
67 const char *cwd;
68 const char *file;
69 char **cdpathp; /* & of : separated list */
70 XString *xsp;
71 int *phys_pathp;
73 int rval = 0;
74 int use_cdpath = 1;
75 char *plist;
76 int len;
77 int plen = 0;
78 char *xp = Xstring(*xsp, xp);
80 if (!file)
81 file = null;
83 if (!ISRELPATH(file)) {
84 *phys_pathp = 0;
85 use_cdpath = 0;
86 } else {
87 if (file[0] == '.') {
88 char c = file[1];
90 if (c == '.')
91 c = file[2];
92 if (ISDIRSEP(c) || c == '\0')
93 use_cdpath = 0;
96 plist = *cdpathp;
97 if (!plist)
98 use_cdpath = 0;
99 else if (use_cdpath) {
100 char *pend;
102 for (pend = plist; *pend && *pend != PATHSEP; pend++)
104 plen = pend - plist;
105 *cdpathp = *pend ? ++pend : (char *) 0;
108 if ((use_cdpath == 0 || !plen || ISRELPATH(plist))
109 && (cwd && *cwd))
111 len = strlen(cwd);
112 XcheckN(*xsp, xp, len);
113 memcpy(xp, cwd, len);
114 xp += len;
115 if (!ISDIRSEP(cwd[len - 1]))
116 Xput(*xsp, xp, DIRSEP);
118 *phys_pathp = Xlength(*xsp, xp);
119 if (use_cdpath && plen) {
120 XcheckN(*xsp, xp, plen);
121 memcpy(xp, plist, plen);
122 xp += plen;
123 if (!ISDIRSEP(plist[plen - 1]))
124 Xput(*xsp, xp, DIRSEP);
125 rval = 1;
129 len = strlen(file) + 1;
130 XcheckN(*xsp, xp, len);
131 memcpy(xp, file, len);
133 if (!use_cdpath)
134 *cdpathp = (char *) 0;
136 return rval;
140 * Simplify pathnames containing "." and ".." entries.
141 * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
143 void
144 simplify_path(path)
145 char *path;
147 char *cur;
148 char *t;
149 int isrooted;
150 char *very_start = path;
151 char *start;
153 if (!*path)
154 return;
156 if ((isrooted = ISROOTEDPATH(path)))
157 very_start++;
158 #if defined (OS2) || defined (__CYGWIN__)
159 if (path[0] && path[1] == ':') /* skip a: */
160 very_start += 2;
161 #endif /* OS2 || __CYGWIN__ */
163 /* Before After
164 * /foo/ /foo
165 * /foo/../../bar /bar
166 * /foo/./blah/.. /foo
167 * . .
168 * .. ..
169 * ./foo foo
170 * foo/../../../bar ../../bar
171 * OS2 and CYGWIN:
172 * a:/foo/../.. a:/
173 * a:. a:
174 * a:.. a:..
175 * a:foo/../../blah a:../blah
178 #ifdef __CYGWIN__
179 /* preserve leading double-slash on pathnames (for UNC paths) */
180 if (path[0] && ISDIRSEP(path[0]) && path[1] && ISDIRSEP(path[1]))
181 very_start++;
182 #endif /* __CYGWIN__ */
184 for (cur = t = start = very_start; ; ) {
185 /* treat multiple '/'s as one '/' */
186 while (ISDIRSEP(*t))
187 t++;
189 if (*t == '\0') {
190 if (cur == path)
191 /* convert empty path to dot */
192 *cur++ = '.';
193 *cur = '\0';
194 break;
197 if (t[0] == '.') {
198 if (!t[1] || ISDIRSEP(t[1])) {
199 t += 1;
200 continue;
201 } else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
202 if (!isrooted && cur == start) {
203 if (cur != very_start)
204 *cur++ = DIRSEP;
205 *cur++ = '.';
206 *cur++ = '.';
207 start = cur;
208 } else if (cur != start)
209 while (--cur > start && !ISDIRSEP(*cur))
211 t += 2;
212 continue;
216 if (cur != very_start)
217 *cur++ = DIRSEP;
219 /* find/copy next component of pathname */
220 while (*t && !ISDIRSEP(*t))
221 *cur++ = *t++;
226 void
227 set_current_wd(char *path)
229 int len;
230 char *p = path;
232 if (!p && !(p = get_current_dir_name()))
233 p = NULL;
235 len = strlen(p) + 1;
237 if (len > current_wd_size)
238 current_wd = aresize(current_wd, current_wd_size = len, APERM);
239 memcpy(current_wd, p, len);
240 if (p != path && p != NULL)
241 free(p);
244 #ifdef TEST
246 main(argc, argv)
248 int rv;
249 char *cp, cdpath[256], pwd[256], file[256], result[256];
251 printf("enter CDPATH: "); gets(cdpath);
252 printf("enter PWD: "); gets(pwd);
253 while (1) {
254 if (printf("Enter file: "), gets(file) == 0)
255 return 0;
256 cp = cdpath;
257 do {
258 rv = make_path(pwd, file, &cp, result, sizeof(result));
259 printf("make_path returns (%d), \"%s\" ", rv, result);
260 simplify_path(result);
261 printf("(simpifies to \"%s\")\n", result);
262 } while (cp);
265 #endif /* TEST */