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 "config.h"
  37: #if !defined(lint) && !defined(pdp11)
  38: static char *rcsid()
  39:     { return "$Id: sh.dir.c,v 3.0.1 1996/04/04 21:49:28 sms Exp $"; }
  40: #endif
  41: 
  42: 
  43: #include "sh.h"
  44: /*
  45:  * C Shell - directory management
  46:  */
  47: 
  48: static  struct directory    *dfind      __P((Char *));
  49: static  Char            *dfollow    __P((Char *));
  50: static  void             printdirs  __P((void));
  51: static  Char            *dgoto      __P((Char *));
  52: static  void             dnewcwd    __P((struct directory *));
  53: static  void             dset       __P((Char *));
  54: 
  55: struct directory dhead;     /* "head" of loop */
  56: int     printd;         /* force name to be printed */
  57: 
  58: #ifdef CSHDIRS
  59: int     bequiet = 0;        /* do not print dir stack -strike */
  60: 
  61: #endif
  62: static int dirflag = 0;
  63: 
  64: /*
  65:  * dinit - initialize current working directory
  66:  */
  67: void
  68: dinit(hp)
  69:     Char   *hp;
  70: {
  71:     register char *tcp;
  72:     register Char *cp;
  73:     register struct directory *dp;
  74:     char    path[MAXPATHLEN];
  75:     static char *emsg = "tcsh: Trying to start from \"%s\"\n";
  76: 
  77:     /* Don't believe the login shell home, because it may be a symlink */
  78:     tcp = getwd(path);      /* see ngetwd.c for System V version */
  79:     if (tcp == NULL || *tcp == '\0') {
  80:     (void) xprintf("tcsh: %s\n", path);
  81:     if (hp && *hp) {
  82:         tcp = short2str(hp);
  83:         (void) xprintf(emsg, tcp);
  84:         if (chdir(tcp) == -1)
  85:         cp = NULL;
  86:         else
  87:         cp = hp;
  88:     }
  89:     else
  90:         cp = NULL;
  91:     if (cp == NULL) {
  92:         (void) xprintf(emsg, "/");
  93:         if (chdir("/") == -1)
  94:         /* I am not even try to print an error message! */
  95:         xexit(1);
  96:         cp = SAVE("/");
  97:     }
  98:     }
  99:     else {
 100: #ifdef S_IFLNK
 101:     struct stat swd, shp;
 102: 
 103:     /*
 104: 	 * See if $HOME is the working directory we got and use that
 105: 	 */
 106:     if (hp && *hp &&
 107:         stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
 108:         swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
 109:         cp = hp;
 110:     else {
 111:         char   *cwd;
 112: 
 113:         /*
 114: 	     * use PWD if we have it (for subshells)
 115: 	     */
 116:         if (cwd = getenv("PWD")) {
 117:         if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
 118:             swd.st_ino == shp.st_ino)
 119:             tcp = cwd;
 120:         }
 121:         cp = dcanon(str2short(tcp), STRNULL);
 122:     }
 123: #else               /* S_IFLNK */
 124:     cp = dcanon(str2short(tcp), STRNULL);
 125: #endif				/* S_IFLNK */
 126:     }
 127: 
 128:     dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 129:     dp->di_name = Strsave(cp);
 130:     dp->di_count = 0;
 131:     dhead.di_next = dhead.di_prev = dp;
 132:     dp->di_next = dp->di_prev = &dhead;
 133:     printd = 0;
 134:     dnewcwd(dp);
 135: }
 136: 
 137: static void
 138: dset(dp)
 139: Char *dp;
 140: {
 141:     /*
 142:      * Don't call set() directly cause if the directory contains ` or
 143:      * other junk characters glob will fail.
 144:      */
 145:     register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
 146: 
 147:     vec[0] = Strsave(dp);
 148:     vec[1] = 0;
 149:     setq(STRcwd, vec, &shvhed);
 150:     Setenv(STRPWD, dp);
 151: }
 152: 
 153: #define DIR_LONG 1
 154: #define DIR_VERT 2
 155: #define DIR_LINE 4
 156: 
 157: static void
 158: skipargs(v, str)
 159:     Char ***v;
 160:     char   *str;
 161: {
 162:     register Char  **n = *v, *s;
 163: 
 164:     dirflag = 0;
 165:     for (n++; *n != NOSTR && (*n)[0] == '-'; n++)
 166:     for (s = &((*n)[1]); *s; s++)
 167:         switch (*s) {
 168:         case 'l':
 169:         dirflag |= DIR_LONG;
 170:         break;
 171:         case 'v':
 172:         dirflag |= DIR_VERT;
 173:         break;
 174:         case 'n':
 175:         dirflag |= DIR_LINE;
 176:         break;
 177:         default:
 178:         stderror(ERR_DIRUS, short2str(**v), str);
 179:         break;
 180:         }
 181:     *v = n;
 182: }
 183: 
 184: /*
 185:  * dodirs - list all directories in directory loop
 186:  */
 187: void
 188: dodirs(v)
 189:     Char  **v;
 190: {
 191:     skipargs(&v, "");
 192: 
 193:     if (*v != NOSTR)
 194:     stderror(ERR_DIRUS, "dirs", "");
 195:     printdirs();
 196: }
 197: 
 198: static void
 199: printdirs()
 200: {
 201:     register struct directory *dp;
 202:     Char   *s, *hp = value(STRhome);
 203:     int     idx, len, cur;
 204:     extern int T_Cols;
 205: 
 206:     if (*hp == '\0')
 207:     hp = NOSTR;
 208:     dp = dcwd;
 209:     idx = 0;
 210:     cur = 0;
 211:     do {
 212:     if (dp == &dhead)
 213:         continue;
 214:     if (dirflag & DIR_VERT) {
 215:         xprintf("%d\t", idx++);
 216:         cur = 0;
 217:     }
 218:     if (!(dirflag & DIR_LONG) && hp != NOSTR && !eq(hp, STRslash) &&
 219:         prefix(hp, dp->di_name))
 220:         len = Strlen(s = (dp->di_name + Strlen(hp))) + 2;
 221:     else
 222:         len = Strlen(s = dp->di_name) + 1;
 223: 
 224:     cur += len;
 225:     if ((dirflag & DIR_LINE) && cur >= T_Cols - 1 && len < T_Cols) {
 226:         xprintf("\n");
 227:         cur = len;
 228:     }
 229:     xprintf(s != dp->di_name ? "~%s%c" : "%s%c",
 230:         short2str(s), (dirflag & DIR_VERT) ? '\n' : ' ');
 231:     } while ((dp = dp->di_prev) != dcwd);
 232:     if (!(dirflag & DIR_VERT))
 233:     xprintf("\n");
 234: }
 235: 
 236: void
 237: dtildepr(home, dir)
 238:     register Char *home, *dir;
 239: {
 240: 
 241:     if (!eq(home, STRslash) && prefix(home, dir))
 242:     xprintf("~%s", short2str(dir + Strlen(home)));
 243:     else
 244:     xprintf("%s", short2str(dir));
 245: }
 246: 
 247: void
 248: dtilde()
 249: {
 250:     register struct directory *d = dcwd;
 251: 
 252:     do {
 253:     if (d == &dhead)
 254:         continue;
 255:     d->di_name = dcanon(d->di_name, STRNULL);
 256:     } while ((d = d->di_prev) != dcwd);
 257: 
 258:     dset(dcwd->di_name);
 259: }
 260: 
 261: 
 262: /* dnormalize():
 263:  *	If the name starts with . or .. then we might need to normalize
 264:  *	it depending on the symbolic link flags
 265:  */
 266: Char   *
 267: dnormalize(cp)
 268:     register Char   *cp;
 269: {
 270: 
 271: #define UC (unsigned char)
 272: #define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))
 273: #define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1])))
 274: 
 275:     if ((unsigned char) cp[0] == '/')
 276:     return (Strsave(cp));
 277: 
 278: #ifdef S_IFLNK
 279:     if (adrof(STRig__symlinks)) {
 280:     int     dotdot = 0;
 281:     register Char   *dp, *cwd;
 282: #ifdef apollo
 283:     bool slashslash;
 284: #endif
 285: 
 286:     cwd = (Char *) xmalloc((size_t) ((Strlen(dcwd->di_name) + 3) *
 287:                      sizeof(Char)));
 288:     (void) Strcpy(cwd, dcwd->di_name);
 289: #ifdef apollo
 290:     slashslash = cwd[0] == '/' && cwd[1] == '/';
 291: #endif
 292: 
 293:     /*
 294: 	 * Ignore . and count ..'s
 295: 	 */
 296:     while (*cp) {
 297:         if (ISDOT(cp)) {
 298:         if (*++cp)
 299:             cp++;
 300:         }
 301:         else if (ISDOTDOT(cp)) {
 302:         dotdot++;
 303:         cp += 2;
 304:         if (*cp)
 305:             cp++;
 306:         }
 307:         else
 308:         break;
 309:     }
 310:     while (dotdot > 0)
 311:         if ((dp = Strrchr(cwd, '/'))) {
 312: #ifdef apollo
 313:         if (dp == &cwd[1])
 314:             slashslash = 1;
 315: #endif
 316:         *dp = '\0';
 317:         dotdot--;
 318:         }
 319:         else
 320:         break;
 321: 
 322:     if (*cp) {
 323:         if (((unsigned char) cwd[(dotdot = Strlen(cwd)) - 1]) != '/')
 324:         cwd[dotdot++] = '/';
 325:         cwd[dotdot] = '\0';
 326:         dp = Strspl(cwd, cp);
 327:         xfree((ptr_t) cwd);
 328:         return dp;
 329:     }
 330:     else {
 331:         if (!*cwd) {
 332:         cwd[0] = '/';
 333: #ifdef apollo
 334:         cwd[1] = '/';
 335:         cwd[2] = '\0';
 336: #else
 337:         cwd[1] = '\0';
 338: #endif
 339:         }
 340: #ifdef apollo
 341:         else if (slashslash && cwd[1] == '\0') {
 342:         cwd[1] = '/';
 343:         cwd[2] = '\0';
 344:         }
 345: #endif
 346:         return cwd;
 347:     }
 348:     }
 349: #endif
 350:     return Strsave(cp);
 351: }
 352: 
 353: /*
 354:  * dochngd - implement chdir command.
 355:  */
 356: void
 357: dochngd(v)
 358:     Char  **v;
 359: {
 360:     register Char *cp;
 361:     register struct directory *dp;
 362: 
 363:     skipargs(&v, " [<dir>]");
 364:     printd = 0;
 365:     if (*v == NOSTR) {
 366:     if ((cp = value(STRhome)) == NOSTR || *cp == 0)
 367:         stderror(ERR_NAME | ERR_NOHOMEDIR);
 368:     if (chdir(short2str(cp)) < 0)
 369:         stderror(ERR_NAME | ERR_CANTCHANGE);
 370:     cp = Strsave(cp);
 371:     }
 372:     else if (v[1] != NOSTR) {
 373:     stderror(ERR_NAME | ERR_TOOMANY);
 374:     /* NOTREACHED */
 375:     return;
 376:     }
 377:     else if ((dp = dfind(*v)) != 0) {
 378:     char   *tmp;
 379: 
 380:     printd = 1;
 381:     if (chdir(tmp = short2str(dp->di_name)) < 0)
 382:         stderror(ERR_SYSTEM, tmp, strerror(errno));
 383:     dcwd->di_prev->di_next = dcwd->di_next;
 384:     dcwd->di_next->di_prev = dcwd->di_prev;
 385:     dfree(dcwd);
 386:     dnewcwd(dp);
 387:     return;
 388:     }
 389:     else
 390:     cp = dfollow(*v);
 391:     dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 392:     dp->di_name = cp;
 393:     dp->di_count = 0;
 394:     dp->di_next = dcwd->di_next;
 395:     dp->di_prev = dcwd->di_prev;
 396:     dp->di_prev->di_next = dp;
 397:     dp->di_next->di_prev = dp;
 398:     dfree(dcwd);
 399:     dnewcwd(dp);
 400: }
 401: 
 402: static Char *
 403: dgoto(cp)
 404:     Char   *cp;
 405: {
 406:     Char   *dp;
 407: 
 408:     if (*cp != '/') {
 409:     register Char *p, *q;
 410:     int     cwdlen;
 411: 
 412:     for (p = dcwd->di_name; *p++;);
 413:     if ((cwdlen = p - dcwd->di_name - 1) == 1)  /* root */
 414:         cwdlen = 0;
 415:     for (p = cp; *p++;);
 416:     dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char)));
 417:     for (p = dp, q = dcwd->di_name; *p++ = *q++;);
 418:     if (cwdlen)
 419:         p[-1] = '/';
 420:     else
 421:         p--;        /* don't add a / after root */
 422:     for (q = cp; *p++ = *q++;);
 423:     xfree((ptr_t) cp);
 424:     cp = dp;
 425:     dp += cwdlen;
 426:     }
 427:     else
 428:     dp = cp;
 429: 
 430:     cp = dcanon(cp, dp);
 431:     return cp;
 432: }
 433: 
 434: /*
 435:  * dfollow - change to arg directory; fall back on cdpath if not valid
 436:  */
 437: static Char *
 438: dfollow(cp)
 439:     register Char *cp;
 440: {
 441:     register Char *dp;
 442:     struct varent *c;
 443:     char    ebuf[MAXPATHLEN];
 444:     int serrno;
 445: 
 446:     cp = globone(cp, G_ERROR);
 447: #ifdef apollo
 448:     if (Strchr(cp, '`')) {
 449:     char *dptr, *ptr;
 450:     if (chdir(dptr = short2str(cp)) < 0)
 451:         stderror(ERR_SYSTEM, dptr, strerror(errno));
 452:     else if ((ptr = getwd(ebuf)) && *ptr != '\0') {
 453:         xfree((ptr_t) cp);
 454:         cp = Strsave(str2short(ptr));
 455:         return dgoto(cp);
 456:     }
 457:     else
 458:         stderror(ERR_SYSTEM, dptr, ebuf);
 459:     }
 460: #endif
 461: 
 462:     /*
 463:      * if we are ignoring symlinks, try to fix relatives now.
 464:      */
 465:     dp = dnormalize(cp);
 466:     if (chdir(short2str(dp)) >= 0) {
 467:     xfree((ptr_t) cp);
 468:     return dgoto(dp);
 469:     }
 470:     else {
 471:     xfree((ptr_t) dp);
 472:     if (chdir(short2str(cp)) >= 0)
 473:         return dgoto(cp);
 474:     serrno = errno;
 475:     }
 476: 
 477:     if (cp[0] != '/' && !prefix(STRdt_l, cp) && !prefix(STRdotdotsl, cp)
 478:     && (c = adrof(STRcdpath))) {
 479:     Char  **cdp;
 480:     register Char *p;
 481:     Char    buf[MAXPATHLEN];
 482: 
 483:     for (cdp = c->vec; *cdp; cdp++) {
 484:         for (dp = buf, p = *cdp; *dp++ = *p++;);
 485:         dp[-1] = '/';
 486:         for (p = cp; *dp++ = *p++;);
 487:         if (chdir(short2str(buf)) >= 0) {
 488:         printd = 1;
 489:         xfree((ptr_t) cp);
 490:         cp = Strsave(buf);
 491:         return dgoto(cp);
 492:         }
 493:     }
 494:     }
 495:     dp = value(cp);
 496:     if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
 497:     xfree((ptr_t) cp);
 498:     cp = Strsave(dp);
 499:     printd = 1;
 500:     return dgoto(cp);
 501:     }
 502:     (void) strcpy(ebuf, short2str(cp));
 503:     xfree((ptr_t) cp);
 504: #ifdef CSHDIRS
 505:     /*
 506:      * on login source of ~/.cshdirs, errors are eaten. the dir stack is all
 507:      * directories we could get to.
 508:      */
 509:     if (!bequiet)
 510:     stderror(ERR_SYSTEM, ebuf, strerror(serrno));
 511:     else
 512:     return (NOSTR);
 513: #else
 514:     stderror(ERR_SYSTEM, ebuf, strerror(serrno));
 515: #endif
 516:     /* NOTREACHED */
 517:     return (NOSTR);
 518: }
 519: 
 520: 
 521: /*
 522:  * dopushd - push new directory onto directory stack.
 523:  *	with no arguments exchange top and second.
 524:  *	with numeric argument (+n) bring it to top.
 525:  */
 526: void
 527: dopushd(v)
 528:     Char  **v;
 529: {
 530:     register struct directory *dp;
 531:     register Char *cp;
 532: 
 533:     skipargs(&v, " [<dir>|+<n>]");
 534:     printd = 1;
 535:     if (*v == NOSTR) {
 536:     if (adrof(STRputohome)) {
 537:         if ((cp = value(STRhome)) == NOSTR || *cp == 0)
 538:         stderror(ERR_NAME | ERR_NOHOMEDIR);
 539:         if (chdir(short2str(cp)) < 0)
 540:         stderror(ERR_NAME | ERR_CANTCHANGE);
 541:         cp = Strsave(cp);   /* hmmm... PWP */
 542:         cp = dfollow(cp);
 543:         dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 544:         dp->di_name = cp;
 545:         dp->di_count = 0;
 546:         dp->di_prev = dcwd;
 547:         dp->di_next = dcwd->di_next;
 548:         dcwd->di_next = dp;
 549:         dp->di_next->di_prev = dp;
 550:     }
 551:     else {
 552:         char   *tmp;
 553: 
 554:         if ((dp = dcwd->di_prev) == &dhead)
 555:         dp = dhead.di_prev;
 556:         if (dp == dcwd)
 557:         stderror(ERR_NAME | ERR_NODIR);
 558:         if (chdir(tmp = short2str(dp->di_name)) < 0)
 559:         stderror(ERR_SYSTEM, tmp, strerror(errno));
 560:         dp->di_prev->di_next = dp->di_next;
 561:         dp->di_next->di_prev = dp->di_prev;
 562:         dp->di_next = dcwd->di_next;
 563:         dp->di_prev = dcwd;
 564:         dcwd->di_next->di_prev = dp;
 565:         dcwd->di_next = dp;
 566:     }
 567:     }
 568:     else if (v[1] != NOSTR) {
 569:     stderror(ERR_NAME | ERR_TOOMANY);
 570:     /* NOTREACHED */
 571:     return;
 572:     }
 573:     else if (dp = dfind(*v)) {
 574:     char   *tmp;
 575: 
 576:     if (chdir(tmp = short2str(dp->di_name)) < 0)
 577:         stderror(ERR_SYSTEM, tmp, strerror(errno));
 578:     /*
 579: 	 * kfk - 10 Feb 1984 - added new "extraction style" pushd +n
 580: 	 */
 581:     if (adrof(STRdextract))
 582:         dextract(dp);
 583:     }
 584:     else {
 585:     register Char *ccp;
 586: 
 587:     ccp = dfollow(*v);
 588:     dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
 589:     dp->di_name = ccp;
 590:     dp->di_count = 0;
 591:     dp->di_prev = dcwd;
 592:     dp->di_next = dcwd->di_next;
 593:     dcwd->di_next = dp;
 594:     dp->di_next->di_prev = dp;
 595:     }
 596:     dnewcwd(dp);
 597: }
 598: 
 599: /*
 600:  * dfind - find a directory if specified by numeric (+n) argument
 601:  */
 602: static struct directory *
 603: dfind(cp)
 604:     register Char *cp;
 605: {
 606:     register struct directory *dp;
 607:     register int i;
 608:     register Char *ep;
 609: 
 610:     if (*cp++ != '+')
 611:     return (0);
 612:     for (ep = cp; Isdigit(*ep); ep++)
 613:     continue;
 614:     if (*ep)
 615:     return (0);
 616:     i = getn(cp);
 617:     if (i <= 0)
 618:     return (0);
 619:     for (dp = dcwd; i != 0; i--) {
 620:     if ((dp = dp->di_prev) == &dhead)
 621:         dp = dp->di_prev;
 622:     if (dp == dcwd)
 623:         stderror(ERR_NAME | ERR_DEEP);
 624:     }
 625:     return (dp);
 626: }
 627: 
 628: /*
 629:  * dopopd - pop a directory out of the directory stack
 630:  *	with a numeric argument just discard it.
 631:  */
 632: void
 633: dopopd(v)
 634:     Char  **v;
 635: {
 636:     register struct directory *dp, *p = NULL;
 637: 
 638:     skipargs(&v, " [+<n>]");
 639:     printd = 1;
 640:     if (*v == NOSTR)
 641:     dp = dcwd;
 642:     else if (v[1] != NOSTR) {
 643:     stderror(ERR_NAME | ERR_TOOMANY);
 644:     /* NOTREACHED */
 645:     return;
 646:     }
 647:     else if ((dp = dfind(*v)) == 0)
 648:     stderror(ERR_NAME | ERR_BADDIR);
 649:     if (dp->di_prev == &dhead && dp->di_next == &dhead)
 650:     stderror(ERR_NAME | ERR_EMPTY);
 651:     if (dp == dcwd) {
 652:     char   *tmp;
 653: 
 654:     if ((p = dp->di_prev) == &dhead)
 655:         p = dhead.di_prev;
 656:     if (chdir(tmp = short2str(p->di_name)) < 0)
 657:         stderror(ERR_SYSTEM, tmp, strerror(errno));
 658:     }
 659:     dp->di_prev->di_next = dp->di_next;
 660:     dp->di_next->di_prev = dp->di_prev;
 661:     if (dp == dcwd)
 662:     dnewcwd(p);
 663:     else {
 664:     printdirs();
 665:     }
 666:     dfree(dp);
 667: }
 668: 
 669: /*
 670:  * dfree - free the directory (or keep it if it still has ref count)
 671:  */
 672: void
 673: dfree(dp)
 674:     register struct directory *dp;
 675: {
 676: 
 677:     if (dp->di_count != 0) {
 678:     dp->di_next = dp->di_prev = 0;
 679:     }
 680:     else {
 681:     xfree((char *) dp->di_name);
 682:     xfree((ptr_t) dp);
 683:     }
 684: }
 685: 
 686: /*
 687:  * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
 688:  *	we are of course assuming that the file system is standardly
 689:  *	constructed (always have ..'s, directories have links)
 690:  */
 691: Char   *
 692: dcanon(cp, p)
 693:     register Char *cp, *p;
 694: {
 695:     register Char *sp;
 696:     register Char *p1, *p2; /* general purpose */
 697:     bool    slash;
 698: #ifdef apollo
 699:     bool    slashslash;
 700: #endif
 701: 
 702: #ifdef S_IFLNK          /* if we have symlinks */
 703:     Char    link[MAXPATHLEN];
 704:     char    tlink[MAXPATHLEN];
 705:     int     cc;
 706:     Char   *newcp;
 707: #endif				/* S_IFLNK */
 708: 
 709:     /*
 710:      * christos: if the path given does not start with a slash prepend cwd. If
 711:      * cwd does not start with a slash or the result would be too long abort().
 712:      */
 713:     if (*cp != '/') {
 714:     Char    tmpdir[MAXPATHLEN];
 715: 
 716:     p1 = value(STRcwd);
 717:     if (p1 == NULL || *p1 != '/')
 718:         abort();
 719:     if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
 720:         abort();
 721:     (void) Strcpy(tmpdir, p1);
 722:     (void) Strcat(tmpdir, STRslash);
 723:     (void) Strcat(tmpdir, cp);
 724:     xfree((ptr_t) cp);
 725:     cp = p = Strsave(tmpdir);
 726:     }
 727: 
 728: #ifdef COMMENT
 729:     if (*cp != '/')
 730:     abort();
 731: #endif
 732: 
 733: #ifdef apollo
 734:     slashslash = (cp[0] == '/' && cp[1] == '/');
 735: #endif
 736: 
 737:     while (*p) {        /* for each component */
 738:     sp = p;         /* save slash address */
 739:     while (*++p == '/') /* flush extra slashes */
 740:         ;
 741:     if (p != ++sp)
 742:         for (p1 = sp, p2 = p; *p1++ = *p2++;);
 743:     p = sp;         /* save start of component */
 744:     slash = 0;
 745:     while (*++p)        /* find next slash or end of path */
 746:         if (*p == '/') {
 747:         slash = 1;
 748:         *p = 0;
 749:         break;
 750:         }
 751: 
 752: #ifdef apollo
 753:     if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0')
 754:         slashslash = 1;
 755: #endif
 756:     if (*sp == '\0')    /* if component is null */
 757:         if (--sp == cp) /* if path is one char (i.e. /) */
 758:         break;
 759:         else
 760:         *sp = '\0';
 761:     else if (sp[0] == '.' && sp[1] == 0) {
 762:         if (slash) {
 763:         for (p1 = sp, p2 = p + 1; *p1++ = *p2++;);
 764:         p = --sp;
 765:         }
 766:         else if (--sp != cp)
 767:         *sp = '\0';
 768:     }
 769:     else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
 770:         /*
 771: 	     * We have something like "yyy/xxx/..", where "yyy" can be null or
 772: 	     * a path starting at /, and "xxx" is a single component. Before
 773: 	     * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
 774: 	     * symbolic link.
 775: 	     */
 776:         *--sp = 0;      /* form the pathname for readlink */
 777: #ifdef S_IFLNK          /* if we have symlinks */
 778:         if (sp != cp && !adrof(STRig__symlinks) &&
 779:         (cc = readlink(short2str(cp), tlink,
 780:                    sizeof tlink)) >= 0) {
 781:         (void) Strcpy(link, str2short(tlink));
 782:         link[cc] = '\0';
 783: 
 784:         if (slash)
 785:             *p = '/';
 786:         /*
 787: 		 * Point p to the '/' in "/..", and restore the '/'.
 788: 		 */
 789:         *(p = sp) = '/';
 790:         /*
 791: 		 * find length of p
 792: 		 */
 793:         for (p1 = p; *p1++;);
 794:         if (*link != '/') {
 795:             /*
 796: 		     * Relative path, expand it between the "yyy/" and the
 797: 		     * "/..". First, back sp up to the character past "yyy/".
 798: 		     */
 799:             while (*--sp != '/');
 800:             sp++;
 801:             *sp = 0;
 802:             /*
 803: 		     * New length is "yyy/" + link + "/.." and rest
 804: 		     */
 805:             p1 = newcp = (Char *) xmalloc((size_t)
 806:                         (((sp - cp) + cc + (p1 - p)) *
 807:                          sizeof(Char)));
 808:             /*
 809: 		     * Copy new path into newcp
 810: 		     */
 811:             for (p2 = cp; *p1++ = *p2++;);
 812:             for (p1--, p2 = link; *p1++ = *p2++;);
 813:             for (p1--, p2 = p; *p1++ = *p2++;);
 814:             /*
 815: 		     * Restart canonicalization at expanded "/xxx".
 816: 		     */
 817:             p = sp - cp - 1 + newcp;
 818:         }
 819:         else {
 820:             /*
 821: 		     * New length is link + "/.." and rest
 822: 		     */
 823:             p1 = newcp = (Char *) xmalloc((size_t)
 824:                         ((cc + (p1 - p)) * sizeof(Char)));
 825:             /*
 826: 		     * Copy new path into newcp
 827: 		     */
 828:             for (p2 = link; *p1++ = *p2++;);
 829:             for (p1--, p2 = p; *p1++ = *p2++;);
 830:             /*
 831: 		     * Restart canonicalization at beginning
 832: 		     */
 833:             p = newcp;
 834:         }
 835:         xfree((ptr_t) cp);
 836:         cp = newcp;
 837:         continue;   /* canonicalize the link */
 838:         }
 839: #endif				/* S_IFLNK */
 840:         *sp = '/';
 841:         if (sp != cp)
 842:         while (*--sp != '/');
 843:         if (slash) {
 844:         for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;);
 845:         p = sp;
 846:         }
 847:         else if (cp == sp)
 848:         *++sp = '\0';
 849:         else
 850:         *sp = '\0';
 851:     }
 852:     else {          /* normal dir name (not . or .. or nothing) */
 853: 
 854: #ifdef S_IFLNK          /* if we have symlinks */
 855:         if (sp != cp && adrof(STRchase_symlinks) &&
 856:         !adrof(STRig__symlinks) &&
 857:         (cc = readlink(short2str(cp), tlink,
 858:                    sizeof tlink)) >= 0) {
 859:         (void) Strcpy(link, str2short(tlink));
 860:         link[cc] = '\0';
 861: 
 862:         /*
 863: 		 * restore the '/'.
 864: 		 */
 865:         if (slash)
 866:             *p = '/';
 867: 
 868:         /*
 869: 		 * point sp to p (rather than backing up).
 870: 		 */
 871:         sp = p;
 872: 
 873:         /*
 874: 		 * find length of p
 875: 		 */
 876:         for (p1 = p; *p1++;);
 877:         if (*link != '/') {
 878:             /*
 879: 		     * Relative path, expand it between the "yyy/" and the
 880: 		     * remainder. First, back sp up to the character past
 881: 		     * "yyy/".
 882: 		     */
 883:             while (*--sp != '/');
 884:             sp++;
 885:             *sp = 0;
 886:             /*
 887: 		     * New length is "yyy/" + link + "/.." and rest
 888: 		     */
 889:             p1 = newcp = (Char *) xmalloc((size_t)
 890:                           (((sp - cp) + cc + (p1 - p))
 891:                            * sizeof(Char)));
 892:             /*
 893: 		     * Copy new path into newcp
 894: 		     */
 895:             for (p2 = cp; *p1++ = *p2++;);
 896:             for (p1--, p2 = link; *p1++ = *p2++;);
 897:             for (p1--, p2 = p; *p1++ = *p2++;);
 898:             /*
 899: 		     * Restart canonicalization at expanded "/xxx".
 900: 		     */
 901:             p = sp - cp - 1 + newcp;
 902:         }
 903:         else {
 904:             /*
 905: 		     * New length is link + the rest
 906: 		     */
 907:             p1 = newcp = (Char *) xmalloc((size_t)
 908:                         ((cc + (p1 - p)) * sizeof(Char)));
 909:             /*
 910: 		     * Copy new path into newcp
 911: 		     */
 912:             for (p2 = link; *p1++ = *p2++;);
 913:             for (p1--, p2 = p; *p1++ = *p2++;);
 914:             /*
 915: 		     * Restart canonicalization at beginning
 916: 		     */
 917:             p = newcp;
 918:         }
 919:         xfree((ptr_t) cp);
 920:         cp = newcp;
 921:         continue;   /* canonicalize the link */
 922:         }
 923: #endif				/* S_IFLNK */
 924:         if (slash)
 925:         *p = '/';
 926:     }
 927:     }
 928: 
 929:     /*
 930:      * fix home...
 931:      */
 932: #ifdef S_IFLNK
 933:     p1 = value(STRhome);
 934:     cc = Strlen(p1);
 935:     /*
 936:      * See if we're not in a subdir of STRhome
 937:      */
 938:     if (p1 && *p1 == '/' &&
 939:     (Strncmp(p1, cp, cc) != 0 || (cp[cc] != '/' && cp[cc] != '\0'))) {
 940:     static ino_t home_ino = -1;
 941:     static dev_t home_dev = -1;
 942:     static Char *home_ptr = NULL;
 943:     struct stat statbuf;
 944: 
 945:     /*
 946: 	 * Get dev and ino of STRhome
 947: 	 */
 948:     if (home_ptr != p1 &&
 949:         stat(short2str(p1), &statbuf) != -1) {
 950:         home_dev = statbuf.st_dev;
 951:         home_ino = statbuf.st_ino;
 952:         home_ptr = p1;
 953:     }
 954:     /*
 955: 	 * Start comparing dev & ino backwards
 956: 	 */
 957:     p2 = Strcpy(link, cp);
 958:     for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) {
 959:         if (statbuf.st_dev == home_dev &&
 960:         statbuf.st_ino == home_ino) {
 961:         sp = (Char *) - 1;
 962:         break;
 963:         }
 964:         if (sp = Strrchr(p2, '/'))
 965:         *sp = '\0';
 966:     }
 967:     /*
 968: 	 * See if we found it
 969: 	 */
 970:     if (*p2 && sp == (Char *) -1) {
 971:         /*
 972: 	     * Use STRhome to make '~' work
 973: 	     */
 974:         p2 = cp + Strlen(p2);
 975:         sp = newcp = (Char *) xmalloc((size_t)
 976:                     ((cc + Strlen(p2) + 1) * sizeof(Char)));
 977:         while (*p1)
 978:         *sp++ = *p1++;
 979:         while (*p2)
 980:         *sp++ = *p2++;
 981:         *sp = '\0';
 982:         xfree((ptr_t) cp);
 983:         cp = newcp;
 984:     }
 985:     }
 986: #endif				/* S_IFLNK */
 987: 
 988: #ifdef apollo
 989:     if (slashslash) {
 990:     if (cp[1] != '/') {
 991:         p = (Char *) xmalloc((size_t) (Strlen(cp) + 2) * sizeof(Char));
 992:         *p = '/';
 993:         (void) Strcpy(&p[1], cp);
 994:         xfree((ptr_t) cp);
 995:         cp = p;
 996:     }
 997:     }
 998:     if (cp[1] == '/' && cp[2] == '/')
 999:     (void) Strcpy(&cp[1], &cp[2]);
