mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-11-04 07:21:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			2191 lines
		
	
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2191 lines
		
	
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * params.c - parameters
 | 
						|
 *
 | 
						|
 * This file is part of zsh, the Z shell.
 | 
						|
 *
 | 
						|
 * Copyright (c) 1992-1997 Paul Falstad
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Permission is hereby granted, without written agreement and without
 | 
						|
 * license or royalty fees, to use, copy, modify, and distribute this
 | 
						|
 * software and to distribute modified versions of this software for any
 | 
						|
 * purpose, provided that the above copyright notice and the following
 | 
						|
 * two paragraphs appear in all copies of this software.
 | 
						|
 *
 | 
						|
 * In no event shall Paul Falstad or the Zsh Development Group be liable
 | 
						|
 * to any party for direct, indirect, special, incidental, or consequential
 | 
						|
 * damages arising out of the use of this software and its documentation,
 | 
						|
 * even if Paul Falstad and the Zsh Development Group have been advised of
 | 
						|
 * the possibility of such damage.
 | 
						|
 *
 | 
						|
 * Paul Falstad and the Zsh Development Group specifically disclaim any
 | 
						|
 * warranties, including, but not limited to, the implied warranties of
 | 
						|
 * merchantability and fitness for a particular purpose.  The software
 | 
						|
 * provided hereunder is on an "as is" basis, and Paul Falstad and the
 | 
						|
 * Zsh Development Group have no obligation to provide maintenance,
 | 
						|
 * support, updates, enhancements, or modifications.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "zsh.mdh"
 | 
						|
#include "params.pro"
 | 
						|
 | 
						|
#include "version.h"
 | 
						|
 | 
						|
/* what level of localness we are at */
 | 
						|
 
 | 
						|
/**/
 | 
						|
int locallevel;
 | 
						|
 
 | 
						|
/* Variables holding values of special parameters */
 | 
						|
 
 | 
						|
/**/
 | 
						|
char **pparams,		/* $argv        */
 | 
						|
     **cdpath,		/* $cdpath      */
 | 
						|
     **fignore,		/* $fignore     */
 | 
						|
     **fpath,		/* $fpath       */
 | 
						|
     **mailpath,	/* $mailpath    */
 | 
						|
     **manpath,		/* $manpath     */
 | 
						|
     **path,		/* $path        */
 | 
						|
     **psvar,		/* $psvar       */
 | 
						|
     **watch;		/* $watch       */
 | 
						|
 
 | 
						|
/**/
 | 
						|
char *argzero,		/* $0           */
 | 
						|
     *underscore,	/* $_           */
 | 
						|
     *home,		/* $HOME        */
 | 
						|
     *hostnam,		/* $HOST        */
 | 
						|
     *ifs,		/* $IFS         */
 | 
						|
     *nullcmd,		/* $NULLCMD     */
 | 
						|
     *oldpwd,		/* $OLDPWD      */
 | 
						|
     *zoptarg,		/* $OPTARG      */
 | 
						|
     *postedit,		/* $POSTEDIT    */
 | 
						|
     *prompt,		/* $PROMPT      */
 | 
						|
     *prompt2,		/* $PROMPT2     */
 | 
						|
     *prompt3,		/* $PROMPT3     */
 | 
						|
     *prompt4,		/* $PROMPT4     */
 | 
						|
     *pwd,		/* $PWD         */
 | 
						|
     *readnullcmd,	/* $READNULLCMD */
 | 
						|
     *rprompt,		/* $RPROMPT     */
 | 
						|
     *sprompt,		/* $SPROMPT     */
 | 
						|
     *term,		/* $TERM        */
 | 
						|
     *ttystrname,	/* $TTY         */
 | 
						|
     *wordchars,	/* $WORDCHARS   */
 | 
						|
     *zsh_name;		/* $ZSH_NAME    */
 | 
						|
 | 
						|
/**/
 | 
						|
long lastval,		/* $?           */
 | 
						|
     mypid,		/* $$           */
 | 
						|
     lastpid,		/* $!           */
 | 
						|
     columns,		/* $COLUMNS     */
 | 
						|
     lineno,		/* $LINENO      */
 | 
						|
     lines,		/* $LINES       */
 | 
						|
     zoptind,		/* $OPTIND      */
 | 
						|
     ppid,		/* $PPID        */
 | 
						|
     shlvl;		/* $SHLVL       */
 | 
						|
 | 
						|
/* $histchars */
 | 
						|
 
 | 
						|
/**/
 | 
						|
unsigned char bangchar, hatchar, hashchar;
 | 
						|
 
 | 
						|
/* $SECONDS = time(NULL) - shtimer.tv_sec */
 | 
						|
 
 | 
						|
/**/
 | 
						|
struct timeval shtimer;
 | 
						|
 
 | 
						|
/* 0 if this $TERM setup is usable, otherwise it contains TERM_* flags */
 | 
						|
 | 
						|
/**/
 | 
						|
int termflags;
 | 
						|
 
 | 
						|
/* Nodes for special parameters for parameter hash table */
 | 
						|
 | 
						|
static
 | 
						|
#ifdef HAVE_UNION_INIT
 | 
						|
# define BR(X) {X}
 | 
						|
struct param
 | 
						|
#else
 | 
						|
# define BR(X) X
 | 
						|
struct iparam {
 | 
						|
    struct hashnode *next;
 | 
						|
    char *nam;			/* hash data                             */
 | 
						|
    int flags;			/* PM_* flags (defined in zsh.h)         */
 | 
						|
    void *value;
 | 
						|
    void (*func1) _((void));	/* set func                              */
 | 
						|
    char *(*func2) _((void));	/* get func                              */
 | 
						|
    void (*unsetfn) _((Param, int));	/* unset func                    */
 | 
						|
    int ct;			/* output base or field width            */
 | 
						|
    char *env;			/* location in environment, if exported  */
 | 
						|
    char *ename;		/* name of corresponding environment var */
 | 
						|
    Param old;			/* old struct for use with local         */
 | 
						|
    int level;			/* if (old != NULL), level of localness  */
 | 
						|
}
 | 
						|
#endif
 | 
						|
