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