1000: #endif
1001:     return cp;
1002: }
1003: 
1004: 
1005: /*
1006:  * dnewcwd - make a new directory in the loop the current one
1007:  */
1008: static void
1009: dnewcwd(dp)
1010:     register struct directory *dp;
1011: {
1012:     dcwd = dp;
1013:     dset(dcwd->di_name);
1014:     if (printd && !(adrof(STRpusilent)) /* PWP: pushdsilent */
1015: #ifdef CSHDIRS
1016:     && !bequiet     /* be quite while restoring stack -strike */
1017: #endif
1018:     )
1019:     printdirs();
1020:     cwd_cmd();          /* PWP: run the defined cwd command */
1021: }
1022: 
1023: /*
1024:  * getstakd - added by kfk 17 Jan 1984
1025:  * Support routine for the stack hack.  Finds nth directory in
1026:  * the directory stack, or finds last directory in stack.
1027:  */
1028: int
1029: getstakd(s, cnt)
1030:     Char   *s;
1031:     int     cnt;
1032: {
1033:     register struct directory *dp;
1034: 
1035:     dp = dcwd;
1036:     if (cnt < 0) {      /* < 0 ==> last dir requested. */
1037:     dp = dp->di_next;
1038:     if (dp == &dhead)
1039:         dp = dp->di_next;
1040:     }
1041:     else {
1042:     while (cnt-- > 0) {
1043:         dp = dp->di_prev;
1044:         if (dp == &dhead)
1045:         dp = dp->di_prev;
1046:         if (dp == dcwd)
1047:         return (0);
1048:     }
1049:     }
1050:     (void) Strcpy(s, dp->di_name);
1051:     return (1);
1052: }
1053: 
1054: /*
1055:  * Karl Kleinpaste - 10 Feb 1984
1056:  * Added dextract(), which is used in pushd +n.
1057:  * Instead of just rotating the entire stack around, dextract()
1058:  * lets the user have the nth dir extracted from its current
1059:  * position, and pushes it onto the top.
1060:  */
1061: void
1062: dextract(dp)
1063:     register struct directory *dp;
1064: {
1065:     if (dp == dcwd)
1066:     return;
1067:     dp->di_next->di_prev = dp->di_prev;
1068:     dp->di_prev->di_next = dp->di_next;
1069:     dp->di_next = dcwd->di_next;
1070:     dp->di_prev = dcwd;
1071:     dp->di_next->di_prev = dp;
1072:     dcwd->di_next = dp;
1073: }
1074: 
1075: #ifdef CSHDIRS
1076: /*
1077:  * create a file called ~/.cshdirs which has a sequence
1078:  * of pushd commands which will restore the dir stack to
1079:  * its state before exit/logout. remember that the order
1080:  * is reversed in the file because we are pushing.
1081:  * -strike
1082:  */
1083: void
1084: recdirs()
1085: {
1086:     int     fp, ftmp, oldidfds;
1087:     int     cdflag = 0;
1088:     extern int fast;
1089:     Char    buf[BUFSIZ];
1090: 
1091:     if (!fast) {
1092:     if (!adrof(STRsvdirs))/* does it exist */
1093:         return;
1094:     (void) Strcpy(buf, value(STRhome));
1095:     (void) Strcat(buf, STRs_dirs);
1096:     if ((fp = creat(short2str(buf), 0666)) == -1)
1097:         return;
1098:     oldidfds = didfds;
1099:     didfds = 0;
1100:     ftmp = SHOUT;
1101:     SHOUT = fp;
1102:     {
1103:         extern struct directory dhead;
1104:         extern struct directory *dcwd;
1105:         struct directory *dp = dcwd->di_next;
1106: 
1107:         do {
1108:         if (dp == &dhead)
1109:             continue;
1110:         if (cdflag == 0)
1111:             cdflag++, xprintf("cd %s\n",
1112:                       short2str(dp->di_name));
1113:         else
1114:             xprintf("pushd %s\n",
1115:                 short2str(dp->di_name));
1116:         } while ((dp = dp->di_next) != dcwd->di_next);
1117:     }
1118:     xprintf("dirs\n");  /* show the dir stack */
1119: 
1120:     (void) close(fp);
1121:     SHOUT = ftmp;
1122:     didfds = oldidfds;
1123:     }
1124: }
1125: 
1126: #endif

