~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/3rdparty/qtcsh/sh.dir.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * sh.dir.c: Directory manipulation functions
 
3
 */
 
4
/*-
 
5
 * Copyright (c) 1980, 1991 The Regents of the University of California.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions
 
10
 * are met:
 
11
 * 1. Redistributions of source code must retain the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer.
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 * 3. All advertising materials mentioning features or use of this software
 
17
 *    must display the following acknowledgement:
 
18
 *      This product includes software developed by the University of
 
19
 *      California, Berkeley and its contributors.
 
20
 * 4. Neither the name of the University nor the names of its contributors
 
21
 *    may be used to endorse or promote products derived from this software
 
22
 *    without specific prior written permission.
 
23
 *
 
24
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
27
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
28
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
29
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
30
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
31
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
33
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
34
 * SUCH DAMAGE.
 
35
 */
 
36
#include "sh.h"
 
37
 
 
38
RCSID("$Id$")
 
39
 
 
40
/*
 
41
 * C Shell - directory management
 
42
 */
 
43
 
 
44
static  void                     dstart         __P((const char *));
 
45
static  struct directory        *dfind          __P((Char *));
 
46
static  Char                    *dfollow        __P((Char *));
 
47
static  void                     printdirs      __P((int));
 
48
static  Char                    *dgoto          __P((Char *));
 
49
static  void                     dnewcwd        __P((struct directory *, int));
 
50
static  void                     dset           __P((Char *));
 
51
static  void                     dextract       __P((struct directory *));
 
52
static  int                      skipargs       __P((Char ***, char *, char *));
 
53
static  void                     dgetstack      __P((void));
 
54
 
 
55
static struct directory dhead INIT_ZERO_STRUCT;         /* "head" of loop */
 
56
static int    printd;                   /* force name to be printed */
 
57
 
 
58
int     bequiet = 0;            /* do not print dir stack -strike */
 
59
 
 
60
static void
 
61
dstart(from)
 
62
    const char *from;
 
63
{
 
64
    xprintf(CGETS(12, 1, "%s: Trying to start from \"%s\"\n"), progname, from);
 
65
}
 
66
 
 
67
/*
 
68
 * dinit - initialize current working directory
 
69
 */
 
70
void
 
71
dinit(hp)
 
72
    Char   *hp;
 
73
{
 
74
    register char *tcp;
 
75
    register Char *cp;
 
76
    register struct directory *dp;
 
77
    char    path[MAXPATHLEN];
 
78
 
 
79
#ifdef INTERIX
 
80
    if ((tcp = (char *) getenv("PWD")) == NULL)
 
81
#endif
 
82
    /* Don't believe the login shell home, because it may be a symlink */
 
83
    tcp = (char *) getcwd(path, sizeof(path));
 
84
    if (tcp == NULL || *tcp == '\0') {
 
85
        xprintf("%s: %s\n", progname, strerror(errno));
 
86
        if (hp && *hp) {
 
87
            tcp = short2str(hp);
 
88
            dstart(tcp);
 
89
            if (chdir(tcp) == -1)
 
90
                cp = NULL;
 
91
            else
 
92
                cp = Strsave(hp);
 
93
        }
 
94
        else
 
95
            cp = NULL;
 
96
        if (cp == NULL) {
 
97
            dstart("/");
 
98
            if (chdir("/") == -1)
 
99
                /* I am not even try to print an error message! */
 
100
                xexit(1);
 
101
            cp = SAVE("/");
 
102
        }
 
103
    }
 
104
    else {
 
105
#ifdef S_IFLNK
 
106
        struct stat swd, shp;
 
107
 
 
108
        /*
 
109
         * See if $HOME is the working directory we got and use that
 
110
         */
 
111
        if (hp && *hp &&
 
112
            stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
 
113
            DEV_DEV_COMPARE(swd.st_dev, shp.st_dev)  &&
 
114
                swd.st_ino == shp.st_ino)
 
115
            cp = Strsave(hp);
 
116
        else {
 
117
            char   *cwd;
 
118
 
 
119
            /*
 
120
             * use PWD if we have it (for subshells)
 
121
             */
 
122
            if ((cwd = getenv("PWD")) != NULL) {
 
123
                if (stat(cwd, &shp) != -1 && 
 
124
                        DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) &&
 
125
                    swd.st_ino == shp.st_ino)
 
126
                    tcp = cwd;
 
127
            }
 
128
            cp = dcanon(SAVE(tcp), STRNULL);
 
129
        }
 
130
#else /* S_IFLNK */
 
131
        cp = dcanon(SAVE(tcp), STRNULL);
 
132
#endif /* S_IFLNK */
 
133
    }
 
134
 
 
135
    dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 
136
    dp->di_name = cp;
 
137
    dp->di_count = 0;
 
138
    dhead.di_next = dhead.di_prev = dp;
 
139
    dp->di_next = dp->di_prev = &dhead;
 
140
    printd = 0;
 
141
    dnewcwd(dp, 0);
 
142
    set(STRdirstack, Strsave(dp->di_name), VAR_READWRITE|VAR_NOGLOB);
 
143
}
 
144
 
 
145
static void
 
146
dset(dp)
 
147
Char *dp;
 
148
{
 
149
    /*
 
150
     * Don't call set() directly cause if the directory contains ` or
 
151
     * other junk characters glob will fail. 
 
152
     */
 
153
    set(STRowd, Strsave(varval(STRcwd)), VAR_READWRITE|VAR_NOGLOB);
 
154
    set(STRcwd, Strsave(dp), VAR_READWRITE|VAR_NOGLOB);
 
155
 
 
156
    tsetenv(STRPWD, dp);
 
157
}
 
158
 
 
159
#define DIR_PRINT       0x01    /* -p */
 
160
#define DIR_LONG        0x02    /* -l */
 
161
#define DIR_VERT        0x04    /* -v */
 
162
#define DIR_LINE        0x08    /* -n */
 
163
#define DIR_SAVE        0x10    /* -S */
 
164
#define DIR_LOAD        0x20    /* -L */
 
165
#define DIR_CLEAR       0x40    /* -c */
 
166
#define DIR_OLD         0x80    /* - */
 
167
 
 
168
static int
 
169
skipargs(v, dstr, str)
 
170
    Char ***v;
 
171
    char   *dstr;
 
172
    char   *str;
 