special_params[] ={
 | 
						|
#define SFN(X) BR(((void (*)_((Param, char *)))(X)))
 | 
						|
#define GFN(X) BR(((char *(*)_((Param)))(X)))
 | 
						|
#define IPDEF1(A,B,C,D) {NULL,A,PM_INTEGER|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,10,NULL,NULL,NULL,0}
 | 
						|
IPDEF1("#", poundgetfn, nullsetfn, PM_READONLY),
 | 
						|
IPDEF1("ERRNO", errnogetfn, nullsetfn, PM_READONLY),
 | 
						|
IPDEF1("GID", gidgetfn, gidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
 | 
						|
IPDEF1("EGID", egidgetfn, egidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
 | 
						|
IPDEF1("HISTSIZE", histsizegetfn, histsizesetfn, PM_RESTRICTED),
 | 
						|
IPDEF1("RANDOM", randomgetfn, randomsetfn, 0),
 | 
						|
IPDEF1("SECONDS", secondsgetfn, secondssetfn, 0),
 | 
						|
IPDEF1("UID", uidgetfn, uidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
 | 
						|
IPDEF1("EUID", euidgetfn, euidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
 | 
						|
IPDEF1("TTYIDLE", ttyidlegetfn, nullsetfn, PM_READONLY),
 | 
						|
 | 
						|
#define IPDEF2(A,B,C,D) {NULL,A,PM_SCALAR|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,0,NULL,NULL,NULL,0}
 | 
						|
IPDEF2("USERNAME", usernamegetfn, usernamesetfn, PM_DONTIMPORT|PM_RESTRICTED),
 | 
						|
IPDEF2("-", dashgetfn, nullsetfn, PM_READONLY),
 | 
						|
IPDEF2("histchars", histcharsgetfn, histcharssetfn, PM_DONTIMPORT),
 | 
						|
IPDEF2("HOME", homegetfn, homesetfn, 0),
 | 
						|
IPDEF2("TERM", termgetfn, termsetfn, 0),
 | 
						|
IPDEF2("WORDCHARS", wordcharsgetfn, wordcharssetfn, 0),
 | 
						|
IPDEF2("IFS", ifsgetfn, ifssetfn, PM_DONTIMPORT),
 | 
						|
IPDEF2("_", underscoregetfn, nullsetfn, PM_READONLY),
 | 
						|
 | 
						|
#ifdef LC_ALL
 | 
						|
# define LCIPDEF(name) IPDEF2(name, strgetfn, lcsetfn, PM_UNSET)
 | 
						|
IPDEF2("LANG", strgetfn, langsetfn, PM_UNSET),
 | 
						|
IPDEF2("LC_ALL", strgetfn, lc_allsetfn, PM_UNSET),
 | 
						|
# ifdef LC_COLLATE
 | 
						|
LCIPDEF("LC_COLLATE"),
 | 
						|
# endif
 | 
						|
# ifdef LC_CTYPE
 | 
						|
LCIPDEF("LC_CTYPE"),
 | 
						|
# endif
 | 
						|
# ifdef LC_MESSAGES
 | 
						|
LCIPDEF("LC_MESSAGES"),
 | 
						|
# endif
 | 
						|
# ifdef LC_TIME
 | 
						|
LCIPDEF("LC_TIME"),
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
 | 
						|
#define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,BR((void *)B),SFN(nullsetfn),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0}
 | 
						|
IPDEF4("!", &lastpid),
 | 
						|
IPDEF4("$", &mypid),
 | 
						|
IPDEF4("?", &lastval),
 | 
						|
IPDEF4("LINENO", &lineno),
 | 
						|
IPDEF4("PPID", &ppid),
 | 
						|
 | 
						|
#define IPDEF5(A,B,F) {NULL,A,PM_INTEGER|PM_SPECIAL,BR((void *)B),SFN(F),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0}
 | 
						|
IPDEF5("COLUMNS", &columns, zlevarsetfn),
 | 
						|
IPDEF5("LINES", &lines, zlevarsetfn),
 | 
						|
IPDEF5("OPTIND", &zoptind, intvarsetfn),
 | 
						|
IPDEF5("SHLVL", &shlvl, intvarsetfn),
 | 
						|
 | 
						|
#define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(strvarsetfn),GFN(strvargetfn),stdunsetfn,0,NULL,NULL,NULL,0}
 | 
						|
IPDEF7("OPTARG", &zoptarg),
 | 
						|
IPDEF7("NULLCMD", &nullcmd),
 | 
						|
IPDEF7("POSTEDIT", &postedit),
 | 
						|
IPDEF7("READNULLCMD", &readnullcmd),
 | 
						|
IPDEF7("RPROMPT", &rprompt),
 | 
						|
IPDEF7("PS1", &prompt),
 | 
						|
IPDEF7("PS2", &prompt2),
 | 
						|
IPDEF7("PS3", &prompt3),
 | 
						|
IPDEF7("PS4", &prompt4),
 | 
						|
IPDEF7("RPS1", &rprompt),
 | 
						|
IPDEF7("SPROMPT", &sprompt),
 | 
						|
IPDEF7("0", &argzero),
 | 
						|
 | 
						|
#define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(colonarrsetfn),GFN(colonarrgetfn),stdunsetfn,0,NULL,C,NULL,0}
 | 
						|
IPDEF8("CDPATH", &cdpath, "cdpath", 0),
 | 
						|
IPDEF8("FIGNORE", &fignore, "fignore", 0),
 | 
						|
IPDEF8("FPATH", &fpath, "fpath", 0),
 | 
						|
IPDEF8("MAILPATH", &mailpath, "mailpath", 0),
 | 
						|
IPDEF8("WATCH", &watch, "watch", 0),
 | 
						|
IPDEF8("PATH", &path, "path", PM_RESTRICTED),
 | 
						|
IPDEF8("PSVAR", &psvar, "psvar", 0),
 | 
						|
 | 
						|
#ifdef DYNAMIC
 | 
						|
/* MODULE_PATH is not imported for security reasons */
 | 
						|
IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
 | 
						|
#endif
 | 
						|
 | 
						|
#define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,BR((void *)B),SFN(arrvarsetfn),GFN(arrvargetfn),stdunsetfn,0,NULL,C,NULL,0}
 | 
						|
#define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
 | 
						|
IPDEF9("*", &pparams, NULL),
 | 
						|
IPDEF9("@", &pparams, NULL),
 | 
						|
{NULL, NULL},
 | 
						|
 | 
						|
/* The following parameters are not avaible in sh/ksh compatibility *
 | 
						|
 * mode. All of these has sh compatible equivalents.                */
 | 
						|
IPDEF1("ARGC", poundgetfn, nullsetfn, PM_READONLY),
 | 
						|
IPDEF2("HISTCHARS", histcharsgetfn, histcharssetfn, PM_DONTIMPORT),
 | 
						|
IPDEF4("status", &lastval),
 | 
						|
IPDEF7("prompt", &prompt),
 | 
						|
IPDEF7("PROMPT", &prompt),
 | 
						|
IPDEF7("PROMPT2", &prompt2),
 | 
						|
IPDEF7("PROMPT3", &prompt3),
 | 
						|
IPDEF7("PROMPT4", &prompt4),
 | 
						|
IPDEF8("MANPATH", &manpath, "manpath", 0),
 | 
						|
IPDEF9("argv", &pparams, NULL),
 | 
						|
IPDEF9("fignore", &fignore, "FIGNORE"),
 | 
						|
IPDEF9("cdpath", &cdpath, "CDPATH"),
 | 
						|
IPDEF9("fpath", &fpath, "FPATH"),
 | 
						|
IPDEF9("mailpath", &mailpath, "MAILPATH"),
 | 
						|
IPDEF9("manpath", &manpath, "MANPATH"),
 | 
						|
IPDEF9("psvar", &psvar, "PSVAR"),
 | 
						|
IPDEF9("watch", &watch, "WATCH"),
 | 
						|
 | 
						|
#ifdef DYNAMIC
 | 
						|
IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
 | 
						|
#endif
 | 
						|
IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
 | 
						|
 | 
						|
{NULL, NULL}
 | 
						|
};
 | 
						|
#undef BR
 | 
						|
 | 
						|
static Param argvparam;
 | 
						|
 | 
						|
/* hash table containing the parameters */
 | 
						|
 
 | 
						|
/**/
 | 
						|
HashTable paramtab;
 | 
						|
 
 | 
						|
/* Set up parameter hash table.  This will add predefined  *
 | 
						|
 * parameter entries as well as setting up parameter table *
 | 
						|
 * entries for environment variables we inherit.           */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
createparamtable(void)
 | 
						|
{
 | 
						|
    Param ip, pm;
 | 
						|
    char **new_environ, **envp, **envp2, **sigptr, **t;
 | 
						|
    char buf[50], *str, *iname;
 | 
						|
    int num_env;
 | 
						|
 | 
						|
    paramtab = newhashtable(151, "paramtab", NULL);
 | 
						|
 | 
						|
    paramtab->hash        = hasher;
 | 
						|
    paramtab->emptytable  = NULL;
 | 
						|
    paramtab->filltable   = NULL;
 | 
						|
    paramtab->addnode     = addhashnode;
 | 
						|
    paramtab->getnode     = gethashnode2;
 | 
						|
    paramtab->getnode2    = gethashnode2;
 | 
						|
    paramtab->removenode  = removehashnode;
 | 
						|
    paramtab->disablenode = NULL;
 | 
						|
    paramtab->enablenode  = NULL;
 | 
						|
    paramtab->freenode    = freeparamnode;
 | 
						|
    paramtab->printnode   = printparamnode;
 | 
						|
 | 
						|
    /* Add the special parameters to the hash table */
 | 
						|
    for (ip = special_params; ip->nam; ip++)
 | 
						|
	paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
 | 
						|
    if (emulation != EMULATE_SH && emulation != EMULATE_KSH)
 | 
						|
	while ((++ip)->nam)
 | 
						|
	    paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
 | 
						|
 | 
						|
    argvparam = (Param) paramtab->getnode(paramtab, "*");
 | 
						|
 | 
						|
    noerrs = 1;
 | 
						|
 | 
						|
    HEAPALLOC {
 | 
						|
	/* Add the standard non-special parameters which have to    *
 | 
						|
	 * be initialized before we copy the environment variables. *
 | 
						|
	 * We don't want to override whatever values the users has  *
 | 
						|
	 * given them in the environment.                           */
 | 
						|
	setiparam("MAILCHECK", 60);
 | 
						|
	setiparam("LOGCHECK", 60);
 | 
						|
	setiparam("KEYTIMEOUT", 40);
 | 
						|
	setiparam("LISTMAX", 100);
 | 
						|
#ifdef HAVE_SELECT
 | 
						|
	setiparam("BAUD", getbaudrate(&shttyinfo));  /* get the output baudrate */
 | 
						|
#endif
 | 
						|
	setsparam("FCEDIT", ztrdup(DEFAULT_FCEDIT));
 | 
						|
	setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX));
 | 
						|
	setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT));
 | 
						|
	setsparam("WATCHFMT", ztrdup(default_watchfmt));
 | 
						|
	setsparam("HOST", ztrdup(hostnam));
 | 
						|
	setsparam("LOGNAME", ztrdup((str = getlogin()) && *str ? str : cached_username));
 | 
						|
 | 
						|
	/* Copy the environment variables we are inheriting to dynamic *
 | 
						|
	 * memory, so we can do mallocs and frees on it.               */
 | 
						|
	num_env = arrlen(environ);
 | 
						|
	new_environ = (char **) zalloc(sizeof(char *) * (num_env + 1));
 | 
						|
	*new_environ = NULL;
 | 
						|
 | 
						|
	/* Now incorporate environment variables we are inheriting *
 | 
						|
	 * into the parameter hash table.                          */
 | 
						|
	for (envp = new_environ, envp2 = environ; *envp2; envp2++) {
 | 
						|
	    for (str = *envp2; *str && *str != '='; str++);
 | 
						|
	    if (*str == '=') {
 | 
						|
		iname = NULL;
 | 
						|
		*str = '\0';
 | 
						|
		if (!idigit(**envp2) && isident(*envp2) && !strchr(*envp2, '[')) {
 | 
						|
		    iname = *envp2;
 | 
						|
		    if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
 | 
						|
			 !(pm->flags & PM_DONTIMPORT)) &&
 | 
						|
			(pm = setsparam(iname, metafy(str + 1, -1, META_DUP))) &&
 | 
						|
			!(pm->flags & PM_EXPORTED)) {
 | 
						|
			*str = '=';
 | 
						|
			pm->flags |= PM_EXPORTED;
 | 
						|
			pm->env = *envp++ = ztrdup(*envp2);
 | 
						|
			*envp = NULL;
 | 
						|
			if (pm->flags & PM_SPECIAL)
 | 
						|
			    pm->env = replenv(pm->env, getsparam(pm->nam));
 | 
						|
		    }
 | 
						|
		}
 | 
						|
		*str = '=';
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	environ = new_environ;
 | 
						|
 | 
						|
	pm = (Param) paramtab->getnode(paramtab, "HOME");
 | 
						|
	if (!(pm->flags & PM_EXPORTED)) {
 | 
						|
	    pm->flags |= PM_EXPORTED;
 | 
						|
	    pm->env = addenv("HOME", home);
 | 
						|
	}
 | 
						|
	pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
 | 
						|
	if (!(pm->flags & PM_EXPORTED)) {
 | 
						|
	    pm->flags |= PM_EXPORTED;
 | 
						|
	    pm->env = addenv("LOGNAME", pm->u.str);
 | 
						|
	}
 | 
						|
	pm = (Param) paramtab->getnode(paramtab, "SHLVL");
 | 
						|
	if (!(pm->flags & PM_EXPORTED))
 | 
						|
	    pm->flags |= PM_EXPORTED;
 | 
						|
	sprintf(buf, "%d", (int)++shlvl);
 | 
						|
	pm->env = addenv("SHLVL", buf);
 | 
						|
 | 
						|
	/* Add the standard non-special parameters */
 | 
						|
	set_pwd_env();
 | 
						|
	setsparam("MACHTYPE", ztrdup(MACHTYPE));
 | 
						|
	setsparam("OSTYPE", ztrdup(OSTYPE));
 | 
						|
	setsparam("TTY", ztrdup(ttystrname));
 | 
						|
	setsparam("VENDOR", ztrdup(VENDOR));
 | 
						|
	setsparam("ZSH_NAME", ztrdup(zsh_name));
 | 
						|
	setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION));
 | 
						|
	setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));
 | 
						|
	for (t = sigs; (*sigptr++ = ztrdup(*t++)); );
 | 
						|
    } LASTALLOC;
 | 
						|
 | 
						|
    noerrs = 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Create a parameter, so that it can be assigned to.  Returns NULL if the *
 | 
						|
 * parameter already exists or can't be created, otherwise returns the     *
 | 
						|
 * parameter node.  If a parameter of the same name exists in an outer     *
 | 
						|
 * scope, it is hidden by a newly created parameter.  An already existing  *
 | 
						|
 * parameter node at the current level may be `created' and returned       *
 | 
						|
 * provided it is unset and not special.  If the parameter can't be        *
 | 
						|
 * created because it already exists, the PM_UNSET flag is cleared.        */
 | 
						|
 | 
						|
/**/
 | 
						|
Param
 | 
						|
createparam(char *name, int flags)
 | 
						|
{
 | 
						|
    Param pm, oldpm;
 | 
						|
 | 
						|
    if (name != nulstring) {
 | 
						|
	oldpm = (Param) paramtab->getnode(paramtab, name);
 | 
						|
 | 
						|
	if (oldpm && oldpm->level == locallevel) {
 | 
						|
	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
 | 
						|
		oldpm->flags &= ~PM_UNSET;
 | 
						|
		return NULL;
 | 
						|
	    }
 | 
						|
	    if ((oldpm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 | 
						|
		zerr("%s: restricted", name, 0);
 | 
						|
		return NULL;
 | 
						|
	    }
 | 
						|
 | 
						|
	    pm = oldpm;
 | 
						|
	    pm->ct = 0;
 | 
						|
	    oldpm = pm->old;
 | 
						|
	} else {
 | 
						|
	    pm = (Param) zcalloc(sizeof *pm);
 | 
						|
	    if ((pm->old = oldpm)) {
 | 
						|
		/* needed to avoid freeing oldpm */
 | 
						|
		paramtab->removenode(paramtab, name);
 | 
						|
	    }
 | 
						|
	    paramtab->addnode(paramtab, ztrdup(name), pm);
 | 
						|
	}
 | 
						|
 | 
						|
	if (isset(ALLEXPORT) && !oldpm)
 | 
						|
	    flags |= PM_EXPORTED;
 | 
						|
    } else
 | 
						|
	pm = (Param) alloc(sizeof *pm);
 | 
						|
    pm->flags = flags;
 | 
						|
 | 
						|
    if(!(pm->flags & PM_SPECIAL)) {
 | 
						|
	switch (PM_TYPE(flags)) {
 | 
						|
	case PM_SCALAR:
 | 
						|
	    pm->sets.cfn = strsetfn;
 | 
						|
	    pm->gets.cfn = strgetfn;
 | 
						|
	    break;
 | 
						|
	case PM_INTEGER:
 | 
						|
	    pm->sets.ifn = intsetfn;
 | 
						|
	    pm->gets.ifn = intgetfn;
 | 
						|
	    break;
 | 
						|
	case PM_ARRAY:
 | 
						|
	    pm->sets.afn = arrsetfn;
 | 
						|
	    pm->gets.afn = arrgetfn;
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    DPUTS(1, "BUG: tried to create param node without valid flag");
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	pm->unsetfn = stdunsetfn;
 | 
						|
    }
 | 
						|
    return pm;
 | 
						|
}
 | 
						|
 | 
						|
/* Return 1 if the string s is a valid identifier, else return 0. */
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
isident(char *s)
 | 
						|
{
 | 
						|
    char *ss;
 | 
						|
    int ne;
 | 
						|
 | 
						|
    ne = noeval;		/* save the current value of noeval     */
 | 
						|
    if (!*s)			/* empty string is definitely not valid */
 | 
						|
	return 0;
 | 
						|
 | 
						|
    /* find the first character in `s' not in the iident type table */
 | 
						|
    for (ss = s; *ss; ss++)
 | 
						|
	if (!iident(*ss))
 | 
						|
	    break;
 | 
						|
 | 
						|
    /* If this exhaust `s' or the next two characters *
 | 
						|
     * are [(, then it is a valid identifier.         */
 | 
						|
    if (!*ss || (*ss == '[' && ss[1] == '('))
 | 
						|
	return 1;
 | 
						|
 | 
						|
    /* Else if the next character is not [, then it is *
 | 
						|
     * definitely not a valid identifier.              */
 | 
						|
    if (*ss != '[')
 | 
						|
	return 0;
 | 
						|
    noeval = 1;
 | 
						|
    (void)mathevalarg(++ss, &ss);
 | 
						|
    if (*ss == ',')
 | 
						|
	(void)mathevalarg(++ss, &ss);
 | 
						|
    noeval = ne;		/* restore the value of noeval */
 | 
						|
    if (*ss != ']' || ss[1])
 | 
						|
	return 0;
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
static char **garr;
 | 
						|
 | 
						|
