openenvutils/commandshell/shell/src/params.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // params.c - parameters
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007-2008. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1992-1997 Paul Falstad
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Paul Falstad or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Paul Falstad and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Paul Falstad and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Paul Falstad and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 #include "zsh.mdh"
       
    32 #include "params.pro"
       
    33 
       
    34 #include "version.h"
       
    35 
       
    36 #ifdef __SYMBIAN32__
       
    37 #ifdef __WINSCW__
       
    38 #pragma warn_unusedarg off
       
    39 #pragma warn_possunwant off
       
    40 #endif//__WINSCW__
       
    41 #endif//__SYMBIAN32__
       
    42 
       
    43 /* what level of localness we are at */
       
    44  
       
    45 /**/
       
    46 mod_export int locallevel;
       
    47  
       
    48 /* Variables holding values of special parameters */
       
    49  
       
    50 /**/
       
    51 mod_export
       
    52 char **pparams,		/* $argv        */
       
    53      **cdpath,		/* $cdpath      */
       
    54      **fpath,		/* $fpath       */
       
    55      **mailpath,	/* $mailpath    */
       
    56      **manpath,		/* $manpath     */
       
    57      **psvar,		/* $psvar       */
       
    58      **watch;		/* $watch       */
       
    59 /**/
       
    60 mod_export
       
    61 char **path,		/* $path        */
       
    62      **fignore;		/* $fignore     */
       
    63  
       
    64 /**/
       
    65 char *argzero,		/* $0           */
       
    66      *home,		/* $HOME        */
       
    67      *nullcmd,		/* $NULLCMD     */
       
    68      *oldpwd,		/* $OLDPWD      */
       
    69      *zoptarg,		/* $OPTARG      */
       
    70      *prompt,		/* $PROMPT      */
       
    71      *prompt2,		/* $PROMPT2     */
       
    72      *prompt3,		/* $PROMPT3     */
       
    73      *prompt4,		/* $PROMPT4     */
       
    74      *readnullcmd,	/* $READNULLCMD */
       
    75      *rprompt,		/* $RPROMPT     */
       
    76      *rprompt2,		/* $RPROMPT2    */
       
    77      *sprompt,		/* $SPROMPT     */
       
    78      *wordchars,	/* $WORDCHARS   */
       
    79      *zsh_name;		/* $ZSH_NAME    */
       
    80 /**/
       
    81 mod_export
       
    82 char *ifs,		/* $IFS         */
       
    83      *postedit,		/* $POSTEDIT    */
       
    84      *term,		/* $TERM        */
       
    85      *ttystrname,	/* $TTY         */
       
    86      *pwd;		/* $PWD         */
       
    87 
       
    88 /**/
       
    89 mod_export
       
    90 zlong lastval,		/* $?           */
       
    91      mypid,		/* $$           */
       
    92      lastpid,		/* $!           */
       
    93      columns,		/* $COLUMNS     */
       
    94      lines,		/* $LINES       */
       
    95      ppid;		/* $PPID        */
       
    96 /**/
       
    97 zlong lineno,		/* $LINENO      */
       
    98      zoptind,		/* $OPTIND      */
       
    99      shlvl;		/* $SHLVL       */
       
   100 
       
   101 /* $histchars */
       
   102  
       
   103 /**/
       
   104 mod_export unsigned char bangchar;
       
   105 /**/
       
   106 unsigned char hatchar, hashchar;
       
   107  
       
   108 /* $SECONDS = now.tv_sec - shtimer.tv_sec
       
   109  *          + (now.tv_usec - shtimer.tv_usec) / 1000000.0
       
   110  * (rounded to an integer if the parameter is not set to float) */
       
   111  
       
   112 /**/
       
   113 struct timeval shtimer;
       
   114  
       
   115 /* 0 if this $TERM setup is usable, otherwise it contains TERM_* flags */
       
   116 
       
   117 /**/
       
   118 mod_export int termflags;
       
   119 
       
   120 /* Standard methods for get/set/unset pointers in parameters */
       
   121 
       
   122 /**/
       
   123 mod_export const struct gsu_scalar stdscalar_gsu =
       
   124 { strgetfn, strsetfn, stdunsetfn };
       
   125 /**/
       
   126 mod_export const struct gsu_scalar varscalar_gsu =
       
   127 { strvargetfn, strvarsetfn, stdunsetfn };
       
   128 /**/
       
   129 mod_export const struct gsu_scalar nullsetscalar_gsu =
       
   130 { strgetfn, nullstrsetfn, NULL };
       
   131 
       
   132 /**/
       
   133 mod_export const struct gsu_integer stdinteger_gsu =
       
   134 { intgetfn, intsetfn, stdunsetfn };
       
   135 /**/
       
   136 mod_export const struct gsu_integer varinteger_gsu =
       
   137 { intvargetfn, intvarsetfn, stdunsetfn };
       
   138 /**/
       
   139 mod_export const struct gsu_integer nullsetinteger_gsu =
       
   140 { intgetfn, NULL, NULL };
       
   141 
       
   142 /**/
       
   143 mod_export const struct gsu_float stdfloat_gsu =
       
   144 { floatgetfn, floatsetfn, stdunsetfn };
       
   145 
       
   146 /**/
       
   147 mod_export const struct gsu_array stdarray_gsu =
       
   148 { arrgetfn, arrsetfn, stdunsetfn };
       
   149 /**/
       
   150 mod_export const struct gsu_array vararray_gsu =
       
   151 { arrvargetfn, arrvarsetfn, stdunsetfn };
       
   152 
       
   153 /**/
       
   154 mod_export const struct gsu_hash stdhash_gsu =
       
   155 { hashgetfn, hashsetfn, stdunsetfn };
       
   156 /**/
       
   157 mod_export const struct gsu_hash nullsethash_gsu =
       
   158 { hashgetfn, nullsethashfn, nullunsetfn };
       
   159 
       
   160 
       
   161 /* Non standard methods (not exported) */
       
   162 static const struct gsu_integer pound_gsu =
       
   163 { poundgetfn, nullintsetfn, stdunsetfn };
       
   164 static const struct gsu_integer errno_gsu =
       
   165 { errnogetfn, errnosetfn, stdunsetfn };
       
   166 static const struct gsu_integer gid_gsu =
       
   167 { gidgetfn, gidsetfn, stdunsetfn };
       
   168 static const struct gsu_integer egid_gsu =
       
   169 { egidgetfn, egidsetfn, stdunsetfn };
       
   170 static const struct gsu_integer histsize_gsu =
       
   171 { histsizegetfn, histsizesetfn, stdunsetfn };
       
   172 static const struct gsu_integer random_gsu =
       
   173 { randomgetfn, randomsetfn, stdunsetfn };
       
   174 static const struct gsu_integer savehist_gsu =
       
   175 { savehistsizegetfn, savehistsizesetfn, stdunsetfn };
       
   176 static const struct gsu_integer intseconds_gsu =
       
   177 { intsecondsgetfn, intsecondssetfn, stdunsetfn };
       
   178 static const struct gsu_float floatseconds_gsu =
       
   179 { floatsecondsgetfn, floatsecondssetfn, stdunsetfn };
       
   180 static const struct gsu_integer uid_gsu =
       
   181 { uidgetfn, uidsetfn, stdunsetfn };
       
   182 static const struct gsu_integer euid_gsu =
       
   183 { euidgetfn, euidsetfn, stdunsetfn };
       
   184 static const struct gsu_integer ttyidle_gsu =
       
   185 { ttyidlegetfn, nullintsetfn, stdunsetfn };
       
   186 
       
   187 static const struct gsu_scalar username_gsu =
       
   188 { usernamegetfn, usernamesetfn, stdunsetfn };
       
   189 static const struct gsu_scalar dash_gsu =
       
   190 { dashgetfn, nullstrsetfn, stdunsetfn };
       
   191 static const struct gsu_scalar histchars_gsu =
       
   192 { histcharsgetfn, histcharssetfn, stdunsetfn };
       
   193 static const struct gsu_scalar home_gsu =
       
   194 { homegetfn, homesetfn, stdunsetfn };
       
   195 static const struct gsu_scalar term_gsu =
       
   196 { termgetfn, termsetfn, stdunsetfn };
       
   197 static const struct gsu_scalar wordchars_gsu =
       
   198 { wordcharsgetfn, wordcharssetfn, stdunsetfn };
       
   199 static const struct gsu_scalar ifs_gsu =
       
   200 { ifsgetfn, ifssetfn, stdunsetfn };
       
   201 static const struct gsu_scalar underscore_gsu =
       
   202 { underscoregetfn, nullstrsetfn, stdunsetfn };
       
   203 #ifdef USE_LOCALE
       
   204 static const struct gsu_scalar lc_blah_gsu =
       
   205 { strgetfn, lcsetfn, stdunsetfn };
       
   206 static const struct gsu_scalar lang_gsu =
       
   207 { strgetfn, langsetfn, stdunsetfn };
       
   208 static const struct gsu_scalar lc_all_gsu =
       
   209 { strgetfn, lc_allsetfn, stdunsetfn };
       
   210 #endif
       
   211 
       
   212 static const struct gsu_integer varint_readonly_gsu =
       
   213 { intvargetfn, nullintsetfn, stdunsetfn };
       
   214 static const struct gsu_integer zlevar_gsu =
       
   215 { intvargetfn, zlevarsetfn, stdunsetfn };
       
   216 
       
   217 static const struct gsu_scalar colonarr_gsu =
       
   218 { colonarrgetfn, colonarrsetfn, stdunsetfn };
       
   219 
       
   220 static const struct gsu_integer argc_gsu =
       
   221 { poundgetfn, nullintsetfn, stdunsetfn };
       
   222 static const struct gsu_array pipestatus_gsu =
       
   223 { pipestatgetfn, pipestatsetfn, stdunsetfn };
       
   224 
       
   225 /* Nodes for special parameters for parameter hash table */
       
   226 
       
   227 #ifdef HAVE_UNION_INIT
       
   228 # define BR(X) {X}
       
   229 typedef struct param initparam;
       
   230 #else
       
   231 # define BR(X) X
       
   232 typedef struct iparam {
       
   233     struct hashnode *next;
       
   234     char *nam;			/* hash data                             */
       
   235     int flags;			/* PM_* flags (defined in zsh.h)         */
       
   236     void *value;
       
   237     void *gsu;			/* get/set/unset methods */
       
   238     int base;			/* output base                           */
       
   239     int width;			/* output field width                    */
       
   240     char *env;			/* location in environment, if exported  */
       
   241     char *ename;		/* name of corresponding environment var */
       
   242     Param old;			/* old struct for use with local         */
       
   243     int level;			/* if (old != NULL), level of localness  */
       
   244 } initparam;
       
   245 #endif
       
   246 
       
   247 static initparam special_params[] ={
       
   248 #define GSU(X) BR((GsuScalar)(void *)(&(X)))
       
   249 #define NULL_GSU BR((GsuScalar)(void *)NULL)
       
   250 #define IPDEF1(A,B,C) {NULL,A,PM_INTEGER|PM_SPECIAL|C,BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
       
   251 IPDEF1("#", pound_gsu, PM_READONLY),
       
   252 IPDEF1("ERRNO", errno_gsu, 0),
       
   253 IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
       
   254 IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
       
   255 IPDEF1("HISTSIZE", histsize_gsu, PM_RESTRICTED),
       
   256 IPDEF1("RANDOM", random_gsu, 0),
       
   257 IPDEF1("SAVEHIST", savehist_gsu, PM_RESTRICTED),
       
   258 IPDEF1("SECONDS", intseconds_gsu, 0),
       
   259 IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
       
   260 IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
       
   261 IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY),
       
   262 
       
   263 #define IPDEF2(A,B,C) {NULL,A,PM_SCALAR|PM_SPECIAL|C,BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
       
   264 IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
       
   265 IPDEF2("-", dash_gsu, PM_READONLY),
       
   266 IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
       
   267 IPDEF2("HOME", home_gsu, 0),
       
   268 IPDEF2("TERM", term_gsu, 0),
       
   269 IPDEF2("WORDCHARS", wordchars_gsu, 0),
       
   270 IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT),
       
   271 IPDEF2("_", underscore_gsu, PM_READONLY),
       
   272 
       
   273 #ifdef USE_LOCALE
       
   274 # define LCIPDEF(name) IPDEF2(name, lc_blah_gsu, PM_UNSET)
       
   275 IPDEF2("LANG", lang_gsu, PM_UNSET),
       
   276 IPDEF2("LC_ALL", lc_all_gsu, PM_UNSET),
       
   277 # ifdef LC_COLLATE
       
   278 LCIPDEF("LC_COLLATE"),
       
   279 # endif
       
   280 # ifdef LC_CTYPE
       
   281 LCIPDEF("LC_CTYPE"),
       
   282 # endif
       
   283 # ifdef LC_MESSAGES
       
   284 LCIPDEF("LC_MESSAGES"),
       
   285 # endif
       
   286 # ifdef LC_NUMERIC
       
   287 LCIPDEF("LC_NUMERIC"),
       
   288 # endif
       
   289 # ifdef LC_TIME
       
   290 LCIPDEF("LC_TIME"),
       
   291 # endif
       
   292 #endif /* USE_LOCALE */
       
   293 
       
   294 #define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
       
   295 IPDEF4("!", &lastpid),
       
   296 IPDEF4("$", &mypid),
       
   297 IPDEF4("?", &lastval),
       
   298 IPDEF4("HISTCMD", &curhist),
       
   299 IPDEF4("LINENO", &lineno),
       
   300 IPDEF4("PPID", &ppid),
       
   301 
       
   302 #define IPDEF5(A,B,F) {NULL,A,PM_INTEGER|PM_SPECIAL,BR((void *)B),GSU(varinteger_gsu),10,0,NULL,NULL,NULL,0}
       
   303 IPDEF5("COLUMNS", &columns, zlevar_gsu),
       
   304 IPDEF5("LINES", &lines, zlevar_gsu),
       
   305 IPDEF5("OPTIND", &zoptind, varinteger_gsu),
       
   306 IPDEF5("SHLVL", &shlvl, varinteger_gsu),
       
   307 IPDEF5("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu),
       
   308 
       
   309 #define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
       
   310 IPDEF7("OPTARG", &zoptarg),
       
   311 IPDEF7("NULLCMD", &nullcmd),
       
   312 IPDEF7("POSTEDIT", &postedit),
       
   313 IPDEF7("READNULLCMD", &readnullcmd),
       
   314 IPDEF7("PS1", &prompt),
       
   315 IPDEF7("RPS1", &rprompt),
       
   316 IPDEF7("RPROMPT", &rprompt),
       
   317 IPDEF7("PS2", &prompt2),
       
   318 IPDEF7("RPS2", &rprompt2),
       
   319 IPDEF7("RPROMPT2", &rprompt2),
       
   320 IPDEF7("PS3", &prompt3),
       
   321 IPDEF7("PS4", &prompt4),
       
   322 IPDEF7("SPROMPT", &sprompt),
       
   323 IPDEF7("0", &argzero),
       
   324 
       
   325 #define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0}
       
   326 IPDEF8("CDPATH", &cdpath, "cdpath", 0),
       
   327 IPDEF8("FIGNORE", &fignore, "fignore", 0),
       
   328 IPDEF8("FPATH", &fpath, "fpath", 0),
       
   329 IPDEF8("MAILPATH", &mailpath, "mailpath", 0),
       
   330 IPDEF8("WATCH", &watch, "watch", 0),
       
   331 IPDEF8("PATH", &path, "path", PM_RESTRICTED),
       
   332 IPDEF8("PSVAR", &psvar, "psvar", 0),
       
   333 
       
   334 /* MODULE_PATH is not imported for security reasons */
       
   335 IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
       
   336 
       
   337 #define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
       
   338 #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
       
   339 IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
       
   340 IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
       
   341 {NULL,NULL,0,BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
       
   342 
       
   343 #define IPDEF10(A,B) {NULL,A,PM_ARRAY|PM_SPECIAL,BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
       
   344 
       
   345 /* The following parameters are not available in sh/ksh compatibility *
       
   346  * mode. All of these have sh compatible equivalents.                */
       
   347 IPDEF1("ARGC", argc_gsu, PM_READONLY),
       
   348 IPDEF2("HISTCHARS", histchars_gsu, PM_DONTIMPORT),
       
   349 IPDEF4("status", &lastval),
       
   350 IPDEF7("prompt", &prompt),
       
   351 IPDEF7("PROMPT", &prompt),
       
   352 IPDEF7("PROMPT2", &prompt2),
       
   353 IPDEF7("PROMPT3", &prompt3),
       
   354 IPDEF7("PROMPT4", &prompt4),
       
   355 IPDEF8("MANPATH", &manpath, "manpath", 0),
       
   356 IPDEF9("argv", &pparams, NULL),
       
   357 IPDEF9("fignore", &fignore, "FIGNORE"),
       
   358 IPDEF9("cdpath", &cdpath, "CDPATH"),
       
   359 IPDEF9("fpath", &fpath, "FPATH"),
       
   360 IPDEF9("mailpath", &mailpath, "MAILPATH"),
       
   361 IPDEF9("manpath", &manpath, "MANPATH"),
       
   362 IPDEF9("psvar", &psvar, "PSVAR"),
       
   363 IPDEF9("watch", &watch, "WATCH"),
       
   364 
       
   365 IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
       
   366 IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
       
   367 
       
   368 IPDEF10("pipestatus", pipestatus_gsu),
       
   369 
       
   370 {NULL,NULL,0,BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
       
   371 };
       
   372 
       
   373 /*
       
   374  * Special way of referring to the positional parameters.  Unlike $*
       
   375  * and $@, this is not readonly.  This parameter is not directly
       
   376  * visible in user space.
       
   377  */
       
   378 initparam argvparam_pm = IPDEF9F("", &pparams, NULL, \
       
   379 				 PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT);
       
   380 
       
   381 #undef BR
       
   382 
       
   383 #define IS_UNSET_VALUE(V) \
       
   384 	((V) && (!(V)->pm || ((V)->pm->flags & PM_UNSET) || \
       
   385 		 !(V)->pm->nam || !*(V)->pm->nam))
       
   386 
       
   387 static Param argvparam;
       
   388 
       
   389 /* hash table containing the parameters */
       
   390  
       
   391 /**/
       
   392 mod_export HashTable paramtab, realparamtab;
       
   393 
       
   394 /**/
       
   395 mod_export HashTable
       
   396 newparamtable(int size, char const *name)
       
   397 {
       
   398     HashTable ht;
       
   399     if (!size)
       
   400 	size = 17;
       
   401     ht = newhashtable(size, name, NULL);
       
   402 
       
   403     ht->hash        = hasher;
       
   404     ht->emptytable  = emptyhashtable;
       
   405     ht->filltable   = NULL;
       
   406     ht->cmpnodes    = strcmp;
       
   407     ht->addnode     = addhashnode;
       
   408     ht->getnode     = getparamnode;
       
   409     ht->getnode2    = getparamnode;
       
   410     ht->removenode  = removehashnode;
       
   411     ht->disablenode = NULL;
       
   412     ht->enablenode  = NULL;
       
   413     ht->freenode    = freeparamnode;
       
   414     ht->printnode   = printparamnode;
       
   415 
       
   416     return ht;
       
   417 }
       
   418 
       
   419 /**/
       
   420 static HashNode
       
   421 getparamnode(HashTable ht, char *nam)
       
   422 {
       
   423     HashNode hn = gethashnode2(ht, nam);
       
   424     Param pm = (Param) hn;
       
   425 
       
   426     if (pm && pm->u.str && (pm->flags & PM_AUTOLOAD)) {
       
   427 	char *mn = dupstring(pm->u.str);
       
   428 
       
   429 	if (!load_module(mn))
       
   430 	    return NULL;
       
   431 	hn = gethashnode2(ht, nam);
       
   432 	if (((Param) hn) == pm && (pm->flags & PM_AUTOLOAD)) {
       
   433 	    pm->flags &= ~PM_AUTOLOAD;
       
   434 	    zwarnnam(nam, "autoload failed", NULL, 0);
       
   435 	}
       
   436     }
       
   437     return hn;
       
   438 }
       
   439 
       
   440 /* Copy a parameter hash table */
       
   441 
       
   442 static HashTable outtable;
       
   443 
       
   444 /**/
       
   445 static void
       
   446 scancopyparams(HashNode hn, UNUSED(int flags))
       
   447 {
       
   448     /* Going into a real parameter, so always use permanent storage */
       
   449     Param pm = (Param)hn;
       
   450     Param tpm = (Param) zshcalloc(sizeof *tpm);
       
   451     tpm->nam = ztrdup(pm->nam);
       
   452     copyparam(tpm, pm, 0);
       
   453     addhashnode(outtable, tpm->nam, tpm);
       
   454 }
       
   455 
       
   456 /**/
       
   457 HashTable
       
   458 copyparamtable(HashTable ht, char *name)
       
   459 {
       
   460     HashTable nht = newparamtable(ht->hsize, name);
       
   461     outtable = nht;
       
   462     scanhashtable(ht, 0, 0, 0, scancopyparams, 0);
       
   463     outtable = NULL;
       
   464     return nht;
       
   465 }
       
   466 
       
   467 /* Flag to freeparamnode to unset the struct */
       
   468 
       
   469 static int delunset;
       
   470 
       
   471 /* Function to delete a parameter table. */
       
   472 
       
   473 /**/
       
   474 mod_export void
       
   475 deleteparamtable(HashTable t)
       
   476 {
       
   477     /* The parameters in the hash table need to be unset *
       
   478      * before being deleted.                             */
       
   479     int odelunset = delunset;
       
   480     delunset = 1;
       
   481     deletehashtable(t);
       
   482     delunset = odelunset;
       
   483 }
       
   484 
       
   485 static unsigned numparamvals;
       
   486 
       
   487 /**/
       
   488 mod_export void
       
   489 scancountparams(UNUSED(HashNode hn), int flags)
       
   490 {
       
   491     ++numparamvals;
       
   492     if ((flags & SCANPM_WANTKEYS) && (flags & SCANPM_WANTVALS))
       
   493 	++numparamvals;
       
   494 }
       
   495 
       
   496 static Patprog scanprog;
       
   497 static char *scanstr;
       
   498 static char **paramvals;
       
   499 static Param foundparam;     
       
   500 
       
   501 /**/
       
   502 void
       
   503 scanparamvals(HashNode hn, int flags)
       
   504 {
       
   505     struct value v;
       
   506     Patprog prog;
       
   507 
       
   508     if (numparamvals && !(flags & SCANPM_MATCHMANY) &&
       
   509 	(flags & (SCANPM_MATCHVAL|SCANPM_MATCHKEY|SCANPM_KEYMATCH)))
       
   510 	return;
       
   511     v.pm = (Param)hn;
       
   512     if ((flags & SCANPM_KEYMATCH)) {
       
   513 	char *tmp = dupstring(v.pm->nam);
       
   514 
       
   515 	tokenize(tmp);
       
   516 	remnulargs(tmp);
       
   517 
       
   518 	if (!(prog = patcompile(tmp, 0, NULL)) || !pattry(prog, scanstr))
       
   519 	    return;
       
   520     } else if ((flags & SCANPM_MATCHKEY) && !pattry(scanprog, v.pm->nam)) {
       
   521 	return;
       
   522     }
       
   523     foundparam = v.pm;
       
   524     if (flags & SCANPM_WANTKEYS) {
       
   525 	paramvals[numparamvals++] = v.pm->nam;
       
   526 	if (!(flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)))
       
   527 	    return;
       
   528     }
       
   529     v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED));
       
   530     v.inv = 0;
       
   531     v.start = 0;
       
   532     v.end = -1;
       
   533     paramvals[numparamvals] = getstrvalue(&v);
       
   534     if (flags & SCANPM_MATCHVAL) {
       
   535 	if (pattry(scanprog, paramvals[numparamvals])) {
       
   536 	    numparamvals += ((flags & SCANPM_WANTVALS) ? 1 :
       
   537 			     !(flags & SCANPM_WANTKEYS));
       
   538 	} else if (flags & SCANPM_WANTKEYS)
       
   539 	    --numparamvals;	/* Value didn't match, discard key */
       
   540     } else
       
   541 	++numparamvals;
       
   542 }
       
   543 
       
   544 /**/
       
   545 char **
       
   546 paramvalarr(HashTable ht, int flags)
       
   547 {
       
   548     numparamvals = 0;
       
   549     if (ht)
       
   550 	scanhashtable(ht, 0, 0, PM_UNSET, scancountparams, flags);
       
   551     paramvals = (char **) zhalloc((numparamvals + 1) * sizeof(char *));
       
   552     if (ht) {
       
   553 	numparamvals = 0;
       
   554 	scanhashtable(ht, 0, 0, PM_UNSET, scanparamvals, flags);
       
   555     }
       
   556     paramvals[numparamvals] = 0;
       
   557     return paramvals;
       
   558 }
       
   559 
       
   560 /* Return the full array (no indexing) referred to by a Value. *
       
   561  * The array value is cached for the lifetime of the Value.    */
       
   562 
       
   563 /**/
       
   564 static char **
       
   565 getvaluearr(Value v)
       
   566 {
       
   567     if (v->arr)
       
   568 	return v->arr;
       
   569     else if (PM_TYPE(v->pm->flags) == PM_ARRAY)
       
   570 	return v->arr = v->pm->gsu.a->getfn(v->pm);
       
   571     else if (PM_TYPE(v->pm->flags) == PM_HASHED) {
       
   572 	v->arr = paramvalarr(v->pm->gsu.h->getfn(v->pm), v->isarr);
       
   573 	/* Can't take numeric slices of associative arrays */
       
   574 	v->start = 0;
       
   575 	v->end = numparamvals + 1;
       
   576 	return v->arr;
       
   577     } else
       
   578 	return NULL;
       
   579 }
       
   580 
       
   581 /*
       
   582  * Split environment string into (name, value) pair.
       
   583  * this is used to avoid in-place editing of environment table
       
   584  * that results in core dump on some systems
       
   585  */
       
   586 
       
   587 static int
       
   588 split_env_string(char *env, char **name, char **value)
       
   589 {
       
   590     char *str, *tenv;
       
   591 
       
   592     if (!env || !name || !value)
       
   593 	return 0;
       
   594 
       
   595     tenv = strcpy(zhalloc(strlen(env) + 1), env);
       
   596     for (str = tenv; *str && *str != '='; str++)
       
   597 	;
       
   598     if (str != tenv && *str == '=') {
       
   599 	*str = '\0';
       
   600 	*name = tenv;
       
   601 	*value = str + 1;
       
   602 	return 1;
       
   603     } else
       
   604 	return 0;
       
   605 }
       
   606     
       
   607 /* Set up parameter hash table.  This will add predefined  *
       
   608  * parameter entries as well as setting up parameter table *
       
   609  * entries for environment variables we inherit.           */
       
   610 
       
   611 /**/
       
   612 void
       
   613 createparamtable(void)
       
   614 {
       
   615     Param ip, pm;
       
   616 #ifndef HAVE_PUTENV
       
   617     char **new_environ;
       
   618     int  envsize;
       
   619 #endif
       
   620     char **envp, **envp2, **sigptr, **t;
       
   621     char buf[50], *str, *iname, *ivalue, *hostnam;
       
   622     int  oae = opts[ALLEXPORT];
       
   623 #ifdef HAVE_UNAME
       
   624     struct utsname unamebuf;
       
   625     char *machinebuf;
       
   626 #endif
       
   627 
       
   628     paramtab = realparamtab = newparamtable(151, "paramtab");
       
   629 
       
   630     /* Add the special parameters to the hash table */
       
   631     for (ip = special_params; ip->nam; ip++)
       
   632 	paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
       
   633     if (emulation != EMULATE_SH && emulation != EMULATE_KSH)
       
   634 	while ((++ip)->nam)
       
   635 	    paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
       
   636 
       
   637     argvparam = (Param) &argvparam_pm;
       
   638 
       
   639     noerrs = 2;
       
   640 
       
   641     /* Add the standard non-special parameters which have to    *
       
   642      * be initialized before we copy the environment variables. *
       
   643      * We don't want to override whatever values the user has   *
       
   644      * given them in the environment.                           */
       
   645     opts[ALLEXPORT] = 0;
       
   646     setiparam("MAILCHECK", 60);
       
   647     setiparam("LOGCHECK", 60);
       
   648     setiparam("KEYTIMEOUT", 40);
       
   649     setiparam("LISTMAX", 100);
       
   650 #ifdef HAVE_SELECT
       
   651     setiparam("BAUD", getbaudrate(&shttyinfo));  /* get the output baudrate */
       
   652 #endif
       
   653     setsparam("FCEDIT", ztrdup(DEFAULT_FCEDIT));
       
   654     setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX));
       
   655     setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT));
       
   656     
       
   657 #ifndef __SYMBIAN32__    
       
   658     setsparam("WATCHFMT", ztrdup(default_watchfmt));
       
   659 #endif
       
   660 
       
   661     hostnam = (char *)zalloc(256);
       
   662     gethostname(hostnam, 256);
       
   663     setsparam("HOST", ztrdup(hostnam));
       
   664     zfree(hostnam, 256);
       
   665 
       
   666     setsparam("LOGNAME", ztrdup((str = (char*)getlogin()) && *str ? str : cached_username));
       
   667 
       
   668 #ifndef HAVE_PUTENV
       
   669     /* Copy the environment variables we are inheriting to dynamic *
       
   670      * memory, so we can do mallocs and frees on it.               */
       
   671     envsize = sizeof(char *)*(1 + arrlen(environ));
       
   672     new_environ = (char **) zalloc(envsize);
       
   673     memcpy(new_environ, environ, envsize);
       
   674     environ = new_environ;
       
   675 #endif
       
   676 
       
   677     /* Use heap allocation to avoid many small alloc/free calls */
       
   678     pushheap();
       
   679 
       
   680     /* Now incorporate environment variables we are inheriting *
       
   681      * into the parameter hash table. Copy them into dynamic   *
       
   682      * memory so that we can free them if needed               */
       
   683     for (envp = envp2 = environ; *envp2; envp2++) {
       
   684 	if (split_env_string(*envp2, &iname, &ivalue)) {
       
   685 	    if (!idigit(*iname) && isident(iname) && !strchr(iname, '[')) {
       
   686 		if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
       
   687 		     !(pm->flags & PM_DONTIMPORT || pm->flags & PM_EXPORTED)) &&
       
   688 		    (pm = setsparam(iname, metafy(ivalue, -1, META_DUP)))) {
       
   689 		    pm->flags |= PM_EXPORTED;
       
   690 		    if (pm->flags & PM_SPECIAL)
       
   691 			pm->env = mkenvstr (pm->nam,
       
   692 					    getsparam(pm->nam), pm->flags);
       
   693 		    else
       
   694 			pm->env = ztrdup(*envp2);
       
   695 		    *envp++ = pm->env;
       
   696 		}
       
   697 	    }
       
   698 	}
       
   699     }
       
   700     popheap();
       
   701     *envp = '\0';
       
   702     opts[ALLEXPORT] = oae;
       
   703 
       
   704     pm = (Param) paramtab->getnode(paramtab, "HOME");
       
   705     if (!(pm->flags & PM_EXPORTED))
       
   706 	addenv(pm, home);
       
   707     pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
       
   708     if (!(pm->flags & PM_EXPORTED))
       
   709 	addenv(pm, pm->u.str);
       
   710     pm = (Param) paramtab->getnode(paramtab, "SHLVL");
       
   711     sprintf(buf, "%d", (int)++shlvl);
       
   712     /* shlvl value in environment needs updating unconditionally */
       
   713     addenv(pm, buf);
       
   714 
       
   715     /* Add the standard non-special parameters */
       
   716     set_pwd_env();
       
   717 #ifdef HAVE_UNAME
       
   718     if(uname(&unamebuf)) setsparam("CPUTYPE", ztrdup("unknown"));
       
   719     else
       
   720     {
       
   721        machinebuf = ztrdup(unamebuf.machine);
       
   722        setsparam("CPUTYPE", machinebuf);
       
   723     }
       
   724 	
       
   725 #else
       
   726     setsparam("CPUTYPE", ztrdup("unknown"));
       
   727 #endif
       
   728     setsparam("MACHTYPE", ztrdup(MACHTYPE));
       
   729     setsparam("OSTYPE", ztrdup(OSTYPE));
       
   730     setsparam("TTY", ztrdup(ttystrname));
       
   731     setsparam("VENDOR", ztrdup(VENDOR));
       
   732     setsparam("ZSH_NAME", ztrdup(zsh_name));
       
   733     setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION));
       
   734     setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));
       
   735     for (t = sigs; (*sigptr++ = ztrdup(*t++)); );
       
   736 
       
   737     noerrs = 0;
       
   738 }
       
   739 
       
   740 /* assign various functions used for non-special parameters */
       
   741 
       
   742 /**/
       
   743 static void
       
   744 assigngetset(Param pm)
       
   745 {
       
   746     switch (PM_TYPE(pm->flags)) {
       
   747     case PM_SCALAR:
       
   748 	pm->gsu.s = &stdscalar_gsu;
       
   749 	break;
       
   750     case PM_INTEGER:
       
   751 	pm->gsu.i = &stdinteger_gsu;
       
   752 	break;
       
   753     case PM_EFLOAT:
       
   754     case PM_FFLOAT:
       
   755 	pm->gsu.f = &stdfloat_gsu;
       
   756 	break;
       
   757     case PM_ARRAY:
       
   758 	pm->gsu.a = &stdarray_gsu;
       
   759 	break;
       
   760     case PM_HASHED:
       
   761 	pm->gsu.h = &stdhash_gsu;
       
   762 	break;
       
   763     default:
       
   764 	DPUTS(1, "BUG: tried to create param node without valid flag");
       
   765 	break;
       
   766     }
       
   767 }
       
   768 
       
   769 /* Create a parameter, so that it can be assigned to.  Returns NULL if the *
       
   770  * parameter already exists or can't be created, otherwise returns the     *
       
   771  * parameter node.  If a parameter of the same name exists in an outer     *
       
   772  * scope, it is hidden by a newly created parameter.  An already existing  *
       
   773  * parameter node at the current level may be `created' and returned       *
       
   774  * provided it is unset and not special.  If the parameter can't be        *
       
   775  * created because it already exists, the PM_UNSET flag is cleared.        */
       
   776 
       
   777 /**/
       
   778 mod_export Param
       
   779 createparam(char *name, int flags)
       
   780 {
       
   781     Param pm, oldpm;
       
   782 
       
   783     if (paramtab != realparamtab)
       
   784 	flags = (flags & ~PM_EXPORTED) | PM_HASHELEM;
       
   785 
       
   786     if (name != nulstring) {
       
   787 	oldpm = (Param) (paramtab == realparamtab ?
       
   788 			 gethashnode2(paramtab, name) :
       
   789 			 paramtab->getnode(paramtab, name));
       
   790 
       
   791 	DPUTS(oldpm && oldpm->level > locallevel,
       
   792 	      "BUG: old local parameter not deleted");
       
   793 	if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) {
       
   794 	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
       
   795 		oldpm->flags &= ~PM_UNSET;
       
   796 		if ((oldpm->flags & PM_SPECIAL) && oldpm->ename) {
       
   797 		    Param altpm = 
       
   798 			(Param) paramtab->getnode(paramtab, oldpm->ename);
       
   799 		    if (altpm)
       
   800 			altpm->flags &= ~PM_UNSET;
       
   801 		}
       
   802 		return NULL;
       
   803 	    }
       
   804 	    if ((oldpm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
       
   805 		zerr("%s: restricted", name, 0);
       
   806 		return NULL;
       
   807 	    }
       
   808 
       
   809 	    pm = oldpm;
       
   810 	    pm->base = pm->width = 0;
       
   811 	    oldpm = pm->old;
       
   812 	} else {
       
   813 	    pm = (Param) zshcalloc(sizeof *pm);
       
   814 	    if ((pm->old = oldpm)) {
       
   815 		/*
       
   816 		 * needed to avoid freeing oldpm, but we do take it
       
   817 		 * out of the environment when it's hidden.
       
   818 		 */
       
   819 		if (oldpm->env)
       
   820 		    delenv(oldpm);
       
   821 		paramtab->removenode(paramtab, name);
       
   822 	    }
       
   823 	    paramtab->addnode(paramtab, ztrdup(name), pm);
       
   824 	}
       
   825 
       
   826 	if (isset(ALLEXPORT) && !(flags & PM_HASHELEM))
       
   827 	    flags |= PM_EXPORTED;
       
   828     } else {
       
   829 	pm = (Param) hcalloc(sizeof *pm);
       
   830 	pm->nam = nulstring;
       
   831     }
       
   832     pm->flags = flags & ~PM_LOCAL;
       
   833 
       
   834     if(!(pm->flags & PM_SPECIAL))
       
   835 	assigngetset(pm);
       
   836     return pm;
       
   837 }
       
   838 
       
   839 /* Copy a parameter */
       
   840 
       
   841 /**/
       
   842 void
       
   843 copyparam(Param tpm, Param pm, int toplevel)
       
   844 {
       
   845     /*
       
   846      * Note that tpm, into which we're copying, may not be in permanent
       
   847      * storage.  However, the values themselves are later used directly
       
   848      * to set the parameter, so must be permanently allocated (in accordance
       
   849      * with sets.?fn() usage).
       
   850      */
       
   851     tpm->flags = pm->flags;
       
   852     tpm->base = pm->base;
       
   853     tpm->width = pm->width;
       
   854     if (!toplevel)
       
   855 	tpm->flags &= ~PM_SPECIAL;
       
   856     switch (PM_TYPE(pm->flags)) {
       
   857     case PM_SCALAR:
       
   858 	tpm->u.str = ztrdup(pm->gsu.s->getfn(pm));
       
   859 	break;
       
   860     case PM_INTEGER:
       
   861 	tpm->u.val = pm->gsu.i->getfn(pm);
       
   862 	break;
       
   863     case PM_EFLOAT:
       
   864     case PM_FFLOAT:
       
   865 	tpm->u.dval = pm->gsu.f->getfn(pm);
       
   866 	break;
       
   867     case PM_ARRAY:
       
   868 	tpm->u.arr = zarrdup(pm->gsu.a->getfn(pm));
       
   869 	break;
       
   870     case PM_HASHED:
       
   871 	tpm->u.hash = copyparamtable(pm->gsu.h->getfn(pm), pm->nam);
       
   872 	break;
       
   873     }
       
   874     /*
       
   875      * If called from inside an associative array, that array is later going
       
   876      * to be passed as a real parameter, so we need the gets and sets
       
   877      * functions to be useful.  However, the saved associated array is
       
   878      * not itself special, so we just use the standard ones.
       
   879      * This is also why we switch off PM_SPECIAL.
       
   880      */
       
   881     if (!toplevel)
       
   882 	assigngetset(tpm);
       
   883 }
       
   884 
       
   885 /* Return 1 if the string s is a valid identifier, else return 0. */
       
   886 
       
   887 /**/
       
   888 mod_export int
       
   889 isident(char *s)
       
   890 {
       
   891     char *ss;
       
   892     int ne;
       
   893 
       
   894     ne = noeval;		/* save the current value of noeval     */
       
   895     if (!*s)			/* empty string is definitely not valid */
       
   896 	return 0;
       
   897 
       
   898     if (idigit(*s)) {
       
   899 	/* If the first character is `s' is a digit, then all must be */
       
   900 	for (ss = ++s; *ss; ss++)
       
   901 	    if (!idigit(*ss))
       
   902 		break;
       
   903     } else {
       
   904 	/* Find the first character in `s' not in the iident type table */
       
   905 	for (ss = s; *ss; ss++)
       
   906 	    if (!iident(*ss))
       
   907 		break;
       
   908     }
       
   909 
       
   910     /* If the next character is not [, then it is *
       
   911      * definitely not a valid identifier.         */
       
   912     if (!*ss)
       
   913 	return 1;
       
   914     if (*ss != '[')
       
   915 	return 0;
       
   916 
       
   917     /* Require balanced [ ] pairs with something between */
       
   918     if (!(ss = parse_subscript(++ss, 1)))
       
   919 	return 0;
       
   920     untokenize(s);
       
   921     return !ss[1];
       
   922 }
       
   923 
       
   924 /**/
       
   925 static zlong
       
   926 getarg(char **str, int *inv, Value v, int a2, zlong *w)
       
   927 {
       
   928     int hasbeg = 0, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash;
       
   929     int keymatch = 0, needtok = 0;
       
   930     char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt, c;
       
   931     zlong num = 1, beg = 0, r = 0;
       
   932     Patprog pprog = NULL;
       
   933 
       
   934     ishash = (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED);
       
   935 
       
   936     /* first parse any subscription flags */
       
   937     if (v->pm && (*s == '(' || *s == Inpar)) {
       
   938 	int escapes = 0;
       
   939 	int waste;
       
   940 	for (s++; *s != ')' && *s != Outpar && s != *str; s++) {
       
   941 	    switch (*s) {
       
   942 	    case 'r':
       
   943 		rev = 1;
       
   944 		keymatch = down = ind = 0;
       
   945 		break;
       
   946 	    case 'R':
       
   947 		rev = down = 1;
       
   948 		keymatch = ind = 0;
       
   949 		break;
       
   950 	    case 'k':
       
   951 		keymatch = ishash;
       
   952 		rev = 1;
       
   953 		down = ind = 0;
       
   954 		break;
       
   955 	    case 'K':
       
   956 		keymatch = ishash;
       
   957 		rev = down = 1;
       
   958 		ind = 0;
       
   959 		break;
       
   960 	    case 'i':
       
   961 		rev = ind = 1;
       
   962 		down = keymatch = 0;
       
   963 		break;
       
   964 	    case 'I':
       
   965 		rev = ind = down = 1;
       
   966 		keymatch = 0;
       
   967 		break;
       
   968 	    case 'w':
       
   969 		/* If the parameter is a scalar, then make subscription *
       
   970 		 * work on a per-word basis instead of characters.      */
       
   971 		word = 1;
       
   972 		break;
       
   973 	    case 'f':
       
   974 		word = 1;
       
   975 		sep = "\n";
       
   976 		break;
       
   977 	    case 'e':
       
   978 		/* Compatibility flag with no effect except to prevent *
       
   979 		 * special interpretation by getindex() of `*' or `@'. */
       
   980 		break;
       
   981 	    case 'n':
       
   982 		t = get_strarg(++s);
       
   983 		if (!*t)
       
   984 		    goto flagerr;
       
   985 		sav = *t;
       
   986 		*t = '\0';
       
   987 		num = mathevalarg(s + 1, &d);
       
   988 		if (!num)
       
   989 		    num = 1;
       
   990 		*t = sav;
       
   991 		s = t;
       
   992 		break;
       
   993 	    case 'b':
       
   994 		hasbeg = 1;
       
   995 		t = get_strarg(++s);
       
   996 		if (!*t)
       
   997 		    goto flagerr;
       
   998 		sav = *t;
       
   999 		*t = '\0';
       
  1000 		if ((beg = mathevalarg(s + 1, &d)) > 0)
       
  1001 		    beg--;
       
  1002 		*t = sav;
       
  1003 		s = t;
       
  1004 		break;
       
  1005 	    case 'p':
       
  1006 		escapes = 1;
       
  1007 		break;
       
  1008 	    case 's':
       
  1009 		/* This gives the string that separates words *
       
  1010 		 * (for use with the `w' flag).               */
       
  1011 		t = get_strarg(++s);
       
  1012 		if (!*t)
       
  1013 		    goto flagerr;
       
  1014 		sav = *t;
       
  1015 		*t = '\0';
       
  1016 		sep = escapes ? getkeystring(s + 1, &waste, 1, &waste) :
       
  1017 				dupstring(s + 1);
       
  1018 		*t = sav;
       
  1019 		s = t;
       
  1020 		break;
       
  1021 	    default:
       
  1022 	      flagerr:
       
  1023 		num = 1;
       
  1024 		word = rev = ind = down = keymatch = 0;
       
  1025 		sep = NULL;
       
  1026 		s = *str - 1;
       
  1027 	    }
       
  1028 	}
       
  1029 	if (s != *str)
       
  1030 	    s++;
       
  1031     }
       
  1032     if (num < 0) {
       
  1033 	down = !down;
       
  1034 	num = -num;
       
  1035     }
       
  1036     if (v->isarr & SCANPM_WANTKEYS)
       
  1037 	*inv = (ind || !(v->isarr & SCANPM_WANTVALS));
       
  1038     else if (v->isarr & SCANPM_WANTVALS)
       
  1039 	*inv = 0;
       
  1040     else {
       
  1041 	if (v->isarr) {
       
  1042 	    if (ind) {
       
  1043 		v->isarr |= SCANPM_WANTKEYS;
       
  1044 		v->isarr &= ~SCANPM_WANTVALS;
       
  1045 	    } else if (rev)
       
  1046 		v->isarr |= SCANPM_WANTVALS;
       
  1047 	    if (!down && !keymatch && ishash)
       
  1048 		v->isarr &= ~SCANPM_MATCHMANY;
       
  1049 	}
       
  1050 	*inv = ind;
       
  1051     }
       
  1052 
       
  1053     for (t = s, i = 0;
       
  1054 	 (c = *t) && ((c != Outbrack &&
       
  1055 		       (ishash || c != ',')) || i); t++) {
       
  1056 	/* Untokenize INULL() except before brackets and double-quotes */
       
  1057 	if (INULL(c)) {
       
  1058 	    c = t[1];
       
  1059 	    if (c == '[' || c == ']' ||
       
  1060 		c == '(' || c == ')' ||
       
  1061 		c == '{' || c == '}') {
       
  1062 		/* This test handles nested subscripts in hash keys */
       
  1063 		if (ishash && i)
       
  1064 		    *t = ztokens[*t - Pound];
       
  1065 		needtok = 1;
       
  1066 		++t;
       
  1067 	    } else if (c != '"')
       
  1068 		*t = ztokens[*t - Pound];
       
  1069 	    continue;
       
  1070 	}
       
  1071 	/* Inbrack and Outbrack are probably never found here ... */
       
  1072 	if (c == '[' || c == Inbrack)
       
  1073 	    i++;
       
  1074 	else if (c == ']' || c == Outbrack)
       
  1075 	    i--;
       
  1076 	if (ispecial(c))
       
  1077 	    needtok = 1;
       
  1078     }
       
  1079     if (!c)
       
  1080 	return 0;
       
  1081     s = dupstrpfx(s, t - s);
       
  1082     *str = tt = t;
       
  1083     /* If we're NOT reverse subscripting, strip the INULL()s so brackets *
       
  1084      * are not backslashed after parsestr().  Otherwise leave them alone *
       
  1085      * so that the brackets will be escaped when we patcompile() or when *
       
  1086      * subscript arithmetic is performed (for nested subscripts).        */
       
  1087     if (ishash && (keymatch || !rev))
       
  1088 	remnulargs(s);
       
  1089     if (needtok) {
       
  1090 	if (parsestr(s))
       
  1091 	    return 0;
       
  1092 	singsub(&s);
       
  1093     } else if (rev)
       
  1094 	remnulargs(s);	/* This is probably always a no-op, but ... */
       
  1095     if (!rev) {
       
  1096 	if (ishash) {
       
  1097 	    HashTable ht = v->pm->gsu.h->getfn(v->pm);
       
  1098 	    if (!ht) {
       
  1099 		ht = newparamtable(17, v->pm->nam);
       
  1100 		v->pm->gsu.h->setfn(v->pm, ht);
       
  1101 	    }
       
  1102 	    untokenize(s);
       
  1103 	    if (!(v->pm = (Param) ht->getnode(ht, s))) {
       
  1104 		HashTable tht = paramtab;
       
  1105 		paramtab = ht;
       
  1106 		v->pm = createparam(s, PM_SCALAR|PM_UNSET);
       
  1107 		paramtab = tht;
       
  1108 	    }
       
  1109 	    v->isarr = (*inv ? SCANPM_WANTINDEX : 0);
       
  1110 	    v->start = 0;
       
  1111 	    *inv = 0;	/* We've already obtained the "index" (key) */
       
  1112 	    *w = v->end = -1;
       
  1113 	    r = isset(KSHARRAYS) ? 1 : 0;
       
  1114 	} else {
       
  1115 	    r = mathevalarg(s, &s);
       
  1116 	    if (isset(KSHARRAYS) && r >= 0)
       
  1117 		r++;
       
  1118 	}
       
  1119 	if (word && !v->isarr) {
       
  1120 	    s = t = getstrvalue(v);
       
  1121 	    i = wordcount(s, sep, 0);
       
  1122 	    if (r < 0)
       
  1123 		r += i + 1;
       
  1124 	    if (r < 1)
       
  1125 		r = 1;
       
  1126 	    if (r > i)
       
  1127 		r = i;
       
  1128 	    if (!s || !*s)
       
  1129 		return 0;
       
  1130 	    while ((d = findword(&s, sep)) && --r);
       
  1131 	    if (!d)
       
  1132 		return 0;
       
  1133 
       
  1134 	    if (!a2 && *tt != ',')
       
  1135 		*w = (zlong)(s - t);
       
  1136 
       
  1137 	    return (a2 ? s : d + 1) - t;
       
  1138 	} else if (!v->isarr && !word) {
       
  1139 	    s = getstrvalue(v);
       
  1140 	    if (r > 0) {
       
  1141 		for (t = s + r - 1; *s && s < t;)
       
  1142 		    if (*s++ == Meta)
       
  1143 			s++, t++, r++;
       
  1144 	    } else {
       
  1145 		r += ztrlen(s);
       
  1146 		for (t = s + r; *s && s < t; r--)
       
  1147 		    if (*s++ == Meta)
       
  1148 			t++, r++;
       
  1149 		r -= strlen(s);
       
  1150 	    }
       
  1151 	}
       
  1152     } else {
       
  1153 	if (!v->isarr && !word) {
       
  1154 	    l = strlen(s);
       
  1155 	    if (a2) {
       
  1156 		if (!l || *s != '*') {
       
  1157 		    d = (char *) hcalloc(l + 2);
       
  1158 		    *d = '*';
       
  1159 		    strcpy(d + 1, s);
       
  1160 		    s = d;
       
  1161 		}
       
  1162 	    } else {
       
  1163 		if (!l || s[l - 1] != '*' || (l > 1 && s[l - 2] == '\\')) {
       
  1164 		    d = (char *) hcalloc(l + 2);
       
  1165 		    strcpy(d, s);
       
  1166 		    strcat(d, "*");
       
  1167 		    s = d;
       
  1168 		}
       
  1169 	    }
       
  1170 	}
       
  1171 	if (!keymatch) {
       
  1172 	    tokenize(s);
       
  1173 	    remnulargs(s);
       
  1174 	}
       
  1175 
       
  1176 	if (keymatch || (pprog = patcompile(s, 0, NULL))) {
       
  1177 	    int len;
       
  1178 
       
  1179 	    if (v->isarr) {
       
  1180 		if (ishash) {
       
  1181 		    scanprog = pprog;
       
  1182 		    scanstr = s;
       
  1183 		    if (keymatch)
       
  1184 			v->isarr |= SCANPM_KEYMATCH;
       
  1185 		    else if (ind)
       
  1186 			v->isarr |= SCANPM_MATCHKEY;
       
  1187 		    else
       
  1188 			v->isarr |= SCANPM_MATCHVAL;
       
  1189 		    if (down)
       
  1190 			v->isarr |= SCANPM_MATCHMANY;
       
  1191 		    if ((ta = getvaluearr(v)) &&
       
  1192 			(*ta || ((v->isarr & SCANPM_MATCHMANY) &&
       
  1193 				 (v->isarr & (SCANPM_MATCHKEY | SCANPM_MATCHVAL |
       
  1194 					      SCANPM_KEYMATCH))))) {
       
  1195 			*inv = v->inv;
       
  1196 			*w = v->end;
       
  1197 			return 1;
       
  1198 		    }
       
  1199 		} else
       
  1200 		    ta = getarrvalue(v);
       
  1201 		if (!ta || !*ta)
       
  1202 		    return 0;
       
  1203 		len = arrlen(ta);
       
  1204 		if (beg < 0)
       
  1205 		    beg += len;
       
  1206 		if (beg >= 0 && beg < len) {
       
  1207 		    if (down) {
       
  1208 			if (!hasbeg)
       
  1209 			    beg = len - 1;
       
  1210 			for (r = 1 + beg, p = ta + beg; p >= ta; r--, p--) {
       
  1211 			    if (pattry(pprog, *p) && !--num)
       
  1212 				return r;
       
  1213 			}
       
  1214 		    } else
       
  1215 			for (r = 1 + beg, p = ta + beg; *p; r++, p++)
       
  1216 			    if (pattry(pprog, *p) && !--num)
       
  1217 				return r;
       
  1218 		}
       
  1219 	    } else if (word) {
       
  1220 		ta = sepsplit(d = s = getstrvalue(v), sep, 1, 1);
       
  1221 		len = arrlen(ta);
       
  1222 		if (beg < 0)
       
  1223 		    beg += len;
       
  1224 		if (beg >= 0 && beg < len) {
       
  1225 		    if (down) {
       
  1226 			if (!hasbeg)
       
  1227 			    beg = len - 1;
       
  1228 			for (r = 1 + beg, p = ta + beg; p >= ta; p--, r--)
       
  1229 			    if (pattry(pprog, *p) && !--num)
       
  1230 				break;
       
  1231 			if (p < ta)
       
  1232 			    return 0;
       
  1233 		    } else {
       
  1234 			for (r = 1 + beg, p = ta + beg; *p; r++, p++)
       
  1235 			    if (pattry(pprog, *p) && !--num)
       
  1236 				break;
       
  1237 			if (!*p)
       
  1238 			    return 0;
       
  1239 		    }
       
  1240 		}
       
  1241 		if (a2)
       
  1242 		    r++;
       
  1243 		for (i = 0; (t = findword(&d, sep)) && *t; i++)
       
  1244 		    if (!--r) {
       
  1245 			r = (zlong)(t - s + (a2 ? -1 : 1));
       
  1246 			if (!a2 && *tt != ',')
       
  1247 			    *w = r + strlen(ta[i]) - 1;
       
  1248 			return r;
       
  1249 		    }
       
  1250 		return a2 ? -1 : 0;
       
  1251 	    } else {
       
  1252 		d = getstrvalue(v);
       
  1253 		if (!d || !*d)
       
  1254 		    return 0;
       
  1255 		len = strlen(d);
       
  1256 		if (beg < 0)
       
  1257 		    beg += len;
       
  1258 		if (beg >= 0 && beg < len) {
       
  1259                     char *de = d + len;
       
  1260 
       
  1261 		    if (a2) {
       
  1262 			if (down) {
       
  1263 			    if (!hasbeg)
       
  1264 				beg = len;
       
  1265 			    for (r = beg, t = d + beg; t >= d; r--, t--) {
       
  1266 				sav = *t;
       
  1267 				*t = '\0';
       
  1268 				if (pattry(pprog, d)
       
  1269 				    && !--num) {
       
  1270 				    *t = sav;
       
  1271 				    return r;
       
  1272 				}
       
  1273 				*t = sav;
       
  1274 			    }
       
  1275 			} else
       
  1276 			    for (r = beg, t = d + beg; t <= de; r++, t++) {
       
  1277 				sav = *t;
       
  1278 				*t = '\0';
       
  1279 				if (pattry(pprog, d) &&
       
  1280 				    !--num) {
       
  1281 				    *t = sav;
       
  1282 				    return r;
       
  1283 				}
       
  1284 				*t = sav;
       
  1285 			    }
       
  1286 		    } else {
       
  1287 			if (down) {
       
  1288 			    if (!hasbeg)
       
  1289 				beg = len;
       
  1290 			    for (r = beg + 1, t = d + beg; t >= d; r--, t--) {
       
  1291 				if (pattry(pprog, t) &&
       
  1292 				    !--num)
       
  1293 				    return r;
       
  1294 			    }
       
  1295 			} else
       
  1296 			    for (r = beg + 1, t = d + beg; t <= de; r++, t++)
       
  1297 				if (pattry(pprog, t) &&
       
  1298 				    !--num)
       
  1299 				    return r;
       
  1300 		    }
       
  1301 		}
       
  1302 		return down ? 0 : len + 1;
       
  1303 	    }
       
  1304 	}
       
  1305     }
       
  1306     return r;
       
  1307 }
       
  1308 
       
  1309 /**/
       
  1310 int
       
  1311 getindex(char **pptr, Value v, int dq)
       
  1312 {
       
  1313     int start, end, inv = 0;
       
  1314     char *s = *pptr, *tbrack;
       
  1315 
       
  1316     *s++ = '[';
       
  1317     s = parse_subscript(s, dq);	/* Error handled after untokenizing */
       
  1318     /* Now we untokenize everything except INULL() markers so we can check *
       
  1319      * for the '*' and '@' special subscripts.  The INULL()s are removed  *
       
  1320      * in getarg() after we know whether we're doing reverse indexing.    */
       
  1321     for (tbrack = *pptr + 1; *tbrack && tbrack != s; tbrack++) {
       
  1322 	if (INULL(*tbrack) && !*++tbrack)
       
  1323 	    break;
       
  1324 	if (itok(*tbrack))	/* Need to check for Nularg here? */
       
  1325 	    *tbrack = ztokens[*tbrack - Pound];
       
  1326     }
       
  1327     /* If we reached the end of the string (s == NULL) we have an error */
       
  1328     if (*tbrack)
       
  1329 	*tbrack = Outbrack;
       
  1330     else {
       
  1331 	zerr("invalid subscript", NULL, 0);
       
  1332 	*pptr = tbrack;
       
  1333 	return 1;
       
  1334     }
       
  1335     s = *pptr + 1;
       
  1336     if ((s[0] == '*' || s[0] == '@') && s + 1 == tbrack) {
       
  1337 	if ((v->isarr || IS_UNSET_VALUE(v)) && s[0] == '@')
       
  1338 	    v->isarr |= SCANPM_ISVAR_AT;
       
  1339 	v->start = 0;
       
  1340 	v->end = -1;
       
  1341 	s += 2;
       
  1342     } else {
       
  1343 	zlong we = 0, dummy;
       
  1344 
       
  1345 	start = getarg(&s, &inv, v, 0, &we);
       
  1346 
       
  1347 	if (inv) {
       
  1348 	    if (!v->isarr && start != 0) {
       
  1349 		char *t, *p;
       
  1350 		t = getstrvalue(v);
       
  1351 		if (start > 0) {
       
  1352 		    for (p = t + start - 1; p-- > t; )
       
  1353 			if (*p == Meta)
       
  1354 			    start--;
       
  1355 		} else
       
  1356 		    start = -ztrlen(t + start + strlen(t));
       
  1357 	    }
       
  1358 	    if (start > 0 && (isset(KSHARRAYS) || (v->pm->flags & PM_HASHED)))
       
  1359 		start--;
       
  1360 	    if (v->isarr != SCANPM_WANTINDEX) {
       
  1361 		v->inv = 1;
       
  1362 		v->isarr = 0;
       
  1363 		v->start = start;
       
  1364 		v->end = start + 1;
       
  1365 	    }
       
  1366 	    if (*s == ',') {
       
  1367 		zerr("invalid subscript", NULL, 0);
       
  1368 		*tbrack = ']';
       
  1369 		*pptr = tbrack+1;
       
  1370 		return 1;
       
  1371 	    }
       
  1372 	    if (s == tbrack)
       
  1373 		s++;
       
  1374 	} else {
       
  1375 	    int com;
       
  1376 
       
  1377 	    if ((com = (*s == ','))) {
       
  1378 		s++;
       
  1379 		end = getarg(&s, &inv, v, 1, &dummy);
       
  1380 	    } else {
       
  1381 		end = we ? we : start;
       
  1382 	    }
       
  1383 	    if (start != end) com = 1;
       
  1384 	    if (start > 0)
       
  1385 		start--;
       
  1386 	    else if (start == 0 && end == 0)
       
  1387 		end++;
       
  1388 	    if (s == tbrack) {
       
  1389 		s++;
       
  1390 		if (v->isarr && !com &&
       
  1391 		    (!(v->isarr & SCANPM_MATCHMANY) ||
       
  1392 		     !(v->isarr & (SCANPM_MATCHKEY | SCANPM_MATCHVAL |
       
  1393 				   SCANPM_KEYMATCH))))
       
  1394 		    v->isarr = 0;
       
  1395 		v->start = start;
       
  1396 		v->end = end;
       
  1397 	    } else
       
  1398 		s = *pptr;
       
  1399 	}
       
  1400     }
       
  1401     *tbrack = ']';
       
  1402     *pptr = s;
       
  1403     return 0;
       
  1404 }
       
  1405 
       
  1406 
       
  1407 /**/
       
  1408 mod_export Value
       
  1409 getvalue(Value v, char **pptr, int bracks)
       
  1410 {
       
  1411   return fetchvalue(v, pptr, bracks, 0);
       
  1412 }
       
  1413 
       
  1414 /**/
       
  1415 mod_export Value
       
  1416 fetchvalue(Value v, char **pptr, int bracks, int flags)
       
  1417 {
       
  1418     char *s, *t;
       
  1419     char sav, c;
       
  1420     int ppar = 0;
       
  1421 
       
  1422     s = t = *pptr;
       
  1423 
       
  1424     if (idigit(c = *s)) {
       
  1425 	if (bracks >= 0)
       
  1426 	    ppar = zstrtol(s, &s, 10);
       
  1427 	else
       
  1428 	    ppar = *s++ - '0';
       
  1429     }
       
  1430     else if (iident(c))
       
  1431 	while (iident(*s))
       
  1432 	    s++;
       
  1433     else if (c == Quest)
       
  1434 	*s++ = '?';
       
  1435     else if (c == Pound)
       
  1436 	*s++ = '#';
       
  1437     else if (c == String)
       
  1438 	*s++ = '$';
       
  1439     else if (c == Qstring)
       
  1440 	*s++ = '$';
       
  1441     else if (c == Star)
       
  1442 	*s++ = '*';
       
  1443     else if (c == '#' || c == '-' || c == '?' || c == '$' ||
       
  1444 	     c == '!' || c == '@' || c == '*')
       
  1445 	s++;
       
  1446     else
       
  1447 	return NULL;
       
  1448 
       
  1449     if ((sav = *s))
       
  1450 	*s = '\0';
       
  1451     if (ppar) {
       
  1452 	if (v)
       
  1453 	    memset(v, 0, sizeof(*v));
       
  1454 	else
       
  1455 	    v = (Value) hcalloc(sizeof *v);
       
  1456 	v->pm = argvparam;
       
  1457 	v->inv = 0;
       
  1458 	v->start = ppar - 1;
       
  1459 	v->end = ppar;
       
  1460 	if (sav)
       
  1461 	    *s = sav;
       
  1462     } else {
       
  1463 	Param pm;
       
  1464 	int isvarat;
       
  1465 
       
  1466         isvarat = (t[0] == '@' && !t[1]);
       
  1467 	pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
       
  1468 	if (sav)
       
  1469 	    *s = sav;
       
  1470 	*pptr = s;
       
  1471 	if (!pm || (pm->flags & PM_UNSET))
       
  1472 	    return NULL;
       
  1473 	if (v)
       
  1474 	    memset(v, 0, sizeof(*v));
       
  1475 	else
       
  1476 	    v = (Value) hcalloc(sizeof *v);
       
  1477 	if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)) {
       
  1478 	    /* Overload v->isarr as the flag bits for hashed arrays. */
       
  1479 	    v->isarr = flags | (isvarat ? SCANPM_ISVAR_AT : 0);
       
  1480 	    /* If no flags were passed, we need something to represent *
       
  1481 	     * `true' yet differ from an explicit WANTVALS.  This is a *
       
  1482 	     * bit of a hack, but makes some sense:  When no subscript *
       
  1483 	     * is provided, all values are substituted.                */
       
  1484 	    if (!v->isarr)
       
  1485 		v->isarr = SCANPM_MATCHMANY;
       
  1486 	}
       
  1487 	v->pm = pm;
       
  1488 	v->inv = 0;
       
  1489 	v->start = 0;
       
  1490 	v->end = -1;
       
  1491 	if (bracks > 0 && (*s == '[' || *s == Inbrack)) {
       
  1492 	    if (getindex(&s, v, (flags & SCANPM_DQUOTED))) {
       
  1493 		*pptr = s;
       
  1494 		return v;
       
  1495 	    }
       
  1496 	} else if (!(flags & SCANPM_ASSIGNING) && v->isarr &&
       
  1497 		   iident(*t) && isset(KSHARRAYS))
       
  1498 	    v->end = 1, v->isarr = 0;
       
  1499     }
       
  1500     if (!bracks && *s)
       
  1501 	return NULL;
       
  1502     *pptr = s;
       
  1503     if (v->start > MAX_ARRLEN) {
       
  1504 	zerr("subscript too %s: %d", "big", v->start + !isset(KSHARRAYS));
       
  1505 	return NULL;
       
  1506     }
       
  1507     if (v->start < -MAX_ARRLEN) {
       
  1508 	zerr("subscript too %s: %d", "small", v->start);
       
  1509 	return NULL;
       
  1510     }
       
  1511     if (v->end > MAX_ARRLEN+1) {
       
  1512 	zerr("subscript too %s: %d", "big", v->end - !!isset(KSHARRAYS));
       
  1513 	return NULL;
       
  1514     }
       
  1515     if (v->end < -MAX_ARRLEN) {
       
  1516 	zerr("subscript too %s: %d", "small", v->end);
       
  1517 	return NULL;
       
  1518     }
       
  1519     return v;
       
  1520 }
       
  1521 
       
  1522 /**/
       
  1523 mod_export char *
       
  1524 getstrvalue(Value v)
       
  1525 {
       
  1526     char *s, **ss;
       
  1527     char buf[BDIGBUFSIZE];
       
  1528 
       
  1529     if (!v)
       
  1530 	return hcalloc(1);
       
  1531 
       
  1532     if (v->inv && !(v->pm->flags & PM_HASHED)) {
       
  1533 	sprintf(buf, "%d", v->start);
       
  1534 	s = dupstring(buf);
       
  1535 	return s;
       
  1536     }
       
  1537 
       
  1538     switch(PM_TYPE(v->pm->flags)) {
       
  1539     case PM_HASHED:
       
  1540 	/* (!v->isarr) should be impossible unless emulating ksh */
       
  1541 	if (!v->isarr && emulation == EMULATE_KSH) {
       
  1542 	    s = dupstring("[0]");
       
  1543 	    if (getindex(&s, v, 0) == 0)
       
  1544 		s = getstrvalue(v);
       
  1545 	    return s;
       
  1546 	} /* else fall through */
       
  1547     case PM_ARRAY:
       
  1548 	ss = getvaluearr(v);
       
  1549 	if (v->isarr)
       
  1550 	    s = sepjoin(ss, NULL, 1);
       
  1551 	else {
       
  1552 	    if (v->start < 0)
       
  1553 		v->start += arrlen(ss);
       
  1554 	    s = (v->start >= arrlen(ss) || v->start < 0) ?
       
  1555 		(char *) hcalloc(1) : ss[v->start];
       
  1556 	}
       
  1557 	return s;
       
  1558     case PM_INTEGER:
       
  1559 	convbase(buf, v->pm->gsu.i->getfn(v->pm), v->pm->base);
       
  1560 	s = dupstring(buf);
       
  1561 	break;
       
  1562     case PM_EFLOAT:
       
  1563     case PM_FFLOAT:
       
  1564 	s = convfloat(v->pm->gsu.f->getfn(v->pm),
       
  1565 		      v->pm->base, v->pm->flags, NULL);
       
  1566 	break;
       
  1567     case PM_SCALAR:
       
  1568 	s = v->pm->gsu.s->getfn(v->pm);
       
  1569 	break;
       
  1570     default:
       
  1571 	s = NULL;
       
  1572 	DPUTS(1, "BUG: param node without valid type");
       
  1573 	break;
       
  1574     }
       
  1575 
       
  1576     if (v->start == 0 && v->end == -1)
       
  1577 	return s;
       
  1578 
       
  1579     if (v->start < 0) {
       
  1580 	v->start += strlen(s);
       
  1581 	if (v->start < 0)
       
  1582 	    v->start = 0;
       
  1583     }
       
  1584     if (v->end < 0)
       
  1585 	v->end += strlen(s) + 1;
       
  1586     s = (v->start > (int)strlen(s)) ? dupstring("") : dupstring(s + v->start);
       
  1587     if (v->end <= v->start)
       
  1588 	s[0] = '\0';
       
  1589     else if (v->end - v->start <= (int)strlen(s))
       
  1590 	s[v->end - v->start + (s[v->end - v->start - 1] == Meta)] = '\0';
       
  1591 
       
  1592     return s;
       
  1593 }
       
  1594 
       
  1595 static char *nular[] = {"", NULL};
       
  1596 
       
  1597 /**/
       
  1598 mod_export char **
       
  1599 getarrvalue(Value v)
       
  1600 {
       
  1601     char **s;
       
  1602 
       
  1603     if (!v)
       
  1604 	return arrdup(nular);
       
  1605     else if (IS_UNSET_VALUE(v))
       
  1606 	return arrdup(&nular[1]);
       
  1607     if (v->inv) {
       
  1608 	char buf[DIGBUFSIZE];
       
  1609 
       
  1610 	s = arrdup(nular);
       
  1611 	sprintf(buf, "%d", v->start);
       
  1612 	s[0] = dupstring(buf);
       
  1613 	return s;
       
  1614     }
       
  1615     s = getvaluearr(v);
       
  1616     if (v->start == 0 && v->end == -1)
       
  1617 	return s;
       
  1618     if (v->start < 0)
       
  1619 	v->start += arrlen(s);
       
  1620     if (v->end < 0)
       
  1621 	v->end += arrlen(s) + 1;
       
  1622     if (v->start > arrlen(s) || v->start < 0)
       
  1623 	s = arrdup(nular);
       
  1624     else
       
  1625 	s = arrdup(s + v->start);
       
  1626     if (v->end <= v->start)
       
  1627 	s[0] = NULL;
       
  1628     else if (v->end - v->start <= arrlen(s))
       
  1629 	s[v->end - v->start] = NULL;
       
  1630     return s;
       
  1631 }
       
  1632 
       
  1633 /**/
       
  1634 mod_export zlong
       
  1635 getintvalue(Value v)
       
  1636 {
       
  1637     if (!v || v->isarr)
       
  1638 	return 0;
       
  1639     if (v->inv)
       
  1640 	return v->start;
       
  1641     if (PM_TYPE(v->pm->flags) == PM_INTEGER)
       
  1642 	return v->pm->gsu.i->getfn(v->pm);
       
  1643     if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT))
       
  1644 	return (zlong)v->pm->gsu.f->getfn(v->pm);
       
  1645     return mathevali(getstrvalue(v));
       
  1646 }
       
  1647 
       
  1648 /**/
       
  1649 mnumber
       
  1650 getnumvalue(Value v)
       
  1651 {
       
  1652     mnumber mn;
       
  1653     mn.type = MN_INTEGER;
       
  1654 
       
  1655     if (!v || v->isarr) {
       
  1656 	mn.u.l = 0;
       
  1657     } else if (v->inv) {
       
  1658 	mn.u.l = v->start;
       
  1659     } else if (PM_TYPE(v->pm->flags) == PM_INTEGER) {
       
  1660 	mn.u.l = v->pm->gsu.i->getfn(v->pm);
       
  1661     } else if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) {
       
  1662 	mn.type = MN_FLOAT;
       
  1663 	mn.u.d = v->pm->gsu.f->getfn(v->pm);
       
  1664     } else
       
  1665 	return matheval(getstrvalue(v));
       
  1666     return mn;
       
  1667 }
       
  1668 
       
  1669 /**/
       
  1670 void
       
  1671 export_param(Param pm)
       
  1672 {
       
  1673     char buf[BDIGBUFSIZE], *val;
       
  1674 
       
  1675     if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)) {
       
  1676 #if 0	/* Requires changes elsewhere in params.c and builtin.c */
       
  1677 	if (emulation == EMULATE_KSH /* isset(KSHARRAYS) */) {
       
  1678 	    struct value v;
       
  1679 	    v.isarr = 1;
       
  1680 	    v.inv = 0;
       
  1681 	    v.start = 0;
       
  1682 	    v.end = -1;
       
  1683 	    val = getstrvalue(&v);
       
  1684 	} else
       
  1685 #endif
       
  1686 	    return;
       
  1687     } else if (PM_TYPE(pm->flags) == PM_INTEGER)
       
  1688 	convbase(val = buf, pm->gsu.i->getfn(pm), pm->base);
       
  1689     else if (pm->flags & (PM_EFLOAT|PM_FFLOAT))
       
  1690 	val = convfloat(pm->gsu.f->getfn(pm), pm->base,
       
  1691 			pm->flags, NULL);
       
  1692     else
       
  1693 	val = pm->gsu.s->getfn(pm);
       
  1694 
       
  1695     addenv(pm, val);
       
  1696 }
       
  1697 
       
  1698 /**/
       
  1699 mod_export void
       
  1700 setstrvalue(Value v, char *val)
       
  1701 {
       
  1702     if (v->pm->flags & PM_READONLY) {
       
  1703 	zerr("read-only variable: %s", v->pm->nam, 0);
       
  1704 	zsfree(val);
       
  1705 	return;
       
  1706     }
       
  1707     if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
       
  1708 	zerr("%s: restricted", v->pm->nam, 0);
       
  1709 	zsfree(val);
       
  1710 	return;
       
  1711     }
       
  1712     if ((v->pm->flags & PM_HASHED) && (v->isarr & SCANPM_MATCHMANY)) {
       
  1713 	zerr("%s: attempt to set slice of associative array", v->pm->nam, 0);
       
  1714 	zsfree(val);
       
  1715 	return;
       
  1716     }
       
  1717     v->pm->flags &= ~PM_UNSET;
       
  1718     switch (PM_TYPE(v->pm->flags)) {
       
  1719     case PM_SCALAR:
       
  1720 	if (v->start == 0 && v->end == -1) {
       
  1721 	    v->pm->gsu.s->setfn(v->pm, val);
       
  1722 	    if ((v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
       
  1723 		!v->pm->width)
       
  1724 		v->pm->width = strlen(val);
       
  1725 	} else {
       
  1726 	    char *z, *x;
       
  1727 	    int zlen;
       
  1728 
       
  1729 	    z = dupstring(v->pm->gsu.s->getfn(v->pm));
       
  1730 	    zlen = strlen(z);
       
  1731 	    if (v->inv && unset(KSHARRAYS))
       
  1732 		v->start--, v->end--;
       
  1733 	    if (v->start < 0) {
       
  1734 		v->start += zlen;
       
  1735 		if (v->start < 0)
       
  1736 		    v->start = 0;
       
  1737 	    }
       
  1738 	    if (v->start > zlen)
       
  1739 		v->start = zlen;
       
  1740 	    if (v->end < 0)
       
  1741 		v->end += zlen + 1;
       
  1742 	    else if (v->end > zlen)
       
  1743 		v->end = zlen;
       
  1744 	    x = (char *) zalloc(v->start + strlen(val) + zlen - v->end + 1);
       
  1745 	    strncpy(x, z, v->start);
       
  1746 	    strcpy(x + v->start, val);
       
  1747 	    strcat(x + v->start, z + v->end);
       
  1748 	    v->pm->gsu.s->setfn(v->pm, x);
       
  1749 	    zsfree(val);
       
  1750 	}
       
  1751 	break;
       
  1752     case PM_INTEGER:
       
  1753 	if (val) {
       
  1754 	    v->pm->gsu.i->setfn(v->pm, mathevali(val));
       
  1755 	    zsfree(val);
       
  1756 	    if ((v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
       
  1757 		!v->pm->width)
       
  1758 		v->pm->width = strlen(val);
       
  1759 	}
       
  1760 	if (!v->pm->base && lastbase != -1)
       
  1761 	    v->pm->base = lastbase;
       
  1762 	break;
       
  1763     case PM_EFLOAT:
       
  1764     case PM_FFLOAT:
       
  1765 	if (val) {
       
  1766 	    mnumber mn = matheval(val);
       
  1767 	    v->pm->gsu.f->setfn(v->pm, (mn.type & MN_FLOAT) ? mn.u.d :
       
  1768 			       (double)mn.u.l);
       
  1769 	    zsfree(val);
       
  1770 	    if ((v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
       
  1771 		!v->pm->width)
       
  1772 		v->pm->width = strlen(val);
       
  1773 	}
       
  1774 	break;
       
  1775     case PM_ARRAY:
       
  1776 	{
       
  1777 	    char **ss = (char **) zalloc(2 * sizeof(char *));
       
  1778 
       
  1779 	    ss[0] = val;
       
  1780 	    ss[1] = NULL;
       
  1781 	    setarrvalue(v, ss);
       
  1782 	}
       
  1783 	break;
       
  1784     case PM_HASHED:
       
  1785         {
       
  1786 	    foundparam->gsu.s->setfn(foundparam, val);
       
  1787         }
       
  1788 	break;
       
  1789     }
       
  1790     if ((!v->pm->env && !(v->pm->flags & PM_EXPORTED) &&
       
  1791 	 !(isset(ALLEXPORT) && !(v->pm->flags & PM_HASHELEM))) ||
       
  1792 	(v->pm->flags & PM_ARRAY) || v->pm->ename)
       
  1793 	return;
       
  1794     export_param(v->pm);
       
  1795 }
       
  1796 
       
  1797 /**/
       
  1798 void
       
  1799 setnumvalue(Value v, mnumber val)
       
  1800 {
       
  1801     char buf[BDIGBUFSIZE], *p;
       
  1802 
       
  1803     if (v->pm->flags & PM_READONLY) {
       
  1804 	zerr("read-only variable: %s", v->pm->nam, 0);
       
  1805 	return;
       
  1806     }
       
  1807     if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
       
  1808 	zerr("%s: restricted", v->pm->nam, 0);
       
  1809 	return;
       
  1810     }
       
  1811     switch (PM_TYPE(v->pm->flags)) {
       
  1812     case PM_SCALAR:
       
  1813     case PM_ARRAY:
       
  1814 	if ((val.type & MN_INTEGER) || outputradix) {
       
  1815 	    if (!(val.type & MN_INTEGER))
       
  1816 		val.u.l = (zlong) val.u.d;
       
  1817 	    convbase(p = buf, val.u.l, outputradix);
       
  1818 	} else
       
  1819 	    p = convfloat(val.u.d, 0, 0, NULL);
       
  1820 	setstrvalue(v, ztrdup(p));
       
  1821 	break;
       
  1822     case PM_INTEGER:
       
  1823 	v->pm->gsu.i->setfn(v->pm, (val.type & MN_INTEGER) ? val.u.l :
       
  1824 			    (zlong) val.u.d);
       
  1825 	setstrvalue(v, NULL);
       
  1826 	break;
       
  1827     case PM_EFLOAT:
       
  1828     case PM_FFLOAT:
       
  1829 	v->pm->gsu.f->setfn(v->pm, (val.type & MN_INTEGER) ?
       
  1830 			    (double)val.u.l : val.u.d);
       
  1831 	setstrvalue(v, NULL);
       
  1832 	break;
       
  1833     }
       
  1834 }
       
  1835 
       
  1836 /**/
       
  1837 mod_export void
       
  1838 setarrvalue(Value v, char **val)
       
  1839 {
       
  1840     if (v->pm->flags & PM_READONLY) {
       
  1841 	zerr("read-only variable: %s", v->pm->nam, 0);
       
  1842 	freearray(val);
       
  1843 	return;
       
  1844     }
       
  1845     if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
       
  1846 	zerr("%s: restricted", v->pm->nam, 0);
       
  1847 	freearray(val);
       
  1848 	return;
       
  1849     }
       
  1850     if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED))) {
       
  1851 	freearray(val);
       
  1852 	zerr("%s: attempt to assign array value to non-array",
       
  1853 	     v->pm->nam, 0);
       
  1854 	return;
       
  1855     }
       
  1856     if (v->start == 0 && v->end == -1) {
       
  1857 	if (PM_TYPE(v->pm->flags) == PM_HASHED)
       
  1858 	    arrhashsetfn(v->pm, val, 0);
       
  1859 	else
       
  1860 	    v->pm->gsu.a->setfn(v->pm, val);
       
  1861     } else if (v->start == -1 && v->end == 0 &&
       
  1862     	    PM_TYPE(v->pm->flags) == PM_HASHED) {
       
  1863     	arrhashsetfn(v->pm, val, 1);
       
  1864     } else {
       
  1865 	char **old, **new, **p, **q, **r;
       
  1866 	int n, ll, i;
       
  1867 
       
  1868 	if ((PM_TYPE(v->pm->flags) == PM_HASHED)) {
       
  1869 	    freearray(val);
       
  1870 	    zerr("%s: attempt to set slice of associative array",
       
  1871 		 v->pm->nam, 0);
       
  1872 	    return;
       
  1873 	}
       
  1874 	if (v->inv && unset(KSHARRAYS)) {
       
  1875 	    if (v->start > 0)
       
  1876 		v->start--;
       
  1877 	    v->end--;
       
  1878 	}
       
  1879 	if (v->end < v->start)
       
  1880 	    v->end = v->start;
       
  1881 	q = old = v->pm->gsu.a->getfn(v->pm);
       
  1882 	n = arrlen(old);
       
  1883 	if (v->start < 0) {
       
  1884 	    v->start += n;
       
  1885 	    if (v->start < 0)
       
  1886 		v->start = 0;
       
  1887 	}
       
  1888 	if (v->end < 0) {
       
  1889 	    v->end += n + 1;
       
  1890 	    if (v->end < 0)
       
  1891 		v->end = 0;
       
  1892 	}
       
  1893 
       
  1894 	ll = v->start + arrlen(val);
       
  1895 	if (v->end <= n)
       
  1896 	    ll += n - v->end + 1;
       
  1897 
       
  1898 	p = new = (char **) zshcalloc(sizeof(char *) * (ll + 1));
       
  1899 
       
  1900 	for (i = 0; i < v->start; i++)
       
  1901 	    *p++ = i < n ? ztrdup(*q++) : ztrdup("");
       
  1902 	for (r = val; *r;)
       
  1903 	    *p++ = ztrdup(*r++);
       
  1904 	if (v->end < n)
       
  1905 	    for (q = old + v->end; *q;)
       
  1906 		*p++ = ztrdup(*q++);
       
  1907 	*p = NULL;
       
  1908 
       
  1909 	v->pm->gsu.a->setfn(v->pm, new);
       
  1910 	freearray(val);
       
  1911     }
       
  1912 }
       
  1913 
       
  1914 /* Retrieve an integer parameter */
       
  1915 
       
  1916 /**/
       
  1917 mod_export zlong
       
  1918 getiparam(char *s)
       
  1919 {
       
  1920     struct value vbuf;
       
  1921     Value v;
       
  1922 
       
  1923     if (!(v = getvalue(&vbuf, &s, 1)))
       
  1924 	return 0;
       
  1925     return getintvalue(v);
       
  1926 }
       
  1927 
       
  1928 /* Retrieve a numerical parameter, either integer or floating */
       
  1929 
       
  1930 /**/
       
  1931 mnumber
       
  1932 getnparam(char *s)
       
  1933 {
       
  1934     struct value vbuf;
       
  1935     Value v;
       
  1936 
       
  1937     if (!(v = getvalue(&vbuf, &s, 1))) {
       
  1938 	mnumber mn;
       
  1939 	mn.type = MN_INTEGER;
       
  1940 	mn.u.l = 0;
       
  1941 	return mn;
       
  1942     }
       
  1943     return getnumvalue(v);
       
  1944 }
       
  1945 
       
  1946 /* Retrieve a scalar (string) parameter */
       
  1947 
       
  1948 /**/
       
  1949 mod_export char *
       
  1950 getsparam(char *s)
       
  1951 {
       
  1952     struct value vbuf;
       
  1953     Value v;
       
  1954 
       
  1955     if (!(v = getvalue(&vbuf, &s, 0)))
       
  1956 	return NULL;
       
  1957     return getstrvalue(v);
       
  1958 }
       
  1959 
       
  1960 /* Retrieve an array parameter */
       
  1961 
       
  1962 /**/
       
  1963 mod_export char **
       
  1964 getaparam(char *s)
       
  1965 {
       
  1966     struct value vbuf;
       
  1967     Value v;
       
  1968 
       
  1969     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
       
  1970 	PM_TYPE(v->pm->flags) == PM_ARRAY)
       
  1971 	return v->pm->gsu.a->getfn(v->pm);
       
  1972     return NULL;
       
  1973 }
       
  1974 
       
  1975 /* Retrieve an assoc array parameter as an array */
       
  1976 
       
  1977 /**/
       
  1978 mod_export char **
       
  1979 gethparam(char *s)
       
  1980 {
       
  1981     struct value vbuf;
       
  1982     Value v;
       
  1983 
       
  1984     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
       
  1985 	PM_TYPE(v->pm->flags) == PM_HASHED)
       
  1986 	return paramvalarr(v->pm->gsu.h->getfn(v->pm), SCANPM_WANTVALS);
       
  1987     return NULL;
       
  1988 }
       
  1989 
       
  1990 /* Retrieve the keys of an assoc array parameter as an array */
       
  1991 
       
  1992 /**/
       
  1993 mod_export char **
       
  1994 gethkparam(char *s)
       
  1995 {
       
  1996     struct value vbuf;
       
  1997     Value v;
       
  1998 
       
  1999     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
       
  2000 	PM_TYPE(v->pm->flags) == PM_HASHED)
       
  2001 	return paramvalarr(v->pm->gsu.h->getfn(v->pm), SCANPM_WANTKEYS);
       
  2002     return NULL;
       
  2003 }
       
  2004 
       
  2005 /**/
       
  2006 mod_export Param
       
  2007 assignsparam(char *s, char *val, int augment)
       
  2008 {
       
  2009     struct value vbuf;
       
  2010     Value v;
       
  2011     char *t = s;
       
  2012     char *ss, *copy, *var;
       
  2013     size_t lvar;
       
  2014     mnumber lhs, rhs;
       
  2015     int sstart;
       
  2016 
       
  2017     if (!isident(s)) {
       
  2018 	zerr("not an identifier: %s", s, 0);
       
  2019 	zsfree(val);
       
  2020 	errflag = 1;
       
  2021 	return NULL;
       
  2022     }
       
  2023     queue_signals();
       
  2024     if ((ss = strchr(s, '['))) {
       
  2025 	*ss = '\0';
       
  2026 	if (!(v = getvalue(&vbuf, &s, 1)))
       
  2027 	    createparam(t, PM_ARRAY);
       
  2028 	*ss = '[';
       
  2029 	v = NULL;
       
  2030     } else {
       
  2031 	if (!(v = getvalue(&vbuf, &s, 1)))
       
  2032 	    createparam(t, PM_SCALAR);
       
  2033 	else if ((((v->pm->flags & PM_ARRAY) && !augment) ||
       
  2034 	    	 (v->pm->flags & PM_HASHED)) &&
       
  2035 		 !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && 
       
  2036 		 unset(KSHARRAYS)) {
       
  2037 	    unsetparam(t);
       
  2038 	    createparam(t, PM_SCALAR);
       
  2039 	    v = NULL;
       
  2040 	}
       
  2041     }
       
  2042     if (!v && !(v = getvalue(&vbuf, &t, 1))) {
       
  2043 	unqueue_signals();
       
  2044 	zsfree(val);
       
  2045 	return NULL;
       
  2046     }
       
  2047     if (augment) {
       
  2048 	if (v->start == 0 && v->end == -1) {
       
  2049 	    switch (PM_TYPE(v->pm->flags)) {
       
  2050 	    case PM_SCALAR:
       
  2051 		v->start = INT_MAX;  /* just append to scalar value */
       
  2052 		break;
       
  2053 	    case PM_INTEGER:
       
  2054 	    case PM_EFLOAT:
       
  2055 	    case PM_FFLOAT:
       
  2056 		rhs = matheval(val);
       
  2057 		lhs = getnumvalue(v);
       
  2058 		if (lhs.type == MN_FLOAT) {
       
  2059 		    if ((rhs.type) == MN_FLOAT)
       
  2060         		lhs.u.d = lhs.u.d + rhs.u.d;
       
  2061 		    else
       
  2062 			lhs.u.d = lhs.u.d + (double)rhs.u.l;
       
  2063 		} else {
       
  2064         	    if ((rhs.type) == MN_INTEGER)
       
  2065 			lhs.u.l = lhs.u.l + rhs.u.l;
       
  2066 		    else
       
  2067 			lhs.u.l = lhs.u.l + (zlong)rhs.u.d;
       
  2068 		}
       
  2069 		setnumvalue(v, lhs);
       
  2070     	    	unqueue_signals();
       
  2071 		zsfree(val);
       
  2072 		return v->pm; /* avoid later setstrvalue() call */
       
  2073 	    case PM_ARRAY:
       
  2074 	    	if (unset(KSHARRAYS)) {
       
  2075 		    v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
       
  2076 		    v->end = v->start + 1;
       
  2077 		} else {
       
  2078 		    /* ksh appends scalar to first element */
       
  2079 		    v->end = 1;
       
  2080 		    goto kshappend;
       
  2081 		}
       
  2082 		break;
       
  2083 	    }
       
  2084 	} else {
       
  2085 	    switch (PM_TYPE(v->pm->flags)) {
       
  2086 	    case PM_SCALAR:
       
  2087     		if (v->end > 0)
       
  2088 		    v->start = v->end;
       
  2089 		else
       
  2090 		    v->start = v->end = strlen(v->pm->gsu.s->getfn(v->pm)) +
       
  2091 			v->end + 1;
       
  2092 	    	break;
       
  2093 	    case PM_INTEGER:
       
  2094 	    case PM_EFLOAT:
       
  2095 	    case PM_FFLOAT:
       
  2096 		unqueue_signals();
       
  2097 		zerr("attempt to add to slice of a numeric variable",
       
  2098 		    NULL, 0);
       
  2099 		zsfree(val);
       
  2100 		return NULL;
       
  2101 	    case PM_ARRAY:
       
  2102 	      kshappend:
       
  2103 		/* treat slice as the end element */
       
  2104 		v->start = sstart = v->end > 0 ? v->end - 1 : v->end;
       
  2105 		v->isarr = 0;
       
  2106 		var = getstrvalue(v);
       
  2107 		v->start = sstart;
       
  2108 		copy = val;
       
  2109 		lvar = strlen(var);
       
  2110 		val = (char *)zalloc(lvar + strlen(val) + 1);
       
  2111 		strcpy(val, var);
       
  2112 		strcpy(val + lvar, copy);
       
  2113 		zsfree(copy);
       
  2114 		break;
       
  2115 	    }
       
  2116 	}
       
  2117     }
       
  2118     
       
  2119     setstrvalue(v, val);
       
  2120     unqueue_signals();
       
  2121     return v->pm;
       
  2122 }
       
  2123 
       
  2124 /**/
       
  2125 mod_export Param
       
  2126 assignaparam(char *s, char **val, int augment)
       
  2127 {
       
  2128     struct value vbuf;
       
  2129     Value v;
       
  2130     char *t = s;
       
  2131     char *ss;
       
  2132 
       
  2133     if (!isident(s)) {
       
  2134 	zerr("not an identifier: %s", s, 0);
       
  2135 	freearray(val);
       
  2136 	errflag = 1;
       
  2137 	return NULL;
       
  2138     }
       
  2139     queue_signals();
       
  2140     if ((ss = strchr(s, '['))) {
       
  2141 	*ss = '\0';
       
  2142 	if (!(v = getvalue(&vbuf, &s, 1)))
       
  2143 	    createparam(t, PM_ARRAY);
       
  2144 	*ss = '[';
       
  2145 	if (v && PM_TYPE(v->pm->flags) == PM_HASHED) {
       
  2146 	    unqueue_signals();
       
  2147 	    zerr("%s: attempt to set slice of associative array",
       
  2148 		 v->pm->nam, 0);
       
  2149 	    freearray(val);
       
  2150 	    errflag = 1;
       
  2151 	    return NULL;
       
  2152 	}
       
  2153 	v = NULL;
       
  2154     } else {
       
  2155 	if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
       
  2156 	    createparam(t, PM_ARRAY);
       
  2157 	else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
       
  2158 		 !(v->pm->flags & (PM_SPECIAL|PM_TIED))) {
       
  2159 	    int uniq = v->pm->flags & PM_UNIQUE;
       
  2160 	    if (augment) {
       
  2161 	    	/* insert old value at the beginning of the val array */
       
  2162 		char **new;
       
  2163 		int lv = arrlen(val);
       
  2164 
       
  2165 		new = (char **) zalloc(sizeof(char *) * (lv + 2));
       
  2166 		*new = ztrdup(getstrvalue(v));
       
  2167 		memcpy(new+1, val, sizeof(char *) * (lv + 1));
       
  2168 		free(val);
       
  2169 		val = new;
       
  2170 		
       
  2171 	    }
       
  2172 	    unsetparam(t);
       
  2173 	    createparam(t, PM_ARRAY | uniq);
       
  2174 	    v = NULL;
       
  2175 	}
       
  2176     }
       
  2177     if (!v)
       
  2178 	if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
       
  2179 	    unqueue_signals();
       
  2180 	    freearray(val);
       
  2181 	    return NULL;
       
  2182 	}
       
  2183 
       
  2184     if (augment) {
       
  2185     	if (v->start == 0 && v->end == -1) {
       
  2186 	    if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
       
  2187 	    	v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
       
  2188 	    	v->end = v->start + 1;
       
  2189 	    } else if (PM_TYPE(v->pm->flags) & PM_HASHED)
       
  2190 	    	v->start = -1, v->end = 0;
       
  2191 	} else {
       
  2192 	    if (v->end > 0)
       
  2193 		v->start = v->end--;
       
  2194 	    else if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
       
  2195 		v->end = arrlen(v->pm->gsu.a->getfn(v->pm)) + v->end;
       
  2196 		v->start = v->end + 1;
       
  2197 	    }
       
  2198 	}
       
  2199     }
       
  2200 
       
  2201     setarrvalue(v, val);
       
  2202     unqueue_signals();
       
  2203     return v->pm;
       
  2204 }
       
  2205 
       
  2206 /**/
       
  2207 mod_export Param
       
  2208 sethparam(char *s, char **val)
       
  2209 {
       
  2210     struct value vbuf;
       
  2211     Value v;
       
  2212     char *t = s;
       
  2213 
       
  2214     if (!isident(s)) {
       
  2215 	zerr("not an identifier: %s", s, 0);
       
  2216 	freearray(val);
       
  2217 	errflag = 1;
       
  2218 	return NULL;
       
  2219     }
       
  2220     if (strchr(s, '[')) {
       
  2221 	freearray(val);
       
  2222 	zerr("nested associative arrays not yet supported", NULL, 0);
       
  2223 	errflag = 1;
       
  2224 	return NULL;
       
  2225     }
       
  2226     queue_signals();
       
  2227     if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
       
  2228 	createparam(t, PM_HASHED);
       
  2229     else if (!(PM_TYPE(v->pm->flags) & PM_HASHED) &&
       
  2230 	     !(v->pm->flags & PM_SPECIAL)) {
       
  2231 	unsetparam(t);
       
  2232 	createparam(t, PM_HASHED);
       
  2233 	v = NULL;
       
  2234     }
       
  2235     if (!v)
       
  2236 	if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
       
  2237 	    unqueue_signals();
       
  2238 	    return NULL;
       
  2239 	}
       
  2240     setarrvalue(v, val);
       
  2241     unqueue_signals();
       
  2242     return v->pm;
       
  2243 }
       
  2244 
       
  2245 /**/
       
  2246 mod_export Param
       
  2247 setiparam(char *s, zlong val)
       
  2248 {
       
  2249     struct value vbuf;
       
  2250     Value v;
       
  2251     char *t = s, *ss;
       
  2252     Param pm;
       
  2253     mnumber mnval;
       
  2254 
       
  2255     if (!isident(s)) {
       
  2256 	zerr("not an identifier: %s", s, 0);
       
  2257 	errflag = 1;
       
  2258 	return NULL;
       
  2259     }
       
  2260     queue_signals();
       
  2261     if (!(v = getvalue(&vbuf, &s, 1))) {
       
  2262 	if ((ss = strchr(s, '[')))
       
  2263 	    *ss = '\0';
       
  2264 	if (!(pm = createparam(t, ss ? PM_ARRAY : PM_INTEGER)))
       
  2265 	    pm = (Param) paramtab->getnode(paramtab, t);
       
  2266 	DPUTS(!pm, "BUG: parameter not created");
       
  2267 	if (ss) {
       
  2268 	    *ss = '[';
       
  2269 	} else {
       
  2270 	    pm->base = outputradix;
       
  2271 	}
       
  2272 	v = getvalue(&vbuf, &t, 1);
       
  2273 	DPUTS(!v, "BUG: value not found for new parameter");
       
  2274     }
       
  2275     mnval.type = MN_INTEGER;
       
  2276     mnval.u.l = val;
       
  2277     setnumvalue(v, mnval);
       
  2278     unqueue_signals();
       
  2279     return v->pm;
       
  2280 }
       
  2281 
       
  2282 /*
       
  2283  * Like setiparam(), but can take an mnumber which can be integer or
       
  2284  * floating.
       
  2285  */
       
  2286 
       
  2287 /**/
       
  2288 Param
       
  2289 setnparam(char *s, mnumber val)
       
  2290 {
       
  2291     struct value vbuf;
       
  2292     Value v;
       
  2293     char *t = s, *ss = NULL;
       
  2294     Param pm;
       
  2295 
       
  2296     if (!isident(s)) {
       
  2297 	zerr("not an identifier: %s", s, 0);
       
  2298 	errflag = 1;
       
  2299 	return NULL;
       
  2300     }
       
  2301     queue_signals();
       
  2302     if (!(v = getvalue(&vbuf, &s, 1))) {
       
  2303 	if ((ss = strchr(s, '[')))
       
  2304 	    *ss = '\0';
       
  2305 	pm = createparam(t, ss ? PM_ARRAY :
       
  2306 			 (val.type & MN_INTEGER) ? PM_INTEGER : PM_FFLOAT);
       
  2307 	if (!pm)
       
  2308 	    pm = (Param) paramtab->getnode(paramtab, t);
       
  2309 	DPUTS(!pm, "BUG: parameter not created");
       
  2310 	if (ss) {
       
  2311 	    *ss = '[';
       
  2312 	} else if (val.type & MN_INTEGER) {
       
  2313 	    pm->base = outputradix;
       
  2314 	}
       
  2315 	v = getvalue(&vbuf, &t, 1);
       
  2316 	DPUTS(!v, "BUG: value not found for new parameter");
       
  2317     }
       
  2318     setnumvalue(v, val);
       
  2319     unqueue_signals();
       
  2320     return v->pm;
       
  2321 }
       
  2322 
       
  2323 /* Unset a parameter */
       
  2324 
       
  2325 /**/
       
  2326 mod_export void
       
  2327 unsetparam(char *s)
       
  2328 {
       
  2329     Param pm;
       
  2330 
       
  2331     queue_signals();
       
  2332     if ((pm = (Param) (paramtab == realparamtab ?
       
  2333 		       gethashnode2(paramtab, s) :
       
  2334 		       paramtab->getnode(paramtab, s))))
       
  2335 	unsetparam_pm(pm, 0, 1);
       
  2336     unqueue_signals();
       
  2337 }
       
  2338 
       
  2339 /* Unset a parameter */
       
  2340 
       
  2341 /**/
       
  2342 mod_export int
       
  2343 unsetparam_pm(Param pm, int altflag, int exp)
       
  2344 {
       
  2345     Param oldpm, altpm;
       
  2346     char *altremove;
       
  2347 
       
  2348     if ((pm->flags & PM_READONLY) && pm->level <= locallevel) {
       
  2349 	zerr("read-only variable: %s", pm->nam, 0);
       
  2350 	return 1;
       
  2351     }
       
  2352     if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
       
  2353 	zerr("%s: restricted", pm->nam, 0);
       
  2354 	return 1;
       
  2355     }
       
  2356 
       
  2357     if (pm->ename && !altflag)
       
  2358 	altremove = ztrdup(pm->ename);
       
  2359     else
       
  2360 	altremove = NULL;
       
  2361 
       
  2362     if (!(pm->flags & PM_UNSET))
       
  2363 	pm->gsu.s->unsetfn(pm, exp);
       
  2364     if (pm->env)
       
  2365 	delenv(pm);
       
  2366 
       
  2367     /* remove it under its alternate name if necessary */
       
  2368     if (altremove) {
       
  2369 	altpm = (Param) paramtab->getnode(paramtab, altremove);
       
  2370 	/* tied parameters are at the same local level as each other */
       
  2371 	oldpm = NULL;
       
  2372 	while (altpm && altpm->level > pm->level) {
       
  2373 	    /* param under alternate name hidden by a local */
       
  2374 	    oldpm = altpm;
       
  2375 	    altpm = altpm->old;
       
  2376 	}
       
  2377 	if (altpm) {
       
  2378 	    if (oldpm && !altpm->level) {
       
  2379 		oldpm->old = NULL;
       
  2380 		/* fudge things so removenode isn't called */
       
  2381 		altpm->level = 1;
       
  2382 	    }
       
  2383 	    unsetparam_pm(altpm, 1, exp);
       
  2384 	}
       
  2385 
       
  2386 	zsfree(altremove);
       
  2387     }
       
  2388 
       
  2389     /*
       
  2390      * If this was a local variable, we need to keep the old
       
  2391      * struct so that it is resurrected at the right level.
       
  2392      * This is partly because when an array/scalar value is set
       
  2393      * and the parameter used to be the other sort, unsetparam()
       
  2394      * is called.  Beyond that, there is an ambiguity:  should
       
  2395      * foo() { local bar; unset bar; } make the global bar
       
  2396      * available or not?  The following makes the answer "no".
       
  2397      *
       
  2398      * Some specials, such as those used in zle, still need removing
       
  2399      * from the parameter table; they have the PM_REMOVABLE flag.
       
  2400      */
       
  2401     if ((pm->level && locallevel >= pm->level) ||
       
  2402 	(pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
       
  2403 	return 0;
       
  2404 
       
  2405     /* remove parameter node from table */
       
  2406     paramtab->removenode(paramtab, pm->nam);
       
  2407 
       
  2408     if (pm->old) {
       
  2409 	oldpm = pm->old;
       
  2410 	paramtab->addnode(paramtab, oldpm->nam, oldpm);
       
  2411 	if ((PM_TYPE(oldpm->flags) == PM_SCALAR) &&
       
  2412 	    !(pm->flags & PM_HASHELEM) &&
       
  2413 	    (oldpm->flags & PM_NAMEDDIR) &&
       
  2414 	    oldpm->gsu.s == &stdscalar_gsu)
       
  2415 	    adduserdir(oldpm->nam, oldpm->u.str, 0, 0);
       
  2416 	if (oldpm->flags & PM_EXPORTED) {
       
  2417 	    /*
       
  2418 	     * Re-export the old value which we removed in typeset_single().
       
  2419 	     * I don't think we need to test for ALL_EXPORT here, since if
       
  2420 	     * it was used to export the parameter originally the parameter
       
  2421 	     * should still have the PM_EXPORTED flag.
       
  2422 	     */
       
  2423 	    export_param(oldpm);
       
  2424 	}
       
  2425     }
       
  2426 
       
  2427     paramtab->freenode((HashNode) pm); /* free parameter node */
       
  2428 
       
  2429     return 0;
       
  2430 }
       
  2431 
       
  2432 /* Standard function to unset a parameter.  This is mostly delegated to *
       
  2433  * the specific set function.
       
  2434  *
       
  2435  * This could usefully be made type-specific, but then we need
       
  2436  * to be more careful when calling the unset method directly.
       
  2437  */
       
  2438 
       
  2439 /**/
       
  2440 mod_export void
       
  2441 stdunsetfn(Param pm, UNUSED(int exp))
       
  2442 {
       
  2443     switch (PM_TYPE(pm->flags)) {
       
  2444 	case PM_SCALAR: pm->gsu.s->setfn(pm, NULL); break;
       
  2445 	case PM_ARRAY:  pm->gsu.a->setfn(pm, NULL); break;
       
  2446 	case PM_HASHED: pm->gsu.h->setfn(pm, NULL); break;
       
  2447 	default:
       
  2448 	    if (!(pm->flags & PM_SPECIAL))
       
  2449 	    	pm->u.str = NULL;
       
  2450 	    break;
       
  2451     }
       
  2452     if (!(pm->flags & PM_SPECIAL))
       
  2453 	pm->flags &= ~PM_TIED;
       
  2454     pm->flags |= PM_UNSET;
       
  2455 }
       
  2456 
       
  2457 /* Function to get value of an integer parameter */
       
  2458 
       
  2459 /**/
       
  2460 mod_export zlong
       
  2461 intgetfn(Param pm)
       
  2462 {
       
  2463     return pm->u.val;
       
  2464 }
       
  2465 
       
  2466 /* Function to set value of an integer parameter */
       
  2467 
       
  2468 /**/
       
  2469 static void
       
  2470 intsetfn(Param pm, zlong x)
       
  2471 {
       
  2472     pm->u.val = x;
       
  2473 }
       
  2474 
       
  2475 /* Function to get value of a floating point parameter */
       
  2476 
       
  2477 /**/
       
  2478 static double
       
  2479 floatgetfn(Param pm)
       
  2480 {
       
  2481     return pm->u.dval;
       
  2482 }
       
  2483 
       
  2484 /* Function to set value of an integer parameter */
       
  2485 
       
  2486 /**/
       
  2487 static void
       
  2488 floatsetfn(Param pm, double x)
       
  2489 {
       
  2490     pm->u.dval = x;
       
  2491 }
       
  2492 
       
  2493 /* Function to get value of a scalar (string) parameter */
       
  2494 
       
  2495 /**/
       
  2496 mod_export char *
       
  2497 strgetfn(Param pm)
       
  2498 {
       
  2499     return pm->u.str ? pm->u.str : (char *) hcalloc(1);
       
  2500 }
       
  2501 
       
  2502 /* Function to set value of a scalar (string) parameter */
       
  2503 
       
  2504 /**/
       
  2505 static void
       
  2506 strsetfn(Param pm, char *x)
       
  2507 {
       
  2508     zsfree(pm->u.str);
       
  2509     pm->u.str = x;
       
  2510     if (!(pm->flags & PM_HASHELEM) &&
       
  2511 	((pm->flags & PM_NAMEDDIR) || isset(AUTONAMEDIRS))) {
       
  2512 	pm->flags |= PM_NAMEDDIR;
       
  2513 	adduserdir(pm->nam, x, 0, 0);
       
  2514     }
       
  2515 }
       
  2516 
       
  2517 /* Function to get value of an array parameter */
       
  2518 
       
  2519 static char *nullarray = NULL;
       
  2520 
       
  2521 /**/
       
  2522 char **
       
  2523 arrgetfn(Param pm)
       
  2524 {
       
  2525     return pm->u.arr ? pm->u.arr : &nullarray;
       
  2526 }
       
  2527 
       
  2528 /* Function to set value of an array parameter */
       
  2529 
       
  2530 /**/
       
  2531 mod_export void
       
  2532 arrsetfn(Param pm, char **x)
       
  2533 {
       
  2534     if (pm->u.arr && pm->u.arr != x)
       
  2535 	freearray(pm->u.arr);
       
  2536     if (pm->flags & PM_UNIQUE)
       
  2537 	uniqarray(x);
       
  2538     pm->u.arr = x;
       
  2539     /* Arrays tied to colon-arrays may need to fix the environment */
       
  2540     if (pm->ename && x)
       
  2541 	arrfixenv(pm->ename, x);
       
  2542 }
       
  2543 
       
  2544 /* Function to get value of an association parameter */
       
  2545 
       
  2546 /**/
       
  2547 mod_export HashTable
       
  2548 hashgetfn(Param pm)
       
  2549 {
       
  2550     return pm->u.hash;
       
  2551 }
       
  2552 
       
  2553 /* Function to set value of an association parameter */
       
  2554 
       
  2555 /**/
       
  2556 mod_export void
       
  2557 hashsetfn(Param pm, HashTable x)
       
  2558 {
       
  2559     if (pm->u.hash && pm->u.hash != x)
       
  2560 	deleteparamtable(pm->u.hash);
       
  2561     pm->u.hash = x;
       
  2562 }
       
  2563 
       
  2564 /* Function to dispose of setting of an unsettable hash */
       
  2565 
       
  2566 /**/
       
  2567 mod_export void
       
  2568 nullsethashfn(Param pm, HashTable x)
       
  2569 {
       
  2570     deleteparamtable(x);
       
  2571 }
       
  2572 
       
  2573 /* Function to set value of an association parameter using key/value pairs */
       
  2574 
       
  2575 /**/
       
  2576 static void
       
  2577 arrhashsetfn(Param pm, char **val, int augment)
       
  2578 {
       
  2579     /* Best not to shortcut this by using the existing hash table,   *
       
  2580      * since that could cause trouble for special hashes.  This way, *
       
  2581      * it's up to pm->gsu.h->setfn() what to do.                     */
       
  2582     int alen = arrlen(val);
       
  2583     HashTable opmtab = paramtab, ht = 0;
       
  2584     char **aptr = val;
       
  2585     Value v = (Value) hcalloc(sizeof *v);
       
  2586     v->end = -1;
       
  2587 
       
  2588     if (alen % 2) {
       
  2589 	freearray(val);
       
  2590 	zerr("bad set of key/value pairs for associative array",
       
  2591 	     NULL, 0);
       
  2592 	return;
       
  2593     }
       
  2594     if (alen)
       
  2595     	if (!(augment && (ht = paramtab = pm->gsu.h->getfn(pm))))
       
  2596 	    ht = paramtab = newparamtable(17, pm->nam);
       
  2597     while (*aptr) {
       
  2598 	/* The parameter name is ztrdup'd... */
       
  2599 	v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
       
  2600 	/*
       
  2601 	 * createparam() doesn't return anything if the parameter
       
  2602 	 * already existed.
       
  2603 	 */
       
  2604 	if (!v->pm)
       
  2605 	    v->pm = (Param) paramtab->getnode(paramtab, *aptr);
       
  2606 	zsfree(*aptr++);
       
  2607 	/* ...but we can use the value without copying. */
       
  2608 	setstrvalue(v, *aptr++);
       
  2609     }
       
  2610     paramtab = opmtab;
       
  2611     pm->gsu.h->setfn(pm, ht);
       
  2612     free(val);		/* not freearray() */
       
  2613 }
       
  2614 
       
  2615 /*
       
  2616  * These functions are used as the set function for special parameters that
       
  2617  * cannot be set by the user.  The set is incomplete as the only such
       
  2618  * parameters are scalar and integer.
       
  2619  */
       
  2620 
       
  2621 /**/
       
  2622 mod_export void
       
  2623 nullstrsetfn(UNUSED(Param pm), char *x)
       
  2624 {
       
  2625     zsfree(x);
       
  2626 }
       
  2627 
       
  2628 /**/
       
  2629 void
       
  2630 nullintsetfn(UNUSED(Param pm), UNUSED(zlong x))
       
  2631 {}
       
  2632 
       
  2633 /**/
       
  2634 mod_export void
       
  2635 nullunsetfn(UNUSED(Param pm), UNUSED(int exp))
       
  2636 {}
       
  2637 
       
  2638 
       
  2639 /* Function to get value of generic special integer *
       
  2640  * parameter.  data is pointer to global variable   *
       
  2641  * containing the integer value.                    */
       
  2642 
       
  2643 /**/
       
  2644 mod_export zlong
       
  2645 intvargetfn(Param pm)
       
  2646 {
       
  2647     return *pm->u.valptr;
       
  2648 }
       
  2649 
       
  2650 /* Function to set value of generic special integer *
       
  2651  * parameter.  data is pointer to global variable   *
       
  2652  * where the value is to be stored.                 */
       
  2653 
       
  2654 /**/
       
  2655 mod_export void
       
  2656 intvarsetfn(Param pm, zlong x)
       
  2657 {
       
  2658     *pm->u.valptr = x;
       
  2659 }
       
  2660 
       
  2661 /* Function to set value of any ZLE-related integer *
       
  2662  * parameter.  data is pointer to global variable   *
       
  2663  * where the value is to be stored.                 */
       
  2664 
       
  2665 /**/
       
  2666 void
       
  2667 zlevarsetfn(Param pm, zlong x)
       
  2668 {
       
  2669     zlong *p = pm->u.valptr;
       
  2670 
       
  2671     *p = x;
       
  2672     if (p == &lines || p == &columns)
       
  2673 	adjustwinsize(2 + (p == &columns));
       
  2674 }
       
  2675 
       
  2676 /* Function to set value of generic special scalar    *
       
  2677  * parameter.  data is pointer to a character pointer *
       
  2678  * representing the scalar (string).                  */
       
  2679 
       
  2680 /**/
       
  2681 mod_export void
       
  2682 strvarsetfn(Param pm, char *x)
       
  2683 {
       
  2684     char **q = ((char **)pm->u.data);
       
  2685 
       
  2686     zsfree(*q);
       
  2687     *q = x;
       
  2688 }
       
  2689 
       
  2690 /* Function to get value of generic special scalar    *
       
  2691  * parameter.  data is pointer to a character pointer *
       
  2692  * representing the scalar (string).                  */
       
  2693 
       
  2694 /**/
       
  2695 mod_export char *
       
  2696 strvargetfn(Param pm)
       
  2697 {
       
  2698     char *s = *((char **)pm->u.data);
       
  2699 
       
  2700     if (!s)
       
  2701 	return hcalloc(1);
       
  2702     return s;
       
  2703 }
       
  2704 
       
  2705 /* Function to get value of generic special array  *
       
  2706  * parameter.  data is a pointer to the pointer to *
       
  2707  * a pointer (a pointer to a variable length array *
       
  2708  * of pointers).                                   */
       
  2709 
       
  2710 /**/
       
  2711 mod_export char **
       
  2712 arrvargetfn(Param pm)
       
  2713 {
       
  2714     char **arrptr = *((char ***)pm->u.data);
       
  2715 
       
  2716     return arrptr ? arrptr : &nullarray;
       
  2717 }
       
  2718 
       
  2719 /* Function to set value of generic special array parameter.    *
       
  2720  * data is pointer to a variable length array of pointers which *
       
  2721  * represents this array of scalars (strings).  If pm->ename is *
       
  2722  * non NULL, then it is a colon separated environment variable  *
       
  2723  * version of this array which will need to be updated.         */
       
  2724 
       
  2725 /**/
       
  2726 mod_export void
       
  2727 arrvarsetfn(Param pm, char **x)
       
  2728 {
       
  2729     char ***dptr = (char ***)pm->u.data;
       
  2730 
       
  2731     if (*dptr != x)
       
  2732 	freearray(*dptr);
       
  2733     if (pm->flags & PM_UNIQUE)
       
  2734 	uniqarray(x);
       
  2735     /*
       
  2736      * Special tied arrays point to variables accessible in other
       
  2737      * ways which need to be set to NULL.  We can't do this
       
  2738      * with user tied variables since we can leak memory.
       
  2739      */
       
  2740     if ((pm->flags & PM_SPECIAL) && !x)
       
  2741 	*dptr = mkarray(NULL);
       
  2742     else
       
  2743 	*dptr = x;
       
  2744     if (pm->ename && x)
       
  2745 	arrfixenv(pm->ename, x);
       
  2746 }
       
  2747 
       
  2748 /**/
       
  2749 char *
       
  2750 colonarrgetfn(Param pm)
       
  2751 {
       
  2752     char ***dptr = (char ***)pm->u.data;
       
  2753     return *dptr ? zjoin(*dptr, ':', 1) : "";
       
  2754 }
       
  2755 
       
  2756 /**/
       
  2757 void
       
  2758 colonarrsetfn(Param pm, char *x)
       
  2759 {
       
  2760     char ***dptr = (char ***)pm->u.data;
       
  2761     /*
       
  2762      * We have to make sure this is never NULL, since that
       
  2763      * can cause problems.
       
  2764      */
       
  2765     if (*dptr)
       
  2766 	freearray(*dptr);
       
  2767     if (x)
       
  2768 	*dptr = colonsplit(x, pm->flags & PM_UNIQUE);
       
  2769     else
       
  2770 	*dptr = mkarray(NULL);
       
  2771     if (pm->ename)
       
  2772 	arrfixenv(pm->nam, *dptr);
       
  2773     zsfree(x);
       
  2774 }
       
  2775 
       
  2776 /**/
       
  2777 char *
       
  2778 tiedarrgetfn(Param pm)
       
  2779 {
       
  2780     struct tieddata *dptr = (struct tieddata *)pm->u.data;
       
  2781     return *dptr->arrptr ? zjoin(*dptr->arrptr, dptr->joinchar, 1) : "";
       
  2782 }
       
  2783 
       
  2784 /**/
       
  2785 void
       
  2786 tiedarrsetfn(Param pm, char *x)
       
  2787 {
       
  2788     struct tieddata *dptr = (struct tieddata *)pm->u.data;
       
  2789 
       
  2790     if (*dptr->arrptr)
       
  2791 	freearray(*dptr->arrptr);
       
  2792     if (x) {
       
  2793 	char sepbuf[3];
       
  2794 	if (imeta(dptr->joinchar))
       
  2795 	{
       
  2796 	    sepbuf[0] = Meta;
       
  2797 	    sepbuf[1] = dptr->joinchar ^ 32;
       
  2798 	    sepbuf[2] = '\0';
       
  2799 	}
       
  2800 	else
       
  2801 	{
       
  2802 	    sepbuf[0] = dptr->joinchar;
       
  2803 	    sepbuf[1] = '\0';
       
  2804 	}
       
  2805 	*dptr->arrptr = sepsplit(x, sepbuf, 0, 0);
       
  2806 	if (pm->flags & PM_UNIQUE)
       
  2807 	    uniqarray(*dptr->arrptr);
       
  2808     } else
       
  2809 	*dptr->arrptr = NULL;
       
  2810     if (pm->ename)
       
  2811 	arrfixenv(pm->nam, *dptr->arrptr);
       
  2812     zsfree(x);
       
  2813 }
       
  2814 
       
  2815 /**/
       
  2816 void
       
  2817 tiedarrunsetfn(Param pm, UNUSED(int exp))
       
  2818 {
       
  2819     /*
       
  2820      * Special unset function because we allocated a struct tieddata
       
  2821      * in typeset_single to hold the special data which we now
       
  2822      * need to delete.
       
  2823      */
       
  2824     pm->gsu.s->setfn(pm, NULL);
       
  2825     zfree(pm->u.data, sizeof(struct tieddata));
       
  2826     /* paranoia -- shouldn't need these, but in case we reuse the struct... */
       
  2827     pm->u.data = NULL;
       
  2828     zsfree(pm->ename);
       
  2829     pm->ename = NULL;
       
  2830     pm->flags &= ~PM_TIED;
       
  2831     pm->flags |= PM_UNSET;
       
  2832 }
       
  2833 
       
  2834 /**/
       
  2835 void
       
  2836 uniqarray(char **x)
       
  2837 {
       
  2838     char **t, **p = x;
       
  2839 
       
  2840     if (!x || !*x)
       
  2841 	return;
       
  2842     while (*++p)
       
  2843 	for (t = x; t < p; t++)
       
  2844 	    if (!strcmp(*p, *t)) {
       
  2845 		zsfree(*p);
       
  2846 		for (t = p--; (*t = t[1]) != NULL; t++);
       
  2847 		break;
       
  2848 	    }
       
  2849 }
       
  2850 
       
  2851 /**/
       
  2852 void
       
  2853 zhuniqarray(char **x)
       
  2854 {
       
  2855     char **t, **p = x;
       
  2856 
       
  2857     if (!x || !*x)
       
  2858 	return;
       
  2859     while (*++p)
       
  2860 	for (t = x; t < p; t++)
       
  2861 	    if (!strcmp(*p, *t)) {
       
  2862 		for (t = p--; (*t = t[1]) != NULL; t++);
       
  2863 		break;
       
  2864 	    }
       
  2865 }
       
  2866 
       
  2867 /* Function to get value of special parameter `#' and `ARGC' */
       
  2868 
       
  2869 /**/
       
  2870 zlong
       
  2871 poundgetfn(UNUSED(Param pm))
       
  2872 {
       
  2873     return arrlen(pparams);
       
  2874 }
       
  2875 
       
  2876 /* Function to get value for special parameter `RANDOM' */
       
  2877 
       
  2878 /**/
       
  2879 zlong
       
  2880 randomgetfn(UNUSED(Param pm))
       
  2881 {
       
  2882     return rand() & 0x7fff;
       
  2883 }
       
  2884 
       
  2885 /* Function to set value of special parameter `RANDOM' */
       
  2886 
       
  2887 /**/
       
  2888 void
       
  2889 randomsetfn(UNUSED(Param pm), zlong v)
       
  2890 {
       
  2891     srand((unsigned int)v);
       
  2892 }
       
  2893 
       
  2894 /* Function to get value for special parameter `SECONDS' */
       
  2895 
       
  2896 /**/
       
  2897 zlong
       
  2898 intsecondsgetfn(UNUSED(Param pm))
       
  2899 {
       
  2900     struct timeval now;
       
  2901     struct timezone dummy_tz;
       
  2902 
       
  2903     gettimeofday(&now, &dummy_tz);
       
  2904 
       
  2905     return (zlong)(now.tv_sec - shtimer.tv_sec) +
       
  2906 	(zlong)(now.tv_usec - shtimer.tv_usec) / (zlong)1000000;
       
  2907 }
       
  2908 
       
  2909 /* Function to set value of special parameter `SECONDS' */
       
  2910 
       
  2911 /**/
       
  2912 void
       
  2913 intsecondssetfn(UNUSED(Param pm), zlong x)
       
  2914 {
       
  2915     struct timeval now;
       
  2916     struct timezone dummy_tz;
       
  2917     zlong diff;
       
  2918 
       
  2919     gettimeofday(&now, &dummy_tz);
       
  2920     diff = (zlong)now.tv_sec - x;
       
  2921     shtimer.tv_sec = diff;
       
  2922     if ((zlong)shtimer.tv_sec != diff)
       
  2923 	zwarn("SECONDS truncated on assignment", NULL, 0);
       
  2924     shtimer.tv_usec = 0;
       
  2925 }
       
  2926 
       
  2927 /**/
       
  2928 double
       
  2929 floatsecondsgetfn(UNUSED(Param pm))
       
  2930 {
       
  2931     struct timeval now;
       
  2932     struct timezone dummy_tz;
       
  2933 
       
  2934     gettimeofday(&now, &dummy_tz);
       
  2935 
       
  2936     return (double)(now.tv_sec - shtimer.tv_sec) +
       
  2937 	(double)(now.tv_usec - shtimer.tv_usec) / 1000000.0;
       
  2938 }
       
  2939 
       
  2940 /**/
       
  2941 void
       
  2942 floatsecondssetfn(UNUSED(Param pm), double x)
       
  2943 {
       
  2944     struct timeval now;
       
  2945     struct timezone dummy_tz;
       
  2946 
       
  2947     gettimeofday(&now, &dummy_tz);
       
  2948     shtimer.tv_sec = now.tv_sec - (zlong)x;
       
  2949     shtimer.tv_usec = now.tv_usec - (zlong)((x - (zlong)x) * 1000000.0);
       
  2950 }
       
  2951 
       
  2952 /**/
       
  2953 double
       
  2954 getrawseconds(void)
       
  2955 {
       
  2956     return (double)shtimer.tv_sec + (double)shtimer.tv_usec / 1000000.0;
       
  2957 }
       
  2958 
       
  2959 /**/
       
  2960 void
       
  2961 setrawseconds(double x)
       
  2962 {
       
  2963     shtimer.tv_sec = (zlong)x;
       
  2964     shtimer.tv_usec = (zlong)((x - (zlong)x) * 1000000.0);
       
  2965 }
       
  2966 
       
  2967 /**/
       
  2968 int
       
  2969 setsecondstype(Param pm, int on, int off)
       
  2970 {
       
  2971     int newflags = (pm->flags | on) & ~off;
       
  2972     int tp = PM_TYPE(newflags);
       
  2973     /* Only one of the numeric types is allowed. */
       
  2974     if (tp == PM_EFLOAT || tp == PM_FFLOAT)
       
  2975     {
       
  2976 	pm->gsu.f = &floatseconds_gsu;
       
  2977     }
       
  2978     else if (tp == PM_INTEGER)
       
  2979     {
       
  2980 	pm->gsu.i = &intseconds_gsu;
       
  2981     }
       
  2982     else
       
  2983 	return 1;
       
  2984     pm->flags = newflags;
       
  2985     return 0;
       
  2986 }
       
  2987 
       
  2988 /* Function to get value for special parameter `USERNAME' */
       
  2989 
       
  2990 /**/
       
  2991 char *
       
  2992 usernamegetfn(UNUSED(Param pm))
       
  2993 {
       
  2994     return get_username();
       
  2995 }
       
  2996 
       
  2997 /* Function to set value of special parameter `USERNAME' */
       
  2998 
       
  2999 /**/
       
  3000 void
       
  3001 usernamesetfn(UNUSED(Param pm), char *x)
       
  3002 {
       
  3003 #if defined(HAVE_SETUID) && defined(HAVE_GETPWNAM)
       
  3004     struct passwd *pswd;
       
  3005 
       
  3006     if (x && (pswd = getpwnam(x)) && (pswd->pw_uid != cached_uid)) {
       
  3007 # ifdef HAVE_INITGROUPS
       
  3008 	initgroups(x, pswd->pw_gid);
       
  3009 # endif
       
  3010 	if(!setgid(pswd->pw_gid) && !setuid(pswd->pw_uid)) {
       
  3011 	    zsfree(cached_username);
       
  3012 	    cached_username = ztrdup(pswd->pw_name);
       
  3013 	    cached_uid = pswd->pw_uid;
       
  3014 	}
       
  3015     }
       
  3016 #endif /* HAVE_SETUID && HAVE_GETPWNAM */
       
  3017     zsfree(x);
       
  3018 }
       
  3019 
       
  3020 /* Function to get value for special parameter `UID' */
       
  3021 
       
  3022 /**/
       
  3023 zlong
       
  3024 uidgetfn(UNUSED(Param pm))
       
  3025 {
       
  3026     return getuid();
       
  3027 }
       
  3028 
       
  3029 /* Function to set value of special parameter `UID' */
       
  3030 
       
  3031 /**/
       
  3032 void
       
  3033 uidsetfn(UNUSED(Param pm), zlong x)
       
  3034 {
       
  3035 #ifdef HAVE_SETUID
       
  3036     setuid((uid_t)x);
       
  3037 #endif
       
  3038 }
       
  3039 
       
  3040 /* Function to get value for special parameter `EUID' */
       
  3041 
       
  3042 /**/
       
  3043 zlong
       
  3044 euidgetfn(UNUSED(Param pm))
       
  3045 {
       
  3046     return geteuid();
       
  3047 }
       
  3048 
       
  3049 /* Function to set value of special parameter `EUID' */
       
  3050 
       
  3051 /**/
       
  3052 void
       
  3053 euidsetfn(UNUSED(Param pm), zlong x)
       
  3054 {
       
  3055 #ifdef HAVE_SETEUID
       
  3056     seteuid((uid_t)x);
       
  3057 #endif
       
  3058 }
       
  3059 
       
  3060 /* Function to get value for special parameter `GID' */
       
  3061 
       
  3062 /**/
       
  3063 zlong
       
  3064 gidgetfn(UNUSED(Param pm))
       
  3065 {
       
  3066     return getgid();
       
  3067 }
       
  3068 
       
  3069 /* Function to set value of special parameter `GID' */
       
  3070 
       
  3071 /**/
       
  3072 void
       
  3073 gidsetfn(UNUSED(Param pm), zlong x)
       
  3074 {
       
  3075 #ifdef HAVE_SETUID
       
  3076     setgid((gid_t)x);
       
  3077 #endif
       
  3078 }
       
  3079 
       
  3080 /* Function to get value for special parameter `EGID' */
       
  3081 
       
  3082 /**/
       
  3083 zlong
       
  3084 egidgetfn(UNUSED(Param pm))
       
  3085 {
       
  3086     return getegid();
       
  3087 }
       
  3088 
       
  3089 /* Function to set value of special parameter `EGID' */
       
  3090 
       
  3091 /**/
       
  3092 void
       
  3093 egidsetfn(UNUSED(Param pm), zlong x)
       
  3094 {
       
  3095 #ifdef HAVE_SETEUID
       
  3096     setegid((gid_t)x);
       
  3097 #endif
       
  3098 }
       
  3099 
       
  3100 /**/
       
  3101 zlong
       
  3102 ttyidlegetfn(UNUSED(Param pm))
       
  3103 {
       
  3104     struct stat ttystat;
       
  3105 
       
  3106     if (SHTTY == -1 || fstat(SHTTY, &ttystat))
       
  3107 	return -1;
       
  3108     return time(NULL) - ttystat.st_atime;
       
  3109 }
       
  3110 
       
  3111 /* Function to get value for special parameter `IFS' */
       
  3112 
       
  3113 /**/
       
  3114 char *
       
  3115 ifsgetfn(UNUSED(Param pm))
       
  3116 {
       
  3117     return ifs;
       
  3118 }
       
  3119 
       
  3120 /* Function to set value of special parameter `IFS' */
       
  3121 
       
  3122 /**/
       
  3123 void
       
  3124 ifssetfn(UNUSED(Param pm), char *x)
       
  3125 {
       
  3126     zsfree(ifs);
       
  3127     ifs = x;
       
  3128     inittyptab();
       
  3129 }
       
  3130 
       
  3131 /* Functions to set value of special parameters `LANG' and `LC_*' */
       
  3132 
       
  3133 #ifdef USE_LOCALE
       
  3134 static struct localename {
       
  3135     char *name;
       
  3136     int category;
       
  3137 } lc_names[] = {
       
  3138 #ifdef LC_COLLATE
       
  3139     {"LC_COLLATE", LC_COLLATE},
       
  3140 #endif
       
  3141 #ifdef LC_CTYPE
       
  3142     {"LC_CTYPE", LC_CTYPE},
       
  3143 #endif
       
  3144 #ifdef LC_MESSAGES
       
  3145     {"LC_MESSAGES", LC_MESSAGES},
       
  3146 #endif
       
  3147 #ifdef LC_NUMERIC
       
  3148     {"LC_NUMERIC", LC_NUMERIC},
       
  3149 #endif
       
  3150 #ifdef LC_TIME
       
  3151     {"LC_TIME", LC_TIME},
       
  3152 #endif
       
  3153     {NULL, 0}
       
  3154 };
       
  3155 
       
  3156 /**/
       
  3157 static void
       
  3158 setlang(char *x)
       
  3159 {
       
  3160     struct localename *ln;
       
  3161 
       
  3162     setlocale(LC_ALL, x ? x : "");
       
  3163     queue_signals();
       
  3164     for (ln = lc_names; ln->name; ln++)
       
  3165 	if ((x = getsparam(ln->name)))
       
  3166 	    setlocale(ln->category, x);
       
  3167     unqueue_signals();
       
  3168 }
       
  3169 
       
  3170 /**/
       
  3171 void
       
  3172 lc_allsetfn(Param pm, char *x)
       
  3173 {
       
  3174     strsetfn(pm, x);
       
  3175     if (!x) {
       
  3176 	queue_signals();
       
  3177 	setlang(getsparam("LANG"));
       
  3178 	unqueue_signals();
       
  3179     }
       
  3180     else
       
  3181 	setlocale(LC_ALL, x);
       
  3182 }
       
  3183 
       
  3184 /**/
       
  3185 void
       
  3186 langsetfn(Param pm, char *x)
       
  3187 {
       
  3188     strsetfn(pm, x);
       
  3189     setlang(x);
       
  3190 }
       
  3191 
       
  3192 /**/
       
  3193 void
       
  3194 lcsetfn(Param pm, char *x)
       
  3195 {
       
  3196     struct localename *ln;
       
  3197 
       
  3198     strsetfn(pm, x);
       
  3199     if (getsparam("LC_ALL"))
       
  3200 	return;
       
  3201     queue_signals();
       
  3202     if (!x)
       
  3203 	x = getsparam("LANG");
       
  3204 
       
  3205     for (ln = lc_names; ln->name; ln++)
       
  3206 	if (!strcmp(ln->name, pm->nam))
       
  3207 	    setlocale(ln->category, x ? x : "");
       
  3208     unqueue_signals();
       
  3209 }
       
  3210 #endif /* USE_LOCALE */
       
  3211 
       
  3212 /* Function to get value for special parameter `HISTSIZE' */
       
  3213 
       
  3214 /**/
       
  3215 zlong
       
  3216 histsizegetfn(UNUSED(Param pm))
       
  3217 {
       
  3218     return histsiz;
       
  3219 }
       
  3220 
       
  3221 /* Function to set value of special parameter `HISTSIZE' */
       
  3222 
       
  3223 /**/
       
  3224 void
       
  3225 histsizesetfn(UNUSED(Param pm), zlong v)
       
  3226 {
       
  3227     if ((histsiz = v) < 1)
       
  3228 	histsiz = 1;
       
  3229     resizehistents();
       
  3230 }
       
  3231 
       
  3232 /* Function to get value for special parameter `SAVEHIST' */
       
  3233 
       
  3234 /**/
       
  3235 zlong
       
  3236 savehistsizegetfn(UNUSED(Param pm))
       
  3237 {
       
  3238     return savehistsiz;
       
  3239 }
       
  3240 
       
  3241 /* Function to set value of special parameter `SAVEHIST' */
       
  3242 
       
  3243 /**/
       
  3244 void
       
  3245 savehistsizesetfn(UNUSED(Param pm), zlong v)
       
  3246 {
       
  3247     if ((savehistsiz = v) < 0)
       
  3248 	savehistsiz = 0;
       
  3249 }
       
  3250 
       
  3251 /* Function to set value for special parameter `ERRNO' */
       
  3252 
       
  3253 /**/
       
  3254 void
       
  3255 errnosetfn(UNUSED(Param pm), zlong x)
       
  3256 {
       
  3257     errno = (int)x;
       
  3258     if ((zlong)errno != x)
       
  3259 	zwarn("errno truncated on assignment", NULL, 0);
       
  3260 }
       
  3261 
       
  3262 /* Function to get value for special parameter `ERRNO' */
       
  3263 
       
  3264 /**/
       
  3265 zlong
       
  3266 errnogetfn(UNUSED(Param pm))
       
  3267 {
       
  3268     return errno;
       
  3269 }
       
  3270 
       
  3271 /* Function to get value for special parameter `histchar' */
       
  3272 
       
  3273 /**/
       
  3274 char *
       
  3275 histcharsgetfn(UNUSED(Param pm))
       
  3276 {
       
  3277     static char buf[4];
       
  3278 
       
  3279     buf[0] = bangchar;
       
  3280     buf[1] = hatchar;
       
  3281     buf[2] = hashchar;
       
  3282     buf[3] = '\0';
       
  3283     return buf;
       
  3284 }
       
  3285 
       
  3286 /* Function to set value of special parameter `histchar' */
       
  3287 
       
  3288 /**/
       
  3289 void
       
  3290 histcharssetfn(UNUSED(Param pm), char *x)
       
  3291 {
       
  3292     if (x) {
       
  3293 	bangchar = x[0];
       
  3294 	hatchar = (bangchar) ? x[1] : '\0';
       
  3295 	hashchar = (hatchar) ? x[2] : '\0';
       
  3296 	zsfree(x);
       
  3297     } else {
       
  3298 	bangchar = '!';
       
  3299 	hashchar = '#';
       
  3300 	hatchar = '^';
       
  3301     }
       
  3302     inittyptab();
       
  3303 }
       
  3304 
       
  3305 /* Function to get value for special parameter `HOME' */
       
  3306 
       
  3307 /**/
       
  3308 char *
       
  3309 homegetfn(UNUSED(Param pm))
       
  3310 {
       
  3311     return home;
       
  3312 }
       
  3313 
       
  3314 /* Function to set value of special parameter `HOME' */
       
  3315 
       
  3316 /**/
       
  3317 void
       
  3318 homesetfn(UNUSED(Param pm), char *x)
       
  3319 {
       
  3320     zsfree(home);
       
  3321     if (x && isset(CHASELINKS) && (home = xsymlink(x)))
       
  3322 	zsfree(x);
       
  3323     else
       
  3324 	home = x ? x : ztrdup("");
       
  3325     finddir(NULL);
       
  3326 }
       
  3327 
       
  3328 /* Function to get value for special parameter `WORDCHARS' */
       
  3329 
       
  3330 /**/
       
  3331 char *
       
  3332 wordcharsgetfn(UNUSED(Param pm))
       
  3333 {
       
  3334     return wordchars;
       
  3335 }
       
  3336 
       
  3337 /* Function to set value of special parameter `WORDCHARS' */
       
  3338 
       
  3339 /**/
       
  3340 void
       
  3341 wordcharssetfn(UNUSED(Param pm), char *x)
       
  3342 {
       
  3343     zsfree(wordchars);
       
  3344     wordchars = x;
       
  3345     inittyptab();
       
  3346 }
       
  3347 
       
  3348 /* Function to get value for special parameter `_' */
       
  3349 
       
  3350 /**/
       
  3351 char *
       
  3352 underscoregetfn(UNUSED(Param pm))
       
  3353 {
       
  3354     char *u = dupstring(underscore);
       
  3355 
       
  3356     untokenize(u);
       
  3357     return u;
       
  3358 }
       
  3359 
       
  3360 /* Function to get value for special parameter `TERM' */
       
  3361 
       
  3362 /**/
       
  3363 char *
       
  3364 termgetfn(UNUSED(Param pm))
       
  3365 {
       
  3366     return term;
       
  3367 }
       
  3368 
       
  3369 /* Function to set value of special parameter `TERM' */
       
  3370 
       
  3371 /**/
       
  3372 void
       
  3373 termsetfn(UNUSED(Param pm), char *x)
       
  3374 {
       
  3375     zsfree(term);
       
  3376     term = x ? x : ztrdup("");
       
  3377 
       
  3378     /* If non-interactive, delay setting up term till we need it. */
       
  3379     if (unset(INTERACTIVE) || !*term)
       
  3380 	termflags |= TERM_UNKNOWN;
       
  3381     else 
       
  3382 	init_term();
       
  3383 }
       
  3384 
       
  3385 /* Function to get value for special parameter `pipestatus' */
       
  3386 
       
  3387 /**/
       
  3388 static char **
       
  3389 pipestatgetfn(UNUSED(Param pm))
       
  3390 {
       
  3391     char **x = (char **) zhalloc((numpipestats + 1) * sizeof(char *));
       
  3392     char buf[20], **p;
       
  3393     int *q, i;
       
  3394 
       
  3395     for (p = x, q = pipestats, i = numpipestats; i--; p++, q++) {
       
  3396 	sprintf(buf, "%d", *q);
       
  3397 	*p = dupstring(buf);
       
  3398     }
       
  3399     *p = NULL;
       
  3400 
       
  3401     return x;
       
  3402 }
       
  3403 
       
  3404 /* Function to get value for special parameter `pipestatus' */
       
  3405 
       
  3406 /**/
       
  3407 static void
       
  3408 pipestatsetfn(UNUSED(Param pm), char **x)
       
  3409 {
       
  3410     if (x) {
       
  3411         int i;
       
  3412 
       
  3413         for (i = 0; *x && i < MAX_PIPESTATS; i++, x++)
       
  3414             pipestats[i] = atoi(*x);
       
  3415         numpipestats = i;
       
  3416     }
       
  3417     else
       
  3418         numpipestats = 0;
       
  3419 }
       
  3420 
       
  3421 /**/
       
  3422 void
       
  3423 arrfixenv(char *s, char **t)
       
  3424 {
       
  3425     Param pm;
       
  3426     int joinchar;
       
  3427 
       
  3428     if (t == path)
       
  3429 	cmdnamtab->emptytable(cmdnamtab);
       
  3430 
       
  3431     pm = (Param) paramtab->getnode(paramtab, s);
       
  3432     
       
  3433     /*
       
  3434      * Only one level of a parameter can be exported.  Unless
       
  3435      * ALLEXPORT is set, this must be global.
       
  3436      */
       
  3437 
       
  3438     if (pm->flags & PM_HASHELEM)
       
  3439 	return;
       
  3440 
       
  3441     if (isset(ALLEXPORT))
       
  3442 	pm->flags |= PM_EXPORTED;
       
  3443 
       
  3444     /*
       
  3445      * Do not "fix" parameters that were not exported
       
  3446      */
       
  3447 
       
  3448     if (!(pm->flags & PM_EXPORTED))
       
  3449 	return;
       
  3450 
       
  3451     if (pm->flags & PM_TIED)
       
  3452 	joinchar = ((struct tieddata *)pm->u.data)->joinchar;
       
  3453     else
       
  3454 	joinchar = ':';
       
  3455 
       
  3456     addenv(pm, t ? zjoin(t, joinchar, 1) : "");
       
  3457 }
       
  3458 
       
  3459 
       
  3460 /**/
       
  3461 int
       
  3462 zputenv(char *str)
       
  3463 {
       
  3464 #ifdef HAVE_PUTENV
       
  3465     return putenv(str);
       
  3466 #else
       
  3467     char **ep;
       
  3468     int num_env;
       
  3469 
       
  3470 
       
  3471     /* First check if there is already an environment *
       
  3472      * variable matching string `name'.               */
       
  3473     if (findenv(str, &num_env)) {
       
  3474 	environ[num_env] = str;
       
  3475     } else {
       
  3476     /* Else we have to make room and add it */
       
  3477 	num_env = arrlen(environ);
       
  3478 	environ = (char **) zrealloc(environ, (sizeof(char *)) * (num_env + 2));
       
  3479 
       
  3480 	/* Now add it at the end */
       
  3481 	ep = environ + num_env;
       
  3482 	*ep = str;
       
  3483 	*(ep + 1) = NULL;
       
  3484     }
       
  3485     return 0;
       
  3486 #endif
       
  3487 }
       
  3488 
       
  3489 /**/
       
  3490 static int
       
  3491 findenv(char *name, int *pos)
       
  3492 {
       
  3493     char **ep, *eq;
       
  3494     int  nlen;
       
  3495 
       
  3496 
       
  3497     eq = strchr(name, '=');
       
  3498     nlen = eq ? eq - name : (int)strlen(name);
       
  3499     for (ep = environ; *ep; ep++) 
       
  3500 	if (!strncmp (*ep, name, nlen) && *((*ep)+nlen) == '=') {
       
  3501 	    if (pos)
       
  3502 		*pos = ep - environ;
       
  3503 	    return 1;
       
  3504 	}
       
  3505     
       
  3506     return 0;
       
  3507 }
       
  3508 
       
  3509 /* Given *name = "foo", it searches the environment for string *
       
  3510  * "foo=bar", and returns a pointer to the beginning of "bar"  */
       
  3511 
       
  3512 /**/
       
  3513 mod_export char *
       
  3514 zgetenv(char *name)
       
  3515 {
       
  3516 #ifdef HAVE_GETENV
       
  3517     return getenv(name);
       
  3518 #else
       
  3519     char **ep, *s, *t;
       
  3520  
       
  3521     for (ep = environ; *ep; ep++) {
       
  3522        for (s = *ep, t = name; *s && *s == *t; s++, t++);
       
  3523        if (*s == '=' && !*t)
       
  3524            return s + 1;
       
  3525     }
       
  3526     return NULL;
       
  3527 #endif
       
  3528 }
       
  3529 
       
  3530 /**/
       
  3531 static void
       
  3532 copyenvstr(char *s, char *value, int flags)
       
  3533 {
       
  3534     while (*s++) {
       
  3535 	if ((*s = *value++) == Meta)
       
  3536 	    *s = *value++ ^ 32;
       
  3537 	if (flags & PM_LOWER)
       
  3538 	    *s = tulower(*s);
       
  3539 	else if (flags & PM_UPPER)
       
  3540 	    *s = tuupper(*s);
       
  3541     }
       
  3542 }
       
  3543 
       
  3544 /**/
       
  3545 void
       
  3546 addenv(Param pm, char *value)
       
  3547 {
       
  3548     char *oldenv = 0, *newenv = 0, *env = 0;
       
  3549     int pos;
       
  3550 
       
  3551     /* First check if there is already an environment *
       
  3552      * variable matching string `name'. If not, and   *
       
  3553      * we are not requested to add new, return        */
       
  3554     if (findenv(pm->nam, &pos))
       
  3555 	oldenv = environ[pos];
       
  3556 
       
  3557      newenv = mkenvstr(pm->nam, value, pm->flags);
       
  3558      if (zputenv(newenv)) {
       
  3559         zsfree(newenv);
       
  3560 	pm->env = NULL;
       
  3561 	return;
       
  3562     }
       
  3563     /*
       
  3564      * Under Cygwin we must use putenv() to maintain consistency.
       
  3565      * Unfortunately, current version (1.1.2) copies argument and may
       
  3566      * silently reuse existing environment string. This tries to
       
  3567      * check for both cases
       
  3568      */
       
  3569     if (findenv(pm->nam, &pos)) {
       
  3570 	env = environ[pos];
       
  3571     
       
  3572 #ifndef __SYMBIAN32__    
       
  3573     /*Th oldenv ptr is free'ed withing setenv() of libc/stdlib/setenv.c. no need to free here.*/
       
  3574 	if (env != oldenv)
       
  3575 	  zsfree(oldenv); 
       
  3576 #endif //__SYMBIAN32__
       
  3577 	
       
  3578 	if (env != newenv)
       
  3579 	    zsfree(newenv);
       
  3580 	pm->flags |= PM_EXPORTED;
       
  3581 	pm->env = env;
       
  3582 	return;
       
  3583     }
       
  3584 
       
  3585     DPUTS(1, "addenv should never reach the end");
       
  3586     pm->env = NULL;
       
  3587 }
       
  3588 
       
  3589 
       
  3590 /* Given strings *name = "foo", *value = "bar", *
       
  3591  * return a new string *str = "foo=bar".        */
       
  3592 
       
  3593 /**/
       
  3594 static char *
       
  3595 mkenvstr(char *name, char *value, int flags)
       
  3596 {
       
  3597     char *str, *s;
       
  3598     int len_name, len_value;
       
  3599 
       
  3600     len_name = strlen(name);
       
  3601     for (len_value = 0, s = value;
       
  3602 	 *s && (*s++ != Meta || *s++ != 32); len_value++);
       
  3603     s = str = (char *) zalloc(len_name + len_value + 2);
       
  3604     strcpy(s, name);
       
  3605     s += len_name;
       
  3606     *s = '=';
       
  3607     copyenvstr(s, value, flags);
       
  3608     return str;
       
  3609 }
       
  3610 
       
  3611 /* Given *name = "foo", *value = "bar", add the    *
       
  3612  * string "foo=bar" to the environment.  Return a  *
       
  3613  * pointer to the location of this new environment *
       
  3614  * string.                                         */
       
  3615 
       
  3616 
       
  3617 /**/
       
  3618 void
       
  3619 delenvvalue(char *x)
       
  3620 {
       
  3621 #ifdef __SYMBIAN32__
       
  3622 		// Use unsetenv to unset user defined environmental variables. 
       
  3623 		// unsetenv unsets environmental variables from Backend heap, which were allocated by setenv
       
  3624     	unsetenv(x);
       
  3625 #else	
       
  3626     	// use zsfree to unset user defined environmental variables
       
  3627     	// zsfree unsets environmental variables allocated on user heap
       
  3628     	char **ep;
       
  3629         
       
  3630     	for (ep = environ; *ep; ep++) {
       
  3631     	if (*ep == x)
       
  3632     	    break;
       
  3633         }
       
  3634         
       
  3635         if (*ep) {
       
  3636     	for (; (ep[0] = ep[1]); ep++);
       
  3637         }
       
  3638 
       
  3639         zsfree(x);
       
  3640 #endif
       
  3641 }
       
  3642 
       
  3643 /* Delete a pointer from the list of pointers to environment *
       
  3644  * variables by shifting all the other pointers up one slot. */
       
  3645 
       
  3646 /**/
       
  3647 void
       
  3648 delenv(Param pm)
       
  3649 {
       
  3650     delenvvalue(pm->env);
       
  3651     pm->env = NULL;
       
  3652     /*
       
  3653      * Note we don't remove PM_EXPORT from the flags.  This
       
  3654      * may be asking for trouble but we need to know later
       
  3655      * if we restore this parameter to its old value.
       
  3656      */
       
  3657 }
       
  3658 
       
  3659 /**/
       
  3660 mod_export void
       
  3661 convbase(char *s, zlong v, int base)
       
  3662 {
       
  3663     int digs = 0;
       
  3664     zulong x;
       
  3665 
       
  3666     if (v < 0)
       
  3667 	*s++ = '-', v = -v;
       
  3668     if (base >= -1 && base <= 1)
       
  3669 	base = -10;
       
  3670 
       
  3671     if (base > 0) {
       
  3672 	if (isset(CBASES) && base == 16)
       
  3673 	    sprintf(s, "0x");
       
  3674 	else if (isset(CBASES) && base == 8 && isset(OCTALZEROES))
       
  3675 	    sprintf(s, "0");
       
  3676 	else if (base != 10)
       
  3677 	    sprintf(s, "%d#", base);
       
  3678 	else
       
  3679 	    *s = 0;
       
  3680 	s += strlen(s);
       
  3681     } else
       
  3682 	base = -base;
       
  3683     for (x = v; x; digs++)
       
  3684 	x /= base;
       
  3685     if (!digs)
       
  3686 	digs = 1;
       
  3687     s[digs--] = '\0';
       
  3688     x = v;
       
  3689     while (digs >= 0) {
       
  3690 	int dig = x % base;
       
  3691 
       
  3692 	s[digs--] = (dig < 10) ? '0' + dig : dig - 10 + 'A';
       
  3693 	x /= base;
       
  3694     }
       
  3695 }
       
  3696 
       
  3697 /*
       
  3698  * Convert a floating point value for output.
       
  3699  * Unlike convbase(), this has its own internal storage and returns
       
  3700  * a value from the heap.
       
  3701  */
       
  3702 
       
  3703 /**/
       
  3704 char *
       
  3705 convfloat(double dval, int digits, int flags, FILE *fout)
       
  3706 {
       
  3707     char fmt[] = "%.*e";
       
  3708     char *prev_locale, *ret;
       
  3709 
       
  3710     /*
       
  3711      * The difficulty with the buffer size is that a %f conversion
       
  3712      * prints all digits before the decimal point: with 64 bit doubles,
       
  3713      * that's around 310.  We can't check without doing some quite
       
  3714      * serious floating point operations we'd like to avoid.
       
  3715      * Then we are liable to get all the digits
       
  3716      * we asked for after the decimal point, or we should at least
       
  3717      * bargain for it.  So we just allocate 512 + digits.  This
       
  3718      * should work until somebody decides on 128-bit doubles.
       
  3719      */
       
  3720     if (!(flags & (PM_EFLOAT|PM_FFLOAT))) {
       
  3721 	/*
       
  3722 	 * Conversion from a floating point expression without using
       
  3723 	 * a variable.  The best bet in this case just seems to be
       
  3724 	 * to use the general %g format with something like the maximum
       
  3725 	 * double precision.
       
  3726 	 */
       
  3727 	fmt[3] = 'g';
       
  3728 	if (!digits)
       
  3729 	    digits = 17;
       
  3730     } else {
       
  3731 	if (flags & PM_FFLOAT)
       
  3732 	    fmt[3] = 'f';
       
  3733 	if (digits <= 0)
       
  3734 	    digits = 10;
       
  3735 	if (flags & PM_EFLOAT) {
       
  3736 	    /*
       
  3737 	     * Here, we are given the number of significant figures, but
       
  3738 	     * %e wants the number of decimal places (unlike %g)
       
  3739 	     */
       
  3740 	    digits--;
       
  3741 	}
       
  3742     }
       
  3743 #ifdef USE_LOCALE
       
  3744     prev_locale = dupstring(setlocale(LC_NUMERIC, NULL));
       
  3745     setlocale(LC_NUMERIC, "POSIX");
       
  3746 #endif
       
  3747     if (fout) {
       
  3748 	fprintf(fout, fmt, digits, dval);
       
  3749 	ret = NULL;
       
  3750     } else {
       
  3751 	VARARR(char, buf, 512 + digits);
       
  3752 	sprintf(buf, fmt, digits, dval);
       
  3753 	if (!strchr(buf, 'e') && !strchr(buf, '.'))
       
  3754 	    strcat(buf, ".");
       
  3755 	ret = dupstring(buf);
       
  3756     }
       
  3757 #ifdef USE_LOCALE
       
  3758     if (prev_locale) setlocale(LC_NUMERIC, prev_locale);
       
  3759 #endif
       
  3760     return ret;
       
  3761 }
       
  3762 
       
  3763 /* Start a parameter scope */
       
  3764 
       
  3765 /**/
       
  3766 mod_export void
       
  3767 startparamscope(void)
       
  3768 {
       
  3769     locallevel++;
       
  3770 }
       
  3771 
       
  3772 /* End a parameter scope: delete the parameters local to the scope. */
       
  3773 
       
  3774 /**/
       
  3775 mod_export void
       
  3776 endparamscope(void)
       
  3777 {
       
  3778     locallevel--;
       
  3779     /* This pops anything from a higher locallevel */
       
  3780     saveandpophiststack(0, HFILE_USE_OPTIONS);
       
  3781     scanhashtable(paramtab, 0, 0, 0, scanendscope, 0);
       
  3782 }
       
  3783 
       
  3784 /**/
       
  3785 static void
       
  3786 scanendscope(HashNode hn, UNUSED(int flags))
       
  3787 {
       
  3788     Param pm = (Param)hn;
       
  3789     if (pm->level > locallevel) {
       
  3790 	if ((pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL) {
       
  3791 	    /*
       
  3792 	     * Removable specials are normal in that they can be removed
       
  3793 	     * to reveal an ordinary parameter beneath.  Here we handle
       
  3794 	     * non-removable specials, which were made local by stealth
       
  3795 	     * (see newspecial code in typeset_single()).  In fact the
       
  3796 	     * visible pm is always the same struct; the pm->old is
       
  3797 	     * just a place holder for old data and flags.
       
  3798 	     */
       
  3799 	    Param tpm = pm->old;
       
  3800 
       
  3801 	    if (!strcmp(pm->nam, "SECONDS"))
       
  3802 	    {
       
  3803 		setsecondstype(pm, PM_TYPE(tpm->flags), PM_TYPE(pm->flags));
       
  3804 		/*
       
  3805 		 * We restore SECONDS by restoring its raw internal value
       
  3806 		 * that we cached off into tpm->u.dval.
       
  3807 		 */
       
  3808 		setrawseconds(tpm->u.dval);
       
  3809 		tpm->flags |= PM_NORESTORE;
       
  3810 	    }
       
  3811 	    DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) ||
       
  3812 		  !(tpm->flags & PM_SPECIAL),
       
  3813 		  "BUG: in restoring scope of special parameter");
       
  3814 	    pm->old = tpm->old;
       
  3815 	    pm->flags = (tpm->flags & ~PM_NORESTORE);
       
  3816 	    pm->level = tpm->level;
       
  3817 	    pm->base = tpm->base;
       
  3818 	    pm->width = tpm->width;
       
  3819 	    if (pm->env)
       
  3820 		delenv(pm);
       
  3821 
       
  3822 	    if (!(tpm->flags & PM_NORESTORE))
       
  3823 		switch (PM_TYPE(pm->flags)) {
       
  3824 		case PM_SCALAR:
       
  3825 		    pm->gsu.s->setfn(pm, tpm->u.str);
       
  3826 		    break;
       
  3827 		case PM_INTEGER:
       
  3828 		    pm->gsu.i->setfn(pm, tpm->u.val);
       
  3829 		    break;
       
  3830 		case PM_EFLOAT:
       
  3831 		case PM_FFLOAT:
       
  3832 		    pm->gsu.f->setfn(pm, tpm->u.dval);
       
  3833 		    break;
       
  3834 		case PM_ARRAY:
       
  3835 		    pm->gsu.a->setfn(pm, tpm->u.arr);
       
  3836 		    break;
       
  3837 		case PM_HASHED:
       
  3838 		    pm->gsu.h->setfn(pm, tpm->u.hash);
       
  3839 		    break;
       
  3840 		}
       
  3841 	    zfree(tpm, sizeof(*tpm));
       
  3842 
       
  3843 	    if (pm->flags & PM_EXPORTED)
       
  3844 		export_param(pm);
       
  3845 	} else
       
  3846 	    unsetparam_pm(pm, 0, 0);
       
  3847     }
       
  3848 }
       
  3849 
       
  3850 
       
  3851 /**********************************/
       
  3852 /* Parameter Hash Table Functions */
       
  3853 /**********************************/
       
  3854 
       
  3855 /**/
       
  3856 void
       
  3857 freeparamnode(HashNode hn)
       
  3858 {
       
  3859     Param pm = (Param) hn;
       
  3860  
       
  3861     /* Since the second flag to unsetfn isn't used, I don't *
       
  3862      * know what its value should be.                       */
       
  3863     if (delunset)
       
  3864 	pm->gsu.s->unsetfn(pm, 1);
       
  3865     zsfree(pm->nam);
       
  3866     /* If this variable was tied by the user, ename was ztrdup'd */
       
  3867     if (pm->flags & PM_TIED)
       
  3868 	zsfree(pm->ename);
       
  3869     zfree(pm, sizeof(struct param));
       
  3870 }
       
  3871 
       
  3872 /* Print a parameter */
       
  3873 
       
  3874 enum paramtypes_flags {
       
  3875     PMTF_USE_BASE	= (1<<0),
       
  3876     PMTF_USE_WIDTH	= (1<<1),
       
  3877     PMTF_TEST_LEVEL	= (1<<2)
       
  3878 };
       
  3879 
       
  3880 struct paramtypes {
       
  3881     int binflag;	/* The relevant PM_FLAG(S) */
       
  3882     const char *string;	/* String for verbose output */
       
  3883     int typeflag;	/* Flag for typeset -? */
       
  3884     int flags;		/* The enum above */
       
  3885 };
       
  3886 
       
  3887 static const struct paramtypes pmtypes[] = {
       
  3888     { PM_AUTOLOAD, "undefined", 0, 0},
       
  3889     { PM_INTEGER, "integer", 'i', PMTF_USE_BASE},
       
  3890     { PM_EFLOAT, "float", 'E', 0},
       
  3891     { PM_FFLOAT, "float", 'F', 0},
       
  3892     { PM_ARRAY, "array", 'a', 0},
       
  3893     { PM_HASHED, "association", 'A', 0},
       
  3894     { 0, "local", 0, PMTF_TEST_LEVEL},
       
  3895     { PM_LEFT, "left justified", 'L', PMTF_USE_WIDTH},
       
  3896     { PM_RIGHT_B, "right justified", 'R', PMTF_USE_WIDTH},
       
  3897     { PM_RIGHT_Z, "zero filled", 'Z', PMTF_USE_WIDTH},
       
  3898     { PM_LOWER, "lowercase", 'l', 0},
       
  3899     { PM_UPPER, "uppercase", 'u', 0},
       
  3900     { PM_READONLY, "readonly", 'r', 0},
       
  3901     { PM_TAGGED, "tagged", 't', 0},
       
  3902     { PM_EXPORTED, "exported", 'x', 0}
       
  3903 };
       
  3904 
       
  3905 #define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
       
  3906 
       
  3907 /**/
       
  3908 mod_export void
       
  3909 printparamnode(HashNode hn, int printflags)
       
  3910 {
       
  3911     Param p = (Param) hn;
       
  3912     char *t, **u;
       
  3913 
       
  3914     if (p->flags & PM_UNSET)
       
  3915 	return;
       
  3916 
       
  3917     if (printflags & PRINT_TYPESET)
       
  3918 	printf("typeset ");
       
  3919 
       
  3920     /* Print the attributes of the parameter */
       
  3921     if (printflags & (PRINT_TYPE|PRINT_TYPESET)) {
       
  3922 	int doneminus = 0, i;
       
  3923 	const struct paramtypes *pmptr;
       
  3924 
       
  3925 	for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
       
  3926 	    int doprint = 0;
       
  3927 	    if (pmptr->flags & PMTF_TEST_LEVEL) {
       
  3928 		if (p->level)
       
  3929 		    doprint = 1;
       
  3930 	    } else if (p->flags & pmptr->binflag)
       
  3931 		doprint = 1;
       
  3932 
       
  3933 	    if (doprint) {
       
  3934 		if (printflags & PRINT_TYPESET) {
       
  3935 		    if (pmptr->typeflag) {
       
  3936 			if (!doneminus) {
       
  3937 			    putchar('-');
       
  3938 			    doneminus = 1;
       
  3939 			}
       
  3940 			putchar(pmptr->typeflag);
       
  3941 		    }
       
  3942 		} else {
       
  3943 		    printf("%s ", pmptr->string);
       
  3944 		}
       
  3945 		if ((pmptr->flags & PMTF_USE_BASE) && p->base) {
       
  3946 		    printf("%d ", p->base);
       
  3947 		    doneminus = 0;
       
  3948 		}
       
  3949 		if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
       
  3950 		    printf("%d ", p->width);
       
  3951 		    doneminus = 0;
       
  3952 		}
       
  3953 	    }
       
  3954 	}
       
  3955 	if (doneminus)
       
  3956 	    putchar(' ');
       
  3957     }
       
  3958 
       
  3959     if ((printflags & PRINT_NAMEONLY) ||
       
  3960 	((p->flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
       
  3961 	zputs(p->nam, stdout);
       
  3962 	putchar('\n');
       
  3963 	return;
       
  3964     }
       
  3965 
       
  3966     quotedzputs(p->nam, stdout);
       
  3967 
       
  3968     if (p->flags & PM_AUTOLOAD) {
       
  3969 	putchar('\n');
       
  3970 	return;
       
  3971     }
       
  3972     if (printflags & PRINT_KV_PAIR)
       
  3973 	putchar(' ');
       
  3974     else if ((printflags & PRINT_TYPESET) &&
       
  3975 	     (PM_TYPE(p->flags) == PM_ARRAY || PM_TYPE(p->flags) == PM_HASHED))
       
  3976 	printf("\n%s=", p->nam);
       
  3977     else
       
  3978 	putchar('=');
       
  3979 
       
  3980     /* How the value is displayed depends *
       
  3981      * on the type of the parameter       */
       
  3982     switch (PM_TYPE(p->flags)) {
       
  3983     case PM_SCALAR:
       
  3984 	/* string: simple output */
       
  3985 	if (p->gsu.s->getfn && (t = p->gsu.s->getfn(p)))
       
  3986 	    quotedzputs(t, stdout);
       
  3987 	break;
       
  3988     case PM_INTEGER:
       
  3989 	/* integer */
       
  3990 #ifdef ZSH_64_BIT_TYPE
       
  3991 	fputs(output64(p->gsu.i->getfn(p)), stdout);
       
  3992 #else
       
  3993 	printf("%ld", p->gsu.i->getfn(p));
       
  3994 #endif
       
  3995 	break;
       
  3996     case PM_EFLOAT:
       
  3997     case PM_FFLOAT:
       
  3998 	/* float */
       
  3999 	convfloat(p->gsu.f->getfn(p), p->base, p->flags, stdout);
       
  4000 	break;
       
  4001     case PM_ARRAY:
       
  4002 	/* array */
       
  4003 	if (!(printflags & PRINT_KV_PAIR))
       
  4004 	    putchar('(');
       
  4005 	u = p->gsu.a->getfn(p);
       
  4006 	if(*u) {
       
  4007 	    quotedzputs(*u++, stdout);
       
  4008 	    while (*u) {
       
  4009 		putchar(' ');
       
  4010 		quotedzputs(*u++, stdout);
       
  4011 	    }
       
  4012 	}
       
  4013 	if (!(printflags & PRINT_KV_PAIR))
       
  4014 	    putchar(')');
       
  4015 	break;
       
  4016     case PM_HASHED:
       
  4017 	/* association */
       
  4018 	if (!(printflags & PRINT_KV_PAIR))
       
  4019 	    putchar('(');
       
  4020 	{
       
  4021             HashTable ht = p->gsu.h->getfn(p);
       
  4022             if (ht)
       
  4023 		scanhashtable(ht, 0, 0, PM_UNSET,
       
  4024 			      ht->printnode, PRINT_KV_PAIR);
       
  4025 	}
       
  4026 	if (!(printflags & PRINT_KV_PAIR))
       
  4027 	    putchar(')');
       
  4028 	break;
       
  4029     }
       
  4030     if (printflags & PRINT_KV_PAIR)
       
  4031 	putchar(' ');
       
  4032     else
       
  4033 	putchar('\n');
       
  4034 }