Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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