Defined functions

dcanon defined in line 691; used 5 times
dextract defined in line 1061; used 2 times
dfind defined in line 602; used 3 times
dfollow defined in line 437; used 3 times
dfree defined in line 672; used 7 times
dgoto defined in line 402; used 5 times
dinit defined in line 67; never used
dnewcwd defined in line 1008; used 5 times
dnormalize defined in line 266; used 3 times
dochngd defined in line 356; used 3 times
dodirs defined in line 187; used 1 times
dopopd defined in line 632; used 3 times
dopushd defined in line 526; used 3 times
dset defined in line 137; used 2 times
dtilde defined in line 247; used 1 times
dtildepr defined in line 236; used 2 times
getstakd defined in line 1028; used 2 times
printdirs defined in line 198; used 3 times
rcsid defined in line 38; never used
recdirs defined in line 1083; never used
skipargs defined in line 157; used 4 times

Defined variables

bequiet defined in line 59; used 2 times
dhead defined in line 55; used 16 times
dirflag defined in line 62; used 9 times
printd defined in line 56; used 8 times

Defined macros

DIR_LINE defined in line 155; used 2 times
DIR_LONG defined in line 153; used 2 times
DIR_VERT defined in line 154; used 4 times
ISDOT defined in line 272; used 2 times
ISDOTDOT defined in line 273; used 1 times
UC defined in line 271; used 4 times
Last modified: 1996-04-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4707
Valid CSS Valid XHTML 1.0 Strict