📄 dir.c
字号:
/*- * Copyright (c) 1980, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 5/31/93";#endif /* not lint */#include <sys/param.h>#include <sys/stat.h>#include <errno.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#if __STDC__# include <stdarg.h>#else# include <varargs.h>#endif#include "csh.h"#include "dir.h"#include "extern.h"/* Directory management. */static struct directory *dfind __P((Char *));static Char *dfollow __P((Char *));static void printdirs __P((void));static Char *dgoto __P((Char *));static void dnewcwd __P((struct directory *));static void dset __P((Char *));struct directory dhead; /* "head" of loop */int printd; /* force name to be printed */static int dirflag = 0;/* * dinit - initialize current working directory */voiddinit(hp) Char *hp;{ register char *tcp; register Char *cp; register struct directory *dp; char path[MAXPATHLEN]; static char *emsg = "csh: Trying to start from \"%s\"\n"; /* Don't believe the login shell home, because it may be a symlink */ tcp = getwd(path); /* see ngetwd.c for System V version */ if (tcp == NULL || *tcp == '\0') { (void) fprintf(csherr, "csh: %s\n", path); if (hp && *hp) { tcp = short2str(hp); if (chdir(tcp) == -1) cp = NULL; else cp = hp; (void) fprintf(csherr, emsg, vis_str(hp)); } else cp = NULL; if (cp == NULL) { (void) fprintf(csherr, emsg, "/"); if (chdir("/") == -1) /* I am not even try to print an error message! */ xexit(1); cp = SAVE("/"); } } else { struct stat swd, shp; /* * See if $HOME is the working directory we got and use that */ if (hp && *hp && stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 && swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino) cp = hp; else { char *cwd; /* * use PWD if we have it (for subshells) */ if ((cwd = getenv("PWD")) != NULL) { if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino) tcp = cwd; } cp = dcanon(SAVE(tcp), STRNULL); } } dp = (struct directory *) xcalloc(sizeof(struct directory), 1); dp->di_name = Strsave(cp); dp->di_count = 0; dhead.di_next = dhead.di_prev = dp; dp->di_next = dp->di_prev = &dhead; printd = 0; dnewcwd(dp);}static voiddset(dp)Char *dp;{ /* * Don't call set() directly cause if the directory contains ` or * other junk characters glob will fail. */ register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **))); vec[0] = Strsave(dp); vec[1] = 0; setq(STRcwd, vec, &shvhed); Setenv(STRPWD, dp);}#define DIR_LONG 1#define DIR_VERT 2#define DIR_LINE 4static voidskipargs(v, str) Char ***v; char *str;{ Char **n = *v, *s; dirflag = 0; for (n++; *n != NULL && (*n)[0] == '-'; n++) for (s = &((*n)[1]); *s; s++) switch (*s) { case 'l': dirflag |= DIR_LONG; break; case 'v': dirflag |= DIR_VERT; break; case 'n': dirflag |= DIR_LINE; break; default: stderror(ERR_DIRUS, vis_str(**v), str); break; } *v = n;}/* * dodirs - list all directories in directory loop */void/*ARGSUSED*/dodirs(v, t) Char **v; struct command *t;{ skipargs(&v, ""); if (*v != NULL) stderror(ERR_DIRUS, "dirs", ""); printdirs();}static voidprintdirs(){ register struct directory *dp; Char *s, *hp = value(STRhome); int idx, len, cur; if (*hp == '\0') hp = NULL; dp = dcwd; idx = 0; cur = 0; do { if (dp == &dhead) continue; if (dirflag & DIR_VERT) { (void) fprintf(cshout, "%d\t", idx++); cur = 0; } if (!(dirflag & DIR_LONG) && hp != NULL && !eq(hp, STRslash) && (len = Strlen(hp), Strncmp(hp, dp->di_name, len) == 0) && (dp->di_name[len] == '\0' || dp->di_name[len] == '/')) len = Strlen(s = (dp->di_name + len)) + 2; else len = Strlen(s = dp->di_name) + 1; cur += len; if ((dirflag & DIR_LINE) && cur >= 80 - 1 && len < 80) { (void) fprintf(cshout, "\n"); cur = len; } (void) fprintf(cshout, s != dp->di_name ? "~%s%c" : "%s%c", vis_str(s), (dirflag & DIR_VERT) ? '\n' : ' '); } while ((dp = dp->di_prev) != dcwd); if (!(dirflag & DIR_VERT)) (void) fprintf(cshout, "\n");}voiddtildepr(home, dir) register Char *home, *dir;{ if (!eq(home, STRslash) && prefix(home, dir)) (void) fprintf(cshout, "~%s", vis_str(dir + Strlen(home))); else (void) fprintf(cshout, "%s", vis_str(dir));}voiddtilde(){ struct directory *d = dcwd; do { if (d == &dhead) continue; d->di_name = dcanon(d->di_name, STRNULL); } while ((d = d->di_prev) != dcwd); dset(dcwd->di_name);}/* dnormalize(): * If the name starts with . or .. then we might need to normalize * it depending on the symbolic link flags */Char *dnormalize(cp) Char *cp;{#define UC (unsigned char)#define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))#define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1]))) if ((unsigned char) cp[0] == '/') return (Strsave(cp)); if (adrof(STRignore_symlinks)) { int dotdot = 0; Char *dp, *cwd; cwd = (Char *) xmalloc((size_t) ((Strlen(dcwd->di_name) + 3) * sizeof(Char))); (void) Strcpy(cwd, dcwd->di_name); /* * Ignore . and count ..'s */ while (*cp) { if (ISDOT(cp)) { if (*++cp) cp++; } else if (ISDOTDOT(cp)) { dotdot++; cp += 2; if (*cp) cp++; } else break; } while (dotdot > 0) if ((dp = Strrchr(cwd, '/'))) { *dp = '\0'; dotdot--; } else break; if (*cp) { cwd[dotdot = Strlen(cwd)] = '/'; cwd[dotdot + 1] = '\0'; dp = Strspl(cwd, cp); xfree((ptr_t) cwd); return dp; } else { if (!*cwd) { cwd[0] = '/'; cwd[1] = '\0'; } return cwd; } } return Strsave(cp);}/* * dochngd - implement chdir command. */void/*ARGSUSED*/dochngd(v, t) Char **v; struct command *t;{ register Char *cp; register struct directory *dp; skipargs(&v, " [<dir>]"); printd = 0; if (*v == NULL) { if ((cp = value(STRhome)) == NULL || *cp == 0) stderror(ERR_NAME | ERR_NOHOMEDIR); if (chdir(short2str(cp)) < 0) stderror(ERR_NAME | ERR_CANTCHANGE); cp = Strsave(cp); } else if (v[1] != NULL) { stderror(ERR_NAME | ERR_TOOMANY); /* NOTREACHED */ return; } else if ((dp = dfind(*v)) != 0) { char *tmp; printd = 1; if (chdir(tmp = short2str(dp->di_name)) < 0) stderror(ERR_SYSTEM, tmp, strerror(errno)); dcwd->di_prev->di_next = dcwd->di_next; dcwd->di_next->di_prev = dcwd->di_prev; dfree(dcwd); dnewcwd(dp); return; } else cp = dfollow(*v); dp = (struct directory *) xcalloc(sizeof(struct directory), 1); dp->di_name = cp; dp->di_count = 0; dp->di_next = dcwd->di_next; dp->di_prev = dcwd->di_prev; dp->di_prev->di_next = dp; dp->di_next->di_prev = dp; dfree(dcwd); dnewcwd(dp);}static Char *dgoto(cp) Char *cp;{ Char *dp; if (*cp != '/') { register Char *p, *q; int cwdlen; for (p = dcwd->di_name; *p++;) continue; if ((cwdlen = p - dcwd->di_name - 1) == 1) /* root */ cwdlen = 0; for (p = cp; *p++;) continue; dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char))); for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';) continue; if (cwdlen) p[-1] = '/'; else p--; /* don't add a / after root */ for (q = cp; (*p++ = *q++) != '\0';) continue; xfree((ptr_t) cp); cp = dp; dp += cwdlen; } else dp = cp; cp = dcanon(cp, dp); return cp;}/* * dfollow - change to arg directory; fall back on cdpath if not valid */static Char *dfollow(cp) register Char *cp;{ register Char *dp; struct varent *c; char ebuf[MAXPATHLEN]; int serrno; cp = globone(cp, G_ERROR); /* * if we are ignoring symlinks, try to fix relatives now. */ dp = dnormalize(cp); if (chdir(short2str(dp)) >= 0) { xfree((ptr_t) cp); return dgoto(dp); } else { xfree((ptr_t) dp); if (chdir(short2str(cp)) >= 0) return dgoto(cp); serrno = errno; } if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp) && (c = adrof(STRcdpath))) { Char **cdp; register Char *p; Char buf[MAXPATHLEN]; for (cdp = c->vec; *cdp; cdp++) { for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';) continue; dp[-1] = '/'; for (p = cp; (*dp++ = *p++) != '\0';) continue; if (chdir(short2str(buf)) >= 0) { printd = 1; xfree((ptr_t) cp); cp = Strsave(buf); return dgoto(cp); } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -