# 2.11BSD#431 - /usr/src/bin/tcsh/sh.dir.c

##### Functions

    dcanon            X
    dextract          X
    dfree             X
    dinit             X
    dnormalize        X
    dochngd           X
    dodirs            X
    dopopd            X
    dopushd           X
    dtilde            X
    dtildepr          X
    getstakd          X
    recdirs           X

##### Variables

    bequiet           X
    dhead             X
    printd            X

##### Macros

    DIR_LINE          X
    DIR_LONG          X
    DIR_VERT          X
    ISDOT             X
    ISDOTDOT          X
    UC                X

       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

- in line 121-124(2), 255, 430
- in /usr/src/bin/tcsh/sh.set.c line 174

dextract defined in line 1061; used 2 times

- in line 582
- in /usr/src/bin/tcsh/sh.dir.c line 582

dfind defined in line 602; used 3 times

- in line 377, 573, 647

dfollow defined in line 437; used 3 times

- in line 390, 542, 587

dfree defined in line 672; used 7 times

- in line 385, 398, 666
- in /usr/src/bin/tcsh/sh.dir.c line 385, 398, 666
- in /usr/src/bin/tcsh/sh.proc.c line 501

dgoto defined in line 402; used 5 times

- in line 455, 468-473(2), 491, 500

dinit defined in line 67; never used
dnewcwd defined in line 1008; used 5 times

- in line 134, 386, 399, 596, 662

dnormalize defined in line 266; used 3 times

- in line 465
- in /usr/src/bin/tcsh/tc.func.c line 264
- in /usr/src/bin/tcsh/tw.parse.c line 669

dochngd defined in line 356; used 3 times

- in /usr/src/bin/tcsh/sh.init.c line 65-66(2)
- in /usr/src/bin/tcsh/sh.sem.c line 206

dodirs defined in line 187; used 1 times

- in /usr/src/bin/tcsh/sh.init.c line 69

dopopd defined in line 632; used 3 times

- in /usr/src/bin/tcsh/sh.init.c line 118-121(2)
- in /usr/src/bin/tcsh/sh.sem.c line 208

dopushd defined in line 526; used 3 times

- in /usr/src/bin/tcsh/sh.init.c line 86, 119
- in /usr/src/bin/tcsh/sh.sem.c line 207

dset defined in line 137; used 2 times

- in line 258, 1013

dtilde defined in line 247; used 1 times

- in /usr/src/bin/tcsh/sh.set.c line 181

dtildepr defined in line 236; used 2 times

- in /usr/src/bin/tcsh/sh.proc.c line 1081, 1106

getstakd defined in line 1028; used 2 times

- in /usr/src/bin/tcsh/sh.glob.c line 143
- in /usr/src/bin/tcsh/tw.parse.c line 1226

printdirs defined in line 198; used 3 times

- in line 195, 664, 1019

rcsid defined in line 38; never used
recdirs defined in line 1083; never used
skipargs defined in line 157; used 4 times

- in line 191, 363, 533, 638

#### Defined variables

bequiet defined in line 59; used 2 times

- in line 509, 1016

dhead defined in line 55; used 16 times

- in line 131-132(3), 212, 253, 554-555(2), 620, 649-655(4), 1038, 1044, 1103-1108(2)

dirflag defined in line 62; used 9 times

- in line 164-175(4), 214-218(2), 225-232(3)

printd defined in line 56; used 8 times

- in line 133, 364, 380, 488, 499, 534, 639, 1014

#### Defined macros

DIR_LINE defined in line 155; used 2 times

- in line 175, 225

DIR_LONG defined in line 153; used 2 times

- in line 169, 218

DIR_VERT defined in line 154; used 4 times

- in line 172, 214, 230-232(2)

ISDOT defined in line 272; used 2 times

- in line 273, 297

ISDOTDOT defined in line 273; used 1 times

- in line 301

UC defined in line 271; used 4 times

- in line 272-273(4)

Last modified: 1996-04-05 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1942 |