173
{
 
174
    Char  **n = *v, *s;
 
175
 
 
176
    int dflag = 0, loop = 1;
 
177
    for (n++; loop && *n != NULL && (*n)[0] == '-'; n++) 
 
178
        if (*(s = &((*n)[1])) == '\0')  /* test for bare "-" argument */
 
179
            dflag |= DIR_OLD;
 
180
        else {
 
181
            char *p;
 
182
            while (loop && *s != '\0')  /* examine flags */
 
183
            {
 
184
                if ((p = strchr(dstr, *s++)) != NULL)
 
185
                    dflag |= (1 << (p - dstr));
 
186
                else {
 
187
                    stderror(ERR_DIRUS, short2str(**v), dstr, str);
 
188
                    loop = 0;   /* break from both loops */
 
189
                    break;
 
190
                }
 
191
            }
 
192
        }
 
193
    if (*n && (dflag & DIR_OLD))
 
194
        stderror(ERR_DIRUS, short2str(**v), dstr, str);
 
195
    *v = n;
 
196
    /* make -l, -v, and -n imply -p */
 
197
    if (dflag & (DIR_LONG|DIR_VERT|DIR_LINE))
 
198
        dflag |= DIR_PRINT;
 
199
    return dflag;
 
200
}
 
201
 
 
202
/*
 
203
 * dodirs - list all directories in directory loop
 
204
 */
 
205
/*ARGSUSED*/
 
206
void
 
207
dodirs(v, c)
 
208
    Char  **v;
 
209
    struct command *c;
 
210
{
 
211
    static char flags[] = "plvnSLc";
 
212
    int dflag = skipargs(&v, flags, "");
 
213
 
 
214
    USE(c);
 
215
    if ((dflag & DIR_CLEAR) != 0) {
 
216
        struct directory *dp, *fdp;
 
217
        for (dp = dcwd->di_next; dp != dcwd; ) {
 
218
            fdp = dp;
 
219
            dp = dp->di_next;
 
220
            if (fdp != &dhead)
 
221
                dfree(fdp);
 
222
        }
 
223
        dhead.di_next = dhead.di_prev = dp;
 
224
        dp->di_next = dp->di_prev = &dhead;
 
225
    }
 
226
    if ((dflag & DIR_LOAD) != 0) 
 
227
        loaddirs(*v);
 
228
    else if ((dflag & DIR_SAVE) != 0)
 
229
        recdirs(*v, 1);
 
230
 
 
231
    if (*v && (dflag & (DIR_SAVE|DIR_LOAD)))
 
232
        v++;
 
233
 
 
234
    if (*v != NULL || (dflag & DIR_OLD))
 
235
        stderror(ERR_DIRUS, "dirs", flags, "");
 
236
    if ((dflag & (DIR_CLEAR|DIR_LOAD|DIR_SAVE)) == 0 || (dflag & DIR_PRINT))
 
237
        printdirs(dflag);
 
238
}
 
239
 
 
240
static void
 
241
printdirs(dflag)
 
242
    int dflag;
 
243
{
 
244
    register struct directory *dp;
 
245
    Char   *s, *user;
 
246
    int     idx, len, cur;
 
247
    extern int T_Cols;
 
248
 
 
249
    dp = dcwd;
 
250
    idx = 0;
 
251
    cur = 0;
 
252
    do {
 
253
        if (dp == &dhead)
 
254
            continue;
 
255
        if (dflag & DIR_VERT) {
 
256
            xprintf("%d\t", idx++);
 
257
            cur = 0;
 
258
        }
 
259
        s = dp->di_name;                
 
260
        user = NULL;
 
261
        if (!(dflag & DIR_LONG) && (user = getusername(&s)) != NULL)
 
262
            len = (int) (Strlen(user) + Strlen(s) + 2);
 
263
        else
 
264
            len = (int) (Strlen(s) + 1);
 
265
 
 
266
        cur += len;
 
267
        if ((dflag & DIR_LINE) && cur >= T_Cols - 1 && len < T_Cols) {
 
268
            xputchar('\n');
 
269
            cur = len;
 
270
        }
 
271
        if (user) 
 
272
            xprintf("~%S", user);
 
273
        xprintf("%S%c", s, (dflag & DIR_VERT) ? '\n' : ' ');
 
274
    } while ((dp = dp->di_prev) != dcwd);
 
275
    if (!(dflag & DIR_VERT))
 
276
        xputchar('\n');
 
277
}
 
278
 
 
279
void
 
280
dtildepr(dir)
 
281
    Char *dir;
 
282
{
 
283
    Char* user;
 
284
    if ((user = getusername(&dir)) != NULL)
 
285
        xprintf("~%S%S", user, dir);
 
286
    else
 
287
        xprintf("%S", dir);
 
288
}
 
289
 
 
290
void
 
291
dtilde()
 
292
{
 
293
    struct directory *d = dcwd;
 
294
 
 
295
    do {
 
296
        if (d == &dhead)
 
297
            continue;
 
298
        d->di_name = dcanon(d->di_name, STRNULL);
 
299
    } while ((d = d->di_prev) != dcwd);
 
300
 
 
301
    dset(dcwd->di_name);
 
302
}
 
303
 
 
304
 
 
305
/* dnormalize():
 
306
 *      The path will be normalized if it
 
307
 *      1) is "..",
 
308
 *      2) or starts with "../",
 
309
 *      3) or ends with "/..",
 
310
 *      4) or contains the string "/../",
 
311
 *      then it will be normalized, unless those strings are quoted. 
 
312
 *      Otherwise, a copy is made and sent back.
 
313
 */
 
314
Char   *
 
315
dnormalize(cp, exp)
 
316
    Char   *cp;
 
317
    int exp;
 
