sh.dir.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 522 行

C
522
字号
#ifndef lintstatic char *sccsid = "@(#)sh.dir.c	4.2  (ULTRIX)        8/13/90";#endif/************************************************************************ *                                                                      * *                      Copyright (c) 1988 by                           * *              Digital Equipment Corporation, Maynard, MA              * *                      All rights reserved.                            * *                                                                      * *   This software is furnished under a license and may be used and     * *   copied  only  in accordance with the terms of such license and     * *   with the  inclusion  of  the  above  copyright  notice.   This     * *   software  or  any  other copies thereof may not be provided or     * *   otherwise made available to any other person.  No title to and     * *   ownership of the software is hereby transferred.                   * *                                                                      * *   The information in this software is subject to change  without     * *   notice  and should not be construed as a commitment by Digital     * *   Equipment Corporation.                                             * *                                                                      * *   Digital assumes no responsibility for the use  or  reliability     * *   of its software on equipment which is not supplied by Digital.     * *                                                                      * ************************************************************************//* ------------------------------------------------------------------ *//* | Copyright Unpublished, MIPS Computer Systems, Inc.  All Rights | *//* | Reserved.  This software contains proprietary and confidential | *//* | information of MIPS and its suppliers.  Use, disclosure or     | *//* | reproduction is prohibited without the prior express written   | *//* | consent of MIPS.                                               | *//* ------------------------------------------------------------------ *//* $Header: sh.dir.c,v 1.5 87/04/10 18:06:26 dce Exp $ */#include "sh.h"#include "sh.dir.h"/* * C Shell - directory management * * Modification History * * 002 - Bob Fontaine - Thu Jun 21 10:22:20 EDT 1990 *	 Change name of internal printf function to csh_printf to avoid *	 conflicts with the stdio library printf routine . * * 001 - Bob Fontaine   - Fri Jun  1 15:04:31 EDT 1990 *	 fix for QAR #2622.  On the chance that the pathname of the current  *	 directory does not begin with a '/' then, instead of aborting and  * 	 dumping core, attempt to determine the current working directory  *	 using getcwd().  If that succeeds, do what the user requested, and *	 if it fails, then all is lost and bail out. */struct	directory *dfind();char	*dfollow();char	*dcanon();struct	directory dhead;		/* "head" of loop */int	printd;				/* force name to be printed */static	char *fakev[] = { "dirs", NOSTR };/* * dinit - initialize current working directory */dinit(hp)	char *hp;{	register char *cp;	register struct directory *dp;	char path[MAXPATHLEN];	if (loginsh && hp)		cp = hp;	else {		cp = getwd(path);		if (cp == NULL) {			strcat(path, " -- can't start new shell\n");			(void) write(SHDIAG, path, strlen(path));			exit(1);		}	}	dp = (struct directory *)calloc(sizeof (struct directory), 1);	dp->di_name = savestr(cp);	dp->di_count = 0;	dhead.di_next = dhead.di_prev = dp;	dp->di_next = dp->di_prev = &dhead;	printd = 0;	dnewcwd(dp);}/* * dodirs - list all directories in directory loop */dodirs(v)	char **v;{	register struct directory *dp;	bool lflag;	char *hp = value("home");	if (*hp == '\0')		hp = NOSTR;	if (*++v != NOSTR)		if (eq(*v, "-l") && *++v == NOSTR)			lflag = 1;		else			error("Usage: dirs [ -l ]");	else		lflag = 0;	dp = dcwd;	do {		if (dp == &dhead)			continue;		if (!lflag && hp != NOSTR) {			dtildepr(hp, dp->di_name);		} else			csh_printf("%s", dp->di_name);		/* 005 RNF */		csh_printf(" ");				/* 005 RNF */	} while ((dp = dp->di_prev) != dcwd);	csh_printf("\n");					/* 005 RNF */}dtildepr(home, dir)	register char *home, *dir;{	if (!eq(home, "/") && prefix(home, dir))		csh_printf("~%s", dir + strlen(home));		/* 005 RNF */	else		csh_printf("%s", dir);				/* 005 RNF */}/* * dochngd - implement chdir command. */dochngd(v)	char **v;{	register char *cp;	register struct directory *dp;	printd = 0;	if (*++v == NOSTR) {		if ((cp = value("home")) == NOSTR || *cp == 0)			bferr("No home directory");		if (chdir(cp) < 0)			bferr("Can't change to home directory");		cp = savestr(cp);	} else if ((dp = dfind(*v)) != 0) {		printd = 1;		if (chdir(dp->di_name) < 0)			Perror(dp->di_name);		dcwd->di_prev->di_next = dcwd->di_next;		dcwd->di_next->di_prev = dcwd->di_prev;		goto flushcwd;	} else		cp = dfollow(*v);	dp = (struct directory *)calloc(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;flushcwd:	dfree(dcwd);	dnewcwd(dp);}/* * dfollow - change to arg directory; fall back on cdpath if not valid */char *dfollow(cp)	register char *cp;{	register char *dp;	struct varent *c;	cp = globone(cp);	if (chdir(cp) >= 0)		goto gotcha;	if (cp[0] != '/' && !prefix("./", cp) && !prefix("../", cp)	    && (c = adrof("cdpath"))) {		char **cdp;		register char *p;		char buf[MAXPATHLEN];		for (cdp = c->vec; *cdp; cdp++) {			for (dp = buf, p = *cdp; *dp++ = *p++;)				;			dp[-1] = '/';			for (p = cp; *dp++ = *p++;)				;			if (chdir(buf) >= 0) {				printd = 1;				xfree(cp);				cp = savestr(buf);				goto gotcha;			}		}	}	dp = value(cp);	if ((dp[0] == '/' || dp[0] == '.') && chdir(dp) >= 0) {		xfree(cp);		cp = savestr(dp);		printd = 1;		goto gotcha;	}	xfree(cp);			/* XXX, use after free */	Perror(cp);gotcha:	if (*cp != '/') {		register char *p, *q;		int cwdlen;		/*		 * All in the name of efficiency?		 */		for (p = dcwd->di_name; *p++;)			;		if ((cwdlen = p - dcwd->di_name - 1) == 1)	/* root */			cwdlen = 0;		for (p = cp; *p++;)			;		dp = xalloc((unsigned) (cwdlen + (p - cp) + 1));		for (p = dp, q = dcwd->di_name; *p++ = *q++;)			;		if (cwdlen)			p[-1] = '/';		else			p--;			/* don't add a / after root */		for (q = cp; *p++ = *q++;)			;		xfree(cp);		cp = dp;		dp += cwdlen;	} else		dp = cp;	return dcanon(cp, dp);}/* * dopushd - push new directory onto directory stack. *	with no arguments exchange top and second. *	with numeric argument (+n) bring it to top. */dopushd(v)	char **v;{	register struct directory *dp;	printd = 1;	if (*++v == NOSTR) {		if ((dp = dcwd->di_prev) == &dhead)			dp = dhead.di_prev;		if (dp == dcwd)			bferr("No other directory");		if (chdir(dp->di_name) < 0)			Perror(dp->di_name);		dp->di_prev->di_next = dp->di_next;		dp->di_next->di_prev = dp->di_prev;		dp->di_next = dcwd->di_next;		dp->di_prev = dcwd;		dcwd->di_next->di_prev = dp;		dcwd->di_next = dp;	} else if (dp = dfind(*v)) {		if (chdir(dp->di_name) < 0)			Perror(dp->di_name);	} else {		register char *cp;		cp = dfollow(*v);		dp = (struct directory *)calloc(sizeof (struct directory), 1);		dp->di_name = cp;		dp->di_count = 0;		dp->di_prev = dcwd;		dp->di_next = dcwd->di_next;		dcwd->di_next = dp;		dp->di_next->di_prev = dp;	}	dnewcwd(dp);}/* * dfind - find a directory if specified by numeric (+n) argument */struct directory *dfind(cp)	register char *cp;{	register struct directory *dp;	register int i;	register char *ep;	if (*cp++ != '+')		return (0);	for (ep = cp; digit(*ep); ep++)		continue;	if (*ep)		return (0);	i = getn(cp);	if (i <= 0)		return (0);	for (dp = dcwd; i != 0; i--) {		if ((dp = dp->di_prev) == &dhead)			dp = dp->di_prev;		if (dp == dcwd)			bferr("Directory stack not that deep");	}	return (dp);}/* * dopopd - pop a directory out of the directory stack *	with a numeric argument just discard it. */dopopd(v)	char **v;{	register struct directory *dp, *p;	printd = 1;	if (*++v == NOSTR)		dp = dcwd;	else if ((dp = dfind(*v)) == 0)		bferr("Bad directory");	if (dp->di_prev == &dhead && dp->di_next == &dhead)		bferr("Directory stack empty");	if (dp == dcwd) {		if ((p = dp->di_prev) == &dhead)			p = dhead.di_prev;		if (chdir(p->di_name) < 0)			Perror(p->di_name);	}	dp->di_prev->di_next = dp->di_next;	dp->di_next->di_prev = dp->di_prev;	if (dp == dcwd)		dnewcwd(p);	else		dodirs(fakev);	dfree(dp);}/* * dfree - free the directory (or keep it if it still has ref count) */dfree(dp)	register struct directory *dp;{	if (dp->di_count != 0)		dp->di_next = dp->di_prev = 0;	else		xfree(dp->di_name), xfree((char *)dp);}/* * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. *	we are of course assuming that the file system is standardly *	constructed (always have ..'s, directories have links) */char *dcanon(cp, p)	register char *cp, *p;{	char *getcwd();	register char *sp;	register char *p1, *p2;		/* general purpose */	bool slash;	if (*cp != '/')	{		/* 004  rather than just abort when the cwd gets messed up */		/*      try and get the cwd and then do what the user asked */		/*	If that fails then blow up.  QAR #2622		*/		if((cp = getcwd((char *)NULL,MAXPATHLEN)) == NULL)		{			perror("pwd");			abort();		}	}	while (*p) {			/* for each component */		sp = p;			/* save slash address */		while (*++p == '/')	/* flush extra slashes */			;		if (p != ++sp)			for (p1 = sp, p2 = p; *p1++ = *p2++;)				;		p = sp;			/* save start of component */		slash = 0;		while (*++p)		/* find next slash or end of path */			if (*p == '/') {				slash = 1;				*p = 0;				break;			}		if (*sp == '\0')	/* if component is null */			if (--sp == cp)	/* if path is one char (i.e. /) */				break;			else				*sp = '\0';		else if (sp[0] == '.' && sp[1] == 0) {			if (slash) {				for (p1 = sp, p2 = p + 1; *p1++ = *p2++;)					;				p = --sp;			} else if (--sp != cp)				*sp = '\0';		} else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {			char link[MAXPATHLEN];			int cc;			char *newcp;			/*			 * We have something like "yyy/xxx/..", where "yyy"			 * can be null or a path starting at /, and "xxx"			 * is a single component.			 * Before compressing "xxx/..", we want to expand			 * "yyy/xxx", if it is a symbolic link.			 */			*--sp = 0;	/* form the pathname for readlink */			if (sp != cp &&			    (cc = readlink(cp, link, sizeof link)) >= 0) {				link[cc] = '\0';				if (slash)					*p = '/';				/*				 * Point p to the '/' in "/..", and restore				 * the '/'.				 */				*(p = sp) = '/';				/*				 * find length of p				 */				for (p1 = p; *p1++;)					;				if (*link != '/') {					/*					 * Relative path, expand it between					 * the "yyy/" and the "/..".					 * First, back sp up to the character					 * past "yyy/".					 */					while (*--sp != '/')						;					sp++;					*sp = 0;					/*					 * New length is					 * "yyy/" + link + "/.." and rest					 */					p1 = newcp = xalloc((unsigned)						((sp - cp) + cc + (p1 - p)));					/*					 * Copy new path into newcp					 */					for (p2 = cp; *p1++ = *p2++;)						;					for (p1--, p2 = link; *p1++ = *p2++;)						;					for (p1--, p2 = p; *p1++ = *p2++;)						;					/*					 * Restart canonicalization at					 * expanded "/xxx".					 */					p = sp - cp - 1 + newcp;				} else {					/*					 * New length is link + "/.." and rest					 */					p1 = newcp = xalloc((unsigned)						(cc + (p1 - p)));					/*					 * Copy new path into newcp					 */					for (p2 = link; *p1++ = *p2++;)						;					for (p1--, p2 = p; *p1++ = *p2++;)						;					/*					 * Restart canonicalization at beginning					 */					p = newcp;				}				xfree(cp);				cp = newcp;				continue;	/* canonicalize the link */			}			*sp = '/';			if (sp != cp)				while (*--sp != '/')					;			if (slash) {				for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;)					;				p = sp;			} else if (cp == sp)				*++sp = '\0';			else				*sp = '\0';		} else if (slash)			*p = '/';	}	return cp;}/* * dnewcwd - make a new directory in the loop the current one */dnewcwd(dp)	register struct directory *dp;{	dcwd = dp;	set("cwd", savestr(dcwd->di_name));	if (printd || adrof("printdir"))		dodirs(fakev);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?