1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley Software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #if !defined(lint) && defined(DOSCCS)
   8: static char *sccsid = "@(#)sh.dir.c	5.3 (Berkeley) 6/11/85";
   9: #endif
  10: 
  11: #include "sh.h"
  12: #include "sh.dir.h"
  13: 
  14: /*
  15:  * C Shell - directory management
  16:  */
  17: 
  18: struct  directory *dfind();
  19: char    *dfollow();
  20: char    *dcanon();
  21: struct  directory dhead;        /* "head" of loop */
  22: int printd;             /* force name to be printed */
  23: static  char *fakev[] = { "dirs", NOSTR };
  24: 
  25: /*
  26:  * dinit - initialize current working directory
  27:  */
  28: dinit(hp)
  29:     char *hp;
  30: {
  31:     register char *cp;
  32:     register struct directory *dp;
  33:     char path[MAXPATHLEN];
  34: 
  35:     if (loginsh && hp)
  36:         cp = hp;
  37:     else {
  38:         cp = getwd(path);
  39:         if (cp == NULL) {
  40:             (void) write(2, path, strlen(path));
  41:             exit(1);
  42:         }
  43:     }
  44:     dp = (struct directory *)calloc(sizeof (struct directory), 1);
  45:     dp->di_name = savestr(cp);
  46:     dp->di_count = 0;
  47:     dhead.di_next = dhead.di_prev = dp;
  48:     dp->di_next = dp->di_prev = &dhead;
  49:     printd = 0;
  50:     dnewcwd(dp);
  51: }
  52: 
  53: /*
  54:  * dodirs - list all directories in directory loop
  55:  */
  56: dodirs(v)
  57:     char **v;
  58: {
  59:     register struct directory *dp;
  60:     bool lflag;
  61:     char *hp = value("home");
  62: 
  63:     if (*hp == '\0')
  64:         hp = NOSTR;
  65:     if (*++v != NOSTR)
  66:         if (eq(*v, "-l") && *++v == NOSTR)
  67:             lflag = 1;
  68:         else
  69:             error("Usage: dirs [ -l ]");
  70:     else
  71:         lflag = 0;
  72:     dp = dcwd;
  73:     do {
  74:         if (dp == &dhead)
  75:             continue;
  76:         if (!lflag && hp != NOSTR) {
  77:             dtildepr(hp, dp->di_name);
  78:         } else
  79:             printf("%s", dp->di_name);
  80:         printf(" ");
  81:     } while ((dp = dp->di_prev) != dcwd);
  82:     printf("\n");
  83: }
  84: 
  85: dtildepr(home, dir)
  86:     register char *home, *dir;
  87: {
  88: 
  89:     if (!eq(home, "/") && prefix(home, dir))
  90:         printf("~%s", dir + strlen(home));
  91:     else
  92:         printf("%s", dir);
  93: }
  94: 
  95: /*
  96:  * dochngd - implement chdir command.
  97:  */
  98: dochngd(v)
  99:     char **v;
 100: {
 101:     register char *cp;
 102:     register struct directory *dp;
 103: 
 104:     printd = 0;
 105:     if (*++v == NOSTR) {
 106:         if ((cp = value("home")) == NOSTR || *cp == 0)
 107:             bferr("No home directory");
 108:         if (chdir(cp) < 0)
 109:             bferr("Can't change to home directory");
 110:         cp = savestr(cp);
 111:     } else if ((dp = dfind(*v)) != 0) {
 112:         printd = 1;
 113:         if (chdir(dp->di_name) < 0)
 114:             Perror(dp->di_name);
 115:         dcwd->di_prev->di_next = dcwd->di_next;
 116:         dcwd->di_next->di_prev = dcwd->di_prev;
 117:         goto flushcwd;
 118:     } else
 119:         cp = dfollow(*v);
 120:     dp = (struct directory *)calloc(sizeof (struct directory), 1);
 121:     dp->di_name = cp;
 122:     dp->di_count = 0;
 123:     dp->di_next = dcwd->di_next;
 124:     dp->di_prev = dcwd->di_prev;
 125:     dp->di_prev->di_next = dp;
 126:     dp->di_next->di_prev = dp;
 127: flushcwd:
 128:     dfree(dcwd);
 129:     dnewcwd(dp);
 130: }
 131: 
 132: /*
 133:  * dfollow - change to arg directory; fall back on cdpath if not valid
 134:  */
 135: char *
 136: dfollow(cp)
 137:     register char *cp;
 138: {
 139:     register char *dp;
 140:     struct varent *c;
 141: 
 142:     cp = globone(cp);
 143:     if (chdir(cp) >= 0)
 144:         goto gotcha;
 145:     if (cp[0] != '/' && !prefix("./", cp) && !prefix("../", cp)
 146:         && (c = adrof("cdpath"))) {
 147:         char **cdp;
 148:         register char *p;
 149:         char buf[MAXPATHLEN];
 150: 
 151:         for (cdp = c->vec; *cdp; cdp++) {
 152:             for (dp = buf, p = *cdp; *dp++ = *p++;)
 153:                 ;
 154:             dp[-1] = '/';
 155:             for (p = cp; *dp++ = *p++;)
 156:                 ;
 157:             if (chdir(buf) >= 0) {
 158:                 printd = 1;
 159:                 xfree(cp);
 160:                 cp = savestr(buf);
 161:                 goto gotcha;
 162:             }
 163:         }
 164:     }
 165:     dp = value(cp);
 166:     if ((dp[0] == '/' || dp[0] == '.') && chdir(dp) >= 0) {
 167:         xfree(cp);
 168:         cp = savestr(dp);
 169:         printd = 1;
 170:         goto gotcha;
 171:     }
 172:     xfree(cp);          /* XXX, use after free */
 173:     Perror(cp);
 174: 
 175: gotcha:
 176:     if (*cp != '/') {
 177:         register char *p, *q;
 178:         int cwdlen;
 179: 
 180:         /*
 181: 		 * All in the name of efficiency?
 182: 		 */
 183:         for (p = dcwd->di_name; *p++;)
 184:             ;
 185:         if ((cwdlen = p - dcwd->di_name - 1) == 1)  /* root */
 186:             cwdlen = 0;
 187:         for (p = cp; *p++;)
 188:             ;
 189:         dp = xalloc((unsigned) (cwdlen + (p - cp) + 1));
 190:         for (p = dp, q = dcwd->di_name; *p++ = *q++;)
 191:             ;
 192:         if (cwdlen)
 193:             p[-1] = '/';
 194:         else
 195:             p--;            /* don't add a / after root */
 196:         for (q = cp; *p++ = *q++;)
 197:             ;
 198:         xfree(cp);
 199:         cp = dp;
 200:         dp += cwdlen;
 201:     } else
 202:         dp = cp;
 203:     return dcanon(cp, dp);
 204: }
 205: 
 206: /*
 207:  * dopushd - push new directory onto directory stack.
 208:  *	with no arguments exchange top and second.
 209:  *	with numeric argument (+n) bring it to top.
 210:  */
 211: dopushd(v)
 212:     char **v;
 213: {
 214:     register struct directory *dp;
 215: 
 216:     printd = 1;
 217:     if (*++v == NOSTR) {
 218:         if ((dp = dcwd->di_prev) == &dhead)
 219:             dp = dhead.di_prev;
 220:         if (dp == dcwd)
 221:             bferr("No other directory");
 222:         if (chdir(dp->di_name) < 0)
 223:             Perror(dp->di_name);
 224:         dp->di_prev->di_next = dp->di_next;
 225:         dp->di_next->di_prev = dp->di_prev;
 226:         dp->di_next = dcwd->di_next;
 227:         dp->di_prev = dcwd;
 228:         dcwd->di_next->di_prev = dp;
 229:         dcwd->di_next = dp;
 230:     } else if (dp = dfind(*v)) {
 231:         if (chdir(dp->di_name) < 0)
 232:             Perror(dp->di_name);
 233:     } else {
 234:         register char *cp;
 235: 
 236:         cp = dfollow(*v);
 237:         dp = (struct directory *)calloc(sizeof (struct directory), 1);
 238:         dp->di_name = cp;
 239:         dp->di_count = 0;
 240:         dp->di_prev = dcwd;
 241:         dp->di_next = dcwd->di_next;
 242:         dcwd->di_next = dp;
 243:         dp->di_next->di_prev = dp;
 244:     }
 245:     dnewcwd(dp);
 246: }
 247: 
 248: /*
 249:  * dfind - find a directory if specified by numeric (+n) argument
 250:  */
 251: struct directory *
 252: dfind(cp)
 253:     register char *cp;
 254: {
 255:     register struct directory *dp;
 256:     register int i;
 257:     register char *ep;
 258: 
 259:     if (*cp++ != '+')
 260:         return (0);
 261:     for (ep = cp; digit(*ep); ep++)
 262:         continue;
 263:     if (*ep)
 264:         return (0);
 265:     i = getn(cp);
 266:     if (i <= 0)
 267:         return (0);
 268:     for (dp = dcwd; i != 0; i--) {
 269:         if ((dp = dp->di_prev) == &dhead)
 270:             dp = dp->di_prev;
 271:         if (dp == dcwd)
 272:             bferr("Directory stack not that deep");
 273:     }
 274:     return (dp);
 275: }
 276: 
 277: /*
 278:  * dopopd - pop a directory out of the directory stack
 279:  *	with a numeric argument just discard it.
 280:  */
 281: dopopd(v)
 282:     char **v;
 283: {
 284:     register struct directory *dp, *p;
 285: 
 286:     printd = 1;
 287:     if (*++v == NOSTR)
 288:         dp = dcwd;
 289:     else if ((dp = dfind(*v)) == 0)
 290:         bferr("Bad directory");
 291:     if (dp->di_prev == &dhead && dp->di_next == &dhead)
 292:         bferr("Directory stack empty");
 293:     if (dp == dcwd) {
 294:         if ((p = dp->di_prev) == &dhead)
 295:             p = dhead.di_prev;
 296:         if (chdir(p->di_name) < 0)
 297:             Perror(p->di_name);
 298:     }
 299:     dp->di_prev->di_next = dp->di_next;
 300:     dp->di_next->di_prev = dp->di_prev;
 301:     if (dp == dcwd)
 302:         dnewcwd(p);
 303:     else
 304:         dodirs(fakev);
 305:     dfree(dp);
 306: }
 307: 
 308: /*
 309:  * dfree - free the directory (or keep it if it still has ref count)
 310:  */
 311: dfree(dp)
 312:     register struct directory *dp;
 313: {
 314: 
 315:     if (dp->di_count != 0)
 316:         dp->di_next = dp->di_prev = 0;
 317:     else
 318:         xfree(dp->di_name), xfree((char *)dp);
 319: }
 320: 
 321: /*
 322:  * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
 323:  *	we are of course assuming that the file system is standardly
 324:  *	constructed (always have ..'s, directories have links)
 325:  */
 326: char *
 327: dcanon(cp, p)
 328:     register char *cp, *p;
 329: {
 330:     register char *sp;
 331:     register char *p1, *p2;     /* general purpose */
 332:     bool slash;
 333: 
 334:     if (*cp != '/')
 335:         abort();
 336:     while (*p) {            /* for each component */
 337:         sp = p;         /* save slash address */
 338:         while (*++p == '/') /* flush extra slashes */
 339:             ;
 340:         if (p != ++sp)
 341:             for (p1 = sp, p2 = p; *p1++ = *p2++;)
 342:                 ;
 343:         p = sp;         /* save start of component */
 344:         slash = 0;
 345:         while (*++p)        /* find next slash or end of path */
 346:             if (*p == '/') {
 347:                 slash = 1;
 348:                 *p = 0;
 349:                 break;
 350:             }
 351:         if (*sp == '\0')    /* if component is null */
 352:             if (--sp == cp) /* if path is one char (i.e. /) */
 353:                 break;
 354:             else
 355:                 *sp = '\0';
 356:         else if (sp[0] == '.' && sp[1] == 0) {
 357:             if (slash) {
 358:                 for (p1 = sp, p2 = p + 1; *p1++ = *p2++;)
 359:                     ;
 360:                 p = --sp;
 361:             } else if (--sp != cp)
 362:                 *sp = '\0';
 363:         } else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
 364:             char link[MAXPATHLEN];
 365:             int cc;
 366:             char *newcp;
 367: 
 368:             /*
 369: 			 * We have something like "yyy/xxx/..", where "yyy"
 370: 			 * can be null or a path starting at /, and "xxx"
 371: 			 * is a single component.
 372: 			 * Before compressing "xxx/..", we want to expand
 373: 			 * "yyy/xxx", if it is a symbolic link.
 374: 			 */
 375:             *--sp = 0;  /* form the pathname for readlink */
 376:             if (sp != cp &&
 377:                 (cc = readlink(cp, link, sizeof link)) >= 0) {
 378:                 link[cc] = '\0';
 379:                 if (slash)
 380:                     *p = '/';
 381:                 /*
 382: 				 * Point p to the '/' in "/..", and restore
 383: 				 * the '/'.
 384: 				 */
 385:                 *(p = sp) = '/';
 386:                 /*
 387: 				 * find length of p
 388: 				 */
 389:                 for (p1 = p; *p1++;)
 390:                     ;
 391:                 if (*link != '/') {
 392:                     /*
 393: 					 * Relative path, expand it between
 394: 					 * the "yyy/" and the "/..".
 395: 					 * First, back sp up to the character
 396: 					 * past "yyy/".
 397: 					 */
 398:                     while (*--sp != '/')
 399:                         ;
 400:                     sp++;
 401:                     *sp = 0;
 402:                     /*
 403: 					 * New length is
 404: 					 * "yyy/" + link + "/.." and rest
 405: 					 */
 406:                     p1 = newcp = xalloc((unsigned)
 407:                         ((sp - cp) + cc + (p1 - p)));
 408:                     /*
 409: 					 * Copy new path into newcp
 410: 					 */
 411:                     for (p2 = cp; *p1++ = *p2++;)
 412:                         ;
 413:                     for (p1--, p2 = link; *p1++ = *p2++;)
 414:                         ;
 415:                     for (p1--, p2 = p; *p1++ = *p2++;)
 416:                         ;
 417:                     /*
 418: 					 * Restart canonicalization at
 419: 					 * expanded "/xxx".
 420: 					 */
 421:                     p = sp - cp - 1 + newcp;
 422:                 } else {
 423:                     /*
 424: 					 * New length is link + "/.." and rest
 425: 					 */
 426:                     p1 = newcp = xalloc((unsigned)
 427:                         (cc + (p1 - p)));
 428:                     /*
 429: 					 * Copy new path into newcp
 430: 					 */
 431:                     for (p2 = link; *p1++ = *p2++;)
 432:                         ;
 433:                     for (p1--, p2 = p; *p1++ = *p2++;)
 434:                         ;
 435:                     /*
 436: 					 * Restart canonicalization at beginning
 437: 					 */
 438:                     p = newcp;
 439:                 }
 440:                 xfree(cp);
 441:                 cp = newcp;
 442:                 continue;   /* canonicalize the link */
 443:             }
 444:             *sp = '/';
 445:             if (sp != cp)
 446:                 while (*--sp != '/')
 447:                     ;
 448:             if (slash) {
 449:                 for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;)
 450:                     ;
 451:                 p = sp;
 452:             } else if (cp == sp)
 453:                 *++sp = '\0';
 454:             else
 455:                 *sp = '\0';
 456:         } else if (slash)
 457:             *p = '/';
 458:     }
 459:     return cp;
 460: }
 461: 
 462: /*
 463:  * dnewcwd - make a new directory in the loop the current one
 464:  */
 465: dnewcwd(dp)
 466:     register struct directory *dp;
 467: {
 468: 
 469:     dcwd = dp;
 470:     set("cwd", savestr(dcwd->di_name));
 471:     if (printd)
 472:         dodirs(fakev);
 473: }

Defined functions

dcanon defined in line 326; used 2 times
dfind defined in line 251; used 4 times
dfollow defined in line 135; used 3 times
dfree defined in line 311; used 3 times
dinit defined in line 28; used 1 times
dnewcwd defined in line 465; used 4 times
dochngd defined in line 98; used 3 times
dodirs defined in line 56; used 4 times
dopopd defined in line 281; used 3 times
dopushd defined in line 211; used 3 times
dtildepr defined in line 85; used 3 times

Defined variables

dhead defined in line 21; used 11 times
fakev defined in line 23; used 2 times
printd defined in line 22; used 8 times
sccsid defined in line 8; never used
Last modified: 1991-08-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1534
Valid CSS Valid XHTML 1.0 Strict