318
{
 
319
 
 
320
/* return true if dp is of the form "../xxx" or "/../xxx" */
 
321
#define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))
 
322
#define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))
 
323
 
 
324
#ifdef S_IFLNK
 
325
    if (exp) {
 
326
        int     dotdot = 0;
 
327
        Char   *dp, *cwd, *start = cp, buf[MAXPATHLEN];
 
328
# ifdef apollo
 
329
        bool slashslash;
 
330
# endif /* apollo */
 
331
 
 
332
        /*
 
333
         * count the number of "../xxx" or "xxx/../xxx" in the path
 
334
         */
 
335
        for (dp=start; *dp && *(dp+1); dp++)
 
336
            if (IS_DOTDOT(start, dp))
 
337
                dotdot++;
 
338
        /*
 
339
         * if none, we are done.
 
340
         */
 
341
        if (dotdot == 0)
 
342
            return (Strsave(cp));
 
343
 
 
344
        cwd = (Char *) xmalloc((size_t) (((int) Strlen(dcwd->di_name) + 3) *
 
345
                                           sizeof(Char)));
 
346
        (void) Strcpy(cwd, dcwd->di_name);
 
347
 
 
348
        /*
 
349
         * If the path starts with a slash, we are not relative to
 
350
         * the current working directory.
 
351
         */
 
352
        if (ABSOLUTEP(start))
 
353
            *cwd = '\0';
 
354
# ifdef apollo
 
355
        slashslash = cwd[0] == '/' && cwd[1] == '/';
 
356
# endif /* apollo */
 
357
 
 
358
        /*
 
359
         * Ignore . and count ..'s
 
360
         */
 
361
        for (;;) {
 
362
            dotdot = 0;
 
363
            buf[0] = '\0';
 
364
            dp = buf; 
 
365
            while (*cp) 
 
366
                if (IS_DOT(start, cp)) {
 
367
                    if (*++cp)
 
368
                        cp++;
 
369
                }
 
370
                else if (IS_DOTDOT(start, cp)) {
 
371
                    if (buf[0])
 
372
                        break; /* finish analyzing .././../xxx/[..] */
 
373
                    dotdot++;
 
374
                    cp += 2;
 
375
                    if (*cp)
 
376
                        cp++;
 
377
                }
 
378
                else 
 
379
                        *dp++ = *cp++;
 
380
 
 
381
            *dp = '\0';
 
382
            while (dotdot > 0) 
 
383
                if ((dp = Strrchr(cwd, '/')) != NULL) {
 
384
# ifdef apollo
 
385
                    if (dp == &cwd[1]) 
 
386
                        slashslash = 1;
 
387
# endif /* apollo */
 
388
                        *dp = '\0';
 
389
                        dotdot--;
 
390
                }
 
391
                else
 
392
                    break;
 
393
 
 
394
            if (!*cwd) {        /* too many ..'s, starts with "/" */
 
395
                cwd[0] = '/';
 
396
# ifdef apollo
 
397
                cwd[1] = '/';
 
398
                cwd[2] = '\0';
 
399
# else /* !apollo */
 
400
                cwd[1] = '\0';
 
401
# endif /* apollo */
 
402
            }
 
403
# ifdef apollo
 
404
            else if (slashslash && cwd[1] == '\0') {
 
405
                cwd[1] = '/';
 
406
                cwd[2] = '\0';
 
407
            }
 
408
# endif /* apollo */
 
409
 
 
410
            if (buf[0]) {
 
411
                if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) != '/')
 
412
                    cwd[dotdot++] = '/';
 
413
                cwd[dotdot] = '\0';
 
414
                dp = Strspl(cwd, TRM(buf[0]) == '/' ? &buf[1] : buf);
 
415
                xfree((ptr_t) cwd);
 
416
                cwd = dp;
 
417
                if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) == '/')
 
418
                    cwd[--dotdot] = '\0';
 
419
            }
 
420
            if (!*cp)
 
421
                break;
 
422
        }
 
423
        return cwd;
 
424
    }
 
425
#endif /* S_IFLNK */
 
426
    return Strsave(cp);
 
427
}
 
428
 
 
429
 
 
430
/*
 
431
 * dochngd - implement chdir command.
 
432
 */
 
433
/*ARGSUSED*/
 
434
void
 
435
dochngd(v, c)
 
436
    Char  **v;
 
437
    struct command *c;
 
438
{
 
439
    register Char *cp;
 
440
    register struct directory *dp;
 
441
    int dflag = skipargs(&v, "plvn", "[-|<dir>]");
 
442
 
 
443
    USE(c);
 
444
    printd = 0;
 
445
    cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
 
446
 
 
447
    if (cp == NULL) {
 
448
        if ((cp = varval(STRhome)) == STRNULL || *cp == 0)
 
449
            stderror(ERR_NAME | ERR_NOHOMEDIR);
 
450
        if (chdir(short2str(cp)) < 0)
 
451
            stderror(ERR_NAME | ERR_CANTCHANGE);
 
452
        cp = Strsave(cp);
 
453
    }
 
454
    else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
 
455
        stderror(ERR_NAME | ERR_TOOMANY);
 
456
        /* NOTREACHED */
 
457
        return;
 
458
    }
 
459
    else if ((dp = dfind(cp)) != 0) {
 
460
        char   *tmp;
 
461
 
 
462
        printd = 1;
 
463
        if (chdir(tmp = short2str(dp->di_name)) < 0)
 
464
            stderror(ERR_SYSTEM, tmp, strerror(errno));
 
465
        dcwd->di_prev->di_next = dcwd->di_next;
 
466
        dcwd->di_next->di_prev = dcwd->di_prev;
 
467
        dfree(dcwd);
 
468
        dnewcwd(dp, dflag);
 
469
        return;
 
470
    }
 
471
    else
 
472
        if ((cp = dfollow(cp)) == NULL)
 
473
            return;
 
474
    dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 
475
    dp->di_name = cp;
 
476
    dp->di_count = 0;
 
477
    dp->di_next = dcwd->di_next;
 
478
    dp->di_prev = dcwd->di_prev;
 
479
    dp->di_prev->di_next = dp;
 
480
    dp->di_next->di_prev = dp;
 
481
    dfree(dcwd);
 
482
    dnewcwd(dp, dflag);
 
483
}
 
484
 
 
485
static Char *
 
486
dgoto(cp)
 
487
    Char   *cp;
 
488
{
 
489
    Char   *dp;
 
490
 
 
491
    if (!ABSOLUTEP(cp))
 
492
    {
 
493
        register Char *p, *q;
 
494
        int     cwdlen;
 
495
 
 
496
        for (p = dcwd->di_name; *p++;)
 
497
            continue;
 
498
        if ((cwdlen = (int) (p - dcwd->di_name - 1)) == 1)      /* root */
 
499
            cwdlen = 0;
 
500
        for (p = cp; *p++;)
 
501
            continue;
 
502
        dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char)));
 
503
        for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
 
504
            continue;
 
505
        if (cwdlen)
 
506
            p[-1] = '/';
 
507
        else
 
508
            p--;                /* don't add a / after root */
 
509
        for (q = cp; (*p++ = *q++) != '\0';)
 
510
            continue;
 
511
        xfree((ptr_t) cp);
 
512
        cp = dp;
 
513
        dp += cwdlen;
 
514
    }
 
515
    else
 
516
        dp = cp;
 
517
 
 
518
#ifdef WINNT
 
519
    cp = SAVE(getcwd(NULL, 0));
 
520
#else /* !WINNT */
 
521
    cp = dcanon(cp, dp);
 
522
#endif /* WINNT */
 
523
    return cp;
 
524
}
 
525
 
 
526
/*
 
527
 * dfollow - change to arg directory; fall back on cdpath if not valid
 
528
 */
 
529
static Char *
 
530
dfollow(cp)
 
531
    register Char *cp;
 
