Don't crash when board size is changed.
[AROS-Contrib.git] / gnu / abc-shell / path.c
blob310d8bb61fd2afffb92b389b88433768c3558628
1 #include <sys/stat.h>
2 #include "sh.h"
4 /*
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
8 * a path name.
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.
17 * - make result NULL
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.
30 int
31 make_path(const char *cwd, const char *file,
32 char **cdpathp, /* & of : separated list */
33 XString *xsp,
34 int *phys_pathp)
37 int rval = 0;
38 int use_cdpath = 1;
39 char *plist;
40 int len;
41 int plen = 0;
42 char *xp = Xstring(*xsp, xp);
44 if (!file)
45 file = null;
47 if (!ISRELPATH(file)) {
48 *phys_pathp = 0;
49 use_cdpath = 0;
50 } else {
51 if (file[0] == '.') {
52 char c = file[1];
54 if (c == '.')
55 c = file[2];
56 if (ISDIRSEP(c) || c == '\0')
57 use_cdpath = 0;
60 plist = *cdpathp;
61 if (!plist)
62 use_cdpath = 0;
63 else if (use_cdpath) {
64 char *pend;
66 for (pend = plist; *pend && *pend != PATHSEP; pend++)
68 plen = pend - plist;
69 *cdpathp = *pend ? ++pend : (char *) 0;
72 if ((use_cdpath == 0 || !plen || ISRELPATH(plist)) &&
73 (cwd && *cwd))
75 len = strlen(cwd);
76 XcheckN(*xsp, xp, len);
77 memcpy(xp, cwd, len);
78 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);
86 xp += plen;
87 if (!ISDIRSEP(plist[plen - 1]))
88 Xput(*xsp, xp, DIRSEP);
89 rval = 1;
93 len = strlen(file) + 1;
94 XcheckN(*xsp, xp, len);
95 memcpy(xp, file, len);
97 if (!use_cdpath)
98 *cdpathp = (char *) 0;
100 return rval;
104 * Simplify pathnames containing "." and ".." entries.
105 * ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
107 void
108 simplify_path(char *path)
110 char *cur;
111 char *t;
112 int isrooted;
114 char *very_start = path;
115 char *start;
118 if (!*path)
119 return;
121 if ((isrooted = ISROOTEDPATH(path)))
122 very_start++;
124 /* Before After
125 * /foo/ /foo
126 * /foo/../../bar /bar
127 * /foo/./blah/.. /foo
128 * . .
129 * .. ..
130 * ./foo foo
131 * foo/../../../bar ../../bar
134 for (cur = t = start = very_start; ; ) {
135 /* treat multiple '/'s as one '/' */
136 while (ISDIRSEP(*t))
137 t++;
139 if (*t == '\0') {
140 if (cur == path)
141 /* convert empty path to dot */
142 *cur++ = '.';
143 *cur = '\0';
144 break;
147 if (t[0] == '.') {
148 if (!t[1] || ISDIRSEP(t[1])) {
149 t += 1;
150 continue;
151 } else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
152 if (!isrooted && cur == start) {
153 if (cur != very_start)
154 *cur++ = DIRSEP;
155 *cur++ = '.';
156 *cur++ = '.';
157 start = cur;
158 } else if (cur != start)
159 while (--cur > start && !ISDIRSEP(*cur))
161 t += 2;
162 continue;
168 if (cur != very_start)
169 *cur++ = DIRSEP;
171 /* find/copy next component of pathname */
172 while (*t && !ISDIRSEP(*t))
173 *cur++ = *t++;
179 void
180 set_current_wd(char *path)
182 int len;
183 char *p = path;
185 if (!p && !(p = ksh_get_wd((char *) 0, 0)))
186 p = null;
188 len = strlen(p) + 1;
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)
194 afree(p, ATEMP);
197 char *
198 get_phys_path(const char *path)
200 XString xs;
201 char *xp;
203 Xinit(xs, xp, strlen(path) + 1, ATEMP);
205 xp = do_phys_path(&xs, xp, path);
207 if (!xp)
208 return (char *) 0;
210 if (Xlength(xs, xp) == 0)
211 Xput(xs, xp, DIRSEP);
212 Xput(xs, xp, '\0');
214 return Xclose(xs, xp);
217 static char *
218 do_phys_path(XString *xsp, char *xp, const char *path)
220 const char *p, *q;
221 int len, llen;
222 int savepos;
223 char lbuf[PATH];
225 Xcheck(*xsp, xp);
226 for (p = path; p; p = q) {
227 while (ISDIRSEP(*p))
228 p++;
229 if (!*p)
230 break;
231 len = (q = ksh_strchr_dirsep(p)) ? q - p : strlen(p);
232 if (len == 1 && p[0] == '.')
233 continue;
234 if (len == 2 && p[0] == '.' && p[1] == '.') {
235 while (xp > Xstring(*xsp, xp)) {
236 xp--;
237 if (ISDIRSEP(*xp))
238 break;
240 continue;
243 savepos = Xsavepos(*xsp, xp);
244 Xput(*xsp, xp, DIRSEP);
245 XcheckN(*xsp, xp, len + 1);
246 memcpy(xp, p, len);
247 xp += len;
248 *xp = '\0';
250 llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
251 if (llen < 0) {
252 /* EINVAL means it wasn't a symlink... */
253 if (errno != EINVAL)
254 return (char *) 0;
255 continue;
257 lbuf[llen] = '\0';
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)))
263 return (char *) 0;
265 return xp;
268 #ifdef TEST
271 main(void)
273 int rv;
274 char *cp, cdpath[256], pwd[256], file[256], result[256];
276 printf("enter CDPATH: "); gets(cdpath);
277 printf("enter PWD: "); gets(pwd);
278 while (1) {
279 if (printf("Enter file: "), gets(file) == 0)
280 return 0;
281 cp = cdpath;
282 do {
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);
287 } while (cp);
290 #endif /* TEST */