/**/
 | 
						|
static long
 | 
						|
getarg(char **str, int *inv, Value v, int a2, long *w)
 | 
						|
{
 | 
						|
    int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i;
 | 
						|
    char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt;
 | 
						|
    long r = 0;
 | 
						|
    Comp c;
 | 
						|
 | 
						|
    /* first parse any subscription flags */
 | 
						|
    if (*s == '(' || *s == Inpar) {
 | 
						|
	int escapes = 0;
 | 
						|
	int waste;
 | 
						|
	for (s++; *s != ')' && *s != Outpar && s != *str; s++) {
 | 
						|
	    switch (*s) {
 | 
						|
	    case 'r':
 | 
						|
		rev = 1;
 | 
						|
		down = ind = 0;
 | 
						|
		break;
 | 
						|
	    case 'R':
 | 
						|
		rev = down = 1;
 | 
						|
		ind = 0;
 | 
						|
		break;
 | 
						|
	    case 'i':
 | 
						|
		rev = ind = 1;
 | 
						|
		down = 0;
 | 
						|
		break;
 | 
						|
	    case 'I':
 | 
						|
		rev = ind = down = 1;
 | 
						|
		break;
 | 
						|
	    case 'w':
 | 
						|
		/* If the parameter is a scalar, then make subscription *
 | 
						|
		 * work on a per-word basis instead of characters.      */
 | 
						|
		word = 1;
 | 
						|
		break;
 | 
						|
	    case 'f':
 | 
						|
		word = 1;
 | 
						|
		sep = "\n";
 | 
						|
		break;
 | 
						|
	    case 'e':
 | 
						|
		/* obsolate compatibility flag without any real effect */
 | 
						|
		break;
 | 
						|
	    case 'n':
 | 
						|
		t = get_strarg(++s);
 | 
						|
		if (!*t)
 | 
						|
		    goto flagerr;
 | 
						|
		sav = *t;
 | 
						|
		*t = '\0';
 | 
						|
		num = mathevalarg(s + 1, &d);
 | 
						|
		if (!num)
 | 
						|
		    num = 1;
 | 
						|
		*t = sav;
 | 
						|
		s = t;
 | 
						|
		break;
 | 
						|
	    case 'p':
 | 
						|
		escapes = 1;
 | 
						|
		break;
 | 
						|
	    case 's':
 | 
						|
		/* This gives the string that separates words *
 | 
						|
		 * (for use with the `w' flag.                */
 | 
						|
		t = get_strarg(++s);
 | 
						|
		if (!*t)
 | 
						|
		    goto flagerr;
 | 
						|
		sav = *t;
 | 
						|
		*t = '\0';
 | 
						|
		sep = escapes ? getkeystring(s + 1, &waste, 1, &waste) :
 | 
						|
				dupstring(s + 1);
 | 
						|
		*t = sav;
 | 
						|
		s = t;
 | 
						|
		break;
 | 
						|
	    default:
 | 
						|
	      flagerr:
 | 
						|
		num = 1;
 | 
						|
		word = rev = ind = down = 0;
 | 
						|
		sep = NULL;
 | 
						|
		s = *str - 1;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if (s != *str)
 | 
						|
	    s++;
 | 
						|
    }
 | 
						|
    if (num < 0) {
 | 
						|
	down = !down;
 | 
						|
	num = -num;
 | 
						|
    }
 | 
						|
    *inv = ind;
 | 
						|
 | 
						|
    for (t=s, i=0; *t && ((*t != ']' && *t != Outbrack && *t != ',') || i); t++)
 | 
						|
	if (*t == '[' || *t == Inbrack)
 | 
						|
	    i++;
 | 
						|
	else if (*t == ']' || *t == Outbrack)
 | 
						|
	    i--;
 | 
						|
 | 
						|
    if (!*t)
 | 
						|
	return 0;
 | 
						|
    s = dupstrpfx(s, t - s);
 | 
						|
    *str = tt = t;
 | 
						|
    if (parsestr(s))
 | 
						|
	return 0;
 | 
						|
    singsub(&s);
 | 
						|
 | 
						|
    if (!rev) {
 | 
						|
	if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0))
 | 
						|
	    r++;
 | 
						|
	if (word && !v->isarr) {
 | 
						|
	    s = t = getstrvalue(v);
 | 
						|
	    i = wordcount(s, sep, 0);
 | 
						|
	    if (r < 0)
 | 
						|
		r += i + 1;
 | 
						|
	    if (r < 1)
 | 
						|
		r = 1;
 | 
						|
	    if (r > i)
 | 
						|
		r = i;
 | 
						|
	    if (!s || !*s)
 | 
						|
		return 0;
 | 
						|
	    while ((d = findword(&s, sep)) && --r);
 | 
						|
	    if (!d)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	    if (!a2 && *tt != ',')
 | 
						|
		*w = (long)(s - t) - 1;
 | 
						|
 | 
						|
	    return (a2 ? s : d + 1) - t;
 | 
						|
	} else if (!v->isarr && !word) {
 | 
						|
	    s = getstrvalue(v);
 | 
						|
	    if (r > 0) {
 | 
						|
		for (t = s + r - 1; *s && s < t;)
 | 
						|
		    if (*s++ == Meta)
 | 
						|
			s++, t++, r++;
 | 
						|
	    } else {
 | 
						|
		r += ztrlen(s);
 | 
						|
		for (t = s + r; *s && s < t; r--)
 | 
						|
		    if (*s++ == Meta)
 | 
						|
			t++, r++;
 | 
						|
		r -= strlen(s);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    } else {
 | 
						|
	if (!v->isarr && !word) {
 | 
						|
	    l = strlen(s);
 | 
						|
	    if (a2) {
 | 
						|
		if (!l || *s != '*') {
 | 
						|
		    d = (char *) ncalloc(l + 2);
 | 
						|
		    *d = '*';
 | 
						|
		    strcpy(d + 1, s);
 | 
						|
		    s = d;
 | 
						|
		}
 | 
						|
	    } else {
 | 
						|
		if (!l || s[l - 1] != '*') {
 | 
						|
		    d = (char *) ncalloc(l + 2);
 | 
						|
		    strcpy(d, s);
 | 
						|
		    strcat(d, "*");
 | 
						|
		    s = d;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	tokenize(s);
 | 
						|
 | 
						|
	if ((c = parsereg(s))) {
 | 
						|
	    if (v->isarr) {
 | 
						|
		ta = getarrvalue(v);
 | 
						|
		if (!ta || !*ta)
 | 
						|
		    return 0;
 | 
						|
		if (down)
 | 
						|
		    for (r = -1, p = ta + arrlen(ta) - 1; p >= ta; r--, p--) {
 | 
						|
			if (domatch(*p, c, 0) && !--num)
 | 
						|
			    return r;
 | 
						|
		} else
 | 
						|
		    for (r = 1, p = ta; *p; r++, p++)
 | 
						|
			if (domatch(*p, c, 0) && !--num)
 | 
						|
			    return r;
 | 
						|
	    } else if (word) {
 | 
						|
		ta = sepsplit(d = s = getstrvalue(v), sep, 1);
 | 
						|
		if (down) {
 | 
						|
		    for (p = ta + (r = arrlen(ta)) - 1; p >= ta; p--, r--)
 | 
						|
			if (domatch(*p, c, 0) && !--num)
 | 
						|
			    break;
 | 
						|
		    if (p < ta)
 | 
						|
			return 0;
 | 
						|
		} else {
 | 
						|
		    for (r = 1, p = ta; *p; r++, p++)
 | 
						|
			if (domatch(*p, c, 0) && !--num)
 | 
						|
			    break;
 | 
						|
		    if (!*p)
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		if (a2)
 | 
						|
		    r++;
 | 
						|
		for (i = 0; (t = findword(&d, sep)) && *t; i++)
 | 
						|
		    if (!--r) {
 | 
						|
			r = (long)(t - s + (a2 ? -1 : 1));
 | 
						|
			if (!a2 && *tt != ',')
 | 
						|
			    *w = r + strlen(ta[i]) - 2;
 | 
						|
			return r;
 | 
						|
		    }
 | 
						|
		return a2 ? -1 : 0;
 | 
						|
	    } else {
 | 
						|
		d = getstrvalue(v);
 | 
						|
		if (!d || !*d)
 | 
						|
		    return 0;
 | 
						|
		if (a2) {
 | 
						|
		    if (down)
 | 
						|
			for (r = -2, t = d + strlen(d) - 1; t >= d; r--, t--) {
 | 
						|
			    sav = *t;
 | 
						|
			    *t = '\0';
 | 
						|
			    if (domatch(d, c, 0) && !--num) {
 | 
						|
				*t = sav;
 | 
						|
				return r;
 | 
						|
			    }
 | 
						|
			    *t = sav;
 | 
						|
		    } else
 | 
						|
			for (r = 0, t = d; *t; r++, t++) {
 | 
						|
			    sav = *t;
 | 
						|
			    *t = '\0';
 | 
						|
			    if (domatch(d, c, 0) && !--num) {
 | 
						|
				*t = sav;
 | 
						|
				return r;
 | 
						|
			    }
 | 
						|
			    *t = sav;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
		    if (down)
 | 
						|
			for (r = -1, t = d + strlen(d) - 1; t >= d; r--, t--) {
 | 
						|
			    if (domatch(t, c, 0) && !--num)
 | 
						|
				return r;
 | 
						|
		    } else
 | 
						|
			for (r = 1, t = d; *t; r++, t++)
 | 
						|
			    if (domatch(t, c, 0) && !--num)
 | 
						|
				return r;
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
getindex(char **pptr, Value v)
 | 
						|
{
 | 
						|
    int a, b, inv = 0;
 | 
						|
    char *s = *pptr, *tbrack;
 | 
						|
 | 
						|
    *s++ = '[';
 | 
						|
    for (tbrack = s; *tbrack && *tbrack != ']' && *tbrack != Outbrack; tbrack++)
 | 
						|
	if (itok(*tbrack))
 | 
						|
	    *tbrack = ztokens[*tbrack - Pound];
 | 
						|
    if (*tbrack == Outbrack)
 | 
						|
	*tbrack = ']';
 | 
						|
    if ((s[0] == '*' || s[0] == '@') && s[1] == ']') {
 | 
						|
	if (v->isarr)
 | 
						|
	    v->isarr = (s[0] == '*') ? 1 : -1;
 | 
						|
	v->a = 0;
 | 
						|
	v->b = -1;
 | 
						|
	s += 2;
 | 
						|
    } else {
 | 
						|
	long we = 0, dummy;
 | 
						|
 | 
						|
	a = getarg(&s, &inv, v, 0, &we);
 | 
						|
 | 
						|
	if (inv) {
 | 
						|
	    if (!v->isarr && a != 0) {
 | 
						|
		char *t, *p;
 | 
						|
		t = getstrvalue(v);
 | 
						|
		if (a > 0) {
 | 
						|
		    for (p = t + a - 1; p-- > t; )
 | 
						|
			if (*p == Meta)
 | 
						|
			    a--;
 | 
						|
		} else
 | 
						|
		    a = -ztrlen(t + a + strlen(t));
 | 
						|
	    }
 | 
						|
	    if (a > 0 && isset(KSHARRAYS))
 | 
						|
		a--;
 | 
						|
	    v->inv = 1;
 | 
						|
	    v->isarr = 0;
 | 
						|
	    v->a = v->b = a;
 | 
						|
	    if (*s == ',') {
 | 
						|
		zerr("invalid subscript", NULL, 0);
 | 
						|
		while (*s != ']' && *s != Outbrack)
 | 
						|
		    s++;
 | 
						|
		*pptr = s;
 | 
						|
		return 1;
 | 
						|
	    }
 | 
						|
	    if (*s == ']' || *s == Outbrack)
 | 
						|
		s++;
 | 
						|
	} else {
 | 
						|
	    if (a > 0)
 | 
						|
		a--;
 | 
						|
	    if (*s == ',') {
 | 
						|
		s++;
 | 
						|
		b = getarg(&s, &inv, v, 1, &dummy);
 | 
						|
		if (b > 0)
 | 
						|
		    b--;
 | 
						|
	    } else {
 | 
						|
		b = we ? we : a;
 | 
						|
	    }
 | 
						|
	    if (*s == ']' || *s == Outbrack) {
 | 
						|
		s++;
 | 
						|
		if (v->isarr && a == b)
 | 
						|
		    v->isarr = 0;
 | 
						|
		v->a = a;
 | 
						|
		v->b = b;
 | 
						|
	    } else
 | 
						|
		s = *pptr;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    *pptr = s;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**/
 | 
						|
Value
 | 
						|
getvalue(char **pptr, int bracks)
 | 
						|
{
 | 
						|
    char *s, *t;
 | 
						|
    char sav;
 | 
						|
    Value v;
 | 
						|
    int ppar = 0;
 | 
						|
 | 
						|
    s = t = *pptr;
 | 
						|
    garr = NULL;
 | 
						|
 | 
						|
    if (idigit(*s))
 | 
						|
	if (bracks >= 0)
 | 
						|
	    ppar = zstrtol(s, &s, 10);
 | 
						|
	else
 | 
						|
	    ppar = *s++ - '0';
 | 
						|
    else if (iident(*s))
 | 
						|
	while (iident(*s))
 | 
						|
	    s++;
 | 
						|
    else if (*s == Quest)
 | 
						|
	*s++ = '?';
 | 
						|
    else if (*s == Pound)
 | 
						|
	*s++ = '#';
 | 
						|
    else if (*s == String)
 | 
						|
	*s++ = '$';
 | 
						|
    else if (*s == Qstring)
 | 
						|
	*s++ = '$';
 | 
						|
    else if (*s == Star)
 | 
						|
	*s++ = '*';
 | 
						|
    else if (*s == '#' || *s == '-' || *s == '?' || *s == '$' ||
 | 
						|
	     *s == '_' || *s == '!' || *s == '@' || *s == '*')
 | 
						|
	s++;
 | 
						|
    else
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    if ((sav = *s))
 | 
						|
	*s = '\0';
 | 
						|
    if (ppar) {
 | 
						|
	v = (Value) hcalloc(sizeof *v);
 | 
						|
	v->pm = argvparam;
 | 
						|
	v->inv = 0;
 | 
						|
	v->a = v->b = ppar - 1;
 | 
						|
	if (sav)
 | 
						|
	    *s = sav;
 | 
						|
    } else {
 | 
						|
	Param pm;
 | 
						|
	int isvarat;
 | 
						|
 | 
						|
        isvarat = !strcmp(t, "@");
 | 
						|
	pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
 | 
						|
	if (sav)
 | 
						|
	    *s = sav;
 | 
						|
	*pptr = s;
 | 
						|
	if (!pm || (pm->flags & PM_UNSET))
 | 
						|
	    return NULL;
 | 
						|
	v = (Value) hcalloc(sizeof *v);
 | 
						|
	if (PM_TYPE(pm->flags) == PM_ARRAY)
 | 
						|
	    v->isarr = isvarat ? -1 : 1;
 | 
						|
	v->pm = pm;
 | 
						|
	v->inv = 0;
 | 
						|
	v->a = 0;
 | 
						|
	v->b = -1;
 | 
						|
	if (bracks > 0 && (*s == '[' || *s == Inbrack)) {
 | 
						|
	    if (getindex(&s, v)) {
 | 
						|
		*pptr = s;
 | 
						|
		return v;
 | 
						|
	    }
 | 
						|
	} else if (v->isarr && iident(*t) && isset(KSHARRAYS))
 | 
						|
	    v->b = 0, v->isarr = 0;
 | 
						|
    }
 | 
						|
    if (!bracks && *s)
 | 
						|
	return NULL;
 | 
						|
    *pptr = s;
 | 
						|
    if (v->a > MAX_ARRLEN ||
 | 
						|
	v->a < -MAX_ARRLEN) {
 | 
						|
	zerr("subscript to %s: %d", (v->a < 0) ? "small" : "big", v->a);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    if (v->b > MAX_ARRLEN ||
 | 
						|
	v->b < -MAX_ARRLEN) {
 | 
						|
	zerr("subscript to %s: %d", (v->b < 0) ? "small" : "big", v->b);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    return v;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
getstrvalue(Value v)
 | 
						|
{
 | 
						|
    char *s, **ss;
 | 
						|
    static char buf[(sizeof(long) * 8) + 4];
 | 
						|
 | 
						|
    if (!v)
 | 
						|
	return hcalloc(1);
 | 
						|
    HEAPALLOC {
 | 
						|
	if (v->inv) {
 | 
						|
	    sprintf(buf, "%d", v->a);
 | 
						|
	    s = dupstring(buf);
 | 
						|
	    LASTALLOC_RETURN s;
 | 
						|
	}
 | 
						|
 | 
						|
	switch(PM_TYPE(v->pm->flags)) {
 | 
						|
	case PM_ARRAY:
 | 
						|
	    if (v->isarr)
 | 
						|
		s = sepjoin(v->pm->gets.afn(v->pm), NULL);
 | 
						|
	    else {
 | 
						|
		ss = v->pm->gets.afn(v->pm);
 | 
						|
		if (v->a < 0)
 | 
						|
		    v->a += arrlen(ss);
 | 
						|
		s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a];
 | 
						|
	    }
 | 
						|
	    LASTALLOC_RETURN s;
 | 
						|
	case PM_INTEGER:
 | 
						|
	    convbase(s = buf, v->pm->gets.ifn(v->pm), v->pm->ct);
 | 
						|
	    break;
 | 
						|
	case PM_SCALAR:
 | 
						|
	    s = v->pm->gets.cfn(v->pm);
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    s = NULL;
 | 
						|
	    DPUTS(1, "BUG: param node without valid type");
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (v->a == 0 && v->b == -1)
 | 
						|
	    LASTALLOC_RETURN s;
 | 
						|
	if (v->a < 0)
 | 
						|
	    v->a += strlen(s);
 | 
						|
	if (v->b < 0)
 | 
						|
	    v->b += strlen(s);
 | 
						|
	s = (v->a > (int)strlen(s)) ? dupstring("") : dupstring(s + v->a);
 | 
						|
	if (v->b < v->a)
 | 
						|
	    s[0] = '\0';
 | 
						|
	else if (v->b - v->a < (int)strlen(s))
 | 
						|
	    s[v->b - v->a + 1 + (s[v->b - v->a] == Meta)] = '\0';
 | 
						|
    } LASTALLOC;
 | 
						|
    return s;
 | 
						|
}
 | 
						|
 | 
						|
static char *nular[] = {"", NULL};
 | 
						|
 | 
						|
/**/
 | 
						|
char **
 | 
						|
getarrvalue(Value v)
 | 
						|
{
 | 
						|
    char **s;
 | 
						|
 | 
						|
    if (!v)
 | 
						|
	return arrdup(nular);
 | 
						|
    if (v->inv) {
 | 
						|
	char buf[DIGBUFSIZE];
 | 
						|
 | 
						|
	s = arrdup(nular);
 | 
						|
	sprintf(buf, "%d", v->a);
 | 
						|
	s[0] = dupstring(buf);
 | 
						|
	return s;
 | 
						|
    }
 | 
						|
    s = v->pm->gets.afn(v->pm);
 | 
						|
    if (v->a == 0 && v->b == -1)
 | 
						|
	return s;
 | 
						|
    if (v->a < 0)
 | 
						|
	v->a += arrlen(s);
 | 
						|
    if (v->b < 0)
 | 
						|
	v->b += arrlen(s);
 | 
						|
    if (v->a > arrlen(s) || v->a < 0)
 | 
						|
	s = arrdup(nular);
 | 
						|
    else
 | 
						|
	s = arrdup(s) + v->a;
 | 
						|
    if (v->b < v->a)
 | 
						|
	s[0] = NULL;
 | 
						|
    else if (v->b - v->a < arrlen(s))
 | 
						|
	s[v->b - v->a + 1] = NULL;
 | 
						|
    return s;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
getintvalue(Value v)
 | 
						|
{
 | 
						|
    if (!v || v->isarr)
 | 
						|
	return 0;
 | 
						|
    if (v->inv)
 | 
						|
	return v->a;
 | 
						|
    if (PM_TYPE(v->pm->flags) == PM_INTEGER)
 | 
						|
	return v->pm->gets.ifn(v->pm);
 | 
						|
    return matheval(getstrvalue(v));
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
setstrvalue(Value v, char *val)
 | 
						|
{
 | 
						|
    char buf[(sizeof(long) * 8) + 4];
 | 
						|
 | 
						|
    if (v->pm->flags & PM_READONLY) {
 | 
						|
	zerr("read-only variable: %s", v->pm->nam, 0);
 | 
						|
	zsfree(val);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 | 
						|
	zerr("%s: restricted", v->pm->nam, 0);
 | 
						|
	zsfree(val);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    switch (PM_TYPE(v->pm->flags)) {
 | 
						|
    case PM_SCALAR:
 | 
						|
	MUSTUSEHEAP("setstrvalue");
 | 
						|
	if (v->a == 0 && v->b == -1) {
 | 
						|
	    (v->pm->sets.cfn) (v->pm, val);
 | 
						|
	    if (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z) && !v->pm->ct)
 | 
						|
		v->pm->ct = strlen(val);
 | 
						|
	} else {
 | 
						|
	    char *z, *x;
 | 
						|
	    int zlen;
 | 
						|
 | 
						|
	    z = dupstring((v->pm->gets.cfn) (v->pm));
 | 
						|
	    zlen = strlen(z);
 | 
						|
	    if (v->inv && unset(KSHARRAYS))
 | 
						|
		v->a--, v->b--;
 | 
						|
	    if (v->a < 0) {
 | 
						|
		v->a += zlen;
 | 
						|
		if (v->a < 0)
 | 
						|
		    v->a = 0;
 | 
						|
	    }
 | 
						|
	    if (v->a > zlen)
 | 
						|
		v->a = zlen;
 | 
						|
	    if (v->b < 0)
 | 
						|
		v->b += zlen;
 | 
						|
	    if (v->b > zlen - 1)
 | 
						|
		v->b = zlen - 1;
 | 
						|
	    x = (char *) zalloc(v->a + strlen(val) + zlen - v->b);
 | 
						|
	    strncpy(x, z, v->a);
 | 
						|
	    strcpy(x + v->a, val);
 | 
						|
	    strcat(x + v->a, z + v->b + 1);
 | 
						|
	    (v->pm->sets.cfn) (v->pm, x);
 | 
						|
	    zsfree(val);
 | 
						|
	}
 | 
						|
	break;
 | 
						|
    case PM_INTEGER:
 | 
						|
	if (val) {
 | 
						|
	    (v->pm->sets.ifn) (v->pm, matheval(val));
 | 
						|
	    zsfree(val);
 | 
						|
	}
 | 
						|
	if (!v->pm->ct && lastbase != -1)
 | 
						|
	    v->pm->ct = lastbase;
 | 
						|
	break;
 | 
						|
    case PM_ARRAY:
 | 
						|
	MUSTUSEHEAP("setstrvalue");
 | 
						|
	{
 | 
						|
	    char **ss = (char **) zalloc(2 * sizeof(char *));
 | 
						|
 | 
						|
	    ss[0] = val;
 | 
						|
	    ss[1] = NULL;
 | 
						|
	    setarrvalue(v, ss);
 | 
						|
	}
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    if ((!v->pm->env && !(v->pm->flags & PM_EXPORTED) &&
 | 
						|
	 !(isset(ALLEXPORT) && !v->pm->old)) ||
 | 
						|
	(v->pm->flags & PM_ARRAY) || v->pm->ename)
 | 
						|
	return;
 | 
						|
    if (PM_TYPE(v->pm->flags) == PM_INTEGER)
 | 
						|
	convbase(val = buf, v->pm->gets.ifn(v->pm), v->pm->ct);
 | 
						|
    else
 | 
						|
	val = v->pm->gets.cfn(v->pm);
 | 
						|
    if (v->pm->env)
 | 
						|
	v->pm->env = replenv(v->pm->env, val);
 | 
						|
    else {
 | 
						|
	v->pm->flags |= PM_EXPORTED;
 | 
						|
	v->pm->env = addenv(v->pm->nam, val);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
setintvalue(Value v, long val)
 | 
						|
{
 | 
						|
    char buf[DIGBUFSIZE];
 | 
						|
 | 
						|
    if (v->pm->flags & PM_READONLY) {
 | 
						|
	zerr("read-only variable: %s", v->pm->nam, 0);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 | 
						|
	zerr("%s: restricted", v->pm->nam, 0);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    switch (PM_TYPE(v->pm->flags)) {
 | 
						|
    case PM_SCALAR:
 | 
						|
    case PM_ARRAY:
 | 
						|
	sprintf(buf, "%ld", val);
 | 
						|
	setstrvalue(v, ztrdup(buf));
 | 
						|
	break;
 | 
						|
    case PM_INTEGER:
 | 
						|
	(v->pm->sets.ifn) (v->pm, val);
 | 
						|
	setstrvalue(v, NULL);
 | 
						|
	break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
setarrvalue(Value v, char **val)
 | 
						|
{
 | 
						|
    if (v->pm->flags & PM_READONLY) {
 | 
						|
	zerr("read-only variable: %s", v->pm->nam, 0);
 | 
						|
	freearray(val);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 | 
						|
	zerr("%s: restricted", v->pm->nam, 0);
 | 
						|
	freearray(val);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    if (PM_TYPE(v->pm->flags) != PM_ARRAY) {
 | 
						|
	freearray(val);
 | 
						|
	zerr("attempt to assign array value to non-array", NULL, 0);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    if (v->a == 0 && v->b == -1)
 | 
						|
	(v->pm->sets.afn) (v->pm, val);
 | 
						|
    else {
 | 
						|
	char **old, **new, **p, **q, **r;
 | 
						|
	int n, ll, i;
 | 
						|
 | 
						|
	if (v->inv && unset(KSHARRAYS))
 | 
						|
	    v->a--, v->b--;
 | 
						|
	q = old = v->pm->gets.afn(v->pm);
 | 
						|
	n = arrlen(old);
 | 
						|
	if (v->a < 0)
 | 
						|
	    v->a += n;
 | 
						|
	if (v->b < 0)
 | 
						|
	    v->b += n;
 | 
						|
	if (v->a < 0)
 | 
						|
	    v->a = 0;
 | 
						|
	if (v->b < 0)
 | 
						|
	    v->b = 0;
 | 
						|
 | 
						|
	ll = v->a + arrlen(val);
 | 
						|
	if (v->b < n)
 | 
						|
	    ll += n - v->b;
 | 
						|
 | 
						|
	p = new = (char **) zcalloc(sizeof(char *) * (ll + 1));
 | 
						|
 | 
						|
	for (i = 0; i < v->a; i++)
 | 
						|
	    *p++ = i < n ? ztrdup(*q++) : ztrdup("");
 | 
						|
	for (r = val; *r;)
 | 
						|
	    *p++ = ztrdup(*r++);
 | 
						|
	if (v->b + 1 < n)
 | 
						|
	    for (q = old + v->b + 1; *q;)
 | 
						|
		*p++ = ztrdup(*q++);
 | 
						|
	*p = NULL;
 | 
						|
 | 
						|
	(v->pm->sets.afn) (v->pm, new);
 | 
						|
	freearray(val);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Retrieve an integer parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
getiparam(char *s)
 | 
						|
{
 | 
						|
    Value v;
 | 
						|
 | 
						|
    if (!(v = getvalue(&s, 1)))
 | 
						|
	return 0;
 | 
						|
    return getintvalue(v);
 | 
						|
}
 | 
						|
 | 
						|
/* Retrieve a scalar (string) parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
getsparam(char *s)
 | 
						|
{
 | 
						|
    Value v;
 | 
						|
 | 
						|
    if (!(v = getvalue(&s, 0)))
 | 
						|
	return NULL;
 | 
						|
    return getstrvalue(v);
 | 
						|
}
 | 
						|
 | 
						|
/* Retrieve an array parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
char **
 | 
						|
getaparam(char *s)
 | 
						|
{
 | 
						|
    Value v;
 | 
						|
 | 
						|
    if (!idigit(*s) && (v = getvalue(&s, 0)) &&
 | 
						|
	PM_TYPE(v->pm->flags) == PM_ARRAY)
 | 
						|
	return v->pm->gets.afn(v->pm);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
Param
 | 
						|
setsparam(char *s, char *val)
 | 
						|
{
 | 
						|
    Value v;
 | 
						|
    char *t = s;
 | 
						|
    char *ss;
 | 
						|
 | 
						|
    if (!isident(s)) {
 | 
						|
	zerr("not an identifier: %s", s, 0);
 | 
						|
	zsfree(val);
 | 
						|
	errflag = 1;
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    if ((ss = strchr(s, '['))) {
 | 
						|
	*ss = '\0';
 | 
						|
	if (!(v = getvalue(&s, 1)))
 | 
						|
	    createparam(t, PM_ARRAY);
 | 
						|
	*ss = '[';
 | 
						|
	v = NULL;
 | 
						|
    } else {
 | 
						|
	if (!(v = getvalue(&s, 1)))
 | 
						|
	    createparam(t, PM_SCALAR);
 | 
						|
	else if (PM_TYPE(v->pm->flags) == PM_ARRAY &&
 | 
						|
		 !(v->pm->flags & PM_SPECIAL) && unset(KSHARRAYS)) {
 | 
						|
	    unsetparam(t);
 | 
						|
	    createparam(t, PM_SCALAR);
 | 
						|
	    v = NULL;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (!v && !(v = getvalue(&t, 1))) {
 | 
						|
	zsfree(val);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    setstrvalue(v, val);
 | 
						|
    return v->pm;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
Param
 | 
						|
setaparam(char *s, char **val)
 | 
						|
{
 | 
						|
    Value v;
 | 
						|
    char *t = s;
 | 
						|
    char *ss;
 | 
						|
 | 
						|
    if (!isident(s)) {
 | 
						|
	zerr("not an identifier: %s", s, 0);
 | 
						|
	freearray(val);
 | 
						|
	errflag = 1;
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    if ((ss = strchr(s, '['))) {
 | 
						|
	*ss = '\0';
 | 
						|
	if (!(v = getvalue(&s, 1)))
 | 
						|
	    createparam(t, PM_ARRAY);
 | 
						|
	*ss = '[';
 | 
						|
	v = NULL;
 | 
						|
    } else {
 | 
						|
	if (!(v = getvalue(&s, 1)))
 | 
						|
	    createparam(t, PM_ARRAY);
 | 
						|
	else if (PM_TYPE(v->pm->flags) != PM_ARRAY &&
 | 
						|
		 !(v->pm->flags & PM_SPECIAL)) {
 | 
						|
	    int uniq = v->pm->flags & PM_UNIQUE;
 | 
						|
	    unsetparam(t);
 | 
						|
	    createparam(t, PM_ARRAY | uniq);
 | 
						|
	    v = NULL;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (!v)
 | 
						|
	if (!(v = getvalue(&t, 1)))
 | 
						|
	    return NULL;
 | 
						|
    if (isset(KSHARRAYS) && !ss)
 | 
						|
	/* the whole array should be set instead of only the first element */
 | 
						|
	v->b = -1;
 | 
						|
    setarrvalue(v, val);
 | 
						|
    return v->pm;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
Param
 | 
						|
setiparam(char *s, long val)
 | 
						|
{
 | 
						|
    Value v;
 | 
						|
    char *t = s;
 | 
						|
    Param pm;
 | 
						|
 | 
						|
    if (!isident(s)) {
 | 
						|
	zerr("not an identifier: %s", s, 0);
 | 
						|
	errflag = 1;
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
    if (!(v = getvalue(&s, 1))) {
 | 
						|
	pm = createparam(t, PM_INTEGER);
 | 
						|
	DPUTS(!pm, "BUG: parameter not created");
 | 
						|
	pm->u.val = val;
 | 
						|
	return pm;
 | 
						|
    }
 | 
						|
    setintvalue(v, val);
 | 
						|
    return v->pm;
 | 
						|
}
 | 
						|
 | 
						|
/* Unset a parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
unsetparam(char *s)
 | 
						|
{
 | 
						|
    Param pm;
 | 
						|
 | 
						|
    if ((pm = (Param) paramtab->getnode(paramtab, s)))
 | 
						|
	unsetparam_pm(pm, 0, 1);
 | 
						|
}
 | 
						|
 | 
						|
/* Unset a parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
unsetparam_pm(Param pm, int altflag, int exp)
 | 
						|
{
 | 
						|
    Param oldpm, altpm;
 | 
						|
 | 
						|
    if ((pm->flags & PM_READONLY) && pm->level <= locallevel) {
 | 
						|
	zerr("read-only variable: %s", pm->nam, 0);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 | 
						|
	zerr("%s: restricted", pm->nam, 0);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    pm->unsetfn(pm, exp);
 | 
						|
    if ((pm->flags & PM_EXPORTED) && pm->env) {
 | 
						|
	delenv(pm->env);
 | 
						|
	zsfree(pm->env);
 | 
						|
	pm->env = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* remove it under its alternate name if necessary */
 | 
						|
    if (pm->ename && !altflag) {
 | 
						|
	altpm = (Param) paramtab->getnode(paramtab, pm->ename);
 | 
						|
	if (altpm)
 | 
						|
	    unsetparam_pm(altpm, 1, exp);
 | 
						|
    }
 | 
						|
 | 
						|
    /* If this was a local variable, we need to keep the old     *
 | 
						|
     * struct so that it is resurrected at the right level.      *
 | 
						|
     * This is partly because when an array/scalar value is set  *
 | 
						|
     * and the parameter used to be the other sort, unsetparam() *
 | 
						|
     * is called.  Beyond that, there is an ambiguity:  should   *
 | 
						|
     * foo() { local bar; unset bar; } make the global bar       *
 | 
						|
     * available or not?  The following makes the answer "no".   */
 | 
						|
    if (locallevel >= pm->level)
 | 
						|
	return;
 | 
						|
 | 
						|
    paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */
 | 
						|
 | 
						|
    if (pm->old) {
 | 
						|
	oldpm = pm->old;
 | 
						|
	paramtab->addnode(paramtab, oldpm->nam, oldpm);
 | 
						|
	if ((PM_TYPE(oldpm->flags) == PM_SCALAR) && oldpm->sets.cfn == strsetfn)
 | 
						|
	    adduserdir(oldpm->nam, oldpm->u.str, 0, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    paramtab->freenode((HashNode) pm); /* free parameter node */
 | 
						|
}
 | 
						|
 | 
						|
/* Standard function to unset a parameter.  This is mostly delegated to *
 | 
						|
 * the specific set function.                                           */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
stdunsetfn(Param pm, int exp)
 | 
						|
{
 | 
						|
    switch (PM_TYPE(pm->flags)) {
 | 
						|
	case PM_SCALAR: pm->sets.cfn(pm, NULL); break;
 | 
						|
	case PM_ARRAY:  pm->sets.afn(pm, NULL); break;
 | 
						|
    }
 | 
						|
    pm->flags |= PM_UNSET;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value of an integer parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
static long
 | 
						|
intgetfn(Param pm)
 | 
						|
{
 | 
						|
    return pm->u.val;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of an integer parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
intsetfn(Param pm, long x)
 | 
						|
{
 | 
						|
    pm->u.val = x;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value of a scalar (string) parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
strgetfn(Param pm)
 | 
						|
{
 | 
						|
    return pm->u.str ? pm->u.str : (char *) hcalloc(1);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of a scalar (string) parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
strsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    zsfree(pm->u.str);
 | 
						|
    pm->u.str = x;
 | 
						|
    adduserdir(pm->nam, x, 0, 0);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value of an array parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
static char **
 | 
						|
arrgetfn(Param pm)
 | 
						|
{
 | 
						|
    static char *nullarray = NULL;
 | 
						|
 | 
						|
    return pm->u.arr ? pm->u.arr : &nullarray;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of an array parameter */
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
arrsetfn(Param pm, char **x)
 | 
						|
{
 | 
						|
    if (pm->u.arr && pm->u.arr != x)
 | 
						|
	freearray(pm->u.arr);
 | 
						|
    if (pm->flags & PM_UNIQUE)
 | 
						|
	uniqarray(x);
 | 
						|
    pm->u.arr = x;
 | 
						|
}
 | 
						|
 | 
						|
/* This function is used as the set function for      *
 | 
						|
 * special parameters that cannot be set by the user. */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
nullsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    zsfree(x);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value of generic special integer *
 | 
						|
 * parameter.  data is pointer to global variable   *
 | 
						|
 * containing the integer value.                    */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
intvargetfn(Param pm)
 | 
						|
{
 | 
						|
    return *((long *)pm->u.data);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of generic special integer *
 | 
						|
 * parameter.  data is pointer to global variable   *
 | 
						|
 * where the value is to be stored.                 */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
intvarsetfn(Param pm, long x)
 | 
						|
{
 | 
						|
    *((long *)pm->u.data) = x;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of any ZLE-related integer *
 | 
						|
 * parameter.  data is pointer to global variable   *
 | 
						|
 * where the value is to be stored.                 */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
zlevarsetfn(Param pm, long x)
 | 
						|
{
 | 
						|
    if ((long *)pm->u.data == & columns) {
 | 
						|
	if(x <= 0)
 | 
						|
	    x = tccolumns > 0 ? tccolumns : 80;
 | 
						|
	if (x > 2)
 | 
						|
	    termflags &= ~TERM_NARROW;
 | 
						|
	else
 | 
						|
	    termflags |= TERM_NARROW;
 | 
						|
    } else if ((long *)pm->u.data == & lines) {
 | 
						|
	if(x <= 0)
 | 
						|
	    x = tclines > 0 ? tclines : 24;
 | 
						|
	if (x > 2)
 | 
						|
	    termflags &= ~TERM_SHORT;
 | 
						|
	else
 | 
						|
	    termflags |= TERM_SHORT;
 | 
						|
    }
 | 
						|
 | 
						|
    *((long *)pm->u.data) = x;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of generic special scalar    *
 | 
						|
 * parameter.  data is pointer to a character pointer *
 | 
						|
 * representing the scalar (string).                  */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
strvarsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    char **q = ((char **)pm->u.data);
 | 
						|
 | 
						|
    zsfree(*q);
 | 
						|
    *q = x;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value of generic special scalar    *
 | 
						|
 * parameter.  data is pointer to a character pointer *
 | 
						|
 * representing the scalar (string).                  */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
strvargetfn(Param pm)
 | 
						|
{
 | 
						|
    char *s = *((char **)pm->u.data);
 | 
						|
 | 
						|
    if (!s)
 | 
						|
	return hcalloc(1);
 | 
						|
    return s;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value of generic special array  *
 | 
						|
 * parameter.  data is a pointer to the pointer to *
 | 
						|
 * a pointer (a pointer to a variable length array *
 | 
						|
 * of pointers).                                   */
 | 
						|
 | 
						|
/**/
 | 
						|
char **
 | 
						|
arrvargetfn(Param pm)
 | 
						|
{
 | 
						|
    return *((char ***)pm->u.data);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of generic special array parameter.    *
 | 
						|
 * data is pointer to a variable length array of pointers which *
 | 
						|
 * represents this array of scalars (strings).  If pm->ename is *
 | 
						|
 * non NULL, then it is a colon separated environment variable  *
 | 
						|
 * version of this array which will need to be updated.         */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
arrvarsetfn(Param pm, char **x)
 | 
						|
{
 | 
						|
    char ***dptr = (char ***)pm->u.data;
 | 
						|
 | 
						|
    if (*dptr != x)
 | 
						|
	freearray(*dptr);
 | 
						|
    if (pm->flags & PM_UNIQUE)
 | 
						|
	uniqarray(x);
 | 
						|
    *dptr = x ? x : mkarray(NULL);
 | 
						|
    if (pm->ename && x)
 | 
						|
	arrfixenv(pm->ename, x);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
colonarrgetfn(Param pm)
 | 
						|
{
 | 
						|
    return zjoin(*(char ***)pm->u.data, ':');
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
colonarrsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    char ***dptr = (char ***)pm->u.data;
 | 
						|
 | 
						|
    freearray(*dptr);
 | 
						|
    *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : mkarray(NULL);
 | 
						|
    if (pm->ename)
 | 
						|
	arrfixenv(pm->nam, *dptr);
 | 
						|
    zsfree(x);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
uniqarray(char **x)
 | 
						|
{
 | 
						|
    int changes = 0;
 | 
						|
    char **t, **p = x;
 | 
						|
 | 
						|
    if (!x || !*x)
 | 
						|
	return 0;
 | 
						|
    while (*++p)
 | 
						|
	for (t = x; t < p; t++)
 | 
						|
	    if (!strcmp(*p, *t)) {
 | 
						|
		zsfree(*p);
 | 
						|
		for (t = p--; (*t = t[1]) != NULL; t++);
 | 
						|
		changes++;
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
    return changes;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value of special parameter `#' and `ARGC' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
poundgetfn(Param pm)
 | 
						|
{
 | 
						|
    return arrlen(pparams);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `RANDOM' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
randomgetfn(Param pm)
 | 
						|
{
 | 
						|
    return rand() & 0x7fff;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `RANDOM' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
randomsetfn(Param pm, long v)
 | 
						|
{
 | 
						|
    srand((unsigned int)v);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `SECONDS' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
secondsgetfn(Param pm)
 | 
						|
{
 | 
						|
    return time(NULL) - shtimer.tv_sec;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `SECONDS' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
secondssetfn(Param pm, long x)
 | 
						|
{
 | 
						|
    shtimer.tv_sec = time(NULL) - x;
 | 
						|
    shtimer.tv_usec = 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `USERNAME' */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
usernamegetfn(Param pm)
 | 
						|
{
 | 
						|
    return get_username();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `USERNAME' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
usernamesetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
#if defined(HAVE_SETUID) && defined(HAVE_GETPWNAM)
 | 
						|
    struct passwd *pswd;
 | 
						|
 | 
						|
    if (x && (pswd = getpwnam(x)) && (pswd->pw_uid != cached_uid)) {
 | 
						|
# ifdef HAVE_INITGROUPS
 | 
						|
	initgroups(x, pswd->pw_gid);
 | 
						|
# endif
 | 
						|
	if(!setgid(pswd->pw_gid) && !setuid(pswd->pw_uid)) {
 | 
						|
	    zsfree(cached_username);
 | 
						|
	    cached_username = ztrdup(pswd->pw_name);
 | 
						|
	    cached_uid = pswd->pw_uid;
 | 
						|
	}
 | 
						|
    }
 | 
						|
#endif /* HAVE_SETUID && HAVE_GETPWNAM */
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `UID' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
uidgetfn(Param pm)
 | 
						|
{
 | 
						|
    return getuid();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `UID' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
uidsetfn(Param pm, uid_t x)
 | 
						|
{
 | 
						|
#ifdef HAVE_SETUID
 | 
						|
    setuid(x);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `EUID' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
euidgetfn(Param pm)
 | 
						|
{
 | 
						|
    return geteuid();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `EUID' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
euidsetfn(Param pm, uid_t x)
 | 
						|
{
 | 
						|
#ifdef HAVE_SETEUID
 | 
						|
    seteuid(x);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `GID' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
gidgetfn(Param pm)
 | 
						|
{
 | 
						|
    return getgid();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `GID' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
gidsetfn(Param pm, gid_t x)
 | 
						|
{
 | 
						|
#ifdef HAVE_SETUID
 | 
						|
    setgid(x);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `EGID' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
egidgetfn(Param pm)
 | 
						|
{
 | 
						|
    return getegid();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `EGID' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
egidsetfn(Param pm, gid_t x)
 | 
						|
{
 | 
						|
#ifdef HAVE_SETEUID
 | 
						|
    setegid(x);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
ttyidlegetfn(Param pm)
 | 
						|
{
 | 
						|
    struct stat ttystat;
 | 
						|
 | 
						|
    if (SHTTY == -1 || fstat(SHTTY, &ttystat))
 | 
						|
	return -1;
 | 
						|
    return time(NULL) - ttystat.st_atime;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `IFS' */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
ifsgetfn(Param pm)
 | 
						|
{
 | 
						|
    return ifs;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `IFS' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
ifssetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    zsfree(ifs);
 | 
						|
    ifs = x;
 | 
						|
    inittyptab();
 | 
						|
}
 | 
						|
 | 
						|
/* Functions to set value of special parameters `LANG' and `LC_*' */
 | 
						|
 | 
						|
#ifdef LC_ALL
 | 
						|
static struct localename {
 | 
						|
    char *name;
 | 
						|
    int category;
 | 
						|
} lc_names[] = {
 | 
						|
#ifdef LC_COLLATE
 | 
						|
    {"LC_COLLATE", LC_COLLATE},
 | 
						|
#endif
 | 
						|
#ifdef LC_CTYPE
 | 
						|
    {"LC_CTYPE", LC_CTYPE},
 | 
						|
#endif
 | 
						|
#ifdef LC_MESSAGES
 | 
						|
    {"LC_MESSAGES", LC_MESSAGES},
 | 
						|
#endif
 | 
						|
#ifdef LC_TIME
 | 
						|
    {"LC_TIME", LC_TIME},
 | 
						|
#endif
 | 
						|
    {NULL, 0}
 | 
						|
};
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
setlang(char *x)
 | 
						|
{
 | 
						|
    struct localename *ln;
 | 
						|
 | 
						|
    setlocale(LC_ALL, x ? x : "");
 | 
						|
    for (ln = lc_names; ln->name; ln++)
 | 
						|
	if ((x = getsparam(ln->name)))
 | 
						|
	    setlocale(ln->category, x);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
lc_allsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    strsetfn(pm, x);
 | 
						|
    if (!x)
 | 
						|
	setlang(getsparam("LANG"));
 | 
						|
    else
 | 
						|
	setlocale(LC_ALL, x);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
langsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    strsetfn(pm, x);
 | 
						|
    setlang(x);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
lcsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    struct localename *ln;
 | 
						|
 | 
						|
    strsetfn(pm, x);
 | 
						|
    if (getsparam("LC_ALL"))
 | 
						|
	return;
 | 
						|
    if (!x)
 | 
						|
	x = getsparam("LANG");
 | 
						|
 | 
						|
    for (ln = lc_names; ln->name; ln++)
 | 
						|
	if (!strcmp(ln->name, pm->nam))
 | 
						|
	    setlocale(ln->category, x ? x : "");
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/* Function to get value for special parameter `HISTSIZE' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
histsizegetfn(Param pm)
 | 
						|
{
 | 
						|
    return histsiz;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `HISTSIZE' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
histsizesetfn(Param pm, long v)
 | 
						|
{
 | 
						|
    if ((histsiz = v) <= 2)
 | 
						|
	histsiz = 2;
 | 
						|
    resizehistents();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `ERRNO' */
 | 
						|
 | 
						|
/**/
 | 
						|
long
 | 
						|
errnogetfn(Param pm)
 | 
						|
{
 | 
						|
    return errno;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `histchar' */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
histcharsgetfn(Param pm)
 | 
						|
{
 | 
						|
    static char buf[4];
 | 
						|
 | 
						|
    buf[0] = bangchar;
 | 
						|
    buf[1] = hatchar;
 | 
						|
    buf[2] = hashchar;
 | 
						|
    buf[3] = '\0';
 | 
						|
    return buf;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `histchar' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
histcharssetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    if (x) {
 | 
						|
	bangchar = x[0];
 | 
						|
	hatchar = (bangchar) ? x[1] : '\0';
 | 
						|
	hashchar = (hatchar) ? x[2] : '\0';
 | 
						|
	zsfree(x);
 | 
						|
    } else {
 | 
						|
	bangchar = '!';
 | 
						|
	hashchar = '#';
 | 
						|
	hatchar = '^';
 | 
						|
    }
 | 
						|
    inittyptab();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `HOME' */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
homegetfn(Param pm)
 | 
						|
{
 | 
						|
    return home;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `HOME' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
homesetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    zsfree(home);
 | 
						|
    if (x && isset(CHASELINKS) && (home = xsymlink(x)))
 | 
						|
	zsfree(x);
 | 
						|
    else
 | 
						|
	home = x ? x : ztrdup("");
 | 
						|
    finddir(NULL);
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `WORDCHARS' */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
wordcharsgetfn(Param pm)
 | 
						|
{
 | 
						|
    return wordchars;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `WORDCHARS' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
wordcharssetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    zsfree(wordchars);
 | 
						|
    wordchars = x;
 | 
						|
    inittyptab();
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `_' */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
underscoregetfn(Param pm)
 | 
						|
{
 | 
						|
    return underscore;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to get value for special parameter `TERM' */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
termgetfn(Param pm)
 | 
						|
{
 | 
						|
    return term;
 | 
						|
}
 | 
						|
 | 
						|
/* Function to set value of special parameter `TERM' */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
termsetfn(Param pm, char *x)
 | 
						|
{
 | 
						|
    zsfree(term);
 | 
						|
    term = x ? x : ztrdup("");
 | 
						|
 | 
						|
    /* If non-interactive, delay setting up term till we need it. */
 | 
						|
    if (unset(INTERACTIVE) || !*term)
 | 
						|
	termflags |= TERM_UNKNOWN;
 | 
						|
    else 
 | 
						|
	init_term();
 | 
						|
}
 | 
						|
 | 
						|
/* We could probably replace the replenv with the actual code to *
 | 
						|
 * do the replacing, since we've already scanned for the string. */
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
arrfixenv(char *s, char **t)
 | 
						|
{
 | 
						|
    char **ep, *u;
 | 
						|
    int len_s;
 | 
						|
    Param pm;
 | 
						|
 | 
						|
    MUSTUSEHEAP("arrfixenv");
 | 
						|
    if (t == path)
 | 
						|
	cmdnamtab->emptytable(cmdnamtab);
 | 
						|
    u = zjoin(t, ':');
 | 
						|
    len_s = strlen(s);
 | 
						|
    pm = (Param) paramtab->getnode(paramtab, s);
 | 
						|
    for (ep = environ; *ep; ep++)
 | 
						|
	if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') {
 | 
						|
	    pm->env = replenv(*ep, u);
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
    if (isset(ALLEXPORT))
 | 
						|
	pm->flags |= PM_EXPORTED;
 | 
						|
    if (pm->flags & PM_EXPORTED)
 | 
						|
	pm->env = addenv(s, u);
 | 
						|
}
 | 
						|
 | 
						|
/* Given *name = "foo", it searchs the environment for string *
 | 
						|
 * "foo=bar", and returns a pointer to the beginning of "bar" */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
zgetenv(char *name)
 | 
						|
{
 | 
						|
    char **ep, *s, *t;
 | 
						|
 
 | 
						|
    for (ep = environ; *ep; ep++) {
 | 
						|
	for (s = *ep, t = name; *s && *s == *t; s++, t++);
 | 
						|
	if (*s == '=' && !*t)
 | 
						|
	    return s + 1;
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* Change the value of an existing environment variable */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
replenv(char *e, char *value)
 | 
						|
{
 | 
						|
    char **ep, *s;
 | 
						|
    int len_value;
 | 
						|
 | 
						|
    for (ep = environ; *ep; ep++)
 | 
						|
	if (*ep == e) {
 | 
						|
	    for (len_value = 0, s = value;
 | 
						|
		 *s && (*s++ != Meta || *s++ != 32); len_value++);
 | 
						|
	    s = e;
 | 
						|
	    while (*s++ != '=');
 | 
						|
	    *ep = (char *) zrealloc(e, s - e + len_value + 1);
 | 
						|
	    s = s - e + *ep - 1;
 | 
						|
	    while (*s++)
 | 
						|
		if ((*s = *value++) == Meta)
 | 
						|
		    *s = *value++ ^ 32;
 | 
						|
	    return *ep;
 | 
						|
	}
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* Given strings *name = "foo", *value = "bar", *
 | 
						|
 * return a new string *str = "foo=bar".        */
 | 
						|
 | 
						|
/**/
 | 
						|
static char *
 | 
						|
mkenvstr(char *name, char *value)
 | 
						|
{
 | 
						|
    char *str, *s;
 | 
						|
    int len_name, len_value;
 | 
						|
 | 
						|
    len_name = strlen(name);
 | 
						|
    for (len_value = 0, s = value;
 | 
						|
	 *s && (*s++ != Meta || *s++ != 32); len_value++);
 | 
						|
    s = str = (char *) zalloc(len_name + len_value + 2);
 | 
						|
    strcpy(s, name);
 | 
						|
    s += len_name;
 | 
						|
    *s = '=';
 | 
						|
    while (*s++)
 | 
						|
	if ((*s = *value++) == Meta)
 | 
						|
	    *s = *value++ ^ 32;
 | 
						|
    return str;
 | 
						|
}
 | 
						|
 | 
						|
/* Given *name = "foo", *value = "bar", add the    *
 | 
						|
 * string "foo=bar" to the environment.  Return a  *
 | 
						|
 * pointer to the location of this new environment *
 | 
						|
 * string.                                         */
 | 
						|
 | 
						|
/**/
 | 
						|
char *
 | 
						|
addenv(char *name, char *value)
 | 
						|
{
 | 
						|
    char **ep, *s, *t;
 | 
						|
    int num_env;
 | 
						|
 | 
						|
    /* First check if there is already an environment *
 | 
						|
     * variable matching string `name'.               */
 | 
						|
    for (ep = environ; *ep; ep++) {
 | 
						|
	for (s = *ep, t = name; *s && *s == *t; s++, t++);
 | 
						|
	if (*s == '=' && !*t) {
 | 
						|
	    zsfree(*ep);
 | 
						|
	    return *ep = mkenvstr(name, value);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    /* Else we have to make room and add it */
 | 
						|
    num_env = arrlen(environ);
 | 
						|
    environ = (char **) zrealloc(environ, (sizeof(char *)) * (num_env + 2));
 | 
						|
 | 
						|
    /* Now add it at the end */
 | 
						|
    ep = environ + num_env;
 | 
						|
    *ep = mkenvstr(name, value);
 | 
						|
    *(ep + 1) = NULL;
 | 
						|
    return *ep;
 | 
						|
}
 | 
						|
 | 
						|
/* Delete a pointer from the list of pointers to environment *
 | 
						|
 * variables by shifting all the other pointers up one slot. */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
delenv(char *x)
 | 
						|
{
 | 
						|
    char **ep;
 | 
						|
 | 
						|
    for (ep = environ; *ep; ep++) {
 | 
						|
	if (*ep == x)
 | 
						|
	    break;
 | 
						|
    }
 | 
						|
    if (*ep)
 | 
						|
	for (; (ep[0] = ep[1]); ep++);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
convbase(char *s, long v, int base)
 | 
						|
{
 | 
						|
    int digs = 0;
 | 
						|
    unsigned long x;
 | 
						|
 | 
						|
    if (v < 0)
 | 
						|
	*s++ = '-', v = -v;
 | 
						|
    if (base <= 1)
 | 
						|
	base = 10;
 | 
						|
 | 
						|
    if (base != 10) {
 | 
						|
	sprintf(s, "%d#", base);
 | 
						|
	s += strlen(s);
 | 
						|
    }
 | 
						|
    for (x = v; x; digs++)
 | 
						|
	x /= base;
 | 
						|
    if (!digs)
 | 
						|
	digs = 1;
 | 
						|
    s[digs--] = '\0';
 | 
						|
    x = v;
 | 
						|
    while (digs >= 0) {
 | 
						|
	int dig = x % base;
 | 
						|
 | 
						|
	s[digs--] = (dig < 10) ? '0' + dig : dig - 10 + 'A';
 | 
						|
	x /= base;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Start a parameter scope */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
startparamscope(void)
 | 
						|
{
 | 
						|
    locallevel++;
 | 
						|
}
 | 
						|
 | 
						|
/* End a parameter scope: delete the parameters local to the scope. */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
endparamscope(void)
 | 
						|
{
 | 
						|
    locallevel--;
 | 
						|
    scanhashtable(paramtab, 0, 0, 0, scanendscope, 0);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
scanendscope(HashNode hn, int flags)
 | 
						|
{
 | 
						|
    Param pm = (Param)hn;
 | 
						|
    if(pm->level > locallevel)
 | 
						|
	unsetparam_pm(pm, 0, 0);
 | 
						|
}
 |