532
{
 
533
    register Char *dp;
 
534
    struct varent *c;
 
535
    char    ebuf[MAXPATHLEN];
 
536
    int serrno;
 
537
 
 
538
    cp = globone(cp, G_ERROR);
 
539
#ifdef apollo
 
540
    if (Strchr(cp, '`')) {
 
541
        char *dptr, *ptr;
 
542
        if (chdir(dptr = short2str(cp)) < 0) 
 
543
            stderror(ERR_SYSTEM, dptr, strerror(errno));
 
544
        else if ((ptr = getcwd(ebuf, sizeof(ebuf))) && *ptr != '\0') {
 
545
                xfree((ptr_t) cp);
 
546
                cp = Strsave(str2short(ptr));
 
547
                return dgoto(cp);
 
548
        }
 
549
        else 
 
550
            stderror(ERR_SYSTEM, dptr, ebuf);
 
551
    }
 
552
#endif /* apollo */
 
553
            
 
554
    (void) strncpy(ebuf, short2str(cp), MAXPATHLEN);
 
555
    ebuf[MAXPATHLEN-1] = '\0';
 
556
    /*
 
557
     * if we are ignoring symlinks, try to fix relatives now.
 
558
     * if we are expading symlinks, it should be done by now.
 
559
     */ 
 
560
    dp = dnormalize(cp, symlinks == SYM_IGNORE);
 
561
    if (chdir(short2str(dp)) >= 0) {
 
562
        xfree((ptr_t) cp);
 
563
        return dgoto(dp);
 
564
    }
 
565
    else {
 
566
        xfree((ptr_t) dp);
 
567
        if (chdir(short2str(cp)) >= 0)
 
568
            return dgoto(cp);
 
569
        else if (errno != ENOENT && errno != ENOTDIR)
 
570
            stderror(ERR_SYSTEM, ebuf, strerror(errno));
 
571
        serrno = errno;
 
572
    }
 
573
 
 
574
    if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
 
575
        && (c = adrof(STRcdpath))) {
 
576
        Char  **cdp;
 
577
        register Char *p;
 
578
        Char    buf[MAXPATHLEN];
 
579
 
 
580
        for (cdp = c->vec; *cdp; cdp++) {
 
581
            for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';)
 
582
                continue;
 
583
            dp[-1] = '/';
 
584
            for (p = cp; (*dp++ = *p++) != '\0';)
 
585
                continue;
 
586
            /*
 
587
             * We always want to fix the directory here
 
588
             * If we are normalizing symlinks
 
589
             */
 
590
            dp = dnormalize(buf, symlinks == SYM_IGNORE || 
 
591
                                 symlinks == SYM_EXPAND);
 
592
            if (chdir(short2str(dp)) >= 0) {
 
593
                printd = 1;
 
594
                xfree((ptr_t) cp);
 
595
                return dgoto(dp);
 
596
            }
 
597
            else if (chdir(short2str(cp)) >= 0) {
 
598
                printd = 1;
 
599
                xfree((ptr_t) dp);
 
600
                return dgoto(cp);
 
601
            }
 
602
        }
 
603
    }
 
604
    dp = varval(cp);
 
605
    if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
 
606
        xfree((ptr_t) cp);
 
607
        cp = Strsave(dp);
 
608
        printd = 1;
 
609
        return dgoto(cp);
 
610
    }
 
611
    xfree((ptr_t) cp);
 
612
    /*
 
613
     * on login source of ~/.cshdirs, errors are eaten. the dir stack is all
 
614
     * directories we could get to.
 
615
     */
 
616
    if (!bequiet) {
 
617
        stderror(ERR_SYSTEM, ebuf, strerror(serrno));
 
618
        return (NULL);
 
619
    }
 
620
    else
 
621
        return (NULL);
 
622
}
 
623
 
 
624
 
 
625
/*
 
626
 * dopushd - push new directory onto directory stack.
 
627
 *      with no arguments exchange top and second.
 
628
 *      with numeric argument (+n) bring it to top.
 
629
 */
 
630
/*ARGSUSED*/
 
631
void
 
632
dopushd(v, c)
 
633
    Char  **v;
 
634
    struct command *c;
 
635
{
 
636
    register struct directory *dp;
 
637
    register Char *cp;
 
638
    int dflag = skipargs(&v, "plvn", " [-|<dir>|+<n>]");
 
639
    
 
640
    USE(c);
 
641
    printd = 1;
 
642
    cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
 
643
 
 
644
    if (cp == NULL) {
 
645
        if (adrof(STRpushdtohome)) {
 
646
            if ((cp = varval(STRhome)) == STRNULL || *cp == 0)
 
647
                stderror(ERR_NAME | ERR_NOHOMEDIR);
 
648
            if (chdir(short2str(cp)) < 0)
 
649
                stderror(ERR_NAME | ERR_CANTCHANGE);
 
650
            cp = Strsave(cp);   /* hmmm... PWP */
 
651
            if ((cp = dfollow(cp)) == NULL)
 
652
                return;
 
653
            dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 
654
            dp->di_name = cp;
 
655
            dp->di_count = 0;
 
656
            dp->di_prev = dcwd;
 
657
            dp->di_next = dcwd->di_next;
 
658
            dcwd->di_next = dp;
 
659
            dp->di_next->di_prev = dp;
 
660
        }
 
661
        else {
 
662
            char   *tmp;
 
663
 
 
664
            if ((dp = dcwd->di_prev) == &dhead)
 
665
                dp = dhead.di_prev;
 
666
            if (dp == dcwd)
 
667
                stderror(ERR_NAME | ERR_NODIR);
 
668
            if (chdir(tmp = short2str(dp->di_name)) < 0)
 
669
                stderror(ERR_SYSTEM, tmp, strerror(errno));
 
670
            dp->di_prev->di_next = dp->di_next;
 
671
            dp->di_next->di_prev = dp->di_prev;
 
672
            dp->di_next = dcwd->di_next;
 
673
            dp->di_prev = dcwd;
 
674
            dcwd->di_next->di_prev = dp;
 
675
            dcwd->di_next = dp;
 
676
        }
 
677
    }
 
678
    else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
 
679
        stderror(ERR_NAME | ERR_TOOMANY);
 
680
        /* NOTREACHED */
 
681
        return;
 
682
    }
 
683
    else if ((dp = dfind(cp)) != NULL) {
 
684
        char   *tmp;
 
685
 
 
686
        if (chdir(tmp = short2str(dp->di_name)) < 0)
 
687
            stderror(ERR_SYSTEM, tmp, strerror(errno));
 
688
        /*
 
689
         * kfk - 10 Feb 1984 - added new "extraction style" pushd +n
 
690
         */
 
691
        if (adrof(STRdextract))
 
692
            dextract(dp);
 
693
    }
 
