xref: /dragonfly/contrib/tcsh-6/sh.dir.c (revision d6ab524c)
17d8fb588SMatthias Schmidt /*
27d8fb588SMatthias Schmidt  * sh.dir.c: Directory manipulation functions
37d8fb588SMatthias Schmidt  */
47d8fb588SMatthias Schmidt /*-
57d8fb588SMatthias Schmidt  * Copyright (c) 1980, 1991 The Regents of the University of California.
67d8fb588SMatthias Schmidt  * All rights reserved.
77d8fb588SMatthias Schmidt  *
87d8fb588SMatthias Schmidt  * Redistribution and use in source and binary forms, with or without
97d8fb588SMatthias Schmidt  * modification, are permitted provided that the following conditions
107d8fb588SMatthias Schmidt  * are met:
117d8fb588SMatthias Schmidt  * 1. Redistributions of source code must retain the above copyright
127d8fb588SMatthias Schmidt  *    notice, this list of conditions and the following disclaimer.
137d8fb588SMatthias Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
147d8fb588SMatthias Schmidt  *    notice, this list of conditions and the following disclaimer in the
157d8fb588SMatthias Schmidt  *    documentation and/or other materials provided with the distribution.
167d8fb588SMatthias Schmidt  * 3. Neither the name of the University nor the names of its contributors
177d8fb588SMatthias Schmidt  *    may be used to endorse or promote products derived from this software
187d8fb588SMatthias Schmidt  *    without specific prior written permission.
197d8fb588SMatthias Schmidt  *
207d8fb588SMatthias Schmidt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217d8fb588SMatthias Schmidt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227d8fb588SMatthias Schmidt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237d8fb588SMatthias Schmidt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
247d8fb588SMatthias Schmidt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257d8fb588SMatthias Schmidt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267d8fb588SMatthias Schmidt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277d8fb588SMatthias Schmidt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287d8fb588SMatthias Schmidt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297d8fb588SMatthias Schmidt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307d8fb588SMatthias Schmidt  * SUCH DAMAGE.
317d8fb588SMatthias Schmidt  */
327d8fb588SMatthias Schmidt #include "sh.h"
337d8fb588SMatthias Schmidt #include "ed.h"
347d8fb588SMatthias Schmidt 
357d8fb588SMatthias Schmidt /*
367d8fb588SMatthias Schmidt  * C Shell - directory management
377d8fb588SMatthias Schmidt  */
387d8fb588SMatthias Schmidt 
397d8fb588SMatthias Schmidt static	Char			*agetcwd	(void);
407d8fb588SMatthias Schmidt static	void			 dstart		(const char *);
417d8fb588SMatthias Schmidt static	struct directory	*dfind		(Char *);
4257e3f2b5SSimon 'corecode' Schubert static	Char 			*dfollow	(Char *, int);
437d8fb588SMatthias Schmidt static	void 	 	 	 printdirs	(int);
447d8fb588SMatthias Schmidt static	Char 			*dgoto		(Char *);
457d8fb588SMatthias Schmidt static	void 	 	 	 dnewcwd	(struct directory *, int);
467d8fb588SMatthias Schmidt static	void 	 	 	 dset		(Char *);
477d8fb588SMatthias Schmidt static  void 			 dextract	(struct directory *);
487d8fb588SMatthias Schmidt static  int 			 skipargs	(Char ***, const char *,
497d8fb588SMatthias Schmidt 						 const char *);
507d8fb588SMatthias Schmidt static	void			 dgetstack	(void);
51*d6ab524cSAntonio Huete Jimenez static  Char			*dcanon_internal(Char *, Char *);
527d8fb588SMatthias Schmidt 
537d8fb588SMatthias Schmidt static struct directory dhead INIT_ZERO_STRUCT;		/* "head" of loop */
547d8fb588SMatthias Schmidt static int    printd;			/* force name to be printed */
557d8fb588SMatthias Schmidt 
567d8fb588SMatthias Schmidt int     bequiet = 0;		/* do not print dir stack -strike */
577d8fb588SMatthias Schmidt 
587d8fb588SMatthias Schmidt static Char *
agetcwd(void)597d8fb588SMatthias Schmidt agetcwd(void)
607d8fb588SMatthias Schmidt {
617d8fb588SMatthias Schmidt     char *buf;
627d8fb588SMatthias Schmidt     Char *cwd;
637d8fb588SMatthias Schmidt     size_t len;
647d8fb588SMatthias Schmidt 
657d8fb588SMatthias Schmidt     len = MAXPATHLEN;
667d8fb588SMatthias Schmidt     buf = xmalloc(len);
677d8fb588SMatthias Schmidt     while (getcwd(buf, len) == NULL) {
687d8fb588SMatthias Schmidt 	int err;
697d8fb588SMatthias Schmidt 
707d8fb588SMatthias Schmidt 	err = errno;
717d8fb588SMatthias Schmidt 	if (err != ERANGE) {
727d8fb588SMatthias Schmidt 	    xfree(buf);
737d8fb588SMatthias Schmidt 	    errno = err;
747d8fb588SMatthias Schmidt 	    return NULL;
757d8fb588SMatthias Schmidt 	}
767d8fb588SMatthias Schmidt 	len *= 2;
777d8fb588SMatthias Schmidt 	buf = xrealloc(buf, len);
787d8fb588SMatthias Schmidt     }
797d8fb588SMatthias Schmidt     if (*buf == '\0') {
807d8fb588SMatthias Schmidt 	xfree(buf);
817d8fb588SMatthias Schmidt 	return NULL;
827d8fb588SMatthias Schmidt     }
837d8fb588SMatthias Schmidt     cwd = SAVE(buf);
847d8fb588SMatthias Schmidt     xfree(buf);
857d8fb588SMatthias Schmidt     return cwd;
867d8fb588SMatthias Schmidt }
877d8fb588SMatthias Schmidt 
887d8fb588SMatthias Schmidt static void
dstart(const char * from)897d8fb588SMatthias Schmidt dstart(const char *from)
907d8fb588SMatthias Schmidt {
917d8fb588SMatthias Schmidt     xprintf(CGETS(12, 1, "%s: Trying to start from \"%s\"\n"), progname, from);
927d8fb588SMatthias Schmidt }
937d8fb588SMatthias Schmidt 
947d8fb588SMatthias Schmidt /*
957d8fb588SMatthias Schmidt  * dinit - initialize current working directory
967d8fb588SMatthias Schmidt  */
977d8fb588SMatthias Schmidt void
dinit(Char * hp)987d8fb588SMatthias Schmidt dinit(Char *hp)
997d8fb588SMatthias Schmidt {
1007d8fb588SMatthias Schmidt     Char *cp, *tcp;
1017d8fb588SMatthias Schmidt     struct directory *dp;
1027d8fb588SMatthias Schmidt 
1037d8fb588SMatthias Schmidt     /* Don't believe the login shell home, because it may be a symlink */
1047d8fb588SMatthias Schmidt     tcp = agetcwd();
1057d8fb588SMatthias Schmidt     if (tcp == NULL) {
1067d8fb588SMatthias Schmidt 	xprintf("%s: %s\n", progname, strerror(errno));
1077d8fb588SMatthias Schmidt 	if (hp && *hp) {
1087d8fb588SMatthias Schmidt 	    char *xcp = short2str(hp);
1097d8fb588SMatthias Schmidt 	    dstart(xcp);
1107d8fb588SMatthias Schmidt 	    if (chdir(xcp) == -1)
1117d8fb588SMatthias Schmidt 		cp = NULL;
1127d8fb588SMatthias Schmidt 	    else
1137d8fb588SMatthias Schmidt 		cp = Strsave(hp);
1147d8fb588SMatthias Schmidt 	}
1157d8fb588SMatthias Schmidt 	else
1167d8fb588SMatthias Schmidt 	    cp = NULL;
1177d8fb588SMatthias Schmidt 	if (cp == NULL) {
1187d8fb588SMatthias Schmidt 	    dstart("/");
1197d8fb588SMatthias Schmidt 	    if (chdir("/") == -1)
1207d8fb588SMatthias Schmidt 		/* I am not even try to print an error message! */
1217d8fb588SMatthias Schmidt 		xexit(1);
1227d8fb588SMatthias Schmidt 	    cp = SAVE("/");
1237d8fb588SMatthias Schmidt 	}
1247d8fb588SMatthias Schmidt     }
1257d8fb588SMatthias Schmidt     else {
1267d8fb588SMatthias Schmidt #ifdef S_IFLNK
1277d8fb588SMatthias Schmidt 	struct stat swd, shp;
1287d8fb588SMatthias Schmidt 	int swd_ok;
1297d8fb588SMatthias Schmidt 
1307d8fb588SMatthias Schmidt 	swd_ok = stat(short2str(tcp), &swd) == 0;
1317d8fb588SMatthias Schmidt 	/*
1327d8fb588SMatthias Schmidt 	 * See if $HOME is the working directory we got and use that
1337d8fb588SMatthias Schmidt 	 */
1347d8fb588SMatthias Schmidt 	if (swd_ok && hp && *hp && stat(short2str(hp), &shp) != -1 &&
1357d8fb588SMatthias Schmidt 	    DEV_DEV_COMPARE(swd.st_dev, shp.st_dev)  &&
1367d8fb588SMatthias Schmidt 		swd.st_ino == shp.st_ino)
1377d8fb588SMatthias Schmidt 	    cp = Strsave(hp);
1387d8fb588SMatthias Schmidt 	else {
1397d8fb588SMatthias Schmidt 	    char   *cwd;
1407d8fb588SMatthias Schmidt 
1417d8fb588SMatthias Schmidt 	    /*
1427d8fb588SMatthias Schmidt 	     * use PWD if we have it (for subshells)
1437d8fb588SMatthias Schmidt 	     */
1447d8fb588SMatthias Schmidt 	    if (swd_ok && (cwd = getenv("PWD")) != NULL) {
1457d8fb588SMatthias Schmidt 		if (stat(cwd, &shp) != -1 &&
1467d8fb588SMatthias Schmidt 			DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) &&
1477d8fb588SMatthias Schmidt 		        swd.st_ino == shp.st_ino) {
1487d8fb588SMatthias Schmidt 		    tcp = SAVE(cwd);
1497d8fb588SMatthias Schmidt 		    cleanup_push(tcp, xfree);
1507d8fb588SMatthias Schmidt 		}
1517d8fb588SMatthias Schmidt 	    }
1527d8fb588SMatthias Schmidt 	    cp = dcanon(tcp, STRNULL);
1537d8fb588SMatthias Schmidt 	}
1547d8fb588SMatthias Schmidt #else /* S_IFLNK */
1557d8fb588SMatthias Schmidt 	cp = dcanon(tcp, STRNULL);
1567d8fb588SMatthias Schmidt #endif /* S_IFLNK */
1577d8fb588SMatthias Schmidt     }
1587d8fb588SMatthias Schmidt 
1597d8fb588SMatthias Schmidt     dp = xcalloc(sizeof(struct directory), 1);
1607d8fb588SMatthias Schmidt     dp->di_name = cp;
1617d8fb588SMatthias Schmidt     dp->di_count = 0;
1627d8fb588SMatthias Schmidt     dhead.di_next = dhead.di_prev = dp;
1637d8fb588SMatthias Schmidt     dp->di_next = dp->di_prev = &dhead;
1647d8fb588SMatthias Schmidt     printd = 0;
1657d8fb588SMatthias Schmidt     dnewcwd(dp, 0);
1667d8fb588SMatthias Schmidt     setcopy(STRdirstack, dp->di_name, VAR_READWRITE|VAR_NOGLOB);
1677d8fb588SMatthias Schmidt }
1687d8fb588SMatthias Schmidt 
1697d8fb588SMatthias Schmidt static void
dset(Char * dp)1707d8fb588SMatthias Schmidt dset(Char *dp)
1717d8fb588SMatthias Schmidt {
1727d8fb588SMatthias Schmidt     /*
1737d8fb588SMatthias Schmidt      * Don't call set() directly cause if the directory contains ` or
1747d8fb588SMatthias Schmidt      * other junk characters glob will fail.
1757d8fb588SMatthias Schmidt      */
1767d8fb588SMatthias Schmidt     setcopy(STRowd, varval(STRcwd), VAR_READWRITE|VAR_NOGLOB);
1777d8fb588SMatthias Schmidt     setcopy(STRcwd, dp, VAR_READWRITE|VAR_NOGLOB);
1787d8fb588SMatthias Schmidt     tsetenv(STRPWD, dp);
1797d8fb588SMatthias Schmidt }
1807d8fb588SMatthias Schmidt 
1817d8fb588SMatthias Schmidt #define DIR_PRINT	0x01	/* -p */
1827d8fb588SMatthias Schmidt #define DIR_LONG  	0x02	/* -l */
1837d8fb588SMatthias Schmidt #define DIR_VERT  	0x04	/* -v */
1847d8fb588SMatthias Schmidt #define DIR_LINE  	0x08	/* -n */
1857d8fb588SMatthias Schmidt #define DIR_SAVE 	0x10	/* -S */
1867d8fb588SMatthias Schmidt #define DIR_LOAD	0x20	/* -L */
1877d8fb588SMatthias Schmidt #define DIR_CLEAR	0x40	/* -c */
1887d8fb588SMatthias Schmidt #define DIR_OLD	  	0x80	/* - */
1897d8fb588SMatthias Schmidt 
1907d8fb588SMatthias Schmidt static int
skipargs(Char *** v,const char * dstr,const char * str)1917d8fb588SMatthias Schmidt skipargs(Char ***v, const char *dstr, const char *str)
1927d8fb588SMatthias Schmidt {
1937d8fb588SMatthias Schmidt     Char  **n = *v, *s;
1947d8fb588SMatthias Schmidt 
1957d8fb588SMatthias Schmidt     int dflag = 0, loop = 1;
1967d8fb588SMatthias Schmidt     for (n++; loop && *n != NULL && (*n)[0] == '-'; n++)
1977d8fb588SMatthias Schmidt 	if (*(s = &((*n)[1])) == '\0')	/* test for bare "-" argument */
1987d8fb588SMatthias Schmidt 	    dflag |= DIR_OLD;
19994afa86dSJohn Marino 	else if ((*n)[1] == '-' && (*n)[2] == '\0') {   /* test for -- */
20094afa86dSJohn Marino 	    n++;
20194afa86dSJohn Marino 	    break;
20294afa86dSJohn Marino 	} else {
2037d8fb588SMatthias Schmidt 	    char *p;
20494afa86dSJohn Marino 	    while (*s != '\0')	/* examine flags */ {
2057d8fb588SMatthias Schmidt 		if ((p = strchr(dstr, *s++)) != NULL)
2067d8fb588SMatthias Schmidt 		    dflag |= (1 << (p - dstr));
2077d8fb588SMatthias Schmidt 	        else
2087d8fb588SMatthias Schmidt 		    stderror(ERR_DIRUS, short2str(**v), dstr, str);
2097d8fb588SMatthias Schmidt 	    }
2107d8fb588SMatthias Schmidt 	}
2117d8fb588SMatthias Schmidt     if (*n && (dflag & DIR_OLD))
2127d8fb588SMatthias Schmidt 	stderror(ERR_DIRUS, short2str(**v), dstr, str);
2137d8fb588SMatthias Schmidt     *v = n;
2147d8fb588SMatthias Schmidt     /* make -l, -v, and -n imply -p */
2157d8fb588SMatthias Schmidt     if (dflag & (DIR_LONG|DIR_VERT|DIR_LINE))
2167d8fb588SMatthias Schmidt 	dflag |= DIR_PRINT;
2177d8fb588SMatthias Schmidt     return dflag;
2187d8fb588SMatthias Schmidt }
2197d8fb588SMatthias Schmidt 
2207d8fb588SMatthias Schmidt /*
2217d8fb588SMatthias Schmidt  * dodirs - list all directories in directory loop
2227d8fb588SMatthias Schmidt  */
2237d8fb588SMatthias Schmidt /*ARGSUSED*/
2247d8fb588SMatthias Schmidt void
dodirs(Char ** v,struct command * c)2257d8fb588SMatthias Schmidt dodirs(Char **v, struct command *c)
2267d8fb588SMatthias Schmidt {
2277d8fb588SMatthias Schmidt     static const char flags[] = "plvnSLc";
2287d8fb588SMatthias Schmidt     int dflag = skipargs(&v, flags, "");
2297d8fb588SMatthias Schmidt 
2307d8fb588SMatthias Schmidt     USE(c);
2317d8fb588SMatthias Schmidt     if ((dflag & DIR_CLEAR) != 0) {
2327d8fb588SMatthias Schmidt 	struct directory *dp, *fdp;
2337d8fb588SMatthias Schmidt 	for (dp = dcwd->di_next; dp != dcwd; ) {
2347d8fb588SMatthias Schmidt 	    fdp = dp;
2357d8fb588SMatthias Schmidt 	    dp = dp->di_next;
2367d8fb588SMatthias Schmidt 	    if (fdp != &dhead)
2377d8fb588SMatthias Schmidt 		dfree(fdp);
2387d8fb588SMatthias Schmidt 	}
2397d8fb588SMatthias Schmidt 	dhead.di_next = dhead.di_prev = dp;
2407d8fb588SMatthias Schmidt 	dp->di_next = dp->di_prev = &dhead;
2417d8fb588SMatthias Schmidt     }
2427d8fb588SMatthias Schmidt     if ((dflag & DIR_LOAD) != 0)
2437d8fb588SMatthias Schmidt 	loaddirs(*v);
2447d8fb588SMatthias Schmidt     else if ((dflag & DIR_SAVE) != 0)
2457d8fb588SMatthias Schmidt 	recdirs(*v, 1);
2467d8fb588SMatthias Schmidt 
2477d8fb588SMatthias Schmidt     if (*v && (dflag & (DIR_SAVE|DIR_LOAD)))
2487d8fb588SMatthias Schmidt 	v++;
2497d8fb588SMatthias Schmidt 
2507d8fb588SMatthias Schmidt     if (*v != NULL || (dflag & DIR_OLD))
2517d8fb588SMatthias Schmidt 	stderror(ERR_DIRUS, "dirs", flags, "");
2527d8fb588SMatthias Schmidt     if ((dflag & (DIR_CLEAR|DIR_LOAD|DIR_SAVE)) == 0 || (dflag & DIR_PRINT))
2537d8fb588SMatthias Schmidt 	printdirs(dflag);
2547d8fb588SMatthias Schmidt }
2557d8fb588SMatthias Schmidt 
2567d8fb588SMatthias Schmidt static void
printdirs(int dflag)2577d8fb588SMatthias Schmidt printdirs(int dflag)
2587d8fb588SMatthias Schmidt {
2597d8fb588SMatthias Schmidt     struct directory *dp;
2607d8fb588SMatthias Schmidt     Char   *s, *user;
2617d8fb588SMatthias Schmidt     int     idx, len, cur;
2627d8fb588SMatthias Schmidt 
2637d8fb588SMatthias Schmidt     dp = dcwd;
2647d8fb588SMatthias Schmidt     idx = 0;
2657d8fb588SMatthias Schmidt     cur = 0;
2667d8fb588SMatthias Schmidt     do {
2677d8fb588SMatthias Schmidt 	if (dp == &dhead)
2687d8fb588SMatthias Schmidt 	    continue;
2697d8fb588SMatthias Schmidt 	if (dflag & DIR_VERT) {
2707d8fb588SMatthias Schmidt 	    xprintf("%d\t", idx++);
2717d8fb588SMatthias Schmidt 	    cur = 0;
2727d8fb588SMatthias Schmidt 	}
2737d8fb588SMatthias Schmidt 	s = dp->di_name;
2747d8fb588SMatthias Schmidt 	user = NULL;
2757d8fb588SMatthias Schmidt 	if (!(dflag & DIR_LONG) && (user = getusername(&s)) != NULL)
2767d8fb588SMatthias Schmidt 	    len = (int) (Strlen(user) + Strlen(s) + 2);
2777d8fb588SMatthias Schmidt 	else
2787d8fb588SMatthias Schmidt 	    len = (int) (Strlen(s) + 1);
2797d8fb588SMatthias Schmidt 
2807d8fb588SMatthias Schmidt 	cur += len;
2817d8fb588SMatthias Schmidt 	if ((dflag & DIR_LINE) && cur >= TermH - 1 && len < TermH) {
2827d8fb588SMatthias Schmidt 	    xputchar('\n');
2837d8fb588SMatthias Schmidt 	    cur = len;
2847d8fb588SMatthias Schmidt 	}
2857d8fb588SMatthias Schmidt 	if (user)
286*d6ab524cSAntonio Huete Jimenez 	    xprintf("~%" TCSH_S, user);
287*d6ab524cSAntonio Huete Jimenez 	xprintf("%-" TCSH_S "%c", s, (dflag & DIR_VERT) ? '\n' : ' ');
2887d8fb588SMatthias Schmidt     } while ((dp = dp->di_prev) != dcwd);
2897d8fb588SMatthias Schmidt     if (!(dflag & DIR_VERT))
2907d8fb588SMatthias Schmidt 	xputchar('\n');
2917d8fb588SMatthias Schmidt }
2927d8fb588SMatthias Schmidt 
2937d8fb588SMatthias Schmidt void
dtildepr(Char * dir)2947d8fb588SMatthias Schmidt dtildepr(Char *dir)
2957d8fb588SMatthias Schmidt {
2967d8fb588SMatthias Schmidt     Char* user;
2977d8fb588SMatthias Schmidt     if ((user = getusername(&dir)) != NULL)
298*d6ab524cSAntonio Huete Jimenez 	xprintf("~%-" TCSH_S "%" TCSH_S, user, dir);
2997d8fb588SMatthias Schmidt     else
300*d6ab524cSAntonio Huete Jimenez 	xprintf("%" TCSH_S, dir);
3017d8fb588SMatthias Schmidt }
3027d8fb588SMatthias Schmidt 
3037d8fb588SMatthias Schmidt void
dtilde(void)3047d8fb588SMatthias Schmidt dtilde(void)
3057d8fb588SMatthias Schmidt {
3067d8fb588SMatthias Schmidt     struct directory *d = dcwd;
3077d8fb588SMatthias Schmidt 
3087d8fb588SMatthias Schmidt     do {
3097d8fb588SMatthias Schmidt 	if (d == &dhead)
3107d8fb588SMatthias Schmidt 	    continue;
311*d6ab524cSAntonio Huete Jimenez 	d->di_name = dcanon_internal(d->di_name, STRNULL);
3127d8fb588SMatthias Schmidt     } while ((d = d->di_prev) != dcwd);
3137d8fb588SMatthias Schmidt 
3147d8fb588SMatthias Schmidt     dset(dcwd->di_name);
3157d8fb588SMatthias Schmidt }
3167d8fb588SMatthias Schmidt 
3177d8fb588SMatthias Schmidt 
3187d8fb588SMatthias Schmidt /* dnormalize():
3197d8fb588SMatthias Schmidt  *	The path will be normalized if it
3207d8fb588SMatthias Schmidt  *	1) is "..",
3217d8fb588SMatthias Schmidt  *	2) or starts with "../",
3227d8fb588SMatthias Schmidt  *	3) or ends with "/..",
3237d8fb588SMatthias Schmidt  *	4) or contains the string "/../",
3247d8fb588SMatthias Schmidt  *	then it will be normalized, unless those strings are quoted.
3257d8fb588SMatthias Schmidt  *	Otherwise, a copy is made and sent back.
3267d8fb588SMatthias Schmidt  */
3277d8fb588SMatthias Schmidt Char   *
dnormalize(const Char * cp,int expnd)3287d8fb588SMatthias Schmidt dnormalize(const Char *cp, int expnd)
3297d8fb588SMatthias Schmidt {
3307d8fb588SMatthias Schmidt 
3317d8fb588SMatthias Schmidt /* return true if dp is of the form "../xxx" or "/../xxx" */
3327d8fb588SMatthias Schmidt #define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))
3337d8fb588SMatthias Schmidt #define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))
3347d8fb588SMatthias Schmidt 
3357d8fb588SMatthias Schmidt #ifdef S_IFLNK
3367d8fb588SMatthias Schmidt     if (expnd) {
3377d8fb588SMatthias Schmidt 	struct Strbuf buf = Strbuf_INIT;
3387d8fb588SMatthias Schmidt  	int     dotdot = 0;
3397d8fb588SMatthias Schmidt 	Char   *dp, *cwd;
3407d8fb588SMatthias Schmidt 	const Char *start = cp;
3417d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
3427d8fb588SMatthias Schmidt 	int slashslash;
3437d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
3447d8fb588SMatthias Schmidt 
3457d8fb588SMatthias Schmidt 	/*
3467d8fb588SMatthias Schmidt 	 * count the number of "../xxx" or "xxx/../xxx" in the path
3477d8fb588SMatthias Schmidt 	 */
3487d8fb588SMatthias Schmidt 	for ( ; *cp && *(cp + 1); cp++)
3497d8fb588SMatthias Schmidt 	    if (IS_DOTDOT(start, cp))
3507d8fb588SMatthias Schmidt 	        dotdot++;
3517d8fb588SMatthias Schmidt 
3527d8fb588SMatthias Schmidt 	/*
3537d8fb588SMatthias Schmidt 	 * if none, we are done.
3547d8fb588SMatthias Schmidt 	 */
3557d8fb588SMatthias Schmidt         if (dotdot == 0)
3567d8fb588SMatthias Schmidt 	    return (Strsave(start));
3577d8fb588SMatthias Schmidt 
3587d8fb588SMatthias Schmidt # ifdef notdef
3597d8fb588SMatthias Schmidt 	struct stat sb;
3607d8fb588SMatthias Schmidt 	/*
3617d8fb588SMatthias Schmidt 	 * We disable this test because:
3627d8fb588SMatthias Schmidt 	 * cd /tmp; mkdir dir1 dir2; cd dir2; ln -s /tmp/dir1; cd dir1;
3637d8fb588SMatthias Schmidt 	 * echo ../../dir1 does not expand. We had enabled this before
3647d8fb588SMatthias Schmidt 	 * because it was bothering people with expansions in compilation
3657d8fb588SMatthias Schmidt 	 * lines like -I../../foo. Maybe we need some kind of finer grain
3667d8fb588SMatthias Schmidt 	 * control?
3677d8fb588SMatthias Schmidt 	 *
3687d8fb588SMatthias Schmidt 	 * If the path doesn't exist, we are done too.
3697d8fb588SMatthias Schmidt 	 */
3707d8fb588SMatthias Schmidt 	if (lstat(short2str(start), &sb) != 0 && errno == ENOENT)
3717d8fb588SMatthias Schmidt 	    return (Strsave(start));
3727d8fb588SMatthias Schmidt # endif
3737d8fb588SMatthias Schmidt 
3747d8fb588SMatthias Schmidt 	cwd = xmalloc((Strlen(dcwd->di_name) + 3) * sizeof(Char));
3757d8fb588SMatthias Schmidt 	(void) Strcpy(cwd, dcwd->di_name);
3767d8fb588SMatthias Schmidt 
3777d8fb588SMatthias Schmidt 	/*
3787d8fb588SMatthias Schmidt 	 * If the path starts with a slash, we are not relative to
3797d8fb588SMatthias Schmidt 	 * the current working directory.
3807d8fb588SMatthias Schmidt 	 */
3817d8fb588SMatthias Schmidt 	if (ABSOLUTEP(start))
3827d8fb588SMatthias Schmidt 	    *cwd = '\0';
3837d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
3847d8fb588SMatthias Schmidt 	slashslash = cwd[0] == '/' && cwd[1] == '/';
3857d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
3867d8fb588SMatthias Schmidt 
3877d8fb588SMatthias Schmidt 	/*
3887d8fb588SMatthias Schmidt 	 * Ignore . and count ..'s
3897d8fb588SMatthias Schmidt 	 */
3907d8fb588SMatthias Schmidt 	cp = start;
3917d8fb588SMatthias Schmidt 	do {
3927d8fb588SMatthias Schmidt 	    dotdot = 0;
3937d8fb588SMatthias Schmidt 	    buf.len = 0;
3947d8fb588SMatthias Schmidt 	    while (*cp)
3957d8fb588SMatthias Schmidt 	        if (IS_DOT(start, cp)) {
3967d8fb588SMatthias Schmidt 	            if (*++cp)
3977d8fb588SMatthias Schmidt 	                cp++;
3987d8fb588SMatthias Schmidt 	        }
3997d8fb588SMatthias Schmidt 	        else if (IS_DOTDOT(start, cp)) {
4007d8fb588SMatthias Schmidt 		    if (buf.len != 0)
4017d8fb588SMatthias Schmidt 		        break; /* finish analyzing .././../xxx/[..] */
4027d8fb588SMatthias Schmidt 		    dotdot++;
4037d8fb588SMatthias Schmidt 		    cp += 2;
4047d8fb588SMatthias Schmidt 		    if (*cp)
4057d8fb588SMatthias Schmidt 		        cp++;
4067d8fb588SMatthias Schmidt 	        }
4077d8fb588SMatthias Schmidt 	        else
4087d8fb588SMatthias Schmidt 		    Strbuf_append1(&buf, *cp++);
4097d8fb588SMatthias Schmidt 
4107d8fb588SMatthias Schmidt 	    Strbuf_terminate(&buf);
4117d8fb588SMatthias Schmidt 	    while (dotdot > 0)
4127d8fb588SMatthias Schmidt 	        if ((dp = Strrchr(cwd, '/')) != NULL) {
4137d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
4147d8fb588SMatthias Schmidt 		    if (dp == &cwd[1])
4157d8fb588SMatthias Schmidt 		        slashslash = 1;
4167d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
4177d8fb588SMatthias Schmidt 		        *dp = '\0';
4187d8fb588SMatthias Schmidt 		        dotdot--;
4197d8fb588SMatthias Schmidt 	        }
4207d8fb588SMatthias Schmidt 	        else
4217d8fb588SMatthias Schmidt 		    break;
4227d8fb588SMatthias Schmidt 
4237d8fb588SMatthias Schmidt 	    if (!*cwd) {	/* too many ..'s, starts with "/" */
4247d8fb588SMatthias Schmidt 	        cwd[0] = '/';
4257d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
4267d8fb588SMatthias Schmidt 		/*
4277d8fb588SMatthias Schmidt 		 * Only append another slash, if already the former cwd
4287d8fb588SMatthias Schmidt 		 * was in a double-slash path.
4297d8fb588SMatthias Schmidt 		 */
4307d8fb588SMatthias Schmidt 		cwd[1] = slashslash ? '/' : '\0';
4317d8fb588SMatthias Schmidt 		cwd[2] = '\0';
4327d8fb588SMatthias Schmidt # else /* !HAVE_SLASHSLASH */
4337d8fb588SMatthias Schmidt 		cwd[1] = '\0';
4347d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
4357d8fb588SMatthias Schmidt 	    }
4367d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
4377d8fb588SMatthias Schmidt 	    else if (slashslash && cwd[1] == '\0') {
4387d8fb588SMatthias Schmidt 		cwd[1] = '/';
4397d8fb588SMatthias Schmidt 		cwd[2] = '\0';
4407d8fb588SMatthias Schmidt 	    }
4417d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
4427d8fb588SMatthias Schmidt 
4437d8fb588SMatthias Schmidt 	    if (buf.len != 0) {
4447d8fb588SMatthias Schmidt 		size_t i;
4457d8fb588SMatthias Schmidt 
4467d8fb588SMatthias Schmidt 		i = Strlen(cwd);
4477d8fb588SMatthias Schmidt 		if (TRM(cwd[i - 1]) != '/') {
4487d8fb588SMatthias Schmidt 		    cwd[i++] = '/';
4497d8fb588SMatthias Schmidt 		    cwd[i] = '\0';
4507d8fb588SMatthias Schmidt 		}
4517d8fb588SMatthias Schmidt 	        dp = Strspl(cwd, TRM(buf.s[0]) == '/' ? &buf.s[1] : buf.s);
4527d8fb588SMatthias Schmidt 	        xfree(cwd);
4537d8fb588SMatthias Schmidt 	        cwd = dp;
4547d8fb588SMatthias Schmidt 		i = Strlen(cwd) - 1;
4557d8fb588SMatthias Schmidt 	        if (TRM(cwd[i]) == '/')
4567d8fb588SMatthias Schmidt 		    cwd[i] = '\0';
4577d8fb588SMatthias Schmidt 	    }
4587d8fb588SMatthias Schmidt 	    /* Reduction of ".." following the stuff we collected in buf
4597d8fb588SMatthias Schmidt 	     * only makes sense if the directory item in buf really exists.
4607d8fb588SMatthias Schmidt 	     * Avoid reduction of "-I../.." (typical compiler call) to ""
4617d8fb588SMatthias Schmidt 	     * or "/usr/nonexistant/../bin" to "/usr/bin":
4627d8fb588SMatthias Schmidt 	     */
4637d8fb588SMatthias Schmidt 	    if (cwd[0]) {
4647d8fb588SMatthias Schmidt 	        struct stat exists;
4657d8fb588SMatthias Schmidt 		if (0 != stat(short2str(cwd), &exists)) {
4667d8fb588SMatthias Schmidt 		    xfree(buf.s);
4677d8fb588SMatthias Schmidt 		    xfree(cwd);
4687d8fb588SMatthias Schmidt 		    return Strsave(start);
4697d8fb588SMatthias Schmidt 		}
4707d8fb588SMatthias Schmidt 	    }
4717d8fb588SMatthias Schmidt 	} while (*cp != '\0');
4727d8fb588SMatthias Schmidt 	xfree(buf.s);
4737d8fb588SMatthias Schmidt 	return cwd;
4747d8fb588SMatthias Schmidt     }
4757d8fb588SMatthias Schmidt #endif /* S_IFLNK */
4767d8fb588SMatthias Schmidt     return Strsave(cp);
4777d8fb588SMatthias Schmidt }
4787d8fb588SMatthias Schmidt 
4797d8fb588SMatthias Schmidt 
4807d8fb588SMatthias Schmidt /*
4817d8fb588SMatthias Schmidt  * dochngd - implement chdir command.
4827d8fb588SMatthias Schmidt  */
4837d8fb588SMatthias Schmidt /*ARGSUSED*/
4847d8fb588SMatthias Schmidt void
dochngd(Char ** v,struct command * c)4857d8fb588SMatthias Schmidt dochngd(Char **v, struct command *c)
4867d8fb588SMatthias Schmidt {
4877d8fb588SMatthias Schmidt     Char *cp;
4887d8fb588SMatthias Schmidt     struct directory *dp;
4897d8fb588SMatthias Schmidt     int dflag = skipargs(&v, "plvn", "[-|<dir>]");
4907d8fb588SMatthias Schmidt 
4917d8fb588SMatthias Schmidt     USE(c);
4927d8fb588SMatthias Schmidt     printd = 0;
4937d8fb588SMatthias Schmidt     cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
4947d8fb588SMatthias Schmidt 
4957d8fb588SMatthias Schmidt     if (cp == NULL) {
49660962bbcSJohn Marino 	if (!cdtohome)
49760962bbcSJohn Marino 	    stderror(ERR_NAME | ERR_TOOFEW);
49860962bbcSJohn Marino 	else if ((cp = varval(STRhome)) == STRNULL || *cp == 0)
4997d8fb588SMatthias Schmidt 	    stderror(ERR_NAME | ERR_NOHOMEDIR);
5007d8fb588SMatthias Schmidt 	if (chdir(short2str(cp)) < 0)
5017d8fb588SMatthias Schmidt 	    stderror(ERR_NAME | ERR_CANTCHANGE);
5027d8fb588SMatthias Schmidt 	cp = Strsave(cp);
5037d8fb588SMatthias Schmidt     }
5047d8fb588SMatthias Schmidt     else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
5057d8fb588SMatthias Schmidt 	stderror(ERR_NAME | ERR_TOOMANY);
5067d8fb588SMatthias Schmidt 	/* NOTREACHED */
5077d8fb588SMatthias Schmidt 	return;
5087d8fb588SMatthias Schmidt     }
5097d8fb588SMatthias Schmidt     else if ((dp = dfind(cp)) != 0) {
5107d8fb588SMatthias Schmidt 	char   *tmp;
5117d8fb588SMatthias Schmidt 
5127d8fb588SMatthias Schmidt 	printd = 1;
5137d8fb588SMatthias Schmidt 	if (chdir(tmp = short2str(dp->di_name)) < 0)
5147d8fb588SMatthias Schmidt 	    stderror(ERR_SYSTEM, tmp, strerror(errno));
5157d8fb588SMatthias Schmidt 	dcwd->di_prev->di_next = dcwd->di_next;
5167d8fb588SMatthias Schmidt 	dcwd->di_next->di_prev = dcwd->di_prev;
5177d8fb588SMatthias Schmidt 	dfree(dcwd);
5187d8fb588SMatthias Schmidt 	dnewcwd(dp, dflag);
5197d8fb588SMatthias Schmidt 	return;
5207d8fb588SMatthias Schmidt     }
5217d8fb588SMatthias Schmidt     else
52257e3f2b5SSimon 'corecode' Schubert 	if ((cp = dfollow(cp, dflag & DIR_OLD)) == NULL)
5237d8fb588SMatthias Schmidt 	    return;
5247d8fb588SMatthias Schmidt     dp = xcalloc(sizeof(struct directory), 1);
5257d8fb588SMatthias Schmidt     dp->di_name = cp;
5267d8fb588SMatthias Schmidt     dp->di_count = 0;
5277d8fb588SMatthias Schmidt     dp->di_next = dcwd->di_next;
5287d8fb588SMatthias Schmidt     dp->di_prev = dcwd->di_prev;
5297d8fb588SMatthias Schmidt     dp->di_prev->di_next = dp;
5307d8fb588SMatthias Schmidt     dp->di_next->di_prev = dp;
5317d8fb588SMatthias Schmidt     dfree(dcwd);
5327d8fb588SMatthias Schmidt     dnewcwd(dp, dflag);
5337d8fb588SMatthias Schmidt }
5347d8fb588SMatthias Schmidt 
5357d8fb588SMatthias Schmidt static Char *
dgoto(Char * cp)5367d8fb588SMatthias Schmidt dgoto(Char *cp)
5377d8fb588SMatthias Schmidt {
5387d8fb588SMatthias Schmidt     Char *dp, *ret;
5397d8fb588SMatthias Schmidt 
5407d8fb588SMatthias Schmidt     if (!ABSOLUTEP(cp))
5417d8fb588SMatthias Schmidt     {
5427d8fb588SMatthias Schmidt 	Char *p, *q;
5437d8fb588SMatthias Schmidt 	size_t cwdlen;
5447d8fb588SMatthias Schmidt 
5457d8fb588SMatthias Schmidt 	cwdlen = Strlen(dcwd->di_name);
5467d8fb588SMatthias Schmidt 	if (cwdlen == 1)	/* root */
5477d8fb588SMatthias Schmidt 	    cwdlen = 0;
5487d8fb588SMatthias Schmidt 	dp = xmalloc((cwdlen + Strlen(cp) + 2) * sizeof(Char));
5497d8fb588SMatthias Schmidt 	for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
5507d8fb588SMatthias Schmidt 	    continue;
5517d8fb588SMatthias Schmidt 	if (cwdlen)
5527d8fb588SMatthias Schmidt 	    p[-1] = '/';
5537d8fb588SMatthias Schmidt 	else
5547d8fb588SMatthias Schmidt 	    p--;		/* don't add a / after root */
5557d8fb588SMatthias Schmidt 	Strcpy(p, cp);
5567d8fb588SMatthias Schmidt 	xfree(cp);
5577d8fb588SMatthias Schmidt 	cp = dp;
5587d8fb588SMatthias Schmidt 	dp += cwdlen;
5597d8fb588SMatthias Schmidt     }
5607d8fb588SMatthias Schmidt     else
5617d8fb588SMatthias Schmidt 	dp = cp;
5627d8fb588SMatthias Schmidt 
5637d8fb588SMatthias Schmidt #if defined(WINNT_NATIVE)
5647d8fb588SMatthias Schmidt     return agetcwd();
5657d8fb588SMatthias Schmidt #elif defined(__CYGWIN__)
5667d8fb588SMatthias Schmidt     if (ABSOLUTEP(cp) && cp[1] == ':') { /* Only DOS paths are treated that way */
5677d8fb588SMatthias Schmidt 	return agetcwd();
5687d8fb588SMatthias Schmidt     } else {
5697d8fb588SMatthias Schmidt     	ret = dcanon(cp, dp);
5707d8fb588SMatthias Schmidt     }
5717d8fb588SMatthias Schmidt #else /* !WINNT_NATIVE */
5727d8fb588SMatthias Schmidt     ret = dcanon(cp, dp);
5737d8fb588SMatthias Schmidt #endif /* WINNT_NATIVE */
5747d8fb588SMatthias Schmidt     return ret;
5757d8fb588SMatthias Schmidt }
5767d8fb588SMatthias Schmidt 
5777d8fb588SMatthias Schmidt /*
5787d8fb588SMatthias Schmidt  * dfollow - change to arg directory; fall back on cdpath if not valid
5797d8fb588SMatthias Schmidt  */
5807d8fb588SMatthias Schmidt static Char *
dfollow(Char * cp,int old)58157e3f2b5SSimon 'corecode' Schubert dfollow(Char *cp, int old)
5827d8fb588SMatthias Schmidt {
5837d8fb588SMatthias Schmidt     Char *dp;
5847d8fb588SMatthias Schmidt     struct varent *c;
5857d8fb588SMatthias Schmidt     int serrno;
5867d8fb588SMatthias Schmidt 
58757e3f2b5SSimon 'corecode' Schubert     cp = old ? Strsave(cp) : globone(cp, G_ERROR);
5887d8fb588SMatthias Schmidt     cleanup_push(cp, xfree);
5897d8fb588SMatthias Schmidt #ifdef apollo
5907d8fb588SMatthias Schmidt     if (Strchr(cp, '`')) {
5917d8fb588SMatthias Schmidt 	char *dptr;
5927d8fb588SMatthias Schmidt 	if (chdir(dptr = short2str(cp)) < 0)
5937d8fb588SMatthias Schmidt 	    stderror(ERR_SYSTEM, dptr, strerror(errno));
5947d8fb588SMatthias Schmidt 	dp = agetcwd();
5957d8fb588SMatthias Schmidt 	cleanup_push(dp, xfree);
5967d8fb588SMatthias Schmidt 	if (dp != NULL) {
5977d8fb588SMatthias Schmidt 	    cleanup_until(cp);
5987d8fb588SMatthias Schmidt 	    return dgoto(dp);
5997d8fb588SMatthias Schmidt 	}
6007d8fb588SMatthias Schmidt 	else
6017d8fb588SMatthias Schmidt 	    stderror(ERR_SYSTEM, dptr, strerror(errno));
6027d8fb588SMatthias Schmidt     }
6037d8fb588SMatthias Schmidt #endif /* apollo */
6047d8fb588SMatthias Schmidt 
6057d8fb588SMatthias Schmidt     /*
6067d8fb588SMatthias Schmidt      * if we are ignoring symlinks, try to fix relatives now.
6077d8fb588SMatthias Schmidt      * if we are expading symlinks, it should be done by now.
6087d8fb588SMatthias Schmidt      */
6097d8fb588SMatthias Schmidt     dp = dnormalize(cp, symlinks == SYM_IGNORE);
6107d8fb588SMatthias Schmidt     if (chdir(short2str(dp)) >= 0) {
6117d8fb588SMatthias Schmidt         cleanup_until(cp);
6127d8fb588SMatthias Schmidt         return dgoto(dp);
6137d8fb588SMatthias Schmidt     }
6147d8fb588SMatthias Schmidt     else {
6157d8fb588SMatthias Schmidt         xfree(dp);
6167d8fb588SMatthias Schmidt         if (chdir(short2str(cp)) >= 0) {
6177d8fb588SMatthias Schmidt 	    cleanup_ignore(cp);
6187d8fb588SMatthias Schmidt 	    cleanup_until(cp);
6197d8fb588SMatthias Schmidt 	    return dgoto(cp);
6207d8fb588SMatthias Schmidt 	}
6217d8fb588SMatthias Schmidt 	else if (errno != ENOENT && errno != ENOTDIR) {
6227d8fb588SMatthias Schmidt 	    int err;
6237d8fb588SMatthias Schmidt 
6247d8fb588SMatthias Schmidt 	    err = errno;
6257d8fb588SMatthias Schmidt 	    stderror(ERR_SYSTEM, short2str(cp), strerror(err));
6267d8fb588SMatthias Schmidt 	}
6277d8fb588SMatthias Schmidt 	serrno = errno;
6287d8fb588SMatthias Schmidt     }
6297d8fb588SMatthias Schmidt 
6307d8fb588SMatthias Schmidt     if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
6317d8fb588SMatthias Schmidt 	&& (c = adrof(STRcdpath)) && c->vec != NULL) {
6327d8fb588SMatthias Schmidt 	struct Strbuf buf = Strbuf_INIT;
6337d8fb588SMatthias Schmidt 	Char  **cdp;
6347d8fb588SMatthias Schmidt 
6357d8fb588SMatthias Schmidt 	for (cdp = c->vec; *cdp; cdp++) {
63694afa86dSJohn Marino 	    size_t len = Strlen(*cdp);
6377d8fb588SMatthias Schmidt 	    buf.len = 0;
63894afa86dSJohn Marino 	    if (len > 0) {
6397d8fb588SMatthias Schmidt 		Strbuf_append(&buf, *cdp);
64094afa86dSJohn Marino 		if ((*cdp)[len - 1] != '/')
6417d8fb588SMatthias Schmidt 		    Strbuf_append1(&buf, '/');
64294afa86dSJohn Marino 	    }
6437d8fb588SMatthias Schmidt 	    Strbuf_append(&buf, cp);
6447d8fb588SMatthias Schmidt 	    Strbuf_terminate(&buf);
6457d8fb588SMatthias Schmidt 	    /*
6467d8fb588SMatthias Schmidt 	     * We always want to fix the directory here
6477d8fb588SMatthias Schmidt 	     * If we are normalizing symlinks
6487d8fb588SMatthias Schmidt 	     */
6497d8fb588SMatthias Schmidt 	    dp = dnormalize(buf.s, symlinks == SYM_IGNORE ||
6507d8fb588SMatthias Schmidt 				   symlinks == SYM_EXPAND);
6517d8fb588SMatthias Schmidt 	    if (chdir(short2str(dp)) >= 0) {
6527d8fb588SMatthias Schmidt 		printd = 1;
6537d8fb588SMatthias Schmidt 		xfree(buf.s);
6547d8fb588SMatthias Schmidt 		cleanup_until(cp);
6557d8fb588SMatthias Schmidt 		return dgoto(dp);
6567d8fb588SMatthias Schmidt 	    }
6577d8fb588SMatthias Schmidt 	    else if (chdir(short2str(cp)) >= 0) {
6587d8fb588SMatthias Schmidt 		printd = 1;
6597d8fb588SMatthias Schmidt 		xfree(dp);
6607d8fb588SMatthias Schmidt 		xfree(buf.s);
6617d8fb588SMatthias Schmidt 		cleanup_ignore(cp);
6627d8fb588SMatthias Schmidt 		cleanup_until(cp);
6637d8fb588SMatthias Schmidt 		return dgoto(cp);
6647d8fb588SMatthias Schmidt 	    }
665653fab9eSSascha Wildner 	    xfree(dp);
6667d8fb588SMatthias Schmidt 	}
6677d8fb588SMatthias Schmidt 	xfree(buf.s);
6687d8fb588SMatthias Schmidt     }
6697d8fb588SMatthias Schmidt     dp = varval(cp);
6707d8fb588SMatthias Schmidt     if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
6717d8fb588SMatthias Schmidt 	cleanup_until(cp);
6727d8fb588SMatthias Schmidt 	cp = Strsave(dp);
6737d8fb588SMatthias Schmidt 	printd = 1;
6747d8fb588SMatthias Schmidt 	return dgoto(cp);
6757d8fb588SMatthias Schmidt     }
6767d8fb588SMatthias Schmidt     /*
6777d8fb588SMatthias Schmidt      * on login source of ~/.cshdirs, errors are eaten. the dir stack is all
6787d8fb588SMatthias Schmidt      * directories we could get to.
6797d8fb588SMatthias Schmidt      */
6807d8fb588SMatthias Schmidt     if (!bequiet)
6817d8fb588SMatthias Schmidt 	stderror(ERR_SYSTEM, short2str(cp), strerror(serrno));
6827d8fb588SMatthias Schmidt     cleanup_until(cp);
6837d8fb588SMatthias Schmidt     return (NULL);
6847d8fb588SMatthias Schmidt }
6857d8fb588SMatthias Schmidt 
6867d8fb588SMatthias Schmidt 
6877d8fb588SMatthias Schmidt /*
6887d8fb588SMatthias Schmidt  * dopushd - push new directory onto directory stack.
6897d8fb588SMatthias Schmidt  *	with no arguments exchange top and second.
6907d8fb588SMatthias Schmidt  *	with numeric argument (+n) bring it to top.
6917d8fb588SMatthias Schmidt  */
6927d8fb588SMatthias Schmidt /*ARGSUSED*/
6937d8fb588SMatthias Schmidt void
dopushd(Char ** v,struct command * c)6947d8fb588SMatthias Schmidt dopushd(Char **v, struct command *c)
6957d8fb588SMatthias Schmidt {
6967d8fb588SMatthias Schmidt     struct directory *dp;
6977d8fb588SMatthias Schmidt     Char *cp;
6987d8fb588SMatthias Schmidt     int dflag = skipargs(&v, "plvn", " [-|<dir>|+<n>]");
6997d8fb588SMatthias Schmidt 
7007d8fb588SMatthias Schmidt     USE(c);
7017d8fb588SMatthias Schmidt     printd = 1;
7027d8fb588SMatthias Schmidt     cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
7037d8fb588SMatthias Schmidt 
7047d8fb588SMatthias Schmidt     if (cp == NULL) {
7057d8fb588SMatthias Schmidt 	if (adrof(STRpushdtohome)) {
7067d8fb588SMatthias Schmidt 	    if ((cp = varval(STRhome)) == STRNULL || *cp == 0)
7077d8fb588SMatthias Schmidt 		stderror(ERR_NAME | ERR_NOHOMEDIR);
7087d8fb588SMatthias Schmidt 	    if (chdir(short2str(cp)) < 0)
7097d8fb588SMatthias Schmidt 		stderror(ERR_NAME | ERR_CANTCHANGE);
71057e3f2b5SSimon 'corecode' Schubert 	    if ((cp = dfollow(cp, dflag & DIR_OLD)) == NULL)
7117d8fb588SMatthias Schmidt 		return;
7127d8fb588SMatthias Schmidt 	    dp = xcalloc(sizeof(struct directory), 1);
7137d8fb588SMatthias Schmidt 	    dp->di_name = cp;
7147d8fb588SMatthias Schmidt 	    dp->di_count = 0;
7157d8fb588SMatthias Schmidt 	    dp->di_prev = dcwd;
7167d8fb588SMatthias Schmidt 	    dp->di_next = dcwd->di_next;
7177d8fb588SMatthias Schmidt 	    dcwd->di_next = dp;
7187d8fb588SMatthias Schmidt 	    dp->di_next->di_prev = dp;
7197d8fb588SMatthias Schmidt 	}
7207d8fb588SMatthias Schmidt 	else {
7217d8fb588SMatthias Schmidt 	    char   *tmp;
7227d8fb588SMatthias Schmidt 
7237d8fb588SMatthias Schmidt 	    if ((dp = dcwd->di_prev) == &dhead)
7247d8fb588SMatthias Schmidt 		dp = dhead.di_prev;
7257d8fb588SMatthias Schmidt 	    if (dp == dcwd)
7267d8fb588SMatthias Schmidt 		stderror(ERR_NAME | ERR_NODIR);
7277d8fb588SMatthias Schmidt 	    if (chdir(tmp = short2str(dp->di_name)) < 0)
7287d8fb588SMatthias Schmidt 		stderror(ERR_SYSTEM, tmp, strerror(errno));
7297d8fb588SMatthias Schmidt 	    dp->di_prev->di_next = dp->di_next;
7307d8fb588SMatthias Schmidt 	    dp->di_next->di_prev = dp->di_prev;
7317d8fb588SMatthias Schmidt 	    dp->di_next = dcwd->di_next;
7327d8fb588SMatthias Schmidt 	    dp->di_prev = dcwd;
7337d8fb588SMatthias Schmidt 	    dcwd->di_next->di_prev = dp;
7347d8fb588SMatthias Schmidt 	    dcwd->di_next = dp;
7357d8fb588SMatthias Schmidt 	}
7367d8fb588SMatthias Schmidt     }
7377d8fb588SMatthias Schmidt     else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
7387d8fb588SMatthias Schmidt 	stderror(ERR_NAME | ERR_TOOMANY);
7397d8fb588SMatthias Schmidt 	/* NOTREACHED */
7407d8fb588SMatthias Schmidt 	return;
7417d8fb588SMatthias Schmidt     }
7427d8fb588SMatthias Schmidt     else if ((dp = dfind(cp)) != NULL) {
7437d8fb588SMatthias Schmidt 	char   *tmp;
7447d8fb588SMatthias Schmidt 
7457d8fb588SMatthias Schmidt 	if (chdir(tmp = short2str(dp->di_name)) < 0)
7467d8fb588SMatthias Schmidt 	    stderror(ERR_SYSTEM, tmp, strerror(errno));
7477d8fb588SMatthias Schmidt 	/*
7487d8fb588SMatthias Schmidt 	 * kfk - 10 Feb 1984 - added new "extraction style" pushd +n
7497d8fb588SMatthias Schmidt 	 */
7507d8fb588SMatthias Schmidt 	if (adrof(STRdextract))
7517d8fb588SMatthias Schmidt 	    dextract(dp);
7527d8fb588SMatthias Schmidt     }
7537d8fb588SMatthias Schmidt     else {
7547d8fb588SMatthias Schmidt 	Char *ccp;
7557d8fb588SMatthias Schmidt 
75657e3f2b5SSimon 'corecode' Schubert 	if ((ccp = dfollow(cp, dflag & DIR_OLD)) == NULL)
7577d8fb588SMatthias Schmidt 	    return;
7587d8fb588SMatthias Schmidt 	dp = xcalloc(sizeof(struct directory), 1);
7597d8fb588SMatthias Schmidt 	dp->di_name = ccp;
7607d8fb588SMatthias Schmidt 	dp->di_count = 0;
7617d8fb588SMatthias Schmidt 	dp->di_prev = dcwd;
7627d8fb588SMatthias Schmidt 	dp->di_next = dcwd->di_next;
7637d8fb588SMatthias Schmidt 	dcwd->di_next = dp;
7647d8fb588SMatthias Schmidt 	dp->di_next->di_prev = dp;
7657d8fb588SMatthias Schmidt     }
7667d8fb588SMatthias Schmidt     dnewcwd(dp, dflag);
7677d8fb588SMatthias Schmidt }
7687d8fb588SMatthias Schmidt 
7697d8fb588SMatthias Schmidt /*
7707d8fb588SMatthias Schmidt  * dfind - find a directory if specified by numeric (+n) argument
7717d8fb588SMatthias Schmidt  */
7727d8fb588SMatthias Schmidt static struct directory *
dfind(Char * cp)7737d8fb588SMatthias Schmidt dfind(Char *cp)
7747d8fb588SMatthias Schmidt {
7757d8fb588SMatthias Schmidt     struct directory *dp;
7767d8fb588SMatthias Schmidt     int i;
7777d8fb588SMatthias Schmidt     Char *ep;
7787d8fb588SMatthias Schmidt 
7797d8fb588SMatthias Schmidt     if (*cp++ != '+')
7807d8fb588SMatthias Schmidt 	return (0);
7817d8fb588SMatthias Schmidt     for (ep = cp; Isdigit(*ep); ep++)
7827d8fb588SMatthias Schmidt 	continue;
7837d8fb588SMatthias Schmidt     if (*ep)
7847d8fb588SMatthias Schmidt 	return (0);
7857d8fb588SMatthias Schmidt     i = getn(cp);
7867d8fb588SMatthias Schmidt     if (i <= 0)
7877d8fb588SMatthias Schmidt 	return (0);
7887d8fb588SMatthias Schmidt     for (dp = dcwd; i != 0; i--) {
7897d8fb588SMatthias Schmidt 	if ((dp = dp->di_prev) == &dhead)
7907d8fb588SMatthias Schmidt 	    dp = dp->di_prev;
7917d8fb588SMatthias Schmidt 	if (dp == dcwd)
7927d8fb588SMatthias Schmidt 	    stderror(ERR_NAME | ERR_DEEP);
7937d8fb588SMatthias Schmidt     }
7947d8fb588SMatthias Schmidt     return (dp);
7957d8fb588SMatthias Schmidt }
7967d8fb588SMatthias Schmidt 
7977d8fb588SMatthias Schmidt /*
7987d8fb588SMatthias Schmidt  * dopopd - pop a directory out of the directory stack
7997d8fb588SMatthias Schmidt  *	with a numeric argument just discard it.
8007d8fb588SMatthias Schmidt  */
8017d8fb588SMatthias Schmidt /*ARGSUSED*/
8027d8fb588SMatthias Schmidt void
dopopd(Char ** v,struct command * c)8037d8fb588SMatthias Schmidt dopopd(Char **v, struct command *c)
8047d8fb588SMatthias Schmidt {
8057d8fb588SMatthias Schmidt     Char *cp;
8067d8fb588SMatthias Schmidt     struct directory *dp, *p = NULL;
8077d8fb588SMatthias Schmidt     int dflag = skipargs(&v, "plvn", " [-|+<n>]");
8087d8fb588SMatthias Schmidt 
8097d8fb588SMatthias Schmidt     USE(c);
8107d8fb588SMatthias Schmidt     printd = 1;
8117d8fb588SMatthias Schmidt     cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
8127d8fb588SMatthias Schmidt 
8137d8fb588SMatthias Schmidt     if (cp == NULL)
8147d8fb588SMatthias Schmidt 	dp = dcwd;
8157d8fb588SMatthias Schmidt     else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
8167d8fb588SMatthias Schmidt 	stderror(ERR_NAME | ERR_TOOMANY);
8177d8fb588SMatthias Schmidt 	/* NOTREACHED */
8187d8fb588SMatthias Schmidt 	return;
8197d8fb588SMatthias Schmidt     }
8207d8fb588SMatthias Schmidt     else if ((dp = dfind(cp)) == 0)
8217d8fb588SMatthias Schmidt 	stderror(ERR_NAME | ERR_BADDIR);
8227d8fb588SMatthias Schmidt     if (dp->di_prev == &dhead && dp->di_next == &dhead)
8237d8fb588SMatthias Schmidt 	stderror(ERR_NAME | ERR_EMPTY);
8247d8fb588SMatthias Schmidt     if (dp == dcwd) {
8257d8fb588SMatthias Schmidt 	char   *tmp;
8267d8fb588SMatthias Schmidt 
8277d8fb588SMatthias Schmidt 	if ((p = dp->di_prev) == &dhead)
8287d8fb588SMatthias Schmidt 	    p = dhead.di_prev;
8297d8fb588SMatthias Schmidt 	if (chdir(tmp = short2str(p->di_name)) < 0)
8307d8fb588SMatthias Schmidt 	    stderror(ERR_SYSTEM, tmp, strerror(errno));
8317d8fb588SMatthias Schmidt     }
8327d8fb588SMatthias Schmidt     dp->di_prev->di_next = dp->di_next;
8337d8fb588SMatthias Schmidt     dp->di_next->di_prev = dp->di_prev;
8347d8fb588SMatthias Schmidt     dfree(dp);
8357d8fb588SMatthias Schmidt     if (dp == dcwd) {
8367d8fb588SMatthias Schmidt         dnewcwd(p, dflag);
8377d8fb588SMatthias Schmidt     }
8387d8fb588SMatthias Schmidt     else {
8397d8fb588SMatthias Schmidt 	printdirs(dflag);
8407d8fb588SMatthias Schmidt     }
8417d8fb588SMatthias Schmidt }
8427d8fb588SMatthias Schmidt 
8437d8fb588SMatthias Schmidt /*
8447d8fb588SMatthias Schmidt  * dfree - free the directory (or keep it if it still has ref count)
8457d8fb588SMatthias Schmidt  */
8467d8fb588SMatthias Schmidt void
dfree(struct directory * dp)8477d8fb588SMatthias Schmidt dfree(struct directory *dp)
8487d8fb588SMatthias Schmidt {
8497d8fb588SMatthias Schmidt 
8507d8fb588SMatthias Schmidt     if (dp->di_count != 0) {
8517d8fb588SMatthias Schmidt 	dp->di_next = dp->di_prev = 0;
8527d8fb588SMatthias Schmidt     }
8537d8fb588SMatthias Schmidt     else {
8547d8fb588SMatthias Schmidt 	xfree(dp->di_name);
8557d8fb588SMatthias Schmidt 	xfree(dp);
8567d8fb588SMatthias Schmidt     }
8577d8fb588SMatthias Schmidt }
8587d8fb588SMatthias Schmidt 
8597d8fb588SMatthias Schmidt /*
860*d6ab524cSAntonio Huete Jimenez  * dcanon - a safe version of dcanon_internal that arranges for cleanup
8617d8fb588SMatthias Schmidt  */
8627d8fb588SMatthias Schmidt Char *
dcanon(Char * cp,Char * p)8637d8fb588SMatthias Schmidt dcanon(Char *cp, Char *p)
8647d8fb588SMatthias Schmidt {
865*d6ab524cSAntonio Huete Jimenez     cleanup_push(cp, xfree);
866*d6ab524cSAntonio Huete Jimenez     p = dcanon_internal(cp, p);
867*d6ab524cSAntonio Huete Jimenez     // coverity[use_after_free] we use the pointer as a marker
868*d6ab524cSAntonio Huete Jimenez     cleanup_ignore(cp);
869*d6ab524cSAntonio Huete Jimenez     cleanup_until(cp);
870*d6ab524cSAntonio Huete Jimenez     return p;
871*d6ab524cSAntonio Huete Jimenez }
872*d6ab524cSAntonio Huete Jimenez 
873*d6ab524cSAntonio Huete Jimenez /*
874*d6ab524cSAntonio Huete Jimenez  * dcanon_internal - canonicalize the pathname, removing excess ./ and ../ etc.
875*d6ab524cSAntonio Huete Jimenez  *	we are of course assuming that the file system is standardly
876*d6ab524cSAntonio Huete Jimenez  *	constructed (always have ..'s, directories have links)
877*d6ab524cSAntonio Huete Jimenez  */
878*d6ab524cSAntonio Huete Jimenez static Char *
dcanon_internal(Char * cp,Char * p)879*d6ab524cSAntonio Huete Jimenez dcanon_internal(Char *cp, Char *p)
880*d6ab524cSAntonio Huete Jimenez {
8817d8fb588SMatthias Schmidt     Char *sp;
8827d8fb588SMatthias Schmidt     Char *p1, *p2;	/* general purpose */
8837d8fb588SMatthias Schmidt     int    slash;
8847d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
8857d8fb588SMatthias Schmidt     int    slashslash;
8867d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
8877d8fb588SMatthias Schmidt     size_t  clen;
8887d8fb588SMatthias Schmidt 
8897d8fb588SMatthias Schmidt #ifdef S_IFLNK			/* if we have symlinks */
8907d8fb588SMatthias Schmidt     Char *mlink, *newcp;
8917d8fb588SMatthias Schmidt     char *tlink;
8927d8fb588SMatthias Schmidt     size_t cc;
8937d8fb588SMatthias Schmidt #endif /* S_IFLNK */
8947d8fb588SMatthias Schmidt 
8957d8fb588SMatthias Schmidt     clen = Strlen(cp);
8967d8fb588SMatthias Schmidt 
8977d8fb588SMatthias Schmidt     /*
8987d8fb588SMatthias Schmidt      * christos: if the path given does not start with a slash prepend cwd. If
8997d8fb588SMatthias Schmidt      * cwd does not start with a slash or the result would be too long try to
9007d8fb588SMatthias Schmidt      * correct it.
9017d8fb588SMatthias Schmidt      */
9027d8fb588SMatthias Schmidt     if (!ABSOLUTEP(cp)) {
9037d8fb588SMatthias Schmidt 	Char *tmpdir;
9047d8fb588SMatthias Schmidt 	size_t	len;
9057d8fb588SMatthias Schmidt 
9067d8fb588SMatthias Schmidt 	p1 = varval(STRcwd);
9077d8fb588SMatthias Schmidt 	if (p1 == STRNULL || !ABSOLUTEP(p1)) {
9087d8fb588SMatthias Schmidt 	    Char *new_cwd = agetcwd();
9097d8fb588SMatthias Schmidt 
9107d8fb588SMatthias Schmidt 	    if (new_cwd == NULL) {
9117d8fb588SMatthias Schmidt 		xprintf("%s: %s\n", progname, strerror(errno));
9127d8fb588SMatthias Schmidt 		setcopy(STRcwd, str2short("/"), VAR_READWRITE|VAR_NOGLOB);
9137d8fb588SMatthias Schmidt 	    }
9147d8fb588SMatthias Schmidt 	    else
9157d8fb588SMatthias Schmidt 		setv(STRcwd, new_cwd, VAR_READWRITE|VAR_NOGLOB);
9167d8fb588SMatthias Schmidt 	    p1 = varval(STRcwd);
9177d8fb588SMatthias Schmidt 	}
9187d8fb588SMatthias Schmidt 	len = Strlen(p1);
9197d8fb588SMatthias Schmidt 	tmpdir = xmalloc((len + clen + 2) * sizeof (*tmpdir));
9207d8fb588SMatthias Schmidt 	(void) Strcpy(tmpdir, p1);
9217d8fb588SMatthias Schmidt 	(void) Strcat(tmpdir, STRslash);
9227d8fb588SMatthias Schmidt 	(void) Strcat(tmpdir, cp);
9237d8fb588SMatthias Schmidt 	xfree(cp);
9247d8fb588SMatthias Schmidt 	cp = p = tmpdir;
9257d8fb588SMatthias Schmidt     }
9267d8fb588SMatthias Schmidt 
9277d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
9287d8fb588SMatthias Schmidt     slashslash = (cp[0] == '/' && cp[1] == '/');
9297d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
9307d8fb588SMatthias Schmidt 
9317d8fb588SMatthias Schmidt     while (*p) {		/* for each component */
9327d8fb588SMatthias Schmidt 	sp = p;			/* save slash address */
9337d8fb588SMatthias Schmidt 	while (*++p == '/')	/* flush extra slashes */
9347d8fb588SMatthias Schmidt 	    continue;
9357d8fb588SMatthias Schmidt 	if (p != ++sp)
9367d8fb588SMatthias Schmidt 	    for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
9377d8fb588SMatthias Schmidt 		continue;
9387d8fb588SMatthias Schmidt 	p = sp;			/* save start of component */
9397d8fb588SMatthias Schmidt 	slash = 0;
9407d8fb588SMatthias Schmidt 	if (*p)
9417d8fb588SMatthias Schmidt 	    while (*++p)	/* find next slash or end of path */
9427d8fb588SMatthias Schmidt 		if (*p == '/') {
9437d8fb588SMatthias Schmidt 		    slash = 1;
9447d8fb588SMatthias Schmidt 		    *p = 0;
9457d8fb588SMatthias Schmidt 		    break;
9467d8fb588SMatthias Schmidt 		}
9477d8fb588SMatthias Schmidt 
9487d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
9497d8fb588SMatthias Schmidt 	if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0')
9507d8fb588SMatthias Schmidt 	    slashslash = 1;
9517d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
9527d8fb588SMatthias Schmidt 	if (*sp == '\0') {	/* if component is null */
9537d8fb588SMatthias Schmidt 	    if (--sp == cp)	/* if path is one char (i.e. /) */
9547d8fb588SMatthias Schmidt 		break;
9557d8fb588SMatthias Schmidt 	    else
9567d8fb588SMatthias Schmidt 		*sp = '\0';
9577d8fb588SMatthias Schmidt 	}
9587d8fb588SMatthias Schmidt 	else if (sp[0] == '.' && sp[1] == 0) {
9597d8fb588SMatthias Schmidt 	    if (slash) {
9607d8fb588SMatthias Schmidt 		for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
9617d8fb588SMatthias Schmidt 		    continue;
9627d8fb588SMatthias Schmidt 		p = --sp;
9637d8fb588SMatthias Schmidt 	    }
9647d8fb588SMatthias Schmidt 	    else if (--sp != cp)
9657d8fb588SMatthias Schmidt 		*sp = '\0';
9667d8fb588SMatthias Schmidt 	    else
9677d8fb588SMatthias Schmidt 		sp[1] = '\0';
9687d8fb588SMatthias Schmidt 	}
9697d8fb588SMatthias Schmidt 	else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
9707d8fb588SMatthias Schmidt 	    /*
9717d8fb588SMatthias Schmidt 	     * We have something like "yyy/xxx/..", where "yyy" can be null or
9727d8fb588SMatthias Schmidt 	     * a path starting at /, and "xxx" is a single component. Before
9737d8fb588SMatthias Schmidt 	     * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
9747d8fb588SMatthias Schmidt 	     * symbolic link.
9757d8fb588SMatthias Schmidt 	     */
9767d8fb588SMatthias Schmidt 	    *--sp = 0;		/* form the pathname for readlink */
9777d8fb588SMatthias Schmidt #ifdef S_IFLNK			/* if we have symlinks */
9787d8fb588SMatthias Schmidt 	    if (sp != cp && /* symlinks != SYM_IGNORE && */
9797d8fb588SMatthias Schmidt 		(tlink = areadlink(short2str(cp))) != NULL) {
9807d8fb588SMatthias Schmidt 		mlink = str2short(tlink);
9817d8fb588SMatthias Schmidt 		xfree(tlink);
9827d8fb588SMatthias Schmidt 
9837d8fb588SMatthias Schmidt 		if (slash)
9847d8fb588SMatthias Schmidt 		    *p = '/';
9857d8fb588SMatthias Schmidt 		/*
9867d8fb588SMatthias Schmidt 		 * Point p to the '/' in "/..", and restore the '/'.
9877d8fb588SMatthias Schmidt 		 */
9887d8fb588SMatthias Schmidt 		*(p = sp) = '/';
9897d8fb588SMatthias Schmidt 		if (*mlink != '/') {
9907d8fb588SMatthias Schmidt 		    /*
9917d8fb588SMatthias Schmidt 		     * Relative path, expand it between the "yyy/" and the
9927d8fb588SMatthias Schmidt 		     * "/..". First, back sp up to the character past "yyy/".
9937d8fb588SMatthias Schmidt 		     */
9947d8fb588SMatthias Schmidt 		    while (*--sp != '/')
9957d8fb588SMatthias Schmidt 			continue;
9967d8fb588SMatthias Schmidt 		    sp++;
9977d8fb588SMatthias Schmidt 		    *sp = 0;
9987d8fb588SMatthias Schmidt 		    /*
9997d8fb588SMatthias Schmidt 		     * New length is "yyy/" + mlink + "/.." and rest
10007d8fb588SMatthias Schmidt 		     */
10017d8fb588SMatthias Schmidt 		    p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
10027d8fb588SMatthias Schmidt 					  Strlen(p) + 1) * sizeof(Char));
10037d8fb588SMatthias Schmidt 		    /*
10047d8fb588SMatthias Schmidt 		     * Copy new path into newcp
10057d8fb588SMatthias Schmidt 		     */
10067d8fb588SMatthias Schmidt 		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
10077d8fb588SMatthias Schmidt 			continue;
10087d8fb588SMatthias Schmidt 		    for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
10097d8fb588SMatthias Schmidt 			continue;
10107d8fb588SMatthias Schmidt 		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
10117d8fb588SMatthias Schmidt 			continue;
10127d8fb588SMatthias Schmidt 		    /*
10137d8fb588SMatthias Schmidt 		     * Restart canonicalization at expanded "/xxx".
10147d8fb588SMatthias Schmidt 		     */
10157d8fb588SMatthias Schmidt 		    p = sp - cp - 1 + newcp;
10167d8fb588SMatthias Schmidt 		}
10177d8fb588SMatthias Schmidt 		else {
10187d8fb588SMatthias Schmidt 		    newcp = Strspl(mlink, p);
10197d8fb588SMatthias Schmidt 		    /*
10207d8fb588SMatthias Schmidt 		     * Restart canonicalization at beginning
10217d8fb588SMatthias Schmidt 		     */
10227d8fb588SMatthias Schmidt 		    p = newcp;
10237d8fb588SMatthias Schmidt 		}
10247d8fb588SMatthias Schmidt 		xfree(cp);
10257d8fb588SMatthias Schmidt 		cp = newcp;
10267d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
10277d8fb588SMatthias Schmidt                 slashslash = (cp[0] == '/' && cp[1] == '/');
10287d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
10297d8fb588SMatthias Schmidt 		continue;	/* canonicalize the link */
10307d8fb588SMatthias Schmidt 	    }
10317d8fb588SMatthias Schmidt #endif /* S_IFLNK */
10327d8fb588SMatthias Schmidt 	    *sp = '/';
10337d8fb588SMatthias Schmidt 	    if (sp != cp)
10347d8fb588SMatthias Schmidt 		while (*--sp != '/')
10357d8fb588SMatthias Schmidt 		    continue;
10367d8fb588SMatthias Schmidt 	    if (slash) {
10377d8fb588SMatthias Schmidt 		for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
10387d8fb588SMatthias Schmidt 		    continue;
10397d8fb588SMatthias Schmidt 		p = sp;
10407d8fb588SMatthias Schmidt 	    }
10417d8fb588SMatthias Schmidt 	    else if (cp == sp)
10427d8fb588SMatthias Schmidt 		*++sp = '\0';
10437d8fb588SMatthias Schmidt 	    else
10447d8fb588SMatthias Schmidt 		*sp = '\0';
10457d8fb588SMatthias Schmidt 	}
10467d8fb588SMatthias Schmidt 	else {			/* normal dir name (not . or .. or nothing) */
10477d8fb588SMatthias Schmidt 
10487d8fb588SMatthias Schmidt #ifdef S_IFLNK			/* if we have symlinks */
10497d8fb588SMatthias Schmidt 	    if (sp != cp && symlinks == SYM_CHASE &&
10507d8fb588SMatthias Schmidt 		(tlink = areadlink(short2str(cp))) != NULL) {
10517d8fb588SMatthias Schmidt 		mlink = str2short(tlink);
10527d8fb588SMatthias Schmidt 		xfree(tlink);
10537d8fb588SMatthias Schmidt 
10547d8fb588SMatthias Schmidt 		/*
10557d8fb588SMatthias Schmidt 		 * restore the '/'.
10567d8fb588SMatthias Schmidt 		 */
10577d8fb588SMatthias Schmidt 		if (slash)
10587d8fb588SMatthias Schmidt 		    *p = '/';
10597d8fb588SMatthias Schmidt 
10607d8fb588SMatthias Schmidt 		/*
10617d8fb588SMatthias Schmidt 		 * point sp to p (rather than backing up).
10627d8fb588SMatthias Schmidt 		 */
10637d8fb588SMatthias Schmidt 		sp = p;
10647d8fb588SMatthias Schmidt 
10657d8fb588SMatthias Schmidt 		if (*mlink != '/') {
10667d8fb588SMatthias Schmidt 		    /*
10677d8fb588SMatthias Schmidt 		     * Relative path, expand it between the "yyy/" and the
10687d8fb588SMatthias Schmidt 		     * remainder. First, back sp up to the character past
10697d8fb588SMatthias Schmidt 		     * "yyy/".
10707d8fb588SMatthias Schmidt 		     */
10717d8fb588SMatthias Schmidt 		    while (*--sp != '/')
10727d8fb588SMatthias Schmidt 			continue;
10737d8fb588SMatthias Schmidt 		    sp++;
10747d8fb588SMatthias Schmidt 		    *sp = 0;
10757d8fb588SMatthias Schmidt 		    /*
10767d8fb588SMatthias Schmidt 		     * New length is "yyy/" + mlink + "/.." and rest
10777d8fb588SMatthias Schmidt 		     */
10787d8fb588SMatthias Schmidt 		    p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
10797d8fb588SMatthias Schmidt 					  Strlen(p) + 1) * sizeof(Char));
10807d8fb588SMatthias Schmidt 		    /*
10817d8fb588SMatthias Schmidt 		     * Copy new path into newcp
10827d8fb588SMatthias Schmidt 		     */
10837d8fb588SMatthias Schmidt 		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
10847d8fb588SMatthias Schmidt 			continue;
10857d8fb588SMatthias Schmidt 		    for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
10867d8fb588SMatthias Schmidt 			continue;
10877d8fb588SMatthias Schmidt 		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
10887d8fb588SMatthias Schmidt 			continue;
10897d8fb588SMatthias Schmidt 		    /*
10907d8fb588SMatthias Schmidt 		     * Restart canonicalization at expanded "/xxx".
10917d8fb588SMatthias Schmidt 		     */
10927d8fb588SMatthias Schmidt 		    p = sp - cp - 1 + newcp;
10937d8fb588SMatthias Schmidt 		}
10947d8fb588SMatthias Schmidt 		else {
10957d8fb588SMatthias Schmidt 		    newcp = Strspl(mlink, p);
10967d8fb588SMatthias Schmidt 		    /*
10977d8fb588SMatthias Schmidt 		     * Restart canonicalization at beginning
10987d8fb588SMatthias Schmidt 		     */
10997d8fb588SMatthias Schmidt 		    p = newcp;
11007d8fb588SMatthias Schmidt 		}
11017d8fb588SMatthias Schmidt 		xfree(cp);
11027d8fb588SMatthias Schmidt 		cp = newcp;
11037d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
11047d8fb588SMatthias Schmidt                 slashslash = (cp[0] == '/' && cp[1] == '/');
11057d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
11067d8fb588SMatthias Schmidt 		continue;	/* canonicalize the mlink */
11077d8fb588SMatthias Schmidt 	    }
11087d8fb588SMatthias Schmidt #endif /* S_IFLNK */
11097d8fb588SMatthias Schmidt 	    if (slash)
11107d8fb588SMatthias Schmidt 		*p = '/';
11117d8fb588SMatthias Schmidt 	}
11127d8fb588SMatthias Schmidt     }
11137d8fb588SMatthias Schmidt 
11147d8fb588SMatthias Schmidt     /*
11157d8fb588SMatthias Schmidt      * fix home...
11167d8fb588SMatthias Schmidt      */
11177d8fb588SMatthias Schmidt #ifdef S_IFLNK
11187d8fb588SMatthias Schmidt     p1 = varval(STRhome);
11197d8fb588SMatthias Schmidt     cc = Strlen(p1);
11207d8fb588SMatthias Schmidt     /*
11217d8fb588SMatthias Schmidt      * See if we're not in a subdir of STRhome
11227d8fb588SMatthias Schmidt      */
11237d8fb588SMatthias Schmidt     if (p1 && *p1 == '/' && (Strncmp(p1, cp, cc) != 0 ||
11247d8fb588SMatthias Schmidt 	(cp[cc] != '/' && cp[cc] != '\0'))) {
11257d8fb588SMatthias Schmidt 	static ino_t home_ino = (ino_t) -1;
11267d8fb588SMatthias Schmidt 	static dev_t home_dev = (dev_t) -1;
11277d8fb588SMatthias Schmidt 	static Char *home_ptr = NULL;
11287d8fb588SMatthias Schmidt 	struct stat statbuf;
11297d8fb588SMatthias Schmidt 	int found;
11307d8fb588SMatthias Schmidt 	Char *copy;
11317d8fb588SMatthias Schmidt 
11327d8fb588SMatthias Schmidt 	/*
11337d8fb588SMatthias Schmidt 	 * Get dev and ino of STRhome
11347d8fb588SMatthias Schmidt 	 */
11357d8fb588SMatthias Schmidt 	if (home_ptr != p1 &&
11367d8fb588SMatthias Schmidt 	    stat(short2str(p1), &statbuf) != -1) {
11377d8fb588SMatthias Schmidt 	    home_dev = statbuf.st_dev;
11387d8fb588SMatthias Schmidt 	    home_ino = statbuf.st_ino;
11397d8fb588SMatthias Schmidt 	    home_ptr = p1;
11407d8fb588SMatthias Schmidt 	}
11417d8fb588SMatthias Schmidt 	/*
11427d8fb588SMatthias Schmidt 	 * Start comparing dev & ino backwards
11437d8fb588SMatthias Schmidt 	 */
11447d8fb588SMatthias Schmidt 	p2 = copy = Strsave(cp);
11457d8fb588SMatthias Schmidt 	found = 0;
11467d8fb588SMatthias Schmidt 	while (*p2 && stat(short2str(p2), &statbuf) != -1) {
11477d8fb588SMatthias Schmidt 	    if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) &&
11487d8fb588SMatthias Schmidt 			statbuf.st_ino == home_ino) {
11497d8fb588SMatthias Schmidt 			found = 1;
11507d8fb588SMatthias Schmidt 			break;
11517d8fb588SMatthias Schmidt 	    }
11527d8fb588SMatthias Schmidt 	    if ((sp = Strrchr(p2, '/')) != NULL)
11537d8fb588SMatthias Schmidt 		*sp = '\0';
11547d8fb588SMatthias Schmidt 	}
11557d8fb588SMatthias Schmidt 	/*
11567d8fb588SMatthias Schmidt 	 * See if we found it
11577d8fb588SMatthias Schmidt 	 */
11587d8fb588SMatthias Schmidt 	if (*p2 && found) {
11597d8fb588SMatthias Schmidt 	    /*
11607d8fb588SMatthias Schmidt 	     * Use STRhome to make '~' work
11617d8fb588SMatthias Schmidt 	     */
11627d8fb588SMatthias Schmidt 	    newcp = Strspl(p1, cp + Strlen(p2));
11637d8fb588SMatthias Schmidt 	    xfree(cp);
11647d8fb588SMatthias Schmidt 	    cp = newcp;
11657d8fb588SMatthias Schmidt 	}
11667d8fb588SMatthias Schmidt 	xfree(copy);
11677d8fb588SMatthias Schmidt     }
11687d8fb588SMatthias Schmidt #endif /* S_IFLNK */
11697d8fb588SMatthias Schmidt 
11707d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
11717d8fb588SMatthias Schmidt     if (slashslash) {
11727d8fb588SMatthias Schmidt 	if (cp[1] != '/') {
11737d8fb588SMatthias Schmidt 	    p = xmalloc((Strlen(cp) + 2) * sizeof(Char));
11747d8fb588SMatthias Schmidt 	    *p = '/';
11757d8fb588SMatthias Schmidt 	    (void) Strcpy(&p[1], cp);
11767d8fb588SMatthias Schmidt 	    xfree(cp);
11777d8fb588SMatthias Schmidt 	    cp = p;
11787d8fb588SMatthias Schmidt 	}
11797d8fb588SMatthias Schmidt     }
11807d8fb588SMatthias Schmidt     if (cp[1] == '/' && cp[2] == '/') {
11817d8fb588SMatthias Schmidt 	for (p1 = &cp[1], p2 = &cp[2]; (*p1++ = *p2++) != '\0';)
11827d8fb588SMatthias Schmidt 	    continue;
11837d8fb588SMatthias Schmidt     }
11847d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
11857d8fb588SMatthias Schmidt     return cp;
11867d8fb588SMatthias Schmidt }
11877d8fb588SMatthias Schmidt 
11887d8fb588SMatthias Schmidt 
11897d8fb588SMatthias Schmidt /*
11907d8fb588SMatthias Schmidt  * dnewcwd - make a new directory in the loop the current one
11917d8fb588SMatthias Schmidt  */
11927d8fb588SMatthias Schmidt static void
dnewcwd(struct directory * dp,int dflag)11937d8fb588SMatthias Schmidt dnewcwd(struct directory *dp, int dflag)
11947d8fb588SMatthias Schmidt {
11957d8fb588SMatthias Schmidt     int print;
11967d8fb588SMatthias Schmidt 
11977d8fb588SMatthias Schmidt     if (adrof(STRdunique)) {
11987d8fb588SMatthias Schmidt 	struct directory *dn;
11997d8fb588SMatthias Schmidt 
12007d8fb588SMatthias Schmidt 	for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev)
12017d8fb588SMatthias Schmidt 	    if (dn != dp && Strcmp(dn->di_name, dp->di_name) == 0) {
12027d8fb588SMatthias Schmidt 		dn->di_next->di_prev = dn->di_prev;
12037d8fb588SMatthias Schmidt 		dn->di_prev->di_next = dn->di_next;
12047d8fb588SMatthias Schmidt 		dfree(dn);
12057d8fb588SMatthias Schmidt 		break;
12067d8fb588SMatthias Schmidt 	    }
12077d8fb588SMatthias Schmidt     }
12087d8fb588SMatthias Schmidt     dcwd = dp;
12097d8fb588SMatthias Schmidt     dset(dcwd->di_name);
12107d8fb588SMatthias Schmidt     dgetstack();
12117d8fb588SMatthias Schmidt     print = printd;		/* if printd is set, print dirstack... */
12127d8fb588SMatthias Schmidt     if (adrof(STRpushdsilent))	/* but pushdsilent overrides printd... */
12137d8fb588SMatthias Schmidt 	print = 0;
12147d8fb588SMatthias Schmidt     if (dflag & DIR_PRINT)	/* but DIR_PRINT overrides pushdsilent... */
12157d8fb588SMatthias Schmidt 	print = 1;
12167d8fb588SMatthias Schmidt     if (bequiet)		/* and bequiet overrides everything */
12177d8fb588SMatthias Schmidt 	print = 0;
12187d8fb588SMatthias Schmidt     if (print)
12197d8fb588SMatthias Schmidt 	printdirs(dflag);
12207d8fb588SMatthias Schmidt     cwd_cmd();			/* PWP: run the defined cwd command */
12217d8fb588SMatthias Schmidt }
12227d8fb588SMatthias Schmidt 
12237d8fb588SMatthias Schmidt void
dsetstack(void)12247d8fb588SMatthias Schmidt dsetstack(void)
12257d8fb588SMatthias Schmidt {
12267d8fb588SMatthias Schmidt     Char **cp;
12277d8fb588SMatthias Schmidt     struct varent *vp;
12287d8fb588SMatthias Schmidt     struct directory *dn, *dp;
12297d8fb588SMatthias Schmidt 
12307d8fb588SMatthias Schmidt     if ((vp = adrof(STRdirstack)) == NULL || vp->vec == NULL)
12317d8fb588SMatthias Schmidt 	return;
12327d8fb588SMatthias Schmidt 
12337d8fb588SMatthias Schmidt     /* Free the whole stack */
12347d8fb588SMatthias Schmidt     while ((dn = dhead.di_prev) != &dhead) {
12357d8fb588SMatthias Schmidt 	dn->di_next->di_prev = dn->di_prev;
12367d8fb588SMatthias Schmidt 	dn->di_prev->di_next = dn->di_next;
12377d8fb588SMatthias Schmidt 	if (dn != dcwd)
12387d8fb588SMatthias Schmidt 	    dfree(dn);
12397d8fb588SMatthias Schmidt     }
12407d8fb588SMatthias Schmidt 
12417d8fb588SMatthias Schmidt     /* thread the current working directory */
12427d8fb588SMatthias Schmidt     dhead.di_prev = dhead.di_next = dcwd;
12437d8fb588SMatthias Schmidt     dcwd->di_next = dcwd->di_prev = &dhead;
12447d8fb588SMatthias Schmidt 
12457d8fb588SMatthias Schmidt     /* put back the stack */
12467d8fb588SMatthias Schmidt     for (cp = vp->vec; cp && *cp && **cp; cp++) {
12477d8fb588SMatthias Schmidt 	dp = xcalloc(sizeof(struct directory), 1);
12487d8fb588SMatthias Schmidt 	dp->di_name = Strsave(*cp);
12497d8fb588SMatthias Schmidt 	dp->di_count = 0;
12507d8fb588SMatthias Schmidt 	dp->di_prev = dcwd;
12517d8fb588SMatthias Schmidt 	dp->di_next = dcwd->di_next;
12527d8fb588SMatthias Schmidt 	dcwd->di_next = dp;
12537d8fb588SMatthias Schmidt 	dp->di_next->di_prev = dp;
12547d8fb588SMatthias Schmidt     }
12557d8fb588SMatthias Schmidt     dgetstack();	/* Make $dirstack reflect the current state */
12567d8fb588SMatthias Schmidt }
12577d8fb588SMatthias Schmidt 
12587d8fb588SMatthias Schmidt static void
dgetstack(void)12597d8fb588SMatthias Schmidt dgetstack(void)
12607d8fb588SMatthias Schmidt {
12617d8fb588SMatthias Schmidt     int i = 0;
12627d8fb588SMatthias Schmidt     Char **dblk, **dbp;
12637d8fb588SMatthias Schmidt     struct directory *dn;
12647d8fb588SMatthias Schmidt 
12657d8fb588SMatthias Schmidt     if (adrof(STRdirstack) == NULL)
12667d8fb588SMatthias Schmidt     	return;
12677d8fb588SMatthias Schmidt 
12687d8fb588SMatthias Schmidt     for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, i++)
12697d8fb588SMatthias Schmidt 	continue;
12707d8fb588SMatthias Schmidt     dbp = dblk = xmalloc((i + 1) * sizeof(Char *));
12717d8fb588SMatthias Schmidt     for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, dbp++)
12727d8fb588SMatthias Schmidt 	 *dbp = Strsave(dn->di_name);
12737d8fb588SMatthias Schmidt     *dbp = NULL;
12747d8fb588SMatthias Schmidt     cleanup_push(dblk, blk_cleanup);
12757d8fb588SMatthias Schmidt     setq(STRdirstack, dblk, &shvhed, VAR_READWRITE);
12767d8fb588SMatthias Schmidt     cleanup_ignore(dblk);
12777d8fb588SMatthias Schmidt     cleanup_until(dblk);
12787d8fb588SMatthias Schmidt }
12797d8fb588SMatthias Schmidt 
12807d8fb588SMatthias Schmidt /*
12817d8fb588SMatthias Schmidt  * getstakd - added by kfk 17 Jan 1984
12827d8fb588SMatthias Schmidt  * Support routine for the stack hack.  Finds nth directory in
12837d8fb588SMatthias Schmidt  * the directory stack, or finds last directory in stack.
12847d8fb588SMatthias Schmidt  */
12857d8fb588SMatthias Schmidt const Char *
getstakd(int cnt)12867d8fb588SMatthias Schmidt getstakd(int cnt)
12877d8fb588SMatthias Schmidt {
12887d8fb588SMatthias Schmidt     struct directory *dp;
12897d8fb588SMatthias Schmidt 
12907d8fb588SMatthias Schmidt     dp = dcwd;
12917d8fb588SMatthias Schmidt     if (cnt < 0) {		/* < 0 ==> last dir requested. */
12927d8fb588SMatthias Schmidt 	dp = dp->di_next;
12937d8fb588SMatthias Schmidt 	if (dp == &dhead)
12947d8fb588SMatthias Schmidt 	    dp = dp->di_next;
12957d8fb588SMatthias Schmidt     }
12967d8fb588SMatthias Schmidt     else {
12977d8fb588SMatthias Schmidt 	while (cnt-- > 0) {
12987d8fb588SMatthias Schmidt 	    dp = dp->di_prev;
12997d8fb588SMatthias Schmidt 	    if (dp == &dhead)
13007d8fb588SMatthias Schmidt 		dp = dp->di_prev;
13017d8fb588SMatthias Schmidt 	    if (dp == dcwd)
13027d8fb588SMatthias Schmidt 		return NULL;
13037d8fb588SMatthias Schmidt 	}
13047d8fb588SMatthias Schmidt     }
13057d8fb588SMatthias Schmidt     return dp->di_name;
13067d8fb588SMatthias Schmidt }
13077d8fb588SMatthias Schmidt 
13087d8fb588SMatthias Schmidt /*
13097d8fb588SMatthias Schmidt  * Karl Kleinpaste - 10 Feb 1984
13107d8fb588SMatthias Schmidt  * Added dextract(), which is used in pushd +n.
13117d8fb588SMatthias Schmidt  * Instead of just rotating the entire stack around, dextract()
13127d8fb588SMatthias Schmidt  * lets the user have the nth dir extracted from its current
13137d8fb588SMatthias Schmidt  * position, and pushes it onto the top.
13147d8fb588SMatthias Schmidt  */
13157d8fb588SMatthias Schmidt static void
dextract(struct directory * dp)13167d8fb588SMatthias Schmidt dextract(struct directory *dp)
13177d8fb588SMatthias Schmidt {
13187d8fb588SMatthias Schmidt     if (dp == dcwd)
13197d8fb588SMatthias Schmidt 	return;
13207d8fb588SMatthias Schmidt     dp->di_next->di_prev = dp->di_prev;
13217d8fb588SMatthias Schmidt     dp->di_prev->di_next = dp->di_next;
13227d8fb588SMatthias Schmidt     dp->di_next = dcwd->di_next;
13237d8fb588SMatthias Schmidt     dp->di_prev = dcwd;
13247d8fb588SMatthias Schmidt     dp->di_next->di_prev = dp;
13257d8fb588SMatthias Schmidt     dcwd->di_next = dp;
13267d8fb588SMatthias Schmidt }
13277d8fb588SMatthias Schmidt 
13287d8fb588SMatthias Schmidt static void
bequiet_cleanup(void * dummy)13297d8fb588SMatthias Schmidt bequiet_cleanup(void *dummy)
13307d8fb588SMatthias Schmidt {
13317d8fb588SMatthias Schmidt     USE(dummy);
13327d8fb588SMatthias Schmidt     bequiet = 0;
13337d8fb588SMatthias Schmidt }
13347d8fb588SMatthias Schmidt 
13357d8fb588SMatthias Schmidt void
loaddirs(Char * fname)13367d8fb588SMatthias Schmidt loaddirs(Char *fname)
13377d8fb588SMatthias Schmidt {
13387d8fb588SMatthias Schmidt     static Char *loaddirs_cmd[] = { STRsource, NULL, NULL };
13397d8fb588SMatthias Schmidt 
13407d8fb588SMatthias Schmidt     bequiet = 1;
13417d8fb588SMatthias Schmidt     cleanup_push(&bequiet, bequiet_cleanup);
13427d8fb588SMatthias Schmidt     if (fname)
13437d8fb588SMatthias Schmidt 	loaddirs_cmd[1] = fname;
13447d8fb588SMatthias Schmidt     else if ((fname = varval(STRdirsfile)) != STRNULL)
13457d8fb588SMatthias Schmidt 	loaddirs_cmd[1] = fname;
13467d8fb588SMatthias Schmidt     else
13477d8fb588SMatthias Schmidt 	loaddirs_cmd[1] = STRtildotdirs;
13487d8fb588SMatthias Schmidt     dosource(loaddirs_cmd, NULL);
13497d8fb588SMatthias Schmidt     cleanup_until(&bequiet);
13507d8fb588SMatthias Schmidt }
13517d8fb588SMatthias Schmidt 
13527d8fb588SMatthias Schmidt /*
13537d8fb588SMatthias Schmidt  * create a file called ~/.cshdirs which has a sequence
13547d8fb588SMatthias Schmidt  * of pushd commands which will restore the dir stack to
13557d8fb588SMatthias Schmidt  * its state before exit/logout. remember that the order
13567d8fb588SMatthias Schmidt  * is reversed in the file because we are pushing.
13577d8fb588SMatthias Schmidt  * -strike
13587d8fb588SMatthias Schmidt  */
13597d8fb588SMatthias Schmidt void
recdirs(Char * fname,int def)13607d8fb588SMatthias Schmidt recdirs(Char *fname, int def)
13617d8fb588SMatthias Schmidt {
1362*d6ab524cSAntonio Huete Jimenez     int     fp, ftmp, oldidfds, ophup_disabled;
13637d8fb588SMatthias Schmidt     int     cdflag = 0;
13647d8fb588SMatthias Schmidt     struct directory *dp;
13657d8fb588SMatthias Schmidt     unsigned int    num;
13667d8fb588SMatthias Schmidt     Char   *snum;
13677d8fb588SMatthias Schmidt     struct Strbuf qname = Strbuf_INIT;
13687d8fb588SMatthias Schmidt 
13697d8fb588SMatthias Schmidt     if (fname == NULL && !def)
13707d8fb588SMatthias Schmidt 	return;
13717d8fb588SMatthias Schmidt 
1372*d6ab524cSAntonio Huete Jimenez     ophup_disabled = phup_disabled;
1373*d6ab524cSAntonio Huete Jimenez     phup_disabled = 1;
13747d8fb588SMatthias Schmidt     if (fname == NULL) {
13757d8fb588SMatthias Schmidt 	if ((fname = varval(STRdirsfile)) == STRNULL)
13767d8fb588SMatthias Schmidt 	    fname = Strspl(varval(STRhome), &STRtildotdirs[1]);
13777d8fb588SMatthias Schmidt 	else
13787d8fb588SMatthias Schmidt 	    fname = Strsave(fname);
13797d8fb588SMatthias Schmidt     }
13807d8fb588SMatthias Schmidt     else
13817d8fb588SMatthias Schmidt 	fname = globone(fname, G_ERROR);
13827d8fb588SMatthias Schmidt     cleanup_push(fname, xfree);
13837d8fb588SMatthias Schmidt 
13847d8fb588SMatthias Schmidt     if ((fp = xcreat(short2str(fname), 0600)) == -1) {
13857d8fb588SMatthias Schmidt 	cleanup_until(fname);
1386*d6ab524cSAntonio Huete Jimenez 	phup_disabled = ophup_disabled;
13877d8fb588SMatthias Schmidt 	return;
13887d8fb588SMatthias Schmidt     }
13897d8fb588SMatthias Schmidt 
13907d8fb588SMatthias Schmidt     if ((snum = varval(STRsavedirs)) == STRNULL || snum[0] == '\0')
13917d8fb588SMatthias Schmidt 	num = (unsigned int) ~0;
13927d8fb588SMatthias Schmidt     else
13937d8fb588SMatthias Schmidt 	num = (unsigned int) atoi(short2str(snum));
13947d8fb588SMatthias Schmidt 
13957d8fb588SMatthias Schmidt     oldidfds = didfds;
13967d8fb588SMatthias Schmidt     didfds = 0;
13977d8fb588SMatthias Schmidt     ftmp = SHOUT;
13987d8fb588SMatthias Schmidt     SHOUT = fp;
13997d8fb588SMatthias Schmidt 
14007d8fb588SMatthias Schmidt     cleanup_push(&qname, Strbuf_cleanup);
14017d8fb588SMatthias Schmidt     dp = dcwd->di_next;
14027d8fb588SMatthias Schmidt     do {
14037d8fb588SMatthias Schmidt 	if (dp == &dhead)
14047d8fb588SMatthias Schmidt 	    continue;
14057d8fb588SMatthias Schmidt 
14067d8fb588SMatthias Schmidt 	if (cdflag == 0) {
14077d8fb588SMatthias Schmidt 	    cdflag = 1;
1408*d6ab524cSAntonio Huete Jimenez 	    xprintf("cd %" TCSH_S "\n", quote_meta(&qname, dp->di_name));
14097d8fb588SMatthias Schmidt 	}
14107d8fb588SMatthias Schmidt 	else
1411*d6ab524cSAntonio Huete Jimenez 	    xprintf("pushd %" TCSH_S "\n", quote_meta(&qname, dp->di_name));
14127d8fb588SMatthias Schmidt 
14137d8fb588SMatthias Schmidt 	if (num-- == 0)
14147d8fb588SMatthias Schmidt 	    break;
14157d8fb588SMatthias Schmidt 
14167d8fb588SMatthias Schmidt     } while ((dp = dp->di_next) != dcwd->di_next);
14177d8fb588SMatthias Schmidt 
14187d8fb588SMatthias Schmidt     xclose(fp);
14197d8fb588SMatthias Schmidt     SHOUT = ftmp;
14207d8fb588SMatthias Schmidt     didfds = oldidfds;
14217d8fb588SMatthias Schmidt     cleanup_until(fname);
1422*d6ab524cSAntonio Huete Jimenez     phup_disabled = ophup_disabled;
14237d8fb588SMatthias Schmidt }
1424