⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 var.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	if (*val == '=')		tvar = str_nsave(var, val++ - var, ATEMP);	else {		/* Importing from original envirnment: must have an = */		if (set & IMPORT)			return NULL;		tvar = (char *) var;		val = NULL;	}	/* Prevent typeset from creating a local PATH/ENV/SHELL */	if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0				  || strcmp(tvar, "ENV") == 0				  || strcmp(tvar, "SHELL") == 0))		errorf("%s: restricted", tvar);	vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? TRUE : FALSE)		: global(tvar);	set &= ~(LOCAL|LOCAL_COPY);	vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;	/* only allow export flag to be set.  at&t ksh allows any attribute to	 * be changed, which means it can be truncated or modified	 * (-L/-R/-Z/-i).	 */	if ((vpbase->flag&RDONLY)	    && (val || clr || (set & ~EXPORT)))		/* XXX check calls - is error here ok by POSIX? */		errorf("%s: is read only", tvar);	if (val)		afree(tvar, ATEMP);	/* most calls are with set/clr == 0 */	if (set | clr) {		int ok = 1;		/* XXX if x[0] isn't set, there will be problems: need to have		 * one copy of attributes for arrays...		 */		for (t = vpbase; t; t = t->u.array) {			int fake_assign;			char UNINITIALIZED(*s);			char UNINITIALIZED(*free_me);			fake_assign = (t->flag & ISSET) && (!val || t != vp)				      && ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL))					  || ((t->flag & INTEGER) && (clr & INTEGER))					  || (!(t->flag & INTEGER) && (set & INTEGER)));			if (fake_assign) {				if (t->flag & INTEGER) {					s = str_val(t);					free_me = (char *) 0;				} else {					s = t->val.s + t->type;					free_me = (t->flag & ALLOC) ? t->val.s								  : (char *) 0;				}				t->flag &= ~ALLOC;			}			if (!(t->flag & INTEGER) && (set & INTEGER)) {				t->type = 0;				t->flag &= ~ALLOC;			}			t->flag = (t->flag | set) & ~clr;			/* Don't change base if assignment is to be done,			 * in case assignment fails.			 */			if ((set & INTEGER) && base > 0 && (!val || t != vp))				t->type = base;			if (set & (LJUST|RJUST|ZEROFIL))				t->u2.field = field;			if (fake_assign) {				if (!setstr(t, s, KSH_RETURN_ERROR)) {					/* Somewhat arbitrary action here:					 * zap contents of varibale, but keep					 * the flag settings.					 */					ok = 0;					if (t->flag & INTEGER)						t->flag &= ~ISSET;					else {						if (t->flag & ALLOC)							afree((void*) t->val.s,							      t->areap);						t->flag &= ~(ISSET|ALLOC);						t->type = 0;					}				}				if (free_me)					afree((void *) free_me, t->areap);			}		}		if (!ok)		    errorf(null);	}	if (val != NULL) {		if (vp->flag&INTEGER) {			/* do not zero base before assignment */			setstr(vp, val, KSH_UNWIND_ERROR);			/* Done after assignment to override default */			if (base > 0)				vp->type = base;		} else			/* setstr can't fail (readonly check already done) */			setstr(vp, val, KSH_RETURN_ERROR);	}	/* only x[0] is ever exported, so use vpbase */	if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER)	    && vpbase->type == 0)		export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null);	return vp;}/* Unset a variable.  array_ref is set if there was an array reference in * the name lookup (eg, x[2]). */voidunset(vp, array_ref)	register struct tbl *vp;	int array_ref;{	if (vp->flag & ALLOC)		afree((void*)vp->val.s, vp->areap);	if ((vp->flag & ARRAY) && !array_ref) {		struct tbl *a, *tmp;		/* Free up entire array */		for (a = vp->u.array; a; ) {			tmp = a;			a = a->u.array;			if (tmp->flag & ALLOC)				afree((void *) tmp->val.s, tmp->areap);			afree(tmp, tmp->areap);		}		vp->u.array = (struct tbl *) 0;	}	/* If foo[0] is being unset, the remainder of the array is kept... */	vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);	if (vp->flag & SPECIAL)		unsetspec(vp);	/* responsible for `unspecial'ing var */}/* return a pointer to the first char past a legal variable name (returns the * argument if there is no legal name, returns * a pointer to the terminating * null if whole string is legal). */char *skip_varname(s, aok)	const char *s;	int aok;{	int alen;	if (s && letter(*s)) {		while (*++s && letnum(*s))			;		if (aok && *s == '[' && (alen = array_ref_len(s)))			s += alen;	}	return (char *) s;}/* Return a pointer to the first character past any legal variable name.  */char *skip_wdvarname(s, aok)	const char *s;	int aok;	/* skip array de-reference? */{	if (s[0] == CHAR && letter(s[1])) {		do			s += 2;		while (s[0] == CHAR && letnum(s[1]));		if (aok && s[0] == CHAR && s[1] == '[') {			/* skip possible array de-reference */			const char *p = s;			char c;			int depth = 0;			while (1) {				if (p[0] != CHAR)					break;				c = p[1];				p += 2;				if (c == '[')					depth++;				else if (c == ']' && --depth == 0) {					s = p;					break;				}			}		}	}	return (char *) s;}/* Check if coded string s is a variable name */intis_wdvarname(s, aok)	const char *s;	int aok;{	char *p = skip_wdvarname(s, aok);	return p != s && p[0] == EOS;}/* Check if coded string s is a variable assignment */intis_wdvarassign(s)	const char *s;{	char *p = skip_wdvarname(s, TRUE);	return p != s && p[0] == CHAR && p[1] == '=';}/* * Make the exported environment from the exported names in the dictionary. */char **makenv(){	struct block *l = e->loc;	XPtrV env;	register struct tbl *vp, **vpp;	register int i;	XPinit(env, 64);	for (l = e->loc; l != NULL; l = l->next)		for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )			if ((vp = *vpp++) != NULL			    && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {				register struct block *l2;				register struct tbl *vp2;				unsigned h = hash(vp->name);				/* unexport any redefined instances */				for (l2 = l->next; l2 != NULL; l2 = l2->next) {					vp2 = tsearch(&l2->vars, vp->name, h);					if (vp2 != NULL)						vp2->flag &= ~EXPORT;				}				if ((vp->flag&INTEGER)) {					/* integer to string */					char *val;					val = str_val(vp);					vp->flag &= ~(INTEGER|RDONLY);					/* setstr can't fail here */					setstr(vp, val, KSH_RETURN_ERROR);				}				XPput(env, vp->val.s);			}	XPput(env, NULL);	return (char **) XPclose(env);}/* * Called after a fork in parent to bump the random number generator. * Done to ensure children will not get the same random number sequence * if the parent doesn't use $RANDOM. */voidchange_random(){    rand();}/* * handle special variables with side effects - PATH, SECONDS. *//* Test if name is a special parameter */static intspecial(name)	register const char * name;{	register struct tbl *tp;	tp = tsearch(&specials, name, hash(name));	return tp && (tp->flag & ISSET) ? tp->type : V_NONE;}/* Make a variable non-special */static voidunspecial(name)	register const char * name;{	register struct tbl *tp;	tp = tsearch(&specials, name, hash(name));	if (tp)		tdelete(tp);}#ifdef KSHstatic	time_t	seconds;		/* time SECONDS last set */#endif /* KSH */static	int	user_lineno;		/* what user set $LINENO to */static voidgetspec(vp)	register struct tbl *vp;{	switch (special(vp->name)) {#ifdef KSH	  case V_SECONDS:		vp->flag &= ~SPECIAL;		/* On start up the value of SECONDS is used before seconds		 * has been set - don't do anything in this case		 * (see initcoms[] in main.c).		 */		if (vp->flag & ISSET)			setint(vp, (long) (time((time_t *)0) - seconds));		vp->flag |= SPECIAL;		break;	  case V_RANDOM:		vp->flag &= ~SPECIAL;		setint(vp, (long) (rand() & 0x7fff));		vp->flag |= SPECIAL;		break;#endif /* KSH */#ifdef HISTORY	  case V_HISTSIZE:		vp->flag &= ~SPECIAL;		setint(vp, (long) histsize);		vp->flag |= SPECIAL;		break;#endif /* HISTORY */	  case V_OPTIND:		vp->flag &= ~SPECIAL;		setint(vp, (long) user_opt.uoptind);		vp->flag |= SPECIAL;		break;	  case V_LINENO:		vp->flag &= ~SPECIAL;		setint(vp, (long) current_lineno + user_lineno);		vp->flag |= SPECIAL;		break;	}}static voidsetspec(vp)	register struct tbl *vp;{	char *s;	switch (special(vp->name)) {	  case V_PATH:		if (path)			afree(path, APERM);		path = str_save(str_val(vp), APERM);		flushcom(1);	/* clear tracked aliases */		break;	  case V_IFS:		setctypes(s = str_val(vp), C_IFS);		ifs0 = *s;		break;	  case V_OPTIND:		vp->flag &= ~SPECIAL;		getopts_reset((int) intval(vp));		vp->flag |= SPECIAL;		break;	  case V_POSIXLY_CORRECT:		change_flag(FPOSIX, OF_SPECIAL, 1);		break;	  case V_TMPDIR:		if (tmpdir) {			afree(tmpdir, APERM);			tmpdir = (char *) 0;		}		/* Use tmpdir iff it is an absolute path, is writable and		 * searchable and is a directory...		 */		{			struct stat statb;			s = str_val(vp);			if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0			    && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))				tmpdir = str_save(s, APERM);		}		break;#ifdef HISTORY	  case V_HISTSIZE:		vp->flag &= ~SPECIAL;		sethistsize((int) intval(vp));		vp->flag |= SPECIAL;		break;	  case V_HISTFILE:		sethistfile(str_val(vp));		break;#endif /* HISTORY */#ifdef EDIT	  case V_VISUAL:		set_editmode(str_val(vp));		break;	  case V_EDITOR:		if (!(global("VISUAL")->flag & ISSET))			set_editmode(str_val(vp));		break;	  case V_COLUMNS:		if ((x_cols = intval(vp)) <= MIN_COLS)			x_cols = MIN_COLS;		break;#endif /* EDIT */#ifdef KSH	  case V_MAIL:		mbset(str_val(vp));		break;	  case V_MAILPATH:		mpset(str_val(vp));		break;	  case V_MAILCHECK:		vp->flag &= ~SPECIAL;		mcset(intval(vp));		vp->flag |= SPECIAL;		break;	  case V_RANDOM:		vp->flag &= ~SPECIAL;		srand((unsigned int)intval(vp));		vp->flag |= SPECIAL;		break;	  case V_SECONDS:		vp->flag &= ~SPECIAL;		seconds = time((time_t*) 0) - intval(vp);		vp->flag |= SPECIAL;		break;	  case V_TMOUT:		/* at&t ksh seems to do this (only listen if integer) */		if (vp->flag & INTEGER)			ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;		break;#endif /* KSH */	  case V_LINENO:		vp->flag &= ~SPECIAL;		/* The -1 is because line numbering starts at 1. */		user_lineno = (unsigned int) intval(vp) - current_lineno - 1;		vp->flag |= SPECIAL;		break;	}}static voidunsetspec(vp)	register struct tbl *vp;{	switch (special(vp->name)) {	  case V_PATH:		if (path)			afree(path, APERM);		path = str_save(def_path, APERM);		flushcom(1);	/* clear tracked aliases */		break;	  case V_IFS:		setctypes(" \t\n", C_IFS);		ifs0 = ' ';		break;	  case V_TMPDIR:		/* should not become unspecial */		if (tmpdir) {			afree(tmpdir, APERM);			tmpdir = (char *) 0;		}		break;#ifdef KSH	  case V_MAIL:		mbset((char *) 0);		break;	  case V_MAILPATH:		mpset((char *) 0);		break;#endif /* KSH */	  case V_LINENO:#ifdef KSH	  case V_MAILCHECK:	/* at&t ksh leaves previous value in place */	  case V_RANDOM:	  case V_SECONDS:	  case V_TMOUT:		/* at&t ksh leaves previous value in place */#endif /* KSH */		unspecial(vp->name);		break;	  /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning,	   * but OPTARG does not (still set by getopts) and _ is also still	   * set in various places.	   * Don't know what at&t does for:	   *		MAIL, MAILPATH, HISTSIZE, HISTFILE,	   * Unsetting these in at&t ksh does not loose the `specialness':	   *    no effect: IFS, COLUMNS, PATH, TMPDIR,	   *		VISUAL, EDITOR,	   * pdkshisms: no effect:	   *		POSIXLY_CORRECT (use set +o posix instead)	   */	}}/* * Search for (and possibly create) a table entry starting with * vp, indexed by val. */static struct tbl *arraysearch(vp, val)	struct tbl *vp;	int val;{	struct tbl *prev, *curr, *new;	vp->flag |= ARRAY|DEFINED;	/* The table entry is always [0] */	if (val == 0) {		vp->index = 0;		return vp;	}	prev = vp;	curr = vp->u.array;	while (curr && curr->index < val) {		prev = curr;		curr = curr->u.array;	}	if (curr && curr->index == val) {		if (curr->flag&ISSET)			return curr;		else			new = curr;	} else		new = (struct tbl *)alloc(sizeof(struct tbl)+strlen(vp->name)+1, vp->areap);	strcpy(new->name, vp->name);	new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);	new->type = vp->type;	new->areap = vp->areap;	new->u2.field = vp->u2.field;	new->index = val;	if (curr != new) {		/* not reusing old array entry */		prev->u.array = new;		new->u.array = curr;	}	return new;}/* Return the length of an array reference (eg, [1+2]) - cp is assumed * to point to the open bracket.  Returns 0 if there is no matching closing * bracket. */intarray_ref_len(cp)	const char *cp;{	const char *s = cp;	int c;	int depth = 0;	while ((c = *s++) && (c != ']' || --depth))		if (c == '[')			depth++;	if (!c)		return 0;	return s - cp;}/* * Make a copy of the base of an array name */char *arrayname(str)	const char *str;{	const char *p;	if ((p = strchr(str, '[')) == 0)		/* Shouldn't happen, but why worry? */		return (char *) str;	return str_nsave(str, p - str, ATEMP);}/* Set (or overwrite, if !reset) the array variable var to the values in vals. */voidset_array(var, reset, vals)	const char *var;	int reset;	char **vals;{	struct tbl *vp, *vq;	int i;	/* to get local array, use "typeset foo; set -A foo" */	vp = global(var);	/* Note: at&t ksh allows set -A but not set +A of a read-only var */	if ((vp->flag&RDONLY))		errorf("%s: is read only", var);	/* This code is quite non-optimal */	if (reset > 0)		/* trash existing values and attributes */		unset(vp, 0);	/* todo: would be nice for assignment to completely succeed or	 * completely fail.  Only really effects integer arrays:	 * evaluation of some of vals[] may fail...	 */	for (i = 0; vals[i]; i++) {		vq = arraysearch(vp, i);		/* would be nice to deal with errors here... (see above) */		setstr(vq, vals[i], KSH_RETURN_ERROR);	}}

⌨️ 快捷键说明

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