694
    else {
 
695
        register Char *ccp;
 
696
 
 
697
        if ((ccp = dfollow(cp)) == NULL)
 
698
            return;
 
699
        dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 
700
        dp->di_name = ccp;
 
701
        dp->di_count = 0;
 
702
        dp->di_prev = dcwd;
 
703
        dp->di_next = dcwd->di_next;
 
704
        dcwd->di_next = dp;
 
705
        dp->di_next->di_prev = dp;
 
706
    }
 
707
    dnewcwd(dp, dflag);
 
708
}
 
709
 
 
710
/*
 
711
 * dfind - find a directory if specified by numeric (+n) argument
 
712
 */
 
713
static struct directory *
 
714
dfind(cp)
 
715
    register Char *cp;
 
716
{
 
717
    register struct directory *dp;
 
718
    register int i;
 
719
    register Char *ep;
 
720
 
 
721
    if (*cp++ != '+')
 
722
        return (0);
 
723
    for (ep = cp; Isdigit(*ep); ep++)
 
724
        continue;
 
725
    if (*ep)
 
726
        return (0);
 
727
    i = getn(cp);
 
728
    if (i <= 0)
 
729
        return (0);
 
730
    for (dp = dcwd; i != 0; i--) {
 
731
        if ((dp = dp->di_prev) == &dhead)
 
732
            dp = dp->di_prev;
 
733
        if (dp == dcwd)
 
734
            stderror(ERR_NAME | ERR_DEEP);
 
735
    }
 
736
    return (dp);
 
737
}
 
738
 
 
739
/*
 
740
 * dopopd - pop a directory out of the directory stack
 
741
 *      with a numeric argument just discard it.
 
742
 */
 
743
/*ARGSUSED*/
 
744
void
 
745
dopopd(v, c)
 
746
    Char  **v;
 
747
    struct command *c;
 
748
{
 
749
    Char *cp;
 
750
    register struct directory *dp, *p = NULL;
 
751
    int dflag = skipargs(&v, "plvn", " [-|+<n>]");
 
752
 
 
753
    USE(c);
 
754
    printd = 1;
 
755
    cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
 
756
 
 
757
    if (cp == NULL)
 
758
        dp = dcwd;
 
759
    else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
 
760
        stderror(ERR_NAME | ERR_TOOMANY);
 
761
        /* NOTREACHED */
 
762
        return;
 
763
    }
 
764
    else if ((dp = dfind(cp)) == 0)
 
765
        stderror(ERR_NAME | ERR_BADDIR);
 
766
    if (dp->di_prev == &dhead && dp->di_next == &dhead)
 
767
        stderror(ERR_NAME | ERR_EMPTY);
 
768
    if (dp == dcwd) {
 
769
        char   *tmp;
 
770
 
 
771
        if ((p = dp->di_prev) == &dhead)
 
772
            p = dhead.di_prev;
 
773
        if (chdir(tmp = short2str(p->di_name)) < 0)
 
774
            stderror(ERR_SYSTEM, tmp, strerror(errno));
 
775
    }
 
776
    dp->di_prev->di_next = dp->di_next;
 
777
    dp->di_next->di_prev = dp->di_prev;
 
778
    if (dp == dcwd) {
 
779
        dnewcwd(p, dflag);
 
780
    }
 
781
    else {
 
782
        printdirs(dflag);
 
783
    }
 
784
    dfree(dp);
 
785
}
 
786
 
 
787
/*
 
788
 * dfree - free the directory (or keep it if it still has ref count)
 
789
 */
 
790
void
 
791
dfree(dp)
 
792
    register struct directory *dp;
 
793
{
 
794
 
 
795
    if (dp->di_count != 0) {
 
796
        dp->di_next = dp->di_prev = 0;
 
797
    }
 
798
    else {
 
799
        xfree((ptr_t) dp->di_name);
 
800
        xfree((ptr_t) dp);
 
801
    }
 
802
}
 
803
 
 
804
/*
 
805
 * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
 
806
 *      we are of course assuming that the file system is standardly
 
807
 *      constructed (always have ..'s, directories have links)
 
808
 */
 
809
Char   *
 
810
dcanon(cp, p)
 
811
    register Char *cp, *p;
 
