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