xref: /minix3/bin/csh/dir.c (revision d1e4d7ce7de96b58a7e34cb41f3fd9aa036d9692)
1*d1e4d7ceSDavid van Moolenbroek /* $NetBSD: dir.c,v 1.30 2013/07/16 17:47:43 christos Exp $ */
2*d1e4d7ceSDavid van Moolenbroek 
3*d1e4d7ceSDavid van Moolenbroek /*-
4*d1e4d7ceSDavid van Moolenbroek  * Copyright (c) 1980, 1991, 1993
5*d1e4d7ceSDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
6*d1e4d7ceSDavid van Moolenbroek  *
7*d1e4d7ceSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
8*d1e4d7ceSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
9*d1e4d7ceSDavid van Moolenbroek  * are met:
10*d1e4d7ceSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
11*d1e4d7ceSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
12*d1e4d7ceSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
13*d1e4d7ceSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
14*d1e4d7ceSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
15*d1e4d7ceSDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
16*d1e4d7ceSDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
17*d1e4d7ceSDavid van Moolenbroek  *    without specific prior written permission.
18*d1e4d7ceSDavid van Moolenbroek  *
19*d1e4d7ceSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*d1e4d7ceSDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*d1e4d7ceSDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*d1e4d7ceSDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*d1e4d7ceSDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*d1e4d7ceSDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*d1e4d7ceSDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*d1e4d7ceSDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*d1e4d7ceSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*d1e4d7ceSDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*d1e4d7ceSDavid van Moolenbroek  * SUCH DAMAGE.
30*d1e4d7ceSDavid van Moolenbroek  */
31*d1e4d7ceSDavid van Moolenbroek 
32*d1e4d7ceSDavid van Moolenbroek #include <sys/cdefs.h>
33*d1e4d7ceSDavid van Moolenbroek #ifndef lint
34*d1e4d7ceSDavid van Moolenbroek #if 0
35*d1e4d7ceSDavid van Moolenbroek static char sccsid[] = "@(#)dir.c	8.1 (Berkeley) 5/31/93";
36*d1e4d7ceSDavid van Moolenbroek #else
37*d1e4d7ceSDavid van Moolenbroek __RCSID("$NetBSD: dir.c,v 1.30 2013/07/16 17:47:43 christos Exp $");
38*d1e4d7ceSDavid van Moolenbroek #endif
39*d1e4d7ceSDavid van Moolenbroek #endif /* not lint */
40*d1e4d7ceSDavid van Moolenbroek 
41*d1e4d7ceSDavid van Moolenbroek #include <sys/param.h>
42*d1e4d7ceSDavid van Moolenbroek #include <sys/stat.h>
43*d1e4d7ceSDavid van Moolenbroek 
44*d1e4d7ceSDavid van Moolenbroek #include <errno.h>
45*d1e4d7ceSDavid van Moolenbroek #include <stdarg.h>
46*d1e4d7ceSDavid van Moolenbroek #include <stdlib.h>
47*d1e4d7ceSDavid van Moolenbroek #include <string.h>
48*d1e4d7ceSDavid van Moolenbroek #include <unistd.h>
49*d1e4d7ceSDavid van Moolenbroek 
50*d1e4d7ceSDavid van Moolenbroek #include "csh.h"
51*d1e4d7ceSDavid van Moolenbroek #include "dir.h"
52*d1e4d7ceSDavid van Moolenbroek #include "extern.h"
53*d1e4d7ceSDavid van Moolenbroek 
54*d1e4d7ceSDavid van Moolenbroek /* Directory management. */
55*d1e4d7ceSDavid van Moolenbroek 
56*d1e4d7ceSDavid van Moolenbroek static struct directory *dfind(Char *);
57*d1e4d7ceSDavid van Moolenbroek static Char *dfollow(Char *);
58*d1e4d7ceSDavid van Moolenbroek static void printdirs(void);
59*d1e4d7ceSDavid van Moolenbroek static Char *dgoto(Char *);
60*d1e4d7ceSDavid van Moolenbroek static void skipargs(Char ***, const char *);
61*d1e4d7ceSDavid van Moolenbroek static void dnewcwd(struct directory *);
62*d1e4d7ceSDavid van Moolenbroek static void dset(Char *);
63*d1e4d7ceSDavid van Moolenbroek 
64*d1e4d7ceSDavid van Moolenbroek struct directory dhead;		/* "head" of loop */
65*d1e4d7ceSDavid van Moolenbroek int printd;			/* force name to be printed */
66*d1e4d7ceSDavid van Moolenbroek 
67*d1e4d7ceSDavid van Moolenbroek static int dirflag = 0;
68*d1e4d7ceSDavid van Moolenbroek 
69*d1e4d7ceSDavid van Moolenbroek /*
70*d1e4d7ceSDavid van Moolenbroek  * dinit - initialize current working directory
71*d1e4d7ceSDavid van Moolenbroek  */
72*d1e4d7ceSDavid van Moolenbroek void
dinit(Char * hp)73*d1e4d7ceSDavid van Moolenbroek dinit(Char *hp)
74*d1e4d7ceSDavid van Moolenbroek {
75*d1e4d7ceSDavid van Moolenbroek     static const char emsg[] = "csh: Trying to start from \"%s\"\n";
76*d1e4d7ceSDavid van Moolenbroek     char path[MAXPATHLEN];
77*d1e4d7ceSDavid van Moolenbroek     struct directory *dp;
78*d1e4d7ceSDavid van Moolenbroek     const char *ecp;
79*d1e4d7ceSDavid van Moolenbroek     Char *cp;
80*d1e4d7ceSDavid van Moolenbroek 
81*d1e4d7ceSDavid van Moolenbroek     /* Don't believe the login shell home, because it may be a symlink */
82*d1e4d7ceSDavid van Moolenbroek     ecp = getcwd(path, MAXPATHLEN);
83*d1e4d7ceSDavid van Moolenbroek     if (ecp == NULL || *ecp == '\0') {
84*d1e4d7ceSDavid van Moolenbroek 	(void)fprintf(csherr, "csh: %s\n", strerror(errno));
85*d1e4d7ceSDavid van Moolenbroek 	if (hp && *hp) {
86*d1e4d7ceSDavid van Moolenbroek 	    ecp = short2str(hp);
87*d1e4d7ceSDavid van Moolenbroek 	    if (chdir(ecp) == -1)
88*d1e4d7ceSDavid van Moolenbroek 		cp = NULL;
89*d1e4d7ceSDavid van Moolenbroek 	    else
90*d1e4d7ceSDavid van Moolenbroek 		cp = Strsave(hp);
91*d1e4d7ceSDavid van Moolenbroek 	    (void)fprintf(csherr, emsg, vis_str(hp));
92*d1e4d7ceSDavid van Moolenbroek 	}
93*d1e4d7ceSDavid van Moolenbroek 	else
94*d1e4d7ceSDavid van Moolenbroek 	    cp = NULL;
95*d1e4d7ceSDavid van Moolenbroek 	if (cp == NULL) {
96*d1e4d7ceSDavid van Moolenbroek 	    (void)fprintf(csherr, emsg, "/");
97*d1e4d7ceSDavid van Moolenbroek 	    if (chdir("/") == -1) {
98*d1e4d7ceSDavid van Moolenbroek 		/* I am not even try to print an error message! */
99*d1e4d7ceSDavid van Moolenbroek 		xexit(1);
100*d1e4d7ceSDavid van Moolenbroek 	    }
101*d1e4d7ceSDavid van Moolenbroek 	    cp = SAVE("/");
102*d1e4d7ceSDavid van Moolenbroek 	}
103*d1e4d7ceSDavid van Moolenbroek     }
104*d1e4d7ceSDavid van Moolenbroek     else {
105*d1e4d7ceSDavid van Moolenbroek 	struct stat swd, shp;
106*d1e4d7ceSDavid van Moolenbroek 
107*d1e4d7ceSDavid van Moolenbroek 	/*
108*d1e4d7ceSDavid van Moolenbroek 	 * See if $HOME is the working directory we got and use that
109*d1e4d7ceSDavid van Moolenbroek 	 */
110*d1e4d7ceSDavid van Moolenbroek 	if (hp && *hp &&
111*d1e4d7ceSDavid van Moolenbroek 	    stat(ecp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
112*d1e4d7ceSDavid van Moolenbroek 	    swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
113*d1e4d7ceSDavid van Moolenbroek 	    cp = Strsave(hp);
114*d1e4d7ceSDavid van Moolenbroek 	else {
115*d1e4d7ceSDavid van Moolenbroek 	    const char *cwd;
116*d1e4d7ceSDavid van Moolenbroek 
117*d1e4d7ceSDavid van Moolenbroek 	    /*
118*d1e4d7ceSDavid van Moolenbroek 	     * use PWD if we have it (for subshells)
119*d1e4d7ceSDavid van Moolenbroek 	     */
120*d1e4d7ceSDavid van Moolenbroek 	    if ((cwd = getenv("PWD")) != NULL) {
121*d1e4d7ceSDavid van Moolenbroek 		if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
122*d1e4d7ceSDavid van Moolenbroek 		    swd.st_ino == shp.st_ino)
123*d1e4d7ceSDavid van Moolenbroek 		    ecp = cwd;
124*d1e4d7ceSDavid van Moolenbroek 	    }
125*d1e4d7ceSDavid van Moolenbroek 	    cp = dcanon(SAVE(ecp), STRNULL);
126*d1e4d7ceSDavid van Moolenbroek 	}
127*d1e4d7ceSDavid van Moolenbroek     }
128*d1e4d7ceSDavid van Moolenbroek 
129*d1e4d7ceSDavid van Moolenbroek     dp = (struct directory *)xcalloc(1, sizeof(struct directory));
130*d1e4d7ceSDavid van Moolenbroek     dp->di_name = cp;
131*d1e4d7ceSDavid van Moolenbroek     dp->di_count = 0;
132*d1e4d7ceSDavid van Moolenbroek     dhead.di_next = dhead.di_prev = dp;
133*d1e4d7ceSDavid van Moolenbroek     dp->di_next = dp->di_prev = &dhead;
134*d1e4d7ceSDavid van Moolenbroek     printd = 0;
135*d1e4d7ceSDavid van Moolenbroek     dnewcwd(dp);
136*d1e4d7ceSDavid van Moolenbroek }
137*d1e4d7ceSDavid van Moolenbroek 
138*d1e4d7ceSDavid van Moolenbroek static void
dset(Char * dp)139*d1e4d7ceSDavid van Moolenbroek dset(Char *dp)
140*d1e4d7ceSDavid van Moolenbroek {
141*d1e4d7ceSDavid van Moolenbroek     Char **vec;
142*d1e4d7ceSDavid van Moolenbroek 
143*d1e4d7ceSDavid van Moolenbroek     /*
144*d1e4d7ceSDavid van Moolenbroek      * Don't call set() directly cause if the directory contains ` or
145*d1e4d7ceSDavid van Moolenbroek      * other junk characters glob will fail.
146*d1e4d7ceSDavid van Moolenbroek      */
147*d1e4d7ceSDavid van Moolenbroek 
148*d1e4d7ceSDavid van Moolenbroek     vec = xmalloc((size_t)(2 * sizeof(Char **)));
149*d1e4d7ceSDavid van Moolenbroek     vec[0] = Strsave(dp);
150*d1e4d7ceSDavid van Moolenbroek     vec[1] = 0;
151*d1e4d7ceSDavid van Moolenbroek     setq(STRcwd, vec, &shvhed);
152*d1e4d7ceSDavid van Moolenbroek     Setenv(STRPWD, dp);
153*d1e4d7ceSDavid van Moolenbroek }
154*d1e4d7ceSDavid van Moolenbroek 
155*d1e4d7ceSDavid van Moolenbroek #define DIR_LONG 1
156*d1e4d7ceSDavid van Moolenbroek #define DIR_VERT 2
157*d1e4d7ceSDavid van Moolenbroek #define DIR_LINE 4
158*d1e4d7ceSDavid van Moolenbroek 
159*d1e4d7ceSDavid van Moolenbroek static void
skipargs(Char *** v,const char * str)160*d1e4d7ceSDavid van Moolenbroek skipargs(Char ***v, const char *str)
161*d1e4d7ceSDavid van Moolenbroek {
162*d1e4d7ceSDavid van Moolenbroek     Char  **n, *s;
163*d1e4d7ceSDavid van Moolenbroek 
164*d1e4d7ceSDavid van Moolenbroek     n = *v;
165*d1e4d7ceSDavid van Moolenbroek     dirflag = 0;
166*d1e4d7ceSDavid van Moolenbroek     for (n++; *n != NULL && (*n)[0] == '-'; n++)
167*d1e4d7ceSDavid van Moolenbroek 	for (s = &((*n)[1]); *s; s++)
168*d1e4d7ceSDavid van Moolenbroek 	    switch (*s) {
169*d1e4d7ceSDavid van Moolenbroek 	    case 'l':
170*d1e4d7ceSDavid van Moolenbroek 		dirflag |= DIR_LONG;
171*d1e4d7ceSDavid van Moolenbroek 		break;
172*d1e4d7ceSDavid van Moolenbroek 	    case 'n':
173*d1e4d7ceSDavid van Moolenbroek 		dirflag |= DIR_LINE;
174*d1e4d7ceSDavid van Moolenbroek 		break;
175*d1e4d7ceSDavid van Moolenbroek 	    case 'v':
176*d1e4d7ceSDavid van Moolenbroek 		dirflag |= DIR_VERT;
177*d1e4d7ceSDavid van Moolenbroek 		break;
178*d1e4d7ceSDavid van Moolenbroek 	    default:
179*d1e4d7ceSDavid van Moolenbroek 		stderror(ERR_DIRUS, vis_str(**v), str);
180*d1e4d7ceSDavid van Moolenbroek 		/* NOTREACHED */
181*d1e4d7ceSDavid van Moolenbroek 	    }
182*d1e4d7ceSDavid van Moolenbroek     *v = n;
183*d1e4d7ceSDavid van Moolenbroek }
184*d1e4d7ceSDavid van Moolenbroek 
185*d1e4d7ceSDavid van Moolenbroek /*
186*d1e4d7ceSDavid van Moolenbroek  * dodirs - list all directories in directory loop
187*d1e4d7ceSDavid van Moolenbroek  */
188*d1e4d7ceSDavid van Moolenbroek void
189*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dodirs(Char ** v,struct command * t)190*d1e4d7ceSDavid van Moolenbroek dodirs(Char **v, struct command *t)
191*d1e4d7ceSDavid van Moolenbroek {
192*d1e4d7ceSDavid van Moolenbroek     skipargs(&v, "");
193*d1e4d7ceSDavid van Moolenbroek 
194*d1e4d7ceSDavid van Moolenbroek     if (*v != NULL)
195*d1e4d7ceSDavid van Moolenbroek 	stderror(ERR_DIRUS, "dirs", "");
196*d1e4d7ceSDavid van Moolenbroek     printdirs();
197*d1e4d7ceSDavid van Moolenbroek }
198*d1e4d7ceSDavid van Moolenbroek 
199*d1e4d7ceSDavid van Moolenbroek static void
printdirs(void)200*d1e4d7ceSDavid van Moolenbroek printdirs(void)
201*d1e4d7ceSDavid van Moolenbroek {
202*d1e4d7ceSDavid van Moolenbroek     struct directory *dp;
203*d1e4d7ceSDavid van Moolenbroek     Char *hp, *s;
204*d1e4d7ceSDavid van Moolenbroek     size_t cur, idx, len;
205*d1e4d7ceSDavid van Moolenbroek 
206*d1e4d7ceSDavid van Moolenbroek     hp = value(STRhome);
207*d1e4d7ceSDavid van Moolenbroek     if (*hp == '\0')
208*d1e4d7ceSDavid van Moolenbroek 	hp = NULL;
209*d1e4d7ceSDavid van Moolenbroek     dp = dcwd;
210*d1e4d7ceSDavid van Moolenbroek     idx = 0;
211*d1e4d7ceSDavid van Moolenbroek     cur = 0;
212*d1e4d7ceSDavid van Moolenbroek     do {
213*d1e4d7ceSDavid van Moolenbroek 	if (dp == &dhead)
214*d1e4d7ceSDavid van Moolenbroek 	    continue;
215*d1e4d7ceSDavid van Moolenbroek 	if (dirflag & DIR_VERT) {
216*d1e4d7ceSDavid van Moolenbroek 	    (void)fprintf(cshout, "%zu\t", idx++);
217*d1e4d7ceSDavid van Moolenbroek 	    cur = 0;
218*d1e4d7ceSDavid van Moolenbroek 	}
219*d1e4d7ceSDavid van Moolenbroek 	if (!(dirflag & DIR_LONG) && hp != NULL && !eq(hp, STRslash) &&
220*d1e4d7ceSDavid van Moolenbroek 	    (len = Strlen(hp), Strncmp(hp, dp->di_name, len) == 0) &&
221*d1e4d7ceSDavid van Moolenbroek 	    (dp->di_name[len] == '\0' || dp->di_name[len] == '/'))
222*d1e4d7ceSDavid van Moolenbroek 	    len = Strlen(s = (dp->di_name + len)) + 2;
223*d1e4d7ceSDavid van Moolenbroek 	else
224*d1e4d7ceSDavid van Moolenbroek 	    len = Strlen(s = dp->di_name) + 1;
225*d1e4d7ceSDavid van Moolenbroek 
226*d1e4d7ceSDavid van Moolenbroek 	cur += len;
227*d1e4d7ceSDavid van Moolenbroek 	if ((dirflag & DIR_LINE) && cur >= 80 - 1 && len < 80) {
228*d1e4d7ceSDavid van Moolenbroek 	    (void)fprintf(cshout, "\n");
229*d1e4d7ceSDavid van Moolenbroek 	    cur = len;
230*d1e4d7ceSDavid van Moolenbroek 	}
231*d1e4d7ceSDavid van Moolenbroek 	(void) fprintf(cshout, "%s%s%c", (s != dp->di_name)? "~" : "",
232*d1e4d7ceSDavid van Moolenbroek 	    vis_str(s), (dirflag & DIR_VERT) ? '\n' : ' ');
233*d1e4d7ceSDavid van Moolenbroek     } while ((dp = dp->di_prev) != dcwd);
234*d1e4d7ceSDavid van Moolenbroek     if (!(dirflag & DIR_VERT))
235*d1e4d7ceSDavid van Moolenbroek 	(void)fprintf(cshout, "\n");
236*d1e4d7ceSDavid van Moolenbroek }
237*d1e4d7ceSDavid van Moolenbroek 
238*d1e4d7ceSDavid van Moolenbroek void
dtildepr(Char * home,Char * dir)239*d1e4d7ceSDavid van Moolenbroek dtildepr(Char *home, Char *dir)
240*d1e4d7ceSDavid van Moolenbroek {
241*d1e4d7ceSDavid van Moolenbroek     if (!eq(home, STRslash) && prefix(home, dir))
242*d1e4d7ceSDavid van Moolenbroek 	(void)fprintf(cshout, "~%s", vis_str(dir + Strlen(home)));
243*d1e4d7ceSDavid van Moolenbroek     else
244*d1e4d7ceSDavid van Moolenbroek 	(void)fprintf(cshout, "%s", vis_str(dir));
245*d1e4d7ceSDavid van Moolenbroek }
246*d1e4d7ceSDavid van Moolenbroek 
247*d1e4d7ceSDavid van Moolenbroek void
dtilde(void)248*d1e4d7ceSDavid van Moolenbroek dtilde(void)
249*d1e4d7ceSDavid van Moolenbroek {
250*d1e4d7ceSDavid van Moolenbroek     struct directory *d;
251*d1e4d7ceSDavid van Moolenbroek 
252*d1e4d7ceSDavid van Moolenbroek     d = dcwd;
253*d1e4d7ceSDavid van Moolenbroek     do {
254*d1e4d7ceSDavid van Moolenbroek 	if (d == &dhead)
255*d1e4d7ceSDavid van Moolenbroek 	    continue;
256*d1e4d7ceSDavid van Moolenbroek 	d->di_name = dcanon(d->di_name, STRNULL);
257*d1e4d7ceSDavid van Moolenbroek     } while ((d = d->di_prev) != dcwd);
258*d1e4d7ceSDavid van Moolenbroek 
259*d1e4d7ceSDavid van Moolenbroek     dset(dcwd->di_name);
260*d1e4d7ceSDavid van Moolenbroek }
261*d1e4d7ceSDavid van Moolenbroek 
262*d1e4d7ceSDavid van Moolenbroek 
263*d1e4d7ceSDavid van Moolenbroek /* dnormalize():
264*d1e4d7ceSDavid van Moolenbroek  *	If the name starts with . or .. then we might need to normalize
265*d1e4d7ceSDavid van Moolenbroek  *	it depending on the symbolic link flags
266*d1e4d7ceSDavid van Moolenbroek  */
267*d1e4d7ceSDavid van Moolenbroek Char *
dnormalize(Char * cp)268*d1e4d7ceSDavid van Moolenbroek dnormalize(Char *cp)
269*d1e4d7ceSDavid van Moolenbroek {
270*d1e4d7ceSDavid van Moolenbroek #define UC (unsigned char)
271*d1e4d7ceSDavid van Moolenbroek #define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))
272*d1e4d7ceSDavid van Moolenbroek #define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1])))
273*d1e4d7ceSDavid van Moolenbroek     if ((unsigned char) cp[0] == '/')
274*d1e4d7ceSDavid van Moolenbroek 	return (Strsave(cp));
275*d1e4d7ceSDavid van Moolenbroek 
276*d1e4d7ceSDavid van Moolenbroek     if (adrof(STRignore_symlinks)) {
277*d1e4d7ceSDavid van Moolenbroek 	size_t  dotdot = 0;
278*d1e4d7ceSDavid van Moolenbroek 	Char   *dp, *cwd;
279*d1e4d7ceSDavid van Moolenbroek 
280*d1e4d7ceSDavid van Moolenbroek 	cwd = xmalloc((size_t)((Strlen(dcwd->di_name) + 3) *
281*d1e4d7ceSDavid van Moolenbroek 	    sizeof(Char)));
282*d1e4d7ceSDavid van Moolenbroek 	(void)Strcpy(cwd, dcwd->di_name);
283*d1e4d7ceSDavid van Moolenbroek 
284*d1e4d7ceSDavid van Moolenbroek 	/*
285*d1e4d7ceSDavid van Moolenbroek 	 * Ignore . and count ..'s
286*d1e4d7ceSDavid van Moolenbroek 	 */
287*d1e4d7ceSDavid van Moolenbroek 	while (*cp) {
288*d1e4d7ceSDavid van Moolenbroek 	    if (ISDOT(cp)) {
289*d1e4d7ceSDavid van Moolenbroek 		if (*++cp)
290*d1e4d7ceSDavid van Moolenbroek 		    cp++;
291*d1e4d7ceSDavid van Moolenbroek 	    }
292*d1e4d7ceSDavid van Moolenbroek 	    else if (ISDOTDOT(cp)) {
293*d1e4d7ceSDavid van Moolenbroek 		dotdot++;
294*d1e4d7ceSDavid van Moolenbroek 		cp += 2;
295*d1e4d7ceSDavid van Moolenbroek 		if (*cp)
296*d1e4d7ceSDavid van Moolenbroek 		    cp++;
297*d1e4d7ceSDavid van Moolenbroek 	    }
298*d1e4d7ceSDavid van Moolenbroek 	    else
299*d1e4d7ceSDavid van Moolenbroek 		break;
300*d1e4d7ceSDavid van Moolenbroek 	}
301*d1e4d7ceSDavid van Moolenbroek 	while (dotdot > 0) {
302*d1e4d7ceSDavid van Moolenbroek 	    dp = Strrchr(cwd, '/');
303*d1e4d7ceSDavid van Moolenbroek 	    if (dp) {
304*d1e4d7ceSDavid van Moolenbroek 		*dp = '\0';
305*d1e4d7ceSDavid van Moolenbroek 		dotdot--;
306*d1e4d7ceSDavid van Moolenbroek 	    }
307*d1e4d7ceSDavid van Moolenbroek 	    else
308*d1e4d7ceSDavid van Moolenbroek 		break;
309*d1e4d7ceSDavid van Moolenbroek 	}
310*d1e4d7ceSDavid van Moolenbroek 
311*d1e4d7ceSDavid van Moolenbroek 	if (*cp) {
312*d1e4d7ceSDavid van Moolenbroek 	    cwd[dotdot = Strlen(cwd)] = '/';
313*d1e4d7ceSDavid van Moolenbroek 	    cwd[dotdot + 1] = '\0';
314*d1e4d7ceSDavid van Moolenbroek 	    dp = Strspl(cwd, cp);
315*d1e4d7ceSDavid van Moolenbroek 	    xfree((ptr_t) cwd);
316*d1e4d7ceSDavid van Moolenbroek 	    return dp;
317*d1e4d7ceSDavid van Moolenbroek 	}
318*d1e4d7ceSDavid van Moolenbroek 	else {
319*d1e4d7ceSDavid van Moolenbroek 	    if (!*cwd) {
320*d1e4d7ceSDavid van Moolenbroek 		cwd[0] = '/';
321*d1e4d7ceSDavid van Moolenbroek 		cwd[1] = '\0';
322*d1e4d7ceSDavid van Moolenbroek 	    }
323*d1e4d7ceSDavid van Moolenbroek 	    return cwd;
324*d1e4d7ceSDavid van Moolenbroek 	}
325*d1e4d7ceSDavid van Moolenbroek     }
326*d1e4d7ceSDavid van Moolenbroek     return Strsave(cp);
327*d1e4d7ceSDavid van Moolenbroek }
328*d1e4d7ceSDavid van Moolenbroek 
329*d1e4d7ceSDavid van Moolenbroek /*
330*d1e4d7ceSDavid van Moolenbroek  * dochngd - implement chdir command.
331*d1e4d7ceSDavid van Moolenbroek  */
332*d1e4d7ceSDavid van Moolenbroek void
333*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dochngd(Char ** v,struct command * t)334*d1e4d7ceSDavid van Moolenbroek dochngd(Char **v, struct command *t)
335*d1e4d7ceSDavid van Moolenbroek {
336*d1e4d7ceSDavid van Moolenbroek     struct directory *dp;
337*d1e4d7ceSDavid van Moolenbroek     Char *cp;
338*d1e4d7ceSDavid van Moolenbroek 
339*d1e4d7ceSDavid van Moolenbroek     skipargs(&v, " [<dir>]");
340*d1e4d7ceSDavid van Moolenbroek     printd = 0;
341*d1e4d7ceSDavid van Moolenbroek     if (*v == NULL) {
342*d1e4d7ceSDavid van Moolenbroek 	if ((cp = value(STRhome)) == NULL || *cp == 0)
343*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_NAME | ERR_NOHOMEDIR);
344*d1e4d7ceSDavid van Moolenbroek 	if (chdir(short2str(cp)) < 0)
345*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_NAME | ERR_CANTCHANGE);
346*d1e4d7ceSDavid van Moolenbroek 	cp = Strsave(cp);
347*d1e4d7ceSDavid van Moolenbroek     }
348*d1e4d7ceSDavid van Moolenbroek     else if (v[1] != NULL)
349*d1e4d7ceSDavid van Moolenbroek 	stderror(ERR_NAME | ERR_TOOMANY);
350*d1e4d7ceSDavid van Moolenbroek     else if ((dp = dfind(*v)) != 0) {
351*d1e4d7ceSDavid van Moolenbroek 	char   *tmp;
352*d1e4d7ceSDavid van Moolenbroek 
353*d1e4d7ceSDavid van Moolenbroek 	printd = 1;
354*d1e4d7ceSDavid van Moolenbroek 	if (chdir(tmp = short2str(dp->di_name)) < 0)
355*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_SYSTEM, tmp, strerror(errno));
356*d1e4d7ceSDavid van Moolenbroek 	dcwd->di_prev->di_next = dcwd->di_next;
357*d1e4d7ceSDavid van Moolenbroek 	dcwd->di_next->di_prev = dcwd->di_prev;
358*d1e4d7ceSDavid van Moolenbroek 	dfree(dcwd);
359*d1e4d7ceSDavid van Moolenbroek 	dnewcwd(dp);
360*d1e4d7ceSDavid van Moolenbroek 	return;
361*d1e4d7ceSDavid van Moolenbroek     }
362*d1e4d7ceSDavid van Moolenbroek     else
363*d1e4d7ceSDavid van Moolenbroek 	cp = dfollow(*v);
364*d1e4d7ceSDavid van Moolenbroek     dp = (struct directory *)xcalloc(1, sizeof(struct directory));
365*d1e4d7ceSDavid van Moolenbroek     dp->di_name = cp;
366*d1e4d7ceSDavid van Moolenbroek     dp->di_count = 0;
367*d1e4d7ceSDavid van Moolenbroek     dp->di_next = dcwd->di_next;
368*d1e4d7ceSDavid van Moolenbroek     dp->di_prev = dcwd->di_prev;
369*d1e4d7ceSDavid van Moolenbroek     dp->di_prev->di_next = dp;
370*d1e4d7ceSDavid van Moolenbroek     dp->di_next->di_prev = dp;
371*d1e4d7ceSDavid van Moolenbroek     dfree(dcwd);
372*d1e4d7ceSDavid van Moolenbroek     dnewcwd(dp);
373*d1e4d7ceSDavid van Moolenbroek }
374*d1e4d7ceSDavid van Moolenbroek 
375*d1e4d7ceSDavid van Moolenbroek static Char *
dgoto(Char * cp)376*d1e4d7ceSDavid van Moolenbroek dgoto(Char *cp)
377*d1e4d7ceSDavid van Moolenbroek {
378*d1e4d7ceSDavid van Moolenbroek     Char *dp;
379*d1e4d7ceSDavid van Moolenbroek 
380*d1e4d7ceSDavid van Moolenbroek     if (*cp != '/') {
381*d1e4d7ceSDavid van Moolenbroek 	Char *p, *q;
382*d1e4d7ceSDavid van Moolenbroek 	size_t cwdlen;
383*d1e4d7ceSDavid van Moolenbroek 
384*d1e4d7ceSDavid van Moolenbroek 	for (p = dcwd->di_name; *p++;)
385*d1e4d7ceSDavid van Moolenbroek 	    continue;
386*d1e4d7ceSDavid van Moolenbroek 	if ((cwdlen = (size_t)(p - dcwd->di_name - 1)) == 1)	/* root */
387*d1e4d7ceSDavid van Moolenbroek 	    cwdlen = 0;
388*d1e4d7ceSDavid van Moolenbroek 	for (p = cp; *p++;)
389*d1e4d7ceSDavid van Moolenbroek 	    continue;
390*d1e4d7ceSDavid van Moolenbroek 	dp = xmalloc((size_t)(cwdlen + (size_t)(p - cp) + 1) * sizeof(Char));
391*d1e4d7ceSDavid van Moolenbroek 	for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
392*d1e4d7ceSDavid van Moolenbroek 	    continue;
393*d1e4d7ceSDavid van Moolenbroek 	if (cwdlen)
394*d1e4d7ceSDavid van Moolenbroek 	    p[-1] = '/';
395*d1e4d7ceSDavid van Moolenbroek 	else
396*d1e4d7ceSDavid van Moolenbroek 	    p--;		/* don't add a / after root */
397*d1e4d7ceSDavid van Moolenbroek 	for (q = cp; (*p++ = *q++) != '\0';)
398*d1e4d7ceSDavid van Moolenbroek 	    continue;
399*d1e4d7ceSDavid van Moolenbroek 	xfree((ptr_t) cp);
400*d1e4d7ceSDavid van Moolenbroek 	cp = dp;
401*d1e4d7ceSDavid van Moolenbroek 	dp += cwdlen;
402*d1e4d7ceSDavid van Moolenbroek     }
403*d1e4d7ceSDavid van Moolenbroek     else
404*d1e4d7ceSDavid van Moolenbroek 	dp = cp;
405*d1e4d7ceSDavid van Moolenbroek 
406*d1e4d7ceSDavid van Moolenbroek     cp = dcanon(cp, dp);
407*d1e4d7ceSDavid van Moolenbroek     return cp;
408*d1e4d7ceSDavid van Moolenbroek }
409*d1e4d7ceSDavid van Moolenbroek 
410*d1e4d7ceSDavid van Moolenbroek /*
411*d1e4d7ceSDavid van Moolenbroek  * dfollow - change to arg directory; fall back on cdpath if not valid
412*d1e4d7ceSDavid van Moolenbroek  */
413*d1e4d7ceSDavid van Moolenbroek static Char *
dfollow(Char * cp)414*d1e4d7ceSDavid van Moolenbroek dfollow(Char *cp)
415*d1e4d7ceSDavid van Moolenbroek {
416*d1e4d7ceSDavid van Moolenbroek     char ebuf[MAXPATHLEN];
417*d1e4d7ceSDavid van Moolenbroek     struct varent *c;
418*d1e4d7ceSDavid van Moolenbroek     Char *dp;
419*d1e4d7ceSDavid van Moolenbroek     int serrno;
420*d1e4d7ceSDavid van Moolenbroek 
421*d1e4d7ceSDavid van Moolenbroek     cp = globone(cp, G_ERROR);
422*d1e4d7ceSDavid van Moolenbroek     /*
423*d1e4d7ceSDavid van Moolenbroek      * if we are ignoring symlinks, try to fix relatives now.
424*d1e4d7ceSDavid van Moolenbroek      */
425*d1e4d7ceSDavid van Moolenbroek     dp = dnormalize(cp);
426*d1e4d7ceSDavid van Moolenbroek     if (chdir(short2str(dp)) >= 0) {
427*d1e4d7ceSDavid van Moolenbroek 	xfree((ptr_t) cp);
428*d1e4d7ceSDavid van Moolenbroek 	return dgoto(dp);
429*d1e4d7ceSDavid van Moolenbroek     }
430*d1e4d7ceSDavid van Moolenbroek     else {
431*d1e4d7ceSDavid van Moolenbroek 	xfree((ptr_t) dp);
432*d1e4d7ceSDavid van Moolenbroek 	if (chdir(short2str(cp)) >= 0)
433*d1e4d7ceSDavid van Moolenbroek 	    return dgoto(cp);
434*d1e4d7ceSDavid van Moolenbroek 	serrno = errno;
435*d1e4d7ceSDavid van Moolenbroek     }
436*d1e4d7ceSDavid van Moolenbroek 
437*d1e4d7ceSDavid van Moolenbroek     if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
438*d1e4d7ceSDavid van Moolenbroek 	&& (c = adrof(STRcdpath))) {
439*d1e4d7ceSDavid van Moolenbroek 	Char  **cdp;
440*d1e4d7ceSDavid van Moolenbroek 	Char *p;
441*d1e4d7ceSDavid van Moolenbroek 	Char    buf[MAXPATHLEN];
442*d1e4d7ceSDavid van Moolenbroek 
443*d1e4d7ceSDavid van Moolenbroek 	for (cdp = c->vec; *cdp; cdp++) {
444*d1e4d7ceSDavid van Moolenbroek 	    for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';)
445*d1e4d7ceSDavid van Moolenbroek 		continue;
446*d1e4d7ceSDavid van Moolenbroek 	    dp[-1] = '/';
447*d1e4d7ceSDavid van Moolenbroek 	    for (p = cp; (*dp++ = *p++) != '\0';)
448*d1e4d7ceSDavid van Moolenbroek 		continue;
449*d1e4d7ceSDavid van Moolenbroek 	    if (chdir(short2str(buf)) >= 0) {
450*d1e4d7ceSDavid van Moolenbroek 		printd = 1;
451*d1e4d7ceSDavid van Moolenbroek 		xfree((ptr_t) cp);
452*d1e4d7ceSDavid van Moolenbroek 		cp = Strsave(buf);
453*d1e4d7ceSDavid van Moolenbroek 		return dgoto(cp);
454*d1e4d7ceSDavid van Moolenbroek 	    }
455*d1e4d7ceSDavid van Moolenbroek 	}
456*d1e4d7ceSDavid van Moolenbroek     }
457*d1e4d7ceSDavid van Moolenbroek     dp = value(cp);
458*d1e4d7ceSDavid van Moolenbroek     if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
459*d1e4d7ceSDavid van Moolenbroek 	xfree((ptr_t) cp);
460*d1e4d7ceSDavid van Moolenbroek 	cp = Strsave(dp);
461*d1e4d7ceSDavid van Moolenbroek 	printd = 1;
462*d1e4d7ceSDavid van Moolenbroek 	return dgoto(cp);
463*d1e4d7ceSDavid van Moolenbroek     }
464*d1e4d7ceSDavid van Moolenbroek     (void)strcpy(ebuf, short2str(cp));
465*d1e4d7ceSDavid van Moolenbroek     xfree((ptr_t) cp);
466*d1e4d7ceSDavid van Moolenbroek     stderror(ERR_SYSTEM, ebuf, strerror(serrno));
467*d1e4d7ceSDavid van Moolenbroek     /* NOTREACHED */
468*d1e4d7ceSDavid van Moolenbroek }
469*d1e4d7ceSDavid van Moolenbroek 
470*d1e4d7ceSDavid van Moolenbroek /*
471*d1e4d7ceSDavid van Moolenbroek  * dopushd - push new directory onto directory stack.
472*d1e4d7ceSDavid van Moolenbroek  *	with no arguments exchange top and second.
473*d1e4d7ceSDavid van Moolenbroek  *	with numeric argument (+n) bring it to top.
474*d1e4d7ceSDavid van Moolenbroek  */
475*d1e4d7ceSDavid van Moolenbroek void
476*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dopushd(Char ** v,struct command * t)477*d1e4d7ceSDavid van Moolenbroek dopushd(Char **v, struct command *t)
478*d1e4d7ceSDavid van Moolenbroek {
479*d1e4d7ceSDavid van Moolenbroek     struct directory *dp;
480*d1e4d7ceSDavid van Moolenbroek 
481*d1e4d7ceSDavid van Moolenbroek     skipargs(&v, " [<dir>|+<n>]");
482*d1e4d7ceSDavid van Moolenbroek     printd = 1;
483*d1e4d7ceSDavid van Moolenbroek     if (*v == NULL) {
484*d1e4d7ceSDavid van Moolenbroek 	char   *tmp;
485*d1e4d7ceSDavid van Moolenbroek 
486*d1e4d7ceSDavid van Moolenbroek 	if ((dp = dcwd->di_prev) == &dhead)
487*d1e4d7ceSDavid van Moolenbroek 	    dp = dhead.di_prev;
488*d1e4d7ceSDavid van Moolenbroek 	if (dp == dcwd)
489*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_NAME | ERR_NODIR);
490*d1e4d7ceSDavid van Moolenbroek 	if (chdir(tmp = short2str(dp->di_name)) < 0)
491*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_SYSTEM, tmp, strerror(errno));
492*d1e4d7ceSDavid van Moolenbroek 	dp->di_prev->di_next = dp->di_next;
493*d1e4d7ceSDavid van Moolenbroek 	dp->di_next->di_prev = dp->di_prev;
494*d1e4d7ceSDavid van Moolenbroek 	dp->di_next = dcwd->di_next;
495*d1e4d7ceSDavid van Moolenbroek 	dp->di_prev = dcwd;
496*d1e4d7ceSDavid van Moolenbroek 	dcwd->di_next->di_prev = dp;
497*d1e4d7ceSDavid van Moolenbroek 	dcwd->di_next = dp;
498*d1e4d7ceSDavid van Moolenbroek     }
499*d1e4d7ceSDavid van Moolenbroek     else if (v[1] != NULL)
500*d1e4d7ceSDavid van Moolenbroek 	stderror(ERR_NAME | ERR_TOOMANY);
501*d1e4d7ceSDavid van Moolenbroek     else if ((dp = dfind(*v)) != NULL) {
502*d1e4d7ceSDavid van Moolenbroek 	char   *tmp;
503*d1e4d7ceSDavid van Moolenbroek 
504*d1e4d7ceSDavid van Moolenbroek 	if (chdir(tmp = short2str(dp->di_name)) < 0)
505*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_SYSTEM, tmp, strerror(errno));
506*d1e4d7ceSDavid van Moolenbroek     }
507*d1e4d7ceSDavid van Moolenbroek     else {
508*d1e4d7ceSDavid van Moolenbroek 	Char *ccp;
509*d1e4d7ceSDavid van Moolenbroek 
510*d1e4d7ceSDavid van Moolenbroek 	ccp = dfollow(*v);
511*d1e4d7ceSDavid van Moolenbroek 	dp = (struct directory *)xcalloc(1, sizeof(struct directory));
512*d1e4d7ceSDavid van Moolenbroek 	dp->di_name = ccp;
513*d1e4d7ceSDavid van Moolenbroek 	dp->di_count = 0;
514*d1e4d7ceSDavid van Moolenbroek 	dp->di_prev = dcwd;
515*d1e4d7ceSDavid van Moolenbroek 	dp->di_next = dcwd->di_next;
516*d1e4d7ceSDavid van Moolenbroek 	dcwd->di_next = dp;
517*d1e4d7ceSDavid van Moolenbroek 	dp->di_next->di_prev = dp;
518*d1e4d7ceSDavid van Moolenbroek     }
519*d1e4d7ceSDavid van Moolenbroek     dnewcwd(dp);
520*d1e4d7ceSDavid van Moolenbroek }
521*d1e4d7ceSDavid van Moolenbroek 
522*d1e4d7ceSDavid van Moolenbroek /*
523*d1e4d7ceSDavid van Moolenbroek  * dfind - find a directory if specified by numeric (+n) argument
524*d1e4d7ceSDavid van Moolenbroek  */
525*d1e4d7ceSDavid van Moolenbroek static struct directory *
dfind(Char * cp)526*d1e4d7ceSDavid van Moolenbroek dfind(Char *cp)
527*d1e4d7ceSDavid van Moolenbroek {
528*d1e4d7ceSDavid van Moolenbroek     struct directory *dp;
529*d1e4d7ceSDavid van Moolenbroek     Char *ep;
530*d1e4d7ceSDavid van Moolenbroek     int i;
531*d1e4d7ceSDavid van Moolenbroek 
532*d1e4d7ceSDavid van Moolenbroek     if (*cp++ != '+')
533*d1e4d7ceSDavid van Moolenbroek 	return (0);
534*d1e4d7ceSDavid van Moolenbroek     for (ep = cp; Isdigit(*ep); ep++)
535*d1e4d7ceSDavid van Moolenbroek 	continue;
536*d1e4d7ceSDavid van Moolenbroek     if (*ep)
537*d1e4d7ceSDavid van Moolenbroek 	return (0);
538*d1e4d7ceSDavid van Moolenbroek     i = getn(cp);
539*d1e4d7ceSDavid van Moolenbroek     if (i <= 0)
540*d1e4d7ceSDavid van Moolenbroek 	return (0);
541*d1e4d7ceSDavid van Moolenbroek     for (dp = dcwd; i != 0; i--) {
542*d1e4d7ceSDavid van Moolenbroek 	if ((dp = dp->di_prev) == &dhead)
543*d1e4d7ceSDavid van Moolenbroek 	    dp = dp->di_prev;
544*d1e4d7ceSDavid van Moolenbroek 	if (dp == dcwd)
545*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_NAME | ERR_DEEP);
546*d1e4d7ceSDavid van Moolenbroek     }
547*d1e4d7ceSDavid van Moolenbroek     return (dp);
548*d1e4d7ceSDavid van Moolenbroek }
549*d1e4d7ceSDavid van Moolenbroek 
550*d1e4d7ceSDavid van Moolenbroek /*
551*d1e4d7ceSDavid van Moolenbroek  * dopopd - pop a directory out of the directory stack
552*d1e4d7ceSDavid van Moolenbroek  *	with a numeric argument just discard it.
553*d1e4d7ceSDavid van Moolenbroek  */
554*d1e4d7ceSDavid van Moolenbroek void
555*d1e4d7ceSDavid van Moolenbroek /*ARGSUSED*/
dopopd(Char ** v,struct command * t)556*d1e4d7ceSDavid van Moolenbroek dopopd(Char **v, struct command *t)
557*d1e4d7ceSDavid van Moolenbroek {
558*d1e4d7ceSDavid van Moolenbroek     struct directory *dp, *p = NULL;
559*d1e4d7ceSDavid van Moolenbroek 
560*d1e4d7ceSDavid van Moolenbroek     skipargs(&v, " [+<n>]");
561*d1e4d7ceSDavid van Moolenbroek     printd = 1;
562*d1e4d7ceSDavid van Moolenbroek     if (*v == NULL)
563*d1e4d7ceSDavid van Moolenbroek 	dp = dcwd;
564*d1e4d7ceSDavid van Moolenbroek     else if (v[1] != NULL)
565*d1e4d7ceSDavid van Moolenbroek 	stderror(ERR_NAME | ERR_TOOMANY);
566*d1e4d7ceSDavid van Moolenbroek     else if ((dp = dfind(*v)) == 0)
567*d1e4d7ceSDavid van Moolenbroek 	stderror(ERR_NAME | ERR_BADDIR);
568*d1e4d7ceSDavid van Moolenbroek     if (dp->di_prev == &dhead && dp->di_next == &dhead)
569*d1e4d7ceSDavid van Moolenbroek 	stderror(ERR_NAME | ERR_EMPTY);
570*d1e4d7ceSDavid van Moolenbroek     if (dp == dcwd) {
571*d1e4d7ceSDavid van Moolenbroek 	char *tmp;
572*d1e4d7ceSDavid van Moolenbroek 
573*d1e4d7ceSDavid van Moolenbroek 	if ((p = dp->di_prev) == &dhead)
574*d1e4d7ceSDavid van Moolenbroek 	    p = dhead.di_prev;
575*d1e4d7ceSDavid van Moolenbroek 	if (chdir(tmp = short2str(p->di_name)) < 0)
576*d1e4d7ceSDavid van Moolenbroek 	    stderror(ERR_SYSTEM, tmp, strerror(errno));
577*d1e4d7ceSDavid van Moolenbroek     }
578*d1e4d7ceSDavid van Moolenbroek     dp->di_prev->di_next = dp->di_next;
579*d1e4d7ceSDavid van Moolenbroek     dp->di_next->di_prev = dp->di_prev;
580*d1e4d7ceSDavid van Moolenbroek     if (dp == dcwd)
581*d1e4d7ceSDavid van Moolenbroek 	dnewcwd(p);
582*d1e4d7ceSDavid van Moolenbroek     else {
583*d1e4d7ceSDavid van Moolenbroek 	printdirs();
584*d1e4d7ceSDavid van Moolenbroek     }
585*d1e4d7ceSDavid van Moolenbroek     dfree(dp);
586*d1e4d7ceSDavid van Moolenbroek }
587*d1e4d7ceSDavid van Moolenbroek 
588*d1e4d7ceSDavid van Moolenbroek /*
589*d1e4d7ceSDavid van Moolenbroek  * dfree - free the directory (or keep it if it still has ref count)
590*d1e4d7ceSDavid van Moolenbroek  */
591*d1e4d7ceSDavid van Moolenbroek void
dfree(struct directory * dp)592*d1e4d7ceSDavid van Moolenbroek dfree(struct directory *dp)
593*d1e4d7ceSDavid van Moolenbroek {
594*d1e4d7ceSDavid van Moolenbroek 
595*d1e4d7ceSDavid van Moolenbroek     if (dp->di_count != 0) {
596*d1e4d7ceSDavid van Moolenbroek 	dp->di_next = dp->di_prev = 0;
597*d1e4d7ceSDavid van Moolenbroek     }
598*d1e4d7ceSDavid van Moolenbroek     else {
599*d1e4d7ceSDavid van Moolenbroek 	xfree((char *) dp->di_name);
600*d1e4d7ceSDavid van Moolenbroek 	xfree((ptr_t) dp);
601*d1e4d7ceSDavid van Moolenbroek     }
602*d1e4d7ceSDavid van Moolenbroek }
603*d1e4d7ceSDavid van Moolenbroek 
604*d1e4d7ceSDavid van Moolenbroek /*
605*d1e4d7ceSDavid van Moolenbroek  * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
606*d1e4d7ceSDavid van Moolenbroek  *	we are of course assuming that the file system is standardly
607*d1e4d7ceSDavid van Moolenbroek  *	constructed (always have ..'s, directories have links)
608*d1e4d7ceSDavid van Moolenbroek  */
609*d1e4d7ceSDavid van Moolenbroek Char *
dcanon(Char * cp,Char * p)610*d1e4d7ceSDavid van Moolenbroek dcanon(Char *cp, Char *p)
611*d1e4d7ceSDavid van Moolenbroek {
612*d1e4d7ceSDavid van Moolenbroek     Char slink[MAXPATHLEN];
613*d1e4d7ceSDavid van Moolenbroek     char tlink[MAXPATHLEN];
614*d1e4d7ceSDavid van Moolenbroek     Char *newcp, *sp;
615*d1e4d7ceSDavid van Moolenbroek     Char *p1, *p2;	/* general purpose */
616*d1e4d7ceSDavid van Moolenbroek     ssize_t cc;
617*d1e4d7ceSDavid van Moolenbroek     size_t len;
618*d1e4d7ceSDavid van Moolenbroek     int slash;
619*d1e4d7ceSDavid van Moolenbroek 
620*d1e4d7ceSDavid van Moolenbroek     /*
621*d1e4d7ceSDavid van Moolenbroek      * christos: if the path given does not start with a slash prepend cwd. If
622*d1e4d7ceSDavid van Moolenbroek      * cwd does not start with a path or the result would be too long abort().
623*d1e4d7ceSDavid van Moolenbroek      */
624*d1e4d7ceSDavid van Moolenbroek     if (*cp != '/') {
625*d1e4d7ceSDavid van Moolenbroek 	Char tmpdir[MAXPATHLEN];
626*d1e4d7ceSDavid van Moolenbroek 
627*d1e4d7ceSDavid van Moolenbroek 	p1 = value(STRcwd);
628*d1e4d7ceSDavid van Moolenbroek 	if (p1 == NULL || *p1 != '/')
629*d1e4d7ceSDavid van Moolenbroek 	    abort();
630*d1e4d7ceSDavid van Moolenbroek 	if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
631*d1e4d7ceSDavid van Moolenbroek 	    abort();
632*d1e4d7ceSDavid van Moolenbroek 	(void)Strcpy(tmpdir, p1);
633*d1e4d7ceSDavid van Moolenbroek 	(void)Strcat(tmpdir, STRslash);
634*d1e4d7ceSDavid van Moolenbroek 	(void)Strcat(tmpdir, cp);
635*d1e4d7ceSDavid van Moolenbroek 	xfree((ptr_t) cp);
636*d1e4d7ceSDavid van Moolenbroek 	cp = p = Strsave(tmpdir);
637*d1e4d7ceSDavid van Moolenbroek     }
638*d1e4d7ceSDavid van Moolenbroek 
639*d1e4d7ceSDavid van Moolenbroek     while (*p) {		/* for each component */
640*d1e4d7ceSDavid van Moolenbroek 	sp = p;			/* save slash address */
641*d1e4d7ceSDavid van Moolenbroek 	while (*++p == '/')	/* flush extra slashes */
642*d1e4d7ceSDavid van Moolenbroek 	    continue;
643*d1e4d7ceSDavid van Moolenbroek 	if (p != ++sp)
644*d1e4d7ceSDavid van Moolenbroek 	    for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
645*d1e4d7ceSDavid van Moolenbroek 		continue;
646*d1e4d7ceSDavid van Moolenbroek 	p = sp;			/* save start of component */
647*d1e4d7ceSDavid van Moolenbroek 	slash = 0;
648*d1e4d7ceSDavid van Moolenbroek 	while (*++p)		/* find next slash or end of path */
649*d1e4d7ceSDavid van Moolenbroek 	    if (*p == '/') {
650*d1e4d7ceSDavid van Moolenbroek 		slash = 1;
651*d1e4d7ceSDavid van Moolenbroek 		*p = 0;
652*d1e4d7ceSDavid van Moolenbroek 		break;
653*d1e4d7ceSDavid van Moolenbroek 	    }
654*d1e4d7ceSDavid van Moolenbroek 
655*d1e4d7ceSDavid van Moolenbroek 	if (*sp == '\0') {	/* if component is null */
656*d1e4d7ceSDavid van Moolenbroek 	    if (--sp == cp)	/* if path is one char (i.e. /) */
657*d1e4d7ceSDavid van Moolenbroek 		break;
658*d1e4d7ceSDavid van Moolenbroek 	    else
659*d1e4d7ceSDavid van Moolenbroek 		*sp = '\0';
660*d1e4d7ceSDavid van Moolenbroek 	} else if (sp[0] == '.' && sp[1] == 0) {
661*d1e4d7ceSDavid van Moolenbroek 	    if (slash) {
662*d1e4d7ceSDavid van Moolenbroek 		for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
663*d1e4d7ceSDavid van Moolenbroek 		    continue;
664*d1e4d7ceSDavid van Moolenbroek 		p = --sp;
665*d1e4d7ceSDavid van Moolenbroek 	    }
666*d1e4d7ceSDavid van Moolenbroek 	    else if (--sp != cp)
667*d1e4d7ceSDavid van Moolenbroek 		*sp = '\0';
668*d1e4d7ceSDavid van Moolenbroek 	}
669*d1e4d7ceSDavid van Moolenbroek 	else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
670*d1e4d7ceSDavid van Moolenbroek 	    /*
671*d1e4d7ceSDavid van Moolenbroek 	     * We have something like "yyy/xxx/..", where "yyy" can be null or
672*d1e4d7ceSDavid van Moolenbroek 	     * a path starting at /, and "xxx" is a single component. Before
673*d1e4d7ceSDavid van Moolenbroek 	     * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
674*d1e4d7ceSDavid van Moolenbroek 	     * symbolic link.
675*d1e4d7ceSDavid van Moolenbroek 	     */
676*d1e4d7ceSDavid van Moolenbroek 	    *--sp = 0;		/* form the pathname for readlink */
677*d1e4d7ceSDavid van Moolenbroek 	    if (sp != cp && !adrof(STRignore_symlinks) &&
678*d1e4d7ceSDavid van Moolenbroek 		(cc = readlink(short2str(cp), tlink,
679*d1e4d7ceSDavid van Moolenbroek 			       sizeof(tlink) - 1)) >= 0) {
680*d1e4d7ceSDavid van Moolenbroek 		tlink[cc] = '\0';
681*d1e4d7ceSDavid van Moolenbroek 		(void)Strcpy(slink, str2short(tlink));
682*d1e4d7ceSDavid van Moolenbroek 
683*d1e4d7ceSDavid van Moolenbroek 		if (slash)
684*d1e4d7ceSDavid van Moolenbroek 		    *p = '/';
685*d1e4d7ceSDavid van Moolenbroek 		/*
686*d1e4d7ceSDavid van Moolenbroek 		 * Point p to the '/' in "/..", and restore the '/'.
687*d1e4d7ceSDavid van Moolenbroek 		 */
688*d1e4d7ceSDavid van Moolenbroek 		*(p = sp) = '/';
689*d1e4d7ceSDavid van Moolenbroek 		/*
690*d1e4d7ceSDavid van Moolenbroek 		 * find length of p
691*d1e4d7ceSDavid van Moolenbroek 		 */
692*d1e4d7ceSDavid van Moolenbroek 		for (p1 = p; *p1++;)
693*d1e4d7ceSDavid van Moolenbroek 		    continue;
694*d1e4d7ceSDavid van Moolenbroek 		if (*slink != '/') {
695*d1e4d7ceSDavid van Moolenbroek 		    /*
696*d1e4d7ceSDavid van Moolenbroek 		     * Relative path, expand it between the "yyy/" and the
697*d1e4d7ceSDavid van Moolenbroek 		     * "/..". First, back sp up to the character past "yyy/".
698*d1e4d7ceSDavid van Moolenbroek 		     */
699*d1e4d7ceSDavid van Moolenbroek 		    while (*--sp != '/')
700*d1e4d7ceSDavid van Moolenbroek 			continue;
701*d1e4d7ceSDavid van Moolenbroek 		    sp++;
702*d1e4d7ceSDavid van Moolenbroek 		    *sp = 0;
703*d1e4d7ceSDavid van Moolenbroek 		    /*
704*d1e4d7ceSDavid van Moolenbroek 		     * New length is "yyy/" + slink + "/.." and rest
705*d1e4d7ceSDavid van Moolenbroek 		     */
706*d1e4d7ceSDavid van Moolenbroek 		    p1 = newcp = xmalloc(
707*d1e4d7ceSDavid van Moolenbroek 		        (size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char));
708*d1e4d7ceSDavid van Moolenbroek 		    /*
709*d1e4d7ceSDavid van Moolenbroek 		     * Copy new path into newcp
710*d1e4d7ceSDavid van Moolenbroek 		     */
711*d1e4d7ceSDavid van Moolenbroek 		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
712*d1e4d7ceSDavid van Moolenbroek 			continue;
713*d1e4d7ceSDavid van Moolenbroek 		    for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';)
714*d1e4d7ceSDavid van Moolenbroek 			continue;
715*d1e4d7ceSDavid van Moolenbroek 		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
716*d1e4d7ceSDavid van Moolenbroek 			continue;
717*d1e4d7ceSDavid van Moolenbroek 		    /*
718*d1e4d7ceSDavid van Moolenbroek 		     * Restart canonicalization at expanded "/xxx".
719*d1e4d7ceSDavid van Moolenbroek 		     */
720*d1e4d7ceSDavid van Moolenbroek 		    p = sp - cp - 1 + newcp;
721*d1e4d7ceSDavid van Moolenbroek 		}
722*d1e4d7ceSDavid van Moolenbroek 		else {
723*d1e4d7ceSDavid van Moolenbroek 		    /*
724*d1e4d7ceSDavid van Moolenbroek 		     * New length is slink + "/.." and rest
725*d1e4d7ceSDavid van Moolenbroek 		     */
726*d1e4d7ceSDavid van Moolenbroek 		    p1 = newcp = xmalloc(
727*d1e4d7ceSDavid van Moolenbroek 		        (size_t)(cc + (p1 - p)) * sizeof(Char));
728*d1e4d7ceSDavid van Moolenbroek 		    /*
729*d1e4d7ceSDavid van Moolenbroek 		     * Copy new path into newcp
730*d1e4d7ceSDavid van Moolenbroek 		     */
731*d1e4d7ceSDavid van Moolenbroek 		    for (p2 = slink; (*p1++ = *p2++) != '\0';)
732*d1e4d7ceSDavid van Moolenbroek 			continue;
733*d1e4d7ceSDavid van Moolenbroek 		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
734*d1e4d7ceSDavid van Moolenbroek 			continue;
735*d1e4d7ceSDavid van Moolenbroek 		    /*
736*d1e4d7ceSDavid van Moolenbroek 		     * Restart canonicalization at beginning
737*d1e4d7ceSDavid van Moolenbroek 		     */
738*d1e4d7ceSDavid van Moolenbroek 		    p = newcp;
739*d1e4d7ceSDavid van Moolenbroek 		}
740*d1e4d7ceSDavid van Moolenbroek 		xfree((ptr_t) cp);
741*d1e4d7ceSDavid van Moolenbroek 		cp = newcp;
742*d1e4d7ceSDavid van Moolenbroek 		continue;	/* canonicalize the link */
743*d1e4d7ceSDavid van Moolenbroek 	    }
744*d1e4d7ceSDavid van Moolenbroek 	    *sp = '/';
745*d1e4d7ceSDavid van Moolenbroek 	    if (sp != cp)
746*d1e4d7ceSDavid van Moolenbroek 		while (*--sp != '/')
747*d1e4d7ceSDavid van Moolenbroek 		    continue;
748*d1e4d7ceSDavid van Moolenbroek 	    if (slash) {
749*d1e4d7ceSDavid van Moolenbroek 		for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
750*d1e4d7ceSDavid van Moolenbroek 		    continue;
751*d1e4d7ceSDavid van Moolenbroek 		p = sp;
752*d1e4d7ceSDavid van Moolenbroek 	    }
753*d1e4d7ceSDavid van Moolenbroek 	    else if (cp == sp)
754*d1e4d7ceSDavid van Moolenbroek 		*++sp = '\0';
755*d1e4d7ceSDavid van Moolenbroek 	    else
756*d1e4d7ceSDavid van Moolenbroek 		*sp = '\0';
757*d1e4d7ceSDavid van Moolenbroek 	}
758*d1e4d7ceSDavid van Moolenbroek 	else {			/* normal dir name (not . or .. or nothing) */
759*d1e4d7ceSDavid van Moolenbroek 
760*d1e4d7ceSDavid van Moolenbroek 	    if (sp != cp && adrof(STRchase_symlinks) &&
761*d1e4d7ceSDavid van Moolenbroek 		!adrof(STRignore_symlinks) &&
762*d1e4d7ceSDavid van Moolenbroek 		(cc = readlink(short2str(cp), tlink, sizeof(tlink)-1)) >= 0) {
763*d1e4d7ceSDavid van Moolenbroek 		tlink[cc] = '\0';
764*d1e4d7ceSDavid van Moolenbroek 		(void)Strcpy(slink, str2short(tlink));
765*d1e4d7ceSDavid van Moolenbroek 
766*d1e4d7ceSDavid van Moolenbroek 		/*
767*d1e4d7ceSDavid van Moolenbroek 		 * restore the '/'.
768*d1e4d7ceSDavid van Moolenbroek 		 */
769*d1e4d7ceSDavid van Moolenbroek 		if (slash)
770*d1e4d7ceSDavid van Moolenbroek 		    *p = '/';
771*d1e4d7ceSDavid van Moolenbroek 
772*d1e4d7ceSDavid van Moolenbroek 		/*
773*d1e4d7ceSDavid van Moolenbroek 		 * point sp to p (rather than backing up).
774*d1e4d7ceSDavid van Moolenbroek 		 */
775*d1e4d7ceSDavid van Moolenbroek 		sp = p;
776*d1e4d7ceSDavid van Moolenbroek 
777*d1e4d7ceSDavid van Moolenbroek 		/*
778*d1e4d7ceSDavid van Moolenbroek 		 * find length of p
779*d1e4d7ceSDavid van Moolenbroek 		 */
780*d1e4d7ceSDavid van Moolenbroek 		for (p1 = p; *p1++;)
781*d1e4d7ceSDavid van Moolenbroek 		    continue;
782*d1e4d7ceSDavid van Moolenbroek 		if (*slink != '/') {
783*d1e4d7ceSDavid van Moolenbroek 		    /*
784*d1e4d7ceSDavid van Moolenbroek 		     * Relative path, expand it between the "yyy/" and the
785*d1e4d7ceSDavid van Moolenbroek 		     * remainder. First, back sp up to the character past
786*d1e4d7ceSDavid van Moolenbroek 		     * "yyy/".
787*d1e4d7ceSDavid van Moolenbroek 		     */
788*d1e4d7ceSDavid van Moolenbroek 		    while (*--sp != '/')
789*d1e4d7ceSDavid van Moolenbroek 			continue;
790*d1e4d7ceSDavid van Moolenbroek 		    sp++;
791*d1e4d7ceSDavid van Moolenbroek 		    *sp = 0;
792*d1e4d7ceSDavid van Moolenbroek 		    /*
793*d1e4d7ceSDavid van Moolenbroek 		     * New length is "yyy/" + slink + "/.." and rest
794*d1e4d7ceSDavid van Moolenbroek 		     */
795*d1e4d7ceSDavid van Moolenbroek 		    p1 = newcp = xmalloc(
796*d1e4d7ceSDavid van Moolenbroek 		        (size_t)((sp - cp) + cc + (p1 - p)) * sizeof(Char));
797*d1e4d7ceSDavid van Moolenbroek 		    /*
798*d1e4d7ceSDavid van Moolenbroek 		     * Copy new path into newcp
799*d1e4d7ceSDavid van Moolenbroek 		     */
800*d1e4d7ceSDavid van Moolenbroek 		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
801*d1e4d7ceSDavid van Moolenbroek 			continue;
802*d1e4d7ceSDavid van Moolenbroek 		    for (p1--, p2 = slink; (*p1++ = *p2++) != '\0';)
803*d1e4d7ceSDavid van Moolenbroek 			continue;
804*d1e4d7ceSDavid van Moolenbroek 		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
805*d1e4d7ceSDavid van Moolenbroek 			continue;
806*d1e4d7ceSDavid van Moolenbroek 		    /*
807*d1e4d7ceSDavid van Moolenbroek 		     * Restart canonicalization at expanded "/xxx".
808*d1e4d7ceSDavid van Moolenbroek 		     */
809*d1e4d7ceSDavid van Moolenbroek 		    p = sp - cp - 1 + newcp;
810*d1e4d7ceSDavid van Moolenbroek 		}
811*d1e4d7ceSDavid van Moolenbroek 		else {
812*d1e4d7ceSDavid van Moolenbroek 		    /*
813*d1e4d7ceSDavid van Moolenbroek 		     * New length is slink + the rest
814*d1e4d7ceSDavid van Moolenbroek 		     */
815*d1e4d7ceSDavid van Moolenbroek 		    p1 = newcp = xmalloc(
816*d1e4d7ceSDavid van Moolenbroek 		        (size_t)(cc + (p1 - p)) * sizeof(Char));
817*d1e4d7ceSDavid van Moolenbroek 		    /*
818*d1e4d7ceSDavid van Moolenbroek 		     * Copy new path into newcp
819*d1e4d7ceSDavid van Moolenbroek 		     */
820*d1e4d7ceSDavid van Moolenbroek 		    for (p2 = slink; (*p1++ = *p2++) != '\0';)
821*d1e4d7ceSDavid van Moolenbroek 			continue;
822*d1e4d7ceSDavid van Moolenbroek 		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
823*d1e4d7ceSDavid van Moolenbroek 			continue;
824*d1e4d7ceSDavid van Moolenbroek 		    /*
825*d1e4d7ceSDavid van Moolenbroek 		     * Restart canonicalization at beginning
826*d1e4d7ceSDavid van Moolenbroek 		     */
827*d1e4d7ceSDavid van Moolenbroek 		    p = newcp;
828*d1e4d7ceSDavid van Moolenbroek 		}
829*d1e4d7ceSDavid van Moolenbroek 		xfree((ptr_t) cp);
830*d1e4d7ceSDavid van Moolenbroek 		cp = newcp;
831*d1e4d7ceSDavid van Moolenbroek 		continue;	/* canonicalize the link */
832*d1e4d7ceSDavid van Moolenbroek 	    }
833*d1e4d7ceSDavid van Moolenbroek 	    if (slash)
834*d1e4d7ceSDavid van Moolenbroek 		*p = '/';
835*d1e4d7ceSDavid van Moolenbroek 	}
836*d1e4d7ceSDavid van Moolenbroek     }
837*d1e4d7ceSDavid van Moolenbroek 
838*d1e4d7ceSDavid van Moolenbroek     /*
839*d1e4d7ceSDavid van Moolenbroek      * fix home...
840*d1e4d7ceSDavid van Moolenbroek      */
841*d1e4d7ceSDavid van Moolenbroek     p1 = value(STRhome);
842*d1e4d7ceSDavid van Moolenbroek     len = Strlen(p1);
843*d1e4d7ceSDavid van Moolenbroek     /*
844*d1e4d7ceSDavid van Moolenbroek      * See if we're not in a subdir of STRhome
845*d1e4d7ceSDavid van Moolenbroek      */
846*d1e4d7ceSDavid van Moolenbroek     if (p1 && *p1 == '/' &&
847*d1e4d7ceSDavid van Moolenbroek 	(Strncmp(p1, cp, len) != 0 || (cp[len] != '/' && cp[len] != '\0'))) {
848*d1e4d7ceSDavid van Moolenbroek 	static ino_t home_ino;
849*d1e4d7ceSDavid van Moolenbroek 	static dev_t home_dev = NODEV;
850*d1e4d7ceSDavid van Moolenbroek 	static Char *home_ptr = NULL;
851*d1e4d7ceSDavid van Moolenbroek 	struct stat statbuf;
852*d1e4d7ceSDavid van Moolenbroek 
853*d1e4d7ceSDavid van Moolenbroek 	/*
854*d1e4d7ceSDavid van Moolenbroek 	 * Get dev and ino of STRhome
855*d1e4d7ceSDavid van Moolenbroek 	 */
856*d1e4d7ceSDavid van Moolenbroek 	if (home_ptr != p1 &&
857*d1e4d7ceSDavid van Moolenbroek 	    stat(short2str(p1), &statbuf) != -1) {
858*d1e4d7ceSDavid van Moolenbroek 	    home_dev = statbuf.st_dev;
859*d1e4d7ceSDavid van Moolenbroek 	    home_ino = statbuf.st_ino;
860*d1e4d7ceSDavid van Moolenbroek 	    home_ptr = p1;
861*d1e4d7ceSDavid van Moolenbroek 	}
862*d1e4d7ceSDavid van Moolenbroek 	/*
863*d1e4d7ceSDavid van Moolenbroek 	 * Start comparing dev & ino backwards
864*d1e4d7ceSDavid van Moolenbroek 	 */
865*d1e4d7ceSDavid van Moolenbroek 	p2 = Strcpy(slink, cp);
866*d1e4d7ceSDavid van Moolenbroek 	for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) {
867*d1e4d7ceSDavid van Moolenbroek 	    if (statbuf.st_dev == home_dev &&
868*d1e4d7ceSDavid van Moolenbroek 		statbuf.st_ino == home_ino) {
869*d1e4d7ceSDavid van Moolenbroek 		sp = (Char *) - 1;
870*d1e4d7ceSDavid van Moolenbroek 		break;
871*d1e4d7ceSDavid van Moolenbroek 	    }
872*d1e4d7ceSDavid van Moolenbroek 	    if ((sp = Strrchr(p2, '/')) != NULL)
873*d1e4d7ceSDavid van Moolenbroek 		*sp = '\0';
874*d1e4d7ceSDavid van Moolenbroek 	}
875*d1e4d7ceSDavid van Moolenbroek 	/*
876*d1e4d7ceSDavid van Moolenbroek 	 * See if we found it
877*d1e4d7ceSDavid van Moolenbroek 	 */
878*d1e4d7ceSDavid van Moolenbroek 	if (*p2 && sp == (Char *) -1) {
879*d1e4d7ceSDavid van Moolenbroek 	    /*
880*d1e4d7ceSDavid van Moolenbroek 	     * Use STRhome to make '~' work
881*d1e4d7ceSDavid van Moolenbroek 	     */
882*d1e4d7ceSDavid van Moolenbroek 	    newcp = Strspl(p1, cp + Strlen(p2));
883*d1e4d7ceSDavid van Moolenbroek 	    xfree((ptr_t) cp);
884*d1e4d7ceSDavid van Moolenbroek 	    cp = newcp;
885*d1e4d7ceSDavid van Moolenbroek 	}
886*d1e4d7ceSDavid van Moolenbroek     }
887*d1e4d7ceSDavid van Moolenbroek     return cp;
888*d1e4d7ceSDavid van Moolenbroek }
889*d1e4d7ceSDavid van Moolenbroek 
890*d1e4d7ceSDavid van Moolenbroek 
891*d1e4d7ceSDavid van Moolenbroek /*
892*d1e4d7ceSDavid van Moolenbroek  * dnewcwd - make a new directory in the loop the current one
893*d1e4d7ceSDavid van Moolenbroek  */
894*d1e4d7ceSDavid van Moolenbroek static void
dnewcwd(struct directory * dp)895*d1e4d7ceSDavid van Moolenbroek dnewcwd(struct directory *dp)
896*d1e4d7ceSDavid van Moolenbroek {
897*d1e4d7ceSDavid van Moolenbroek     dcwd = dp;
898*d1e4d7ceSDavid van Moolenbroek     dset(dcwd->di_name);
899*d1e4d7ceSDavid van Moolenbroek     if (printd && !(adrof(STRpushdsilent)))
900*d1e4d7ceSDavid van Moolenbroek 	printdirs();
901*d1e4d7ceSDavid van Moolenbroek }
902