812
{
 
813
    register Char *sp;
 
814
    register Char *p1, *p2;     /* general purpose */
 
815
    bool    slash;
 
816
#ifdef apollo
 
817
    bool    slashslash;
 
818
#endif /* apollo */
 
819
 
 
820
#ifdef S_IFLNK                  /* if we have symlinks */
 
821
    Char    link[MAXPATHLEN];
 
822
    char    tlink[MAXPATHLEN];
 
823
    int     cc;
 
824
    Char   *newcp;
 
825
#endif /* S_IFLNK */
 
826
 
 
827
    /*
 
828
     * kim: if the path given is too long abort().
 
829
     */
 
830
    if (Strlen(cp) >= MAXPATHLEN)
 
831
        abort();
 
832
 
 
833
    /*
 
834
     * christos: if the path given does not start with a slash prepend cwd. If
 
835
     * cwd does not start with a slash or the result would be too long abort().
 
836
     */
 
837
    if (!ABSOLUTEP(cp)) {
 
838
        Char    tmpdir[MAXPATHLEN];
 
839
 
 
840
        p1 = varval(STRcwd);
 
841
        if (p1 == STRNULL || !ABSOLUTEP(p1))
 
842
            abort();
 
843
        if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
 
844
            abort();
 
845
        (void) Strcpy(tmpdir, p1);
 
846
        (void) Strcat(tmpdir, STRslash);
 
847
        (void) Strcat(tmpdir, cp);
 
848
        xfree((ptr_t) cp);
 
849
        cp = p = Strsave(tmpdir);
 
850
    }
 
851
 
 
852
#ifdef COMMENT
 
853
    if (*cp != '/')
 
854
        abort();
 
855
#endif /* COMMENT */
 
856
 
 
857
#ifdef apollo
 
858
    slashslash = (cp[0] == '/' && cp[1] == '/');
 
859
#endif /* apollo */
 
860
 
 
861
    while (*p) {                /* for each component */
 
862
        sp = p;                 /* save slash address */
 
863
        while (*++p == '/')     /* flush extra slashes */
 
864
            continue;
 
865
        if (p != ++sp)
 
866
            for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
 
867
                continue;
 
868
        p = sp;                 /* save start of component */
 
869
        slash = 0;
 
870
        if (*p) 
 
871
            while (*++p)        /* find next slash or end of path */
 
872
                if (*p == '/') {
 
873
                    slash = 1;
 
874
                    *p = 0;
 
875
                    break;
 
876
                }
 
877
 
 
878
#ifdef apollo
 
879
        if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0')
 
880
            slashslash = 1;
 
881
#endif /* apollo */
 
882
        if (*sp == '\0') {      /* if component is null */
 
883
            if (--sp == cp)     /* if path is one char (i.e. /) */ 
 
884
                break;
 
885
            else
 
886
                *sp = '\0';
 
887
        }
 
888
        else if (sp[0] == '.' && sp[1] == 0) {
 
889
            if (slash) {
 
890
                for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
 
891
                    continue;
 
892
                p = --sp;
 
893
            }
 
894
            else if (--sp != cp)
 
895
                *sp = '\0';
 
896
            else
 
897
                sp[1] = '\0';
 
898
        }
 
899
        else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
 
900
            /*
 
901
             * We have something like "yyy/xxx/..", where "yyy" can be null or
 
902
             * a path starting at /, and "xxx" is a single component. Before
 
903
             * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
 
904
             * symbolic link.
 
905
             */
 
906
            *--sp = 0;          /* form the pathname for readlink */
 
907
#ifdef S_IFLNK                  /* if we have symlinks */
 
908
            if (sp != cp && /* symlinks != SYM_IGNORE && */
 
909
                (cc = readlink(short2str(cp), tlink,
 
910
                               sizeof tlink)) >= 0) {
 
911
                tlink[cc] = '\0';
 
912
                (void) Strncpy(link, str2short(tlink),
 
913
                    sizeof(link) / sizeof(Char));
 
914
                link[sizeof(link) / sizeof(Char) - 1] = '\0';
 
915
 
 
916
                if (slash)
 
917
                    *p = '/';
 
918
                /*
 
919
                 * Point p to the '/' in "/..", and restore the '/'.
 
920
                 */
 
921
                *(p = sp) = '/';
 
922
                /*
 
923
                 * find length of p
 
924
                 */
 
925
                for (p1 = p; *p1++;)
 
926
                    continue;
 
927
                if (*link != '/') {
 
928
                    /*
 
929
                     * Relative path, expand it between the "yyy/" and the
 
930
                     * "/..". First, back sp up to the character past "yyy/".
 
931
                     */
 
932
                    while (*--sp != '/')
 
933
                        continue;
 
934
                    sp++;
 
935
                    *sp = 0;
 
936
                    /*
 
937
                     * New length is "yyy/" + link + "/.." and rest
 
938
                     */
 
939
                    p1 = newcp = (Char *) xmalloc((size_t)
 
940
                                                (((sp - cp) + cc + (p1 - p)) *
 
941
                                                 sizeof(Char)));
 
942
                    /*
 
943
                     * Copy new path into newcp
 
944
                     */
 
945
                    for (p2 = cp; (*p1++ = *p2++) != '\0';)
 
946
                        continue;
 
947
                    for (p1--, p2 = link; (*p1++ = *p2++) != '\0';)
 
948
                        continue;
 
949
                    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
 
950
                        continue;
 
951
                    /*
 
952
                     * Restart canonicalization at expanded "/xxx".
 
953
                     */
 
954
                    p = sp - cp - 1 + newcp;
 
955
                }
 
956
                else {
 
957
                    /*
 
958
                     * New length is link + "/.." and rest
 
959
                     */
 
960
                    p1 = newcp = (Char *) xmalloc((size_t)
 
961
                                            ((cc + (p1 - p)) * sizeof(Char)));
 
962
                    /*
 
963
                     * Copy new path into newcp
 
964
                     */
 
965
                    for (p2 = link; (*p1++ = *p2++) != '\0';)
 
966
                        continue;
 
967
                    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
 
968
                        continue;
 
969
                    /*
 
970
                     * Restart canonicalization at beginning
 
971
                     */
 
972
                    p = newcp;
 
973
                }
 
974
                xfree((ptr_t) cp);
 
975
                cp = newcp;
 
976
#ifdef apollo
 
977
                slashslash = (cp[0] == '/' && cp[1] == '/');
 
978
#endif /* apollo */
 
979
                continue;       /* canonicalize the link */
 
980
            }
 
981
#endif /* S_IFLNK */
 
982
            *sp = '/';
 
983
            if (sp != cp)
 
984
                while (*--sp != '/')
 
985
                    continue;
 
986
            if (slash) {
 
987
                for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
 
988
                    continue;
 
989
                p = sp;
 
990
            }
 
991
            else if (cp == sp)
 
992
                *++sp = '\0';
 
993
            else
 
994
                *sp = '\0';
 
995
        }
 
996
        else {                  /* normal dir name (not . or .. or nothing) */
 
997
 
 
998
#ifdef S_IFLNK                  /* if we have symlinks */
 
999
            if (sp != cp && symlinks == SYM_CHASE &&
 
1000
                (cc = readlink(short2str(cp), tlink,
 
1001
                               sizeof tlink)) >= 0) {
 
1002
                tlink[cc] = '\0';
 
1003
                (void) Strncpy(link, str2short(tlink),
 
1004
                    sizeof(link) / sizeof(Char));
 
1005
                link[sizeof(link) / sizeof(Char) - 1] = '\0';
 
1006
 
 
1007
                /*
 
1008
                 * restore the '/'.
 
1009
                 */
 
1010
                if (slash)
 
1011
                    *p = '/';
 
1012
 
 
1013
                /*
 
1014
                 * point sp to p (rather than backing up).
 
1015
                 */
 
1016
                sp = p;
 
1017
 
 
1018
                /*
 
1019
                 * find length of p
 
1020
                 */
 
1021
                for (p1 = p; *p1++;)
 
1022
                    continue;
 
1023
                if (*link != '/') {
 
1024
                    /*
 
1025
                     * Relative path, expand it between the "yyy/" and the
 
1026
                     * remainder. First, back sp up to the character past
 
1027
                     * "yyy/".
 
1028
                     */
 
1029
                    while (*--sp != '/')
 
1030
                        continue;
 
1031
                    sp++;
 
1032
                    *sp = 0;
 
1033
                    /*
 
1034
                     * New length is "yyy/" + link + "/.." and rest
 
1035
                     */
 
1036
                    p1 = newcp = (Char *) xmalloc((size_t)
 
1037
                                                  (((sp - cp) + cc + (p1 - p))
 
1038
                                                   * sizeof(Char)));
 
1039
                    /*
 
1040
                     * Copy new path into newcp
 
1041
                     */
 
1042
                    for (p2 = cp; (*p1++ = *p2++) != '\0';)
 
1043
                        continue;
 
1044
                    for (p1--, p2 = link; (*p1++ = *p2++) != '\0';)
 
1045
                        continue;
 
1046
                    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
 
1047
                        continue;
 
1048
                    /*
 
1049
                     * Restart canonicalization at expanded "/xxx".
 
1050
                     */
 
1051
                    p = sp - cp - 1 + newcp;
 
1052
                }
 
1053
                else {
 
1054
                    /*
 
1055
                     * New length is link + the rest
 
1056
                     */
 
1057
                    p1 = newcp = (Char *) xmalloc((size_t)
 
1058
                                            ((cc + (p1 - p)) * sizeof(Char)));
 
1059
                    /*
 
1060
                     * Copy new path into newcp
 
1061
                     */
 
1062
                    for (p2 = link; (*p1++ = *p2++) != '\0';)
 
1063
                        continue;
 
1064
                    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
 
1065
                        continue;
 
1066
                    /*
 
1067
                     * Restart canonicalization at beginning
 
1068
                     */
 
1069
                    p = newcp;
 
1070
                }
 
1071
                xfree((ptr_t) cp);
 
1072
                cp = newcp;
 
1073
#ifdef apollo
 
1074
                slashslash = (cp[0] == '/' && cp[1] == '/');
 
1075
#endif /* apollo */
 
1076
                continue;       /* canonicalize the link */
 
1077
            }
 
1078
#endif /* S_IFLNK */
 
1079
            if (slash)
 
1080
                *p = '/';
 
1081
        }
 
1082
    }
 
1083
 
 
1084
    /*
 
1085
     * fix home...
 
1086
     */
 
1087
#ifdef S_IFLNK
 
1088
    p1 = varval(STRhome);
 
1089
    cc = (int) Strlen(p1);
 
1090
    /*
 
1091
     * See if we're not in a subdir of STRhome
 
1092
     */
 
1093
    if (p1 && *p1 == '/' && (Strncmp(p1, cp, (size_t) cc) != 0 ||
 
1094
        (cp[cc] != '/' && cp[cc] != '\0'))) {
 
1095
        static ino_t home_ino = (ino_t) -1;
 
1096
        static dev_t home_dev = (dev_t) -1;
 
1097
        static Char *home_ptr = NULL;
 
1098
        struct stat statbuf;
 
1099
        int found;
 
1100
 
 
1101
        /*
 
1102
         * Get dev and ino of STRhome
 
1103
         */
 
1104
        if (home_ptr != p1 &&
 
1105
            stat(short2str(p1), &statbuf) != -1) {
 
1106
            home_dev = statbuf.st_dev;
 
1107
            home_ino = statbuf.st_ino;
 
1108
            home_ptr = p1;
 
1109
        }
 
1110
        /*
 
1111
         * Start comparing dev & ino backwards
 
1112
         */
 
1113
        p2 = Strncpy(link, cp, sizeof(link) / sizeof(Char));
 
1114
        link[sizeof(link) / sizeof(Char) - 1] = '\0';
 
1115
        found = 0;
 
1116
        while (*p2 && stat(short2str(p2), &statbuf) != -1) {
 
1117
            if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) &&
 
1118
                        statbuf.st_ino == home_ino) {
 
1119
                        found = 1;
 
1120
                        break;
 
1121
            }
 
1122
            if ((sp = Strrchr(p2, '/')) != NULL)
 
1123
                *sp = '\0';
 
1124
        }
 
1125
        /*
 
1126
         * See if we found it
 
1127
         */
 
1128
        if (*p2 && found) {
 
1129
            /*
 
1130
             * Use STRhome to make '~' work
 
1131
             */
 
1132
            newcp = Strspl(p1, cp + Strlen(p2));
 
1133
            xfree((ptr_t) cp);
 
1134
            cp = newcp;
 
1135
        }
 
1136
    }
 
1137
#endif /* S_IFLNK */
 
1138
 
 
1139
#ifdef apollo
 
1140
    if (slashslash) {
 
1141
        if (cp[1] != '/') {
 
1142
            p = (Char *) xmalloc((size_t) (Strlen(cp) + 2) * sizeof(Char));
 
1143
            *p = '/';
 
1144
            (void) Strcpy(&p[1], cp);
 
1145
            xfree((ptr_t) cp);
 
1146
            cp = p;
 
1147
        }
 
1148
    }
 
1149
    if (cp[1] == '/' && cp[2] == '/') 
 
1150
        (void) Strcpy(&cp[1], &cp[2]);
 
1151
#endif /* apollo */
 
1152
    return cp;
 
1153
}
 
1154
 
 
1155
 
 
1156
/*
 
1157
 * dnewcwd - make a new directory in the loop the current one
 
1158
 */
 
1159
static void
 
1160
dnewcwd(dp, dflag)
 
1161
    register struct directory *dp;
 
1162
    int dflag;
 
1163
{
 
1164
    int print;
 
1165
 
 
1166
    if (adrof(STRdunique)) {
 
1167
        struct directory *dn;
 
1168
 
 
1169
        for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev) 
 
1170
            if (dn != dp && Strcmp(dn->di_name, dp->di_name) == 0) {
 
1171
                dn->di_next->di_prev = dn->di_prev;
 
1172
                dn->di_prev->di_next = dn->di_next;
 
1173
                dfree(dn);
 
1174
                break;
 
1175
            }
 
1176
    }
 
1177
    dcwd = dp;
 
1178
    dset(dcwd->di_name);
 
1179
    dgetstack();
 
1180
    print = printd;             /* if printd is set, print dirstack... */
 
1181
    if (adrof(STRpushdsilent))  /* but pushdsilent overrides printd... */
 
1182
        print = 0;
 
1183
    if (dflag & DIR_PRINT)      /* but DIR_PRINT overrides pushdsilent... */
 
1184
        print = 1;
 
1185
    if (bequiet)                /* and bequiet overrides everything */
 
1186
        print = 0;
 
1187
    if (print)
 
1188
        printdirs(dflag);
 
1189
    cwd_cmd();                  /* PWP: run the defined cwd command */
 
1190
}
 
1191
 
 
1192
void
 
1193
dsetstack()
 
1194
{
 
1195
    Char **cp;
 
1196
    struct varent *vp;
 
1197
    struct directory *dn, *dp;
 
1198
 
 
1199
    if ((vp = adrof(STRdirstack)) == NULL)
 
1200
        return;
 
1201
 
 
1202
    /* Free the whole stack */
 
1203
    while ((dn = dhead.di_prev) != &dhead) {
 
1204
        dn->di_next->di_prev = dn->di_prev;
 
1205
        dn->di_prev->di_next = dn->di_next;
 
1206
        if (dn != dcwd)
 
1207
            dfree(dn);
 
1208
    }
 
1209
 
 
1210
    /* thread the current working directory */
 
1211
    dhead.di_prev = dhead.di_next = dcwd;
 
1212
    dcwd->di_next = dcwd->di_prev = &dhead;
 
1213
 
 
1214
    /* put back the stack */
 
1215
    for (cp = vp->vec; cp && *cp && **cp; cp++) {
 
1216
        dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 
1217
        dp->di_name = Strsave(*cp);
 
1218
        dp->di_count = 0;
 
1219
        dp->di_prev = dcwd;
 
1220
        dp->di_next = dcwd->di_next;
 
1221
        dcwd->di_next = dp;
 
1222
        dp->di_next->di_prev = dp;
 
1223
    }
 
1224
    dgetstack();        /* Make $dirstack reflect the current state */
 
1225
}
 
1226
 
 
1227
static void
 
1228
dgetstack()
 
1229
{
 
1230
    int i = 0;
 
1231
    Char **dblk, **dbp;
 
1232
    struct directory *dn;
 
1233
 
 
1234
    if (adrof(STRdirstack) == NULL) 
 
1235
        return;
 
1236
 
 
1237
    for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, i++) 
 
1238
        continue;
 
1239
    dbp = dblk = (Char**) xmalloc((size_t) (i + 1) * sizeof(Char *));
 
1240
    for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, dbp++) 
 
1241
         *dbp = Strsave(dn->di_name);
 
1242
    *dbp = NULL;
 
1243
    setq(STRdirstack, dblk, &shvhed, VAR_READWRITE);
 
1244
}
 
1245
 
 
1246
/*
 
1247
 * getstakd - added by kfk 17 Jan 1984
 
1248
 * Support routine for the stack hack.  Finds nth directory in
 
1249
 * the directory stack, or finds last directory in stack.
 
1250
 */
 
1251
int
 
1252
getstakd(s, cnt)
 
1253
    Char   *s;
 
1254
    int     cnt;
 
1255
{
 
1256
    struct directory *dp;
 
1257
 
 
1258
    dp = dcwd;
 
1259
    if (cnt < 0) {              /* < 0 ==> last dir requested. */
 
1260
        dp = dp->di_next;
 
1261
        if (dp == &dhead)
 
1262
            dp = dp->di_next;
 
1263
    }
 
1264
    else {
 
1265
        while (cnt-- > 0) {
 
1266
            dp = dp->di_prev;
 
1267
            if (dp == &dhead)
 
1268
                dp = dp->di_prev;
 
1269
            if (dp == dcwd)
 
1270
                return (0);
 
1271
        }
 
1272
    }
 
1273
    (void) Strcpy(s, dp->di_name);
 
1274
    return (1);
 
1275
}
 
1276
 
 
1277
/*
 
1278
 * Karl Kleinpaste - 10 Feb 1984
 
1279
 * Added dextract(), which is used in pushd +n.
 
1280
 * Instead of just rotating the entire stack around, dextract()
 
1281
 * lets the user have the nth dir extracted from its current
 
1282
 * position, and pushes it onto the top.
 
1283
 */
 
1284
static void
 
1285
dextract(dp)
 
1286
    struct directory *dp;
 
1287
{
 
1288
    if (dp == dcwd)
 
1289
        return;
 
1290
    dp->di_next->di_prev = dp->di_prev;
 
1291
    dp->di_prev->di_next = dp->di_next;
 
1292
    dp->di_next = dcwd->di_next;
 
1293
    dp->di_prev = dcwd;
 
1294
    dp->di_next->di_prev = dp;
 
1295
    dcwd->di_next = dp;
 
1296
}
 
1297
 
 
1298
void
 
1299
loaddirs(fname)
 
1300
    Char *fname;
 
1301
{
 
1302
    static Char *loaddirs_cmd[] = { STRsource, NULL, NULL };
 
1303
 
 
1304
    bequiet = 1;
 
1305
    if (fname) 
 
1306
        loaddirs_cmd[1] = fname;
 
1307
    else if ((fname = varval(STRdirsfile)) != STRNULL)
 
1308
        loaddirs_cmd[1] = fname;
 
1309
    else
 
1310
        loaddirs_cmd[1] = STRtildotdirs;
 
1311
    dosource(loaddirs_cmd, (struct command *)0);
 
1312
    bequiet = 0;
 
1313
}
 
1314
 
 
1315
/*
 
1316
 * create a file called ~/.cshdirs which has a sequence
 
1317
 * of pushd commands which will restore the dir stack to
 
1318
 * its state before exit/logout. remember that the order
 
1319
 * is reversed in the file because we are pushing.
 
1320
 * -strike
 
1321
 */
 
1322
void
 
1323
recdirs(fname, def)
 
1324
    Char *fname;
 
1325
    int def;
 
1326
{
 
1327
    int     fp, ftmp, oldidfds;
 
1328
    int     cdflag = 0;
 
1329
    extern struct directory *dcwd;
 
1330
    struct directory *dp;
 
1331
    unsigned int    num;
 
1332
    Char   *snum;
 
1333
    Char    qname[MAXPATHLEN*2];
 
1334
 
 
1335
    if (fname == NULL && !def) 
 
1336
        return;
 
1337
 
 
1338
    if (fname == NULL) {
 
1339
        if ((fname = varval(STRdirsfile)) == STRNULL)
 
1340
            fname = Strspl(varval(STRhome), &STRtildotdirs[1]);
 
1341
        else
 
1342
            fname = Strsave(fname);
 
1343
    }
 
1344
    else 
 
1345
        fname = globone(fname, G_ERROR);
 
1346
                
 
1347
    if ((fp = creat(short2str(fname), 0600)) == -1) {
 
1348
        xfree((ptr_t) fname);
 
1349
        return;
 
1350
    }
 
1351
 
 
1352
    if ((snum = varval(STRsavedirs)) == STRNULL) 
 
1353
        num = (unsigned int) ~0;
 
1354
    else
 
1355
        num = (unsigned int) atoi(short2str(snum));
 
1356
 
 
1357
    oldidfds = didfds;
 
1358
    didfds = 0;
 
1359
    ftmp = SHOUT;
 
1360
    SHOUT = fp;
 
1361
 
 
1362
    dp = dcwd->di_next;
 
1363
    do {
 
1364
        if (dp == &dhead)
 
1365
            continue;
 
1366
 
 
1367
        if (cdflag == 0) {
 
1368
            cdflag = 1;
 
1369
            xprintf("cd %S\n", quote_meta(qname, dp->di_name));
 
1370
        }
 
1371
        else
 
1372
            xprintf("pushd %S\n", quote_meta(qname, dp->di_name));
 
1373
 
 
1374
        if (num-- == 0)
 
1375
            break;
 
1376
 
 
1377
    } while ((dp = dp->di_next) != dcwd->di_next);
 
1378
 
 
1379
    (void) close(fp);
 
1380
    SHOUT = ftmp;
 
1381
    didfds = oldidfds;
 
1382
    xfree((ptr_t) fname);
 
1383
}