summaryrefslogtreecommitdiff
path: root/dotfiles/system/.zsh/modules/Src/params.c
diff options
context:
space:
mode:
Diffstat (limited to 'dotfiles/system/.zsh/modules/Src/params.c')
-rw-r--r--dotfiles/system/.zsh/modules/Src/params.c5884
1 files changed, 0 insertions, 5884 deletions
diff --git a/dotfiles/system/.zsh/modules/Src/params.c b/dotfiles/system/.zsh/modules/Src/params.c
deleted file mode 100644
index a1c299f..0000000
--- a/dotfiles/system/.zsh/modules/Src/params.c
+++ /dev/null
@@ -1,5884 +0,0 @@
-/*
- * params.c - parameters
- *
- * This file is part of zsh, the Z shell.
- *
- * Copyright (c) 1992-1997 Paul Falstad
- * All rights reserved.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and to distribute modified versions of this software for any
- * purpose, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * In no event shall Paul Falstad or the Zsh Development Group be liable
- * to any party for direct, indirect, special, incidental, or consequential
- * damages arising out of the use of this software and its documentation,
- * even if Paul Falstad and the Zsh Development Group have been advised of
- * the possibility of such damage.
- *
- * Paul Falstad and the Zsh Development Group specifically disclaim any
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose. The software
- * provided hereunder is on an "as is" basis, and Paul Falstad and the
- * Zsh Development Group have no obligation to provide maintenance,
- * support, updates, enhancements, or modifications.
- *
- */
-
-#include "zsh.mdh"
-#include "params.pro"
-
-#include "version.h"
-#ifdef CUSTOM_PATCHLEVEL
-#define ZSH_PATCHLEVEL CUSTOM_PATCHLEVEL
-#else
-#include "patchlevel.h"
-
-#include <math.h>
-
-/* If removed from the ChangeLog for some reason */
-#ifndef ZSH_PATCHLEVEL
-#define ZSH_PATCHLEVEL "unknown"
-#endif
-#endif
-
-/* what level of localness we are at */
-
-/**/
-mod_export int locallevel;
-
-/* Variables holding values of special parameters */
-
-/**/
-mod_export
-char **pparams, /* $argv */
- **cdpath, /* $cdpath */
- **fpath, /* $fpath */
- **mailpath, /* $mailpath */
- **manpath, /* $manpath */
- **psvar, /* $psvar */
- **watch, /* $watch */
- **zsh_eval_context; /* $zsh_eval_context */
-/**/
-mod_export
-char **path, /* $path */
- **fignore; /* $fignore */
-
-/**/
-mod_export
-char *argzero, /* $0 */
- *posixzero, /* $0 */
- *home, /* $HOME */
- *nullcmd, /* $NULLCMD */
- *oldpwd, /* $OLDPWD */
- *zoptarg, /* $OPTARG */
- *prompt, /* $PROMPT */
- *prompt2, /* $PROMPT2 */
- *prompt3, /* $PROMPT3 */
- *prompt4, /* $PROMPT4 */
- *readnullcmd, /* $READNULLCMD */
- *rprompt, /* $RPROMPT */
- *rprompt2, /* $RPROMPT2 */
- *sprompt, /* $SPROMPT */
- *wordchars; /* $WORDCHARS */
-/**/
-mod_export
-char *ifs, /* $IFS */
- *postedit, /* $POSTEDIT */
- *term, /* $TERM */
- *zsh_terminfo, /* $TERMINFO */
- *zsh_terminfodirs, /* $TERMINFO_DIRS */
- *ttystrname, /* $TTY */
- *pwd; /* $PWD */
-
-/**/
-mod_export
-zlong lastval, /* $? */
- mypid, /* $$ */
- lastpid, /* $! */
- zterm_columns, /* $COLUMNS */
- zterm_lines, /* $LINES */
- rprompt_indent, /* $ZLE_RPROMPT_INDENT */
- ppid, /* $PPID */
- zsh_subshell; /* $ZSH_SUBSHELL */
-
-/* $FUNCNEST */
-/**/
-mod_export
-zlong zsh_funcnest =
-#ifdef MAX_FUNCTION_DEPTH
- MAX_FUNCTION_DEPTH
-#else
- /* Disabled by default but can be enabled at run time */
- -1
-#endif
- ;
-
-/**/
-zlong lineno, /* $LINENO */
- zoptind, /* $OPTIND */
- shlvl; /* $SHLVL */
-
-/* $histchars */
-
-/**/
-mod_export unsigned char bangchar;
-/**/
-unsigned char hatchar, hashchar;
-
-/**/
-unsigned char keyboardhackchar = '\0';
-
-/* $SECONDS = now.tv_sec - shtimer.tv_sec
- * + (now.tv_usec - shtimer.tv_usec) / 1000000.0
- * (rounded to an integer if the parameter is not set to float) */
-
-/**/
-struct timeval shtimer;
-
-/* 0 if this $TERM setup is usable, otherwise it contains TERM_* flags */
-
-/**/
-mod_export int termflags;
-
-/* Forward declaration */
-
-static void
-rprompt_indent_unsetfn(Param pm, int exp);
-
-/* Standard methods for get/set/unset pointers in parameters */
-
-/**/
-mod_export const struct gsu_scalar stdscalar_gsu =
-{ strgetfn, strsetfn, stdunsetfn };
-/**/
-mod_export const struct gsu_scalar varscalar_gsu =
-{ strvargetfn, strvarsetfn, stdunsetfn };
-/**/
-mod_export const struct gsu_scalar nullsetscalar_gsu =
-{ strgetfn, nullstrsetfn, NULL };
-
-/**/
-mod_export const struct gsu_integer stdinteger_gsu =
-{ intgetfn, intsetfn, stdunsetfn };
-/**/
-mod_export const struct gsu_integer varinteger_gsu =
-{ intvargetfn, intvarsetfn, stdunsetfn };
-/**/
-mod_export const struct gsu_integer nullsetinteger_gsu =
-{ intgetfn, NULL, NULL };
-
-/**/
-mod_export const struct gsu_float stdfloat_gsu =
-{ floatgetfn, floatsetfn, stdunsetfn };
-
-/**/
-mod_export const struct gsu_array stdarray_gsu =
-{ arrgetfn, arrsetfn, stdunsetfn };
-/**/
-mod_export const struct gsu_array vararray_gsu =
-{ arrvargetfn, arrvarsetfn, stdunsetfn };
-
-/**/
-mod_export const struct gsu_hash stdhash_gsu =
-{ hashgetfn, hashsetfn, stdunsetfn };
-/**/
-mod_export const struct gsu_hash nullsethash_gsu =
-{ hashgetfn, nullsethashfn, nullunsetfn };
-
-
-/* Non standard methods (not exported) */
-static const struct gsu_integer pound_gsu =
-{ poundgetfn, nullintsetfn, stdunsetfn };
-static const struct gsu_integer errno_gsu =
-{ errnogetfn, errnosetfn, stdunsetfn };
-static const struct gsu_integer gid_gsu =
-{ gidgetfn, gidsetfn, stdunsetfn };
-static const struct gsu_integer egid_gsu =
-{ egidgetfn, egidsetfn, stdunsetfn };
-static const struct gsu_integer histsize_gsu =
-{ histsizegetfn, histsizesetfn, stdunsetfn };
-static const struct gsu_integer random_gsu =
-{ randomgetfn, randomsetfn, stdunsetfn };
-static const struct gsu_integer savehist_gsu =
-{ savehistsizegetfn, savehistsizesetfn, stdunsetfn };
-static const struct gsu_integer intseconds_gsu =
-{ intsecondsgetfn, intsecondssetfn, stdunsetfn };
-static const struct gsu_float floatseconds_gsu =
-{ floatsecondsgetfn, floatsecondssetfn, stdunsetfn };
-static const struct gsu_integer uid_gsu =
-{ uidgetfn, uidsetfn, stdunsetfn };
-static const struct gsu_integer euid_gsu =
-{ euidgetfn, euidsetfn, stdunsetfn };
-static const struct gsu_integer ttyidle_gsu =
-{ ttyidlegetfn, nullintsetfn, stdunsetfn };
-
-static const struct gsu_scalar argzero_gsu =
-{ argzerogetfn, argzerosetfn, nullunsetfn };
-static const struct gsu_scalar username_gsu =
-{ usernamegetfn, usernamesetfn, stdunsetfn };
-static const struct gsu_scalar dash_gsu =
-{ dashgetfn, nullstrsetfn, stdunsetfn };
-static const struct gsu_scalar histchars_gsu =
-{ histcharsgetfn, histcharssetfn, stdunsetfn };
-static const struct gsu_scalar home_gsu =
-{ homegetfn, homesetfn, stdunsetfn };
-static const struct gsu_scalar term_gsu =
-{ termgetfn, termsetfn, stdunsetfn };
-static const struct gsu_scalar terminfo_gsu =
-{ terminfogetfn, terminfosetfn, stdunsetfn };
-static const struct gsu_scalar terminfodirs_gsu =
-{ terminfodirsgetfn, terminfodirssetfn, stdunsetfn };
-static const struct gsu_scalar wordchars_gsu =
-{ wordcharsgetfn, wordcharssetfn, stdunsetfn };
-static const struct gsu_scalar ifs_gsu =
-{ ifsgetfn, ifssetfn, stdunsetfn };
-static const struct gsu_scalar underscore_gsu =
-{ underscoregetfn, nullstrsetfn, stdunsetfn };
-static const struct gsu_scalar keyboard_hack_gsu =
-{ keyboardhackgetfn, keyboardhacksetfn, stdunsetfn };
-#ifdef USE_LOCALE
-static const struct gsu_scalar lc_blah_gsu =
-{ strgetfn, lcsetfn, stdunsetfn };
-static const struct gsu_scalar lang_gsu =
-{ strgetfn, langsetfn, stdunsetfn };
-static const struct gsu_scalar lc_all_gsu =
-{ strgetfn, lc_allsetfn, stdunsetfn };
-#endif
-
-static const struct gsu_integer varint_readonly_gsu =
-{ intvargetfn, nullintsetfn, stdunsetfn };
-static const struct gsu_integer zlevar_gsu =
-{ intvargetfn, zlevarsetfn, stdunsetfn };
-
-static const struct gsu_scalar colonarr_gsu =
-{ colonarrgetfn, colonarrsetfn, stdunsetfn };
-
-static const struct gsu_integer argc_gsu =
-{ poundgetfn, nullintsetfn, stdunsetfn };
-static const struct gsu_array pipestatus_gsu =
-{ pipestatgetfn, pipestatsetfn, stdunsetfn };
-
-static const struct gsu_integer rprompt_indent_gsu =
-{ intvargetfn, zlevarsetfn, rprompt_indent_unsetfn };
-
-/* Nodes for special parameters for parameter hash table */
-
-#ifdef HAVE_UNION_INIT
-# define BR(X) {X}
-typedef struct param initparam;
-#else
-# define BR(X) X
-typedef struct iparam {
- struct hashnode *next;
- char *nam; /* hash data */
- int flags; /* PM_* flags (defined in zsh.h) */
- void *value;
- void *gsu; /* get/set/unset methods */
- int base; /* output base */
- int width; /* output field width */
- char *env; /* location in environment, if exported */
- char *ename; /* name of corresponding environment var */
- Param old; /* old struct for use with local */
- int level; /* if (old != NULL), level of localness */
-} initparam;
-#endif
-
-static initparam special_params[] ={
-#define GSU(X) BR((GsuScalar)(void *)(&(X)))
-#define NULL_GSU BR((GsuScalar)(void *)NULL)
-#define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
-IPDEF1("#", pound_gsu, PM_READONLY),
-IPDEF1("ERRNO", errno_gsu, PM_UNSET),
-IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("HISTSIZE", histsize_gsu, PM_RESTRICTED),
-IPDEF1("RANDOM", random_gsu, 0),
-IPDEF1("SAVEHIST", savehist_gsu, PM_RESTRICTED),
-IPDEF1("SECONDS", intseconds_gsu, 0),
-IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY),
-
-#define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
-IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
-IPDEF2("-", dash_gsu, PM_READONLY),
-IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
-IPDEF2("HOME", home_gsu, PM_UNSET),
-IPDEF2("TERM", term_gsu, PM_UNSET),
-IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET),
-IPDEF2("TERMINFO_DIRS", terminfodirs_gsu, PM_UNSET),
-IPDEF2("WORDCHARS", wordchars_gsu, 0),
-IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF2("_", underscore_gsu, PM_DONTIMPORT),
-IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT),
-IPDEF2("0", argzero_gsu, 0),
-
-#ifdef USE_LOCALE
-# define LCIPDEF(name) IPDEF2(name, lc_blah_gsu, PM_UNSET)
-IPDEF2("LANG", lang_gsu, PM_UNSET),
-IPDEF2("LC_ALL", lc_all_gsu, PM_UNSET),
-# ifdef LC_COLLATE
-LCIPDEF("LC_COLLATE"),
-# endif
-# ifdef LC_CTYPE
-LCIPDEF("LC_CTYPE"),
-# endif
-# ifdef LC_MESSAGES
-LCIPDEF("LC_MESSAGES"),
-# endif
-# ifdef LC_NUMERIC
-LCIPDEF("LC_NUMERIC"),
-# endif
-# ifdef LC_TIME
-LCIPDEF("LC_TIME"),
-# endif
-#endif /* USE_LOCALE */
-
-#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}
-IPDEF4("!", &lastpid),
-IPDEF4("$", &mypid),
-IPDEF4("?", &lastval),
-IPDEF4("HISTCMD", &curhist),
-IPDEF4("LINENO", &lineno),
-IPDEF4("PPID", &ppid),
-IPDEF4("ZSH_SUBSHELL", &zsh_subshell),
-
-#define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
-#define IPDEF5U(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
-IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu),
-IPDEF5("LINES", &zterm_lines, zlevar_gsu),
-IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, rprompt_indent_gsu),
-IPDEF5("SHLVL", &shlvl, varinteger_gsu),
-IPDEF5("FUNCNEST", &zsh_funcnest, varinteger_gsu),
-
-/* Don't import internal integer status variables. */
-#define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
-IPDEF6("OPTIND", &zoptind, varinteger_gsu),
-IPDEF6("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu),
-IPDEF6("TRY_BLOCK_INTERRUPT", &try_interrupt, varinteger_gsu),
-
-#define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
-#define IPDEF7R(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_DONTIMPORT_SUID},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
-#define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
-IPDEF7("OPTARG", &zoptarg),
-IPDEF7("NULLCMD", &nullcmd),
-IPDEF7U("POSTEDIT", &postedit),
-IPDEF7("READNULLCMD", &readnullcmd),
-IPDEF7("PS1", &prompt),
-IPDEF7U("RPS1", &rprompt),
-IPDEF7U("RPROMPT", &rprompt),
-IPDEF7("PS2", &prompt2),
-IPDEF7U("RPS2", &rprompt2),
-IPDEF7U("RPROMPT2", &rprompt2),
-IPDEF7("PS3", &prompt3),
-IPDEF7R("PS4", &prompt4),
-IPDEF7("SPROMPT", &sprompt),
-
-#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}
-#define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
-IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
-IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
-
-/*
- * This empty row indicates the end of parameters available in
- * all emulations.
- */
-{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
-
-#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}
-IPDEF8("CDPATH", &cdpath, "cdpath", 0),
-IPDEF8("FIGNORE", &fignore, "fignore", 0),
-IPDEF8("FPATH", &fpath, "fpath", 0),
-IPDEF8("MAILPATH", &mailpath, "mailpath", 0),
-IPDEF8("WATCH", &watch, "watch", 0),
-IPDEF8("PATH", &path, "path", PM_RESTRICTED),
-IPDEF8("PSVAR", &psvar, "psvar", 0),
-IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY),
-
-/* MODULE_PATH is not imported for security reasons */
-IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
-
-#define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
-
-/*
- * The following parameters are not available in sh/ksh compatibility *
- * mode.
- */
-
-/* All of these have sh compatible equivalents. */
-IPDEF1("ARGC", argc_gsu, PM_READONLY),
-IPDEF2("HISTCHARS", histchars_gsu, PM_DONTIMPORT),
-IPDEF4("status", &lastval),
-IPDEF7("prompt", &prompt),
-IPDEF7("PROMPT", &prompt),
-IPDEF7("PROMPT2", &prompt2),
-IPDEF7("PROMPT3", &prompt3),
-IPDEF7("PROMPT4", &prompt4),
-IPDEF8("MANPATH", &manpath, "manpath", 0),
-IPDEF9("argv", &pparams, NULL),
-IPDEF9("fignore", &fignore, "FIGNORE"),
-IPDEF9("cdpath", &cdpath, "CDPATH"),
-IPDEF9("fpath", &fpath, "FPATH"),
-IPDEF9("mailpath", &mailpath, "MAILPATH"),
-IPDEF9("manpath", &manpath, "MANPATH"),
-IPDEF9("psvar", &psvar, "PSVAR"),
-IPDEF9("watch", &watch, "WATCH"),
-
-IPDEF9F("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_READONLY),
-
-IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
-IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
-
-/* These are known to zsh alone. */
-
-IPDEF10("pipestatus", pipestatus_gsu),
-
-{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
-};
-
-/*
- * Alternative versions of colon-separated path parameters for
- * sh emulation. These don't link to the array versions.
- */
-static initparam special_params_sh[] = {
-IPDEF8("CDPATH", &cdpath, NULL, 0),
-IPDEF8("FIGNORE", &fignore, NULL, 0),
-IPDEF8("FPATH", &fpath, NULL, 0),
-IPDEF8("MAILPATH", &mailpath, NULL, 0),
-IPDEF8("WATCH", &watch, NULL, 0),
-IPDEF8("PATH", &path, NULL, PM_RESTRICTED),
-IPDEF8("PSVAR", &psvar, NULL, 0),
-IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY),
-
-/* MODULE_PATH is not imported for security reasons */
-IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED),
-
-{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
-};
-
-/*
- * Special way of referring to the positional parameters. Unlike $*
- * and $@, this is not readonly. This parameter is not directly
- * visible in user space.
- */
-static initparam argvparam_pm = IPDEF9F("", &pparams, NULL, \
- PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT);
-
-#undef BR
-
-#define IS_UNSET_VALUE(V) \
- ((V) && (!(V)->pm || ((V)->pm->node.flags & PM_UNSET) || \
- !(V)->pm->node.nam || !*(V)->pm->node.nam))
-
-static Param argvparam;
-
-/* hash table containing the parameters */
-
-/**/
-mod_export HashTable paramtab, realparamtab;
-
-/**/
-mod_export HashTable
-newparamtable(int size, char const *name)
-{
- HashTable ht;
- if (!size)
- size = 17;
- ht = newhashtable(size, name, NULL);
-
- ht->hash = hasher;
- ht->emptytable = emptyhashtable;
- ht->filltable = NULL;
- ht->cmpnodes = strcmp;
- ht->addnode = addhashnode;
- ht->getnode = getparamnode;
- ht->getnode2 = gethashnode2;
- ht->removenode = removehashnode;
- ht->disablenode = NULL;
- ht->enablenode = NULL;
- ht->freenode = freeparamnode;
- ht->printnode = printparamnode;
-
- return ht;
-}
-
-/**/
-static HashNode
-getparamnode(HashTable ht, const char *nam)
-{
- HashNode hn = gethashnode2(ht, nam);
- Param pm = (Param) hn;
-
- if (pm && pm->u.str && (pm->node.flags & PM_AUTOLOAD)) {
- char *mn = dupstring(pm->u.str);
-
- (void)ensurefeature(mn, "p:", (pm->node.flags & PM_AUTOALL) ? NULL :
- nam);
- hn = gethashnode2(ht, nam);
- if (!hn) {
- /*
- * This used to be a warning, but surely if we allow
- * stuff to go ahead with the autoload stub with
- * no error status we're in for all sorts of mayhem?
- */
- zerr("autoloading module %s failed to define parameter: %s", mn,
- nam);
- }
- }
- return hn;
-}
-
-/* Copy a parameter hash table */
-
-static HashTable outtable;
-
-/**/
-static void
-scancopyparams(HashNode hn, UNUSED(int flags))
-{
- /* Going into a real parameter, so always use permanent storage */
- Param pm = (Param)hn;
- Param tpm = (Param) zshcalloc(sizeof *tpm);
- tpm->node.nam = ztrdup(pm->node.nam);
- copyparam(tpm, pm, 0);
- addhashnode(outtable, tpm->node.nam, tpm);
-}
-
-/**/
-HashTable
-copyparamtable(HashTable ht, char *name)
-{
- HashTable nht = 0;
- if (ht) {
- nht = newparamtable(ht->hsize, name);
- outtable = nht;
- scanhashtable(ht, 0, 0, 0, scancopyparams, 0);
- outtable = NULL;
- }
- return nht;
-}
-
-/* Flag to freeparamnode to unset the struct */
-
-static int delunset;
-
-/* Function to delete a parameter table. */
-
-/**/
-mod_export void
-deleteparamtable(HashTable t)
-{
- /* The parameters in the hash table need to be unset *
- * before being deleted. */
- int odelunset = delunset;
- delunset = 1;
- deletehashtable(t);
- delunset = odelunset;
-}
-
-static unsigned numparamvals;
-
-/**/
-mod_export void
-scancountparams(UNUSED(HashNode hn), int flags)
-{
- ++numparamvals;
- if ((flags & SCANPM_WANTKEYS) && (flags & SCANPM_WANTVALS))
- ++numparamvals;
-}
-
-static Patprog scanprog;
-static char *scanstr;
-static char **paramvals;
-static Param foundparam;
-
-/**/
-static void
-scanparamvals(HashNode hn, int flags)
-{
- struct value v;
- Patprog prog;
-
- if (numparamvals && !(flags & SCANPM_MATCHMANY) &&
- (flags & (SCANPM_MATCHVAL|SCANPM_MATCHKEY|SCANPM_KEYMATCH)))
- return;
- v.pm = (Param)hn;
- if ((flags & SCANPM_KEYMATCH)) {
- char *tmp = dupstring(v.pm->node.nam);
-
- tokenize(tmp);
- remnulargs(tmp);
-
- if (!(prog = patcompile(tmp, 0, NULL)) || !pattry(prog, scanstr))
- return;
- } else if ((flags & SCANPM_MATCHKEY) && !pattry(scanprog, v.pm->node.nam)) {
- return;
- }
- foundparam = v.pm;
- if (flags & SCANPM_WANTKEYS) {
- paramvals[numparamvals++] = v.pm->node.nam;
- if (!(flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)))
- return;
- }
- v.isarr = (PM_TYPE(v.pm->node.flags) & (PM_ARRAY|PM_HASHED));
- v.flags = 0;
- v.start = 0;
- v.end = -1;
- paramvals[numparamvals] = getstrvalue(&v);
- if (flags & SCANPM_MATCHVAL) {
- if (pattry(scanprog, paramvals[numparamvals])) {
- numparamvals += ((flags & SCANPM_WANTVALS) ? 1 :
- !(flags & SCANPM_WANTKEYS));
- } else if (flags & SCANPM_WANTKEYS)
- --numparamvals; /* Value didn't match, discard key */
- } else
- ++numparamvals;
- foundparam = NULL;
-}
-
-/**/
-char **
-paramvalarr(HashTable ht, int flags)
-{
- DPUTS((flags & (SCANPM_MATCHKEY|SCANPM_MATCHVAL)) && !scanprog,
- "BUG: scanning hash without scanprog set");
- numparamvals = 0;
- if (ht)
- scanhashtable(ht, 0, 0, PM_UNSET, scancountparams, flags);
- paramvals = (char **) zhalloc((numparamvals + 1) * sizeof(char *));
- if (ht) {
- numparamvals = 0;
- scanhashtable(ht, 0, 0, PM_UNSET, scanparamvals, flags);
- }
- paramvals[numparamvals] = 0;
- return paramvals;
-}
-
-/* Return the full array (no indexing) referred to by a Value. *
- * The array value is cached for the lifetime of the Value. */
-
-/**/
-static char **
-getvaluearr(Value v)
-{
- if (v->arr)
- return v->arr;
- else if (PM_TYPE(v->pm->node.flags) == PM_ARRAY)
- return v->arr = v->pm->gsu.a->getfn(v->pm);
- else if (PM_TYPE(v->pm->node.flags) == PM_HASHED) {
- v->arr = paramvalarr(v->pm->gsu.h->getfn(v->pm), v->isarr);
- /* Can't take numeric slices of associative arrays */
- v->start = 0;
- v->end = numparamvals + 1;
- return v->arr;
- } else
- return NULL;
-}
-
-/* Return whether the variable is set *
- * checks that array slices are within range *
- * used for [[ -v ... ]] condition test */
-
-/**/
-int
-issetvar(char *name)
-{
- struct value vbuf;
- Value v;
- int slice;
- char **arr;
-
- if (!(v = getvalue(&vbuf, &name, 1)) || *name)
- return 0; /* no value or more chars after the variable name */
- if (v->isarr & ~SCANPM_ARRONLY)
- return v->end > 1; /* for extracted elements, end gives us a count */
-
- slice = v->start != 0 || v->end != -1;
- if (PM_TYPE(v->pm->node.flags) != PM_ARRAY || !slice)
- return !slice && !(v->pm->node.flags & PM_UNSET);
-
- if (!v->end) /* empty array slice */
- return 0;
- /* get the array and check end is within range */
- if (!(arr = getvaluearr(v)))
- return 0;
- return arrlen_ge(arr, v->end < 0 ? - v->end : v->end);
-}
-
-/*
- * Split environment string into (name, value) pair.
- * this is used to avoid in-place editing of environment table
- * that results in core dump on some systems
- */
-
-static int
-split_env_string(char *env, char **name, char **value)
-{
- char *str, *tenv;
-
- if (!env || !name || !value)
- return 0;
-
- tenv = strcpy(zhalloc(strlen(env) + 1), env);
- for (str = tenv; *str && *str != '='; str++) {
- if (STOUC(*str) >= 128) {
- /*
- * We'll ignore environment variables with names not
- * from the portable character set since we don't
- * know of a good reason to accept them.
- */
- return 0;
- }
- }
- if (str != tenv && *str == '=') {
- *str = '\0';
- *name = tenv;
- *value = str + 1;
- return 1;
- } else
- return 0;
-}
-
-/**
- * Check parameter flags to see if parameter shouldn't be imported
- * from environment at start.
- *
- * return 1: don't import: 0: ok to import.
- */
-static int dontimport(int flags)
-{
- /* If explicitly marked as don't export */
- if (flags & PM_DONTIMPORT)
- return 1;
- /* If value already exported */
- if (flags & PM_EXPORTED)
- return 1;
- /* If security issue when importing and running with some privilege */
- if ((flags & PM_DONTIMPORT_SUID) && isset(PRIVILEGED))
- return 1;
- /* OK to import */
- return 0;
-}
-
-/* Set up parameter hash table. This will add predefined *
- * parameter entries as well as setting up parameter table *
- * entries for environment variables we inherit. */
-
-/**/
-void
-createparamtable(void)
-{
- Param ip, pm;
-#if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV)
- char **new_environ;
- int envsize;
-#endif
-#ifndef USE_SET_UNSET_ENV
- char **envp;
-#endif
- char **envp2, **sigptr, **t;
- char buf[50], *str, *iname, *ivalue, *hostnam;
- int oae = opts[ALLEXPORT];
-#ifdef HAVE_UNAME
- struct utsname unamebuf;
- char *machinebuf;
-#endif
-
- paramtab = realparamtab = newparamtable(151, "paramtab");
-
- /* Add the special parameters to the hash table */
- for (ip = special_params; ip->node.nam; ip++)
- paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip);
- if (EMULATION(EMULATE_SH|EMULATE_KSH)) {
- for (ip = special_params_sh; ip->node.nam; ip++)
- paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip);
- } else {
- while ((++ip)->node.nam)
- paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip);
- }
-
- argvparam = (Param) &argvparam_pm;
-
- noerrs = 2;
-
- /* Add the standard non-special parameters which have to *
- * be initialized before we copy the environment variables. *
- * We don't want to override whatever values the user has *
- * given them in the environment. */
- opts[ALLEXPORT] = 0;
- setiparam("MAILCHECK", 60);
- setiparam("LOGCHECK", 60);
- setiparam("KEYTIMEOUT", 40);
- setiparam("LISTMAX", 100);
- /*
- * We used to get the output baud rate here. However, that's
- * pretty irrelevant to a terminal on an X display and can lead
- * to unnecessary delays if it's wrong (which it probably is).
- * Furthermore, even if the output is slow it's very likely
- * to be because of WAN delays, not covered by the output
- * baud rate.
- * So allow the user to set it in the special cases where it's
- * useful.
- */
- setsparam("TMPPREFIX", ztrdup_metafy(DEFAULT_TMPPREFIX));
- setsparam("TIMEFMT", ztrdup_metafy(DEFAULT_TIMEFMT));
- setsparam("WATCHFMT", ztrdup_metafy(default_watchfmt));
-
- hostnam = (char *)zalloc(256);
- gethostname(hostnam, 256);
- setsparam("HOST", ztrdup_metafy(hostnam));
- zfree(hostnam, 256);
-
- setsparam("LOGNAME",
- ztrdup_metafy((str = getlogin()) && *str ?
- str : cached_username));
-
-#if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV)
- /* Copy the environment variables we are inheriting to dynamic *
- * memory, so we can do mallocs and frees on it. */
- envsize = sizeof(char *)*(1 + arrlen(environ));
- new_environ = (char **) zalloc(envsize);
- memcpy(new_environ, environ, envsize);
- environ = new_environ;
-#endif
-
- /* Use heap allocation to avoid many small alloc/free calls */
- pushheap();
-
- /* Now incorporate environment variables we are inheriting *
- * into the parameter hash table. Copy them into dynamic *
- * memory so that we can free them if needed */
- for (
-#ifndef USE_SET_UNSET_ENV
- envp =
-#endif
- envp2 = environ; *envp2; envp2++) {
- if (split_env_string(*envp2, &iname, &ivalue)) {
- if (!idigit(*iname) && isident(iname) && !strchr(iname, '[')) {
- /*
- * Parameters that aren't already in the parameter table
- * aren't special to the shell, so it's always OK to
- * import. Otherwise, check parameter flags.
- */
- if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
- !dontimport(pm->node.flags)) &&
- (pm = assignsparam(iname, metafy(ivalue, -1, META_DUP),
- ASSPM_ENV_IMPORT))) {
- pm->node.flags |= PM_EXPORTED;
- if (pm->node.flags & PM_SPECIAL)
- pm->env = mkenvstr (pm->node.nam,
- getsparam(pm->node.nam), pm->node.flags);
- else
- pm->env = ztrdup(*envp2);
-#ifndef USE_SET_UNSET_ENV
- *envp++ = pm->env;
-#endif
- }
- }
- }
- }
- popheap();
-#ifndef USE_SET_UNSET_ENV
- *envp = NULL;
-#endif
- opts[ALLEXPORT] = oae;
-
- /*
- * For native emulation we always set the variable home
- * (see setupvals()).
- */
- pm = (Param) paramtab->getnode(paramtab, "HOME");
- if (EMULATION(EMULATE_ZSH))
- {
- pm->node.flags &= ~PM_UNSET;
- if (!(pm->node.flags & PM_EXPORTED))
- addenv(pm, home);
- } else if (!home)
- pm->node.flags |= PM_UNSET;
- pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
- if (!(pm->node.flags & PM_EXPORTED))
- addenv(pm, pm->u.str);
- pm = (Param) paramtab->getnode(paramtab, "SHLVL");
- sprintf(buf, "%d", (int)++shlvl);
- /* shlvl value in environment needs updating unconditionally */
- addenv(pm, buf);
-
- /* Add the standard non-special parameters */
- set_pwd_env();
-#ifdef HAVE_UNAME
- if(uname(&unamebuf)) setsparam("CPUTYPE", ztrdup("unknown"));
- else
- {
- machinebuf = ztrdup_metafy(unamebuf.machine);
- setsparam("CPUTYPE", machinebuf);
- }
-
-#else
- setsparam("CPUTYPE", ztrdup_metafy("unknown"));
-#endif
- setsparam("MACHTYPE", ztrdup_metafy(MACHTYPE));
- setsparam("OSTYPE", ztrdup_metafy(OSTYPE));
- setsparam("TTY", ztrdup_metafy(ttystrname));
- setsparam("VENDOR", ztrdup_metafy(VENDOR));
- setsparam("ZSH_ARGZERO", ztrdup(posixzero));
- setsparam("ZSH_VERSION", ztrdup_metafy(ZSH_VERSION));
- setsparam("ZSH_PATCHLEVEL", ztrdup_metafy(ZSH_PATCHLEVEL));
- setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));
- for (t = sigs; (*sigptr++ = ztrdup_metafy(*t++)); );
-
- noerrs = 0;
-}
-
-/* assign various functions used for non-special parameters */
-
-/**/
-mod_export void
-assigngetset(Param pm)
-{
- switch (PM_TYPE(pm->node.flags)) {
- case PM_SCALAR:
- pm->gsu.s = &stdscalar_gsu;
- break;
- case PM_INTEGER:
- pm->gsu.i = &stdinteger_gsu;
- break;
- case PM_EFLOAT:
- case PM_FFLOAT:
- pm->gsu.f = &stdfloat_gsu;
- break;
- case PM_ARRAY:
- pm->gsu.a = &stdarray_gsu;
- break;
- case PM_HASHED:
- pm->gsu.h = &stdhash_gsu;
- break;
- default:
- DPUTS(1, "BUG: tried to create param node without valid flag");
- break;
- }
-}
-
-/* Create a parameter, so that it can be assigned to. Returns NULL if the *
- * parameter already exists or can't be created, otherwise returns the *
- * parameter node. If a parameter of the same name exists in an outer *
- * scope, it is hidden by a newly created parameter. An already existing *
- * parameter node at the current level may be `created' and returned *
- * provided it is unset and not special. If the parameter can't be *
- * created because it already exists, the PM_UNSET flag is cleared. */
-
-/**/
-mod_export Param
-createparam(char *name, int flags)
-{
- Param pm, oldpm;
-
- if (paramtab != realparamtab)
- flags = (flags & ~PM_EXPORTED) | PM_HASHELEM;
-
- if (name != nulstring) {
- oldpm = (Param) (paramtab == realparamtab ?
- /* gethashnode2() for direct table read */
- gethashnode2(paramtab, name) :
- paramtab->getnode(paramtab, name));
-
- DPUTS(oldpm && oldpm->level > locallevel,
- "BUG: old local parameter not deleted");
- if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) {
- if (isset(POSIXBUILTINS) && (oldpm->node.flags & PM_READONLY)) {
- zerr("read-only variable: %s", name);
- return NULL;
- }
- if ((oldpm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerr("%s: restricted", name);
- return NULL;
- }
- if (!(oldpm->node.flags & PM_UNSET) ||
- (oldpm->node.flags & PM_SPECIAL) ||
- /* POSIXBUILTINS horror: we need to retain 'export' flags */
- (isset(POSIXBUILTINS) && (oldpm->node.flags & PM_EXPORTED))) {
- oldpm->node.flags &= ~PM_UNSET;
- if ((oldpm->node.flags & PM_SPECIAL) && oldpm->ename) {
- Param altpm =
- (Param) paramtab->getnode(paramtab, oldpm->ename);
- if (altpm)
- altpm->node.flags &= ~PM_UNSET;
- }
- return NULL;
- }
-
- pm = oldpm;
- pm->base = pm->width = 0;
- oldpm = pm->old;
- } else {
- pm = (Param) zshcalloc(sizeof *pm);
- if ((pm->old = oldpm)) {
- /*
- * needed to avoid freeing oldpm, but we do take it
- * out of the environment when it's hidden.
- */
- if (oldpm->env)
- delenv(oldpm);
- paramtab->removenode(paramtab, name);
- }
- paramtab->addnode(paramtab, ztrdup(name), pm);
- }
-
- if (isset(ALLEXPORT) && !(flags & PM_HASHELEM))
- flags |= PM_EXPORTED;
- } else {
- pm = (Param) hcalloc(sizeof *pm);
- pm->node.nam = nulstring;
- }
- pm->node.flags = flags & ~PM_LOCAL;
-
- if(!(pm->node.flags & PM_SPECIAL))
- assigngetset(pm);
- return pm;
-}
-
-/* Empty dummy function for special hash parameters. */
-
-/**/
-static void
-shempty(void)
-{
-}
-
-/*
- * Create a simple special hash parameter.
- *
- * This is for hashes added internally --- it's not possible to add
- * special hashes from shell commands. It's currently used
- * - by addparamdef() for special parameters in the zsh/parameter
- * module
- * - by ztie for special parameters tied to databases.
- */
-
-/**/
-mod_export Param
-createspecialhash(char *name, GetNodeFunc get, ScanTabFunc scan, int flags)
-{
- Param pm;
- HashTable ht;
-
- if (!(pm = createparam(name, PM_SPECIAL|PM_HASHED|flags)))
- return NULL;
-
- /*
- * If there's an old parameter, we'll put the new one at
- * the current locallevel, so that the old parameter is
- * exposed again after leaving the function. Otherwise,
- * we'll leave it alone. Usually this means the parameter
- * will stay in place until explicitly unloaded, however
- * if the parameter was previously unset within a function
- * we'll inherit the level of that function and follow the
- * standard convention that the parameter remains local
- * even if unset.
- *
- * These semantics are similar to those of a normal parameter set
- * within a function without a local definition.
- */
- if (pm->old)
- pm->level = locallevel;
- pm->gsu.h = (flags & PM_READONLY) ? &stdhash_gsu :
- &nullsethash_gsu;
- pm->u.hash = ht = newhashtable(0, name, NULL);
-
- ht->hash = hasher;
- ht->emptytable = (TableFunc) shempty;
- ht->filltable = NULL;
- ht->addnode = (AddNodeFunc) shempty;
- ht->getnode = ht->getnode2 = get;
- ht->removenode = (RemoveNodeFunc) shempty;
- ht->disablenode = NULL;
- ht->enablenode = NULL;
- ht->freenode = (FreeNodeFunc) shempty;
- ht->printnode = printparamnode;
- ht->scantab = scan;
-
- return pm;
-}
-
-
-/*
- * Copy a parameter
- *
- * If fakecopy is set, we are just saving the details of a special
- * parameter. Otherwise, the result will be used as a real parameter
- * and we need to do more work.
- */
-
-/**/
-void
-copyparam(Param tpm, Param pm, int fakecopy)
-{
- /*
- * Note that tpm, into which we're copying, may not be in permanent
- * storage. However, the values themselves are later used directly
- * to set the parameter, so must be permanently allocated (in accordance
- * with sets.?fn() usage).
- */
- tpm->node.flags = pm->node.flags;
- tpm->base = pm->base;
- tpm->width = pm->width;
- tpm->level = pm->level;
- if (!fakecopy)
- tpm->node.flags &= ~PM_SPECIAL;
- switch (PM_TYPE(pm->node.flags)) {
- case PM_SCALAR:
- tpm->u.str = ztrdup(pm->gsu.s->getfn(pm));
- break;
- case PM_INTEGER:
- tpm->u.val = pm->gsu.i->getfn(pm);
- break;
- case PM_EFLOAT:
- case PM_FFLOAT:
- tpm->u.dval = pm->gsu.f->getfn(pm);
- break;
- case PM_ARRAY:
- tpm->u.arr = zarrdup(pm->gsu.a->getfn(pm));
- break;
- case PM_HASHED:
- tpm->u.hash = copyparamtable(pm->gsu.h->getfn(pm), pm->node.nam);
- break;
- }
- /*
- * If the value is going to be passed as a real parameter (e.g. this is
- * called from inside an associative array), we need the gets and sets
- * functions to be useful.
- *
- * In this case we assume the saved parameter is not itself special,
- * so we just use the standard functions. This is also why we switch off
- * PM_SPECIAL.
- */
- if (!fakecopy)
- assigngetset(tpm);
-}
-
-/* Return 1 if the string s is a valid identifier, else return 0. */
-
-/**/
-mod_export int
-isident(char *s)
-{
- char *ss;
-
- if (!*s) /* empty string is definitely not valid */
- return 0;
-
- if (idigit(*s)) {
- /* If the first character is `s' is a digit, then all must be */
- for (ss = ++s; *ss; ss++)
- if (!idigit(*ss))
- break;
- } else {
- /* Find the first character in `s' not in the iident type table */
- ss = itype_end(s, IIDENT, 0);
- }
-
- /* If the next character is not [, then it is *
- * definitely not a valid identifier. */
- if (!*ss)
- return 1;
- if (s == ss)
- return 0;
- if (*ss != '[')
- return 0;
-
- /* Require balanced [ ] pairs with something between */
- if (!(ss = parse_subscript(++ss, 1, ']')))
- return 0;
- untokenize(s);
- return !ss[1];
-}
-
-/*
- * Parse a single argument to a parameter subscript.
- * The subscripts starts at *str; *str is updated (input/output)
- *
- * *inv is set to indicate if the subscript is reversed (output)
- * v is the Value for the parameter being accessed (input; note
- * v->isarr may be modified, and if v is a hash the parameter will
- * be updated to the element of the hash)
- * a2 is 1 if this is the second subscript of a range (input)
- * *w is only set if we need to find the end of a word (input; should
- * be set to 0 by the caller).
- *
- * The final two arguments are to support multibyte characters.
- * If supplied they are set to the length of the character before
- * the index position and the one at the index position. If
- * multibyte characters are not in use they are set to 1 for
- * consistency. Note they aren't fully handled if a2 is non-zero,
- * since they aren't needed.
- *
- * Returns a raw offset into the value from the start or end (i.e.
- * after the arithmetic for Meta and possible multibyte characters has
- * been taken into account). This actually gives the offset *after*
- * the character in question; subtract *prevcharlen if necessary.
- */
-
-/**/
-static zlong
-getarg(char **str, int *inv, Value v, int a2, zlong *w,
- int *prevcharlen, int *nextcharlen, int flags)
-{
- int hasbeg = 0, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash;
- int keymatch = 0, needtok = 0, arglen, len, inpar = 0;
- char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt, c;
- zlong num = 1, beg = 0, r = 0, quote_arg = 0;
- Patprog pprog = NULL;
-
- /*
- * If in NO_EXEC mode, the parameters won't be set up properly,
- * so just pretend everything is a hash for subscript parsing
- */
-
- ishash = (unset(EXECOPT) ||
- (v->pm && PM_TYPE(v->pm->node.flags) == PM_HASHED));
- if (prevcharlen)
- *prevcharlen = 1;
- if (nextcharlen)
- *nextcharlen = 1;
-
- /* first parse any subscription flags */
- if (v->pm && (*s == '(' || *s == Inpar)) {
- int escapes = 0;
- int waste;
- for (s++; *s != ')' && *s != Outpar && s != *str; s++) {
- switch (*s) {
- case 'r':
- rev = 1;
- keymatch = down = ind = 0;
- break;
- case 'R':
- rev = down = 1;
- keymatch = ind = 0;
- break;
- case 'k':
- keymatch = ishash;
- rev = 1;
- down = ind = 0;
- break;
- case 'K':
- keymatch = ishash;
- rev = down = 1;
- ind = 0;
- break;
- case 'i':
- rev = ind = 1;
- down = keymatch = 0;
- break;
- case 'I':
- rev = ind = down = 1;
- keymatch = 0;
- break;
- case 'w':
- /* If the parameter is a scalar, then make subscription *
- * work on a per-word basis instead of characters. */
- word = 1;
- break;
- case 'f':
- word = 1;
- sep = "\n";
- break;
- case 'e':
- quote_arg = 1;
- break;
- case 'n':
- t = get_strarg(++s, &arglen);
- if (!*t)
- goto flagerr;
- sav = *t;
- *t = '\0';
- num = mathevalarg(s + arglen, &d);
- if (!num)
- num = 1;
- *t = sav;
- s = t + arglen - 1;
- break;
- case 'b':
- hasbeg = 1;
- t = get_strarg(++s, &arglen);
- if (!*t)
- goto flagerr;
- sav = *t;
- *t = '\0';
- if ((beg = mathevalarg(s + arglen, &d)) > 0)
- beg--;
- *t = sav;
- s = t + arglen - 1;
- break;
- case 'p':
- escapes = 1;
- break;
- case 's':
- /* This gives the string that separates words *
- * (for use with the `w' flag). */
- t = get_strarg(++s, &arglen);
- if (!*t)
- goto flagerr;
- sav = *t;
- *t = '\0';
- s += arglen;
- sep = escapes ? getkeystring(s, &waste, GETKEYS_SEP, NULL)
- : dupstring(s);
- *t = sav;
- s = t + arglen - 1;
- break;
- default:
- flagerr:
- num = 1;
- word = rev = ind = down = keymatch = 0;
- sep = NULL;
- s = *str - 1;
- }
- }
- if (s != *str)
- s++;
- }
- if (num < 0) {
- down = !down;
- num = -num;
- }
- if (v->isarr & SCANPM_WANTKEYS)
- *inv = (ind || !(v->isarr & SCANPM_WANTVALS));
- else if (v->isarr & SCANPM_WANTVALS)
- *inv = 0;
- else {
- if (v->isarr) {
- if (ind) {
- v->isarr |= SCANPM_WANTKEYS;
- v->isarr &= ~SCANPM_WANTVALS;
- } else if (rev)
- v->isarr |= SCANPM_WANTVALS;
- /*
- * This catches the case where we are using "k" (rather
- * than "K") on a hash.
- */
- if (!down && keymatch && ishash)
- v->isarr &= ~SCANPM_MATCHMANY;
- }
- *inv = ind;
- }
-
- for (t = s, i = 0;
- (c = *t) &&
- ((c != Outbrack && (ishash || c != ',')) || i || inpar);
- t++) {
- /* Untokenize inull() except before brackets and double-quotes */
- if (inull(c)) {
- c = t[1];
- if (c == '[' || c == ']' ||
- c == '(' || c == ')' ||
- c == '{' || c == '}') {
- /* This test handles nested subscripts in hash keys */
- if (ishash && i)
- *t = ztokens[*t - Pound];
- needtok = 1;
- ++t;
- } else if (c != '"')
- *t = ztokens[*t - Pound];
- continue;
- }
- /* Inbrack and Outbrack are probably never found here ... */
- if (c == '[' || c == Inbrack)
- i++;
- else if (c == ']' || c == Outbrack)
- i--;
- if (c == '(' || c == Inpar)
- inpar++;
- else if (c == ')' || c == Outpar)
- inpar--;
- if (ispecial(c))
- needtok = 1;
- }
- if (!c)
- return 0;
- *str = tt = t;
-
- /*
- * If in NO_EXEC mode, the parameters won't be set up properly,
- * so there's no additional sanity checking we can do.
- * Just return 0 now.
- */
- if (unset(EXECOPT))
- return 0;
-
- s = dupstrpfx(s, t - s);
-
- /* If we're NOT reverse subscripting, strip the inull()s so brackets *
- * are not backslashed after parsestr(). Otherwise leave them alone *
- * so that the brackets will be escaped when we patcompile() or when *
- * subscript arithmetic is performed (for nested subscripts). */
- if (ishash && (keymatch || !rev))
- remnulargs(s);
- if (needtok) {
- s = dupstring(s);
- if (parsestr(&s))
- return 0;
- singsub(&s);
- } else if (rev)
- remnulargs(s); /* This is probably always a no-op, but ... */
- if (!rev) {
- if (ishash) {
- HashTable ht = v->pm->gsu.h->getfn(v->pm);
- if (!ht) {
- if (flags & SCANPM_CHECKING)
- return 0;
- ht = newparamtable(17, v->pm->node.nam);
- v->pm->gsu.h->setfn(v->pm, ht);
- }
- untokenize(s);
- if (!(v->pm = (Param) ht->getnode(ht, s))) {
- HashTable tht = paramtab;
- paramtab = ht;
- v->pm = createparam(s, PM_SCALAR|PM_UNSET);
- paramtab = tht;
- }
- v->isarr = (*inv ? SCANPM_WANTINDEX : 0);
- v->start = 0;
- *inv = 0; /* We've already obtained the "index" (key) */
- *w = v->end = -1;
- r = isset(KSHARRAYS) ? 1 : 0;
- } else {
- r = mathevalarg(s, &s);
- if (isset(KSHARRAYS) && r >= 0)
- r++;
- }
- if (word && !v->isarr) {
- s = t = getstrvalue(v);
- i = wordcount(s, sep, 0);
- if (r < 0)
- r += i + 1;
- if (r < 1)
- r = 1;
- if (r > i)
- r = i;
- if (!s || !*s)
- return 0;
- while ((d = findword(&s, sep)) && --r);
- if (!d)
- return 0;
-
- if (!a2 && *tt != ',')
- *w = (zlong)(s - t);
-
- return (a2 ? s : d + 1) - t;
- } else if (!v->isarr && !word) {
- int lastcharlen = 1;
- s = getstrvalue(v);
- /*
- * Note for the confused (= pws): the index r we
- * have so far is that specified by the user. The value
- * passed back is an offset from the start or end of
- * the string. Hence it needs correcting at least
- * for Meta characters and maybe for multibyte characters.
- */
- if (r > 0) {
- zlong nchars = r;
-
- MB_METACHARINIT();
- for (t = s; nchars && *t; nchars--)
- t += (lastcharlen = MB_METACHARLEN(t));
- /* for consistency, keep any remainder off the end */
- r = (zlong)(t - s) + nchars;
- if (prevcharlen && !nchars /* ignore if off the end */)
- *prevcharlen = lastcharlen;
- if (nextcharlen && *t)
- *nextcharlen = MB_METACHARLEN(t);
- } else if (r == 0) {
- if (prevcharlen)
- *prevcharlen = 0;
- if (nextcharlen && *s) {
- MB_METACHARINIT();
- *nextcharlen = MB_METACHARLEN(s);
- }
- } else {
- zlong nchars = (zlong)MB_METASTRLEN(s) + r;
-
- if (nchars < 0) {
- /* make sure this isn't valid as a raw pointer */
- r -= (zlong)strlen(s);
- } else {
- MB_METACHARINIT();
- for (t = s; nchars && *t; nchars--)
- t += (lastcharlen = MB_METACHARLEN(t));
- r = - (zlong)strlen(t); /* keep negative */
- if (prevcharlen)
- *prevcharlen = lastcharlen;
- if (nextcharlen && *t)
- *nextcharlen = MB_METACHARLEN(t);
- }
- }
- }
- } else {
- if (!v->isarr && !word && !quote_arg) {
- l = strlen(s);
- if (a2) {
- if (!l || *s != '*') {
- d = (char *) hcalloc(l + 2);
- *d = '*';
- strcpy(d + 1, s);
- s = d;
- }
- } else {
- if (!l || s[l - 1] != '*' || (l > 1 && s[l - 2] == '\\')) {
- d = (char *) hcalloc(l + 2);
- strcpy(d, s);
- strcat(d, "*");
- s = d;
- }
- }
- }
- if (!keymatch) {
- if (quote_arg) {
- untokenize(s);
- /* Scalar (e) needs implicit asterisk tokens */
- if (!v->isarr && !word) {
- l = strlen(s);
- d = (char *) hcalloc(l + 2);
- if (a2) {
- *d = Star;
- strcpy(d + 1, s);
- } else {
- strcpy(d, s);
- d[l] = Star;
- d[l + 1] = '\0';
- }
- s = d;
- }
- } else
- tokenize(s);
- remnulargs(s);
- pprog = patcompile(s, 0, NULL);
- } else
- pprog = NULL;
-
- if (v->isarr) {
- if (ishash) {
- scanprog = pprog;
- scanstr = s;
- if (keymatch)
- v->isarr |= SCANPM_KEYMATCH;
- else {
- if (!pprog)
- return 1;
- if (ind)
- v->isarr |= SCANPM_MATCHKEY;
- else
- v->isarr |= SCANPM_MATCHVAL;
- }
- if (down)
- v->isarr |= SCANPM_MATCHMANY;
- if ((ta = getvaluearr(v)) &&
- (*ta || ((v->isarr & SCANPM_MATCHMANY) &&
- (v->isarr & (SCANPM_MATCHKEY | SCANPM_MATCHVAL |
- SCANPM_KEYMATCH))))) {
- *inv = (v->flags & VALFLAG_INV) ? 1 : 0;
- *w = v->end;
- scanprog = NULL;
- return 1;
- }
- scanprog = NULL;
- } else
- ta = getarrvalue(v);
- if (!ta || !*ta)
- return !down;
- len = arrlen(ta);
- if (beg < 0)
- beg += len;
- if (down) {
- if (beg < 0)
- return 0;
- } else if (beg >= len)
- return len + 1;
- if (beg >= 0 && beg < len) {
- if (down) {
- if (!hasbeg)
- beg = len - 1;
- for (r = 1 + beg, p = ta + beg; p >= ta; r--, p--) {
- if (pprog && pattry(pprog, *p) && !--num)
- return r;
- }
- } else
- for (r = 1 + beg, p = ta + beg; *p; r++, p++)
- if (pprog && pattry(pprog, *p) && !--num)
- return r;
- }
- } else if (word) {
- ta = sepsplit(d = s = getstrvalue(v), sep, 1, 1);
- len = arrlen(ta);
- if (beg < 0)
- beg += len;
- if (down) {
- if (beg < 0)
- return 0;
- } else if (beg >= len)
- return len + 1;
- if (beg >= 0 && beg < len) {
- if (down) {
- if (!hasbeg)
- beg = len - 1;
- for (r = 1 + beg, p = ta + beg; p >= ta; p--, r--)
- if (pprog && pattry(pprog, *p) && !--num)
- break;
- if (p < ta)
- return 0;
- } else {
- for (r = 1 + beg, p = ta + beg; *p; r++, p++)
- if (pprog && pattry(pprog, *p) && !--num)
- break;
- if (!*p)
- return 0;
- }
- }
- if (a2)
- r++;
- for (i = 0; (t = findword(&d, sep)) && *t; i++)
- if (!--r) {
- r = (zlong)(t - s + (a2 ? -1 : 1));
- if (!a2 && *tt != ',')
- *w = r + strlen(ta[i]) - 1;
- return r;
- }
- return a2 ? -1 : 0;
- } else {
- /* Searching characters */
- int slen;
- d = getstrvalue(v);
- if (!d || !*d)
- return 0;
- /*
- * beg and len are character counts, not raw offsets.
- * Remember we need to return a raw offset.
- */
- len = MB_METASTRLEN(d);
- slen = strlen(d);
- if (beg < 0)
- beg += len;
- MB_METACHARINIT();
- if (beg >= 0 && beg < len) {
- char *de = d + slen;
-
- if (a2) {
- /*
- * Second argument: we don't need to
- * handle prevcharlen or nextcharlen, but
- * we do need to handle characters appropriately.
- */
- if (down) {
- int nmatches = 0;
- char *lastpos = NULL;
-
- if (!hasbeg)
- beg = len;
-
- /*
- * See below: we have to move forward,
- * but need to count from the end.
- */
- for (t = d, r = 0; r <= beg; r++) {
- sav = *t;
- *t = '\0';
- if (pprog && pattry(pprog, d)) {
- nmatches++;
- lastpos = t;
- }
- *t = sav;
- if (t == de)
- break;
- t += MB_METACHARLEN(t);
- }
-
- if (nmatches >= num) {
- if (num > 1) {
- nmatches -= num;
- MB_METACHARINIT();
- for (t = d, r = 0; ; r++) {
- sav = *t;
- *t = '\0';
- if (pprog && pattry(pprog, d) &&
- nmatches-- == 0) {
- lastpos = t;
- *t = sav;
- break;
- }
- *t = sav;
- t += MB_METACHARLEN(t);
- }
- }
- /* else lastpos is already OK */
-
- return lastpos - d;
- }
- } else {
- /*
- * This handling of the b flag
- * gives odd results, but this is the
- * way it's always worked.
- */
- for (t = d; beg && t <= de; beg--)
- t += MB_METACHARLEN(t);
- for (;;) {
- sav = *t;
- *t = '\0';
- if (pprog && pattry(pprog, d) && !--num) {
- *t = sav;
- /*
- * This time, don't increment
- * pointer, since it's already
- * after everything we matched.
- */
- return t - d;
- }
- *t = sav;
- if (t == de)
- break;
- t += MB_METACHARLEN(t);
- }
- }
- } else {
- /*
- * First argument: this is the only case
- * where we need prevcharlen and nextcharlen.
- */
- int lastcharlen;
-
- if (down) {
- int nmatches = 0;
- char *lastpos = NULL;
-
- if (!hasbeg)
- beg = len;
-
- /*
- * We can only move forward through
- * multibyte strings, so record the
- * matches.
- * Unfortunately the count num works
- * from the end, so it's easy to get the
- * last one but we need to repeat if
- * we want another one.
- */
- for (t = d, r = 0; r <= beg; r++) {
- if (pprog && pattry(pprog, t)) {
- nmatches++;
- lastpos = t;
- }
- if (t == de)
- break;
- t += MB_METACHARLEN(t);
- }
-
- if (nmatches >= num) {
- if (num > 1) {
- /*
- * Need to start again and repeat
- * to get the right match.
- */
- nmatches -= num;
- MB_METACHARINIT();
- for (t = d, r = 0; ; r++) {
- if (pprog && pattry(pprog, t) &&
- nmatches-- == 0) {
- lastpos = t;
- break;
- }
- t += MB_METACHARLEN(t);
- }
- }
- /* else lastpos is already OK */
-
- /* return pointer after matched char */
- lastpos +=
- (lastcharlen = MB_METACHARLEN(lastpos));
- if (prevcharlen)
- *prevcharlen = lastcharlen;
- if (nextcharlen)
- *nextcharlen = MB_METACHARLEN(lastpos);
- return lastpos - d;
- }
-
- for (r = beg + 1, t = d + beg; t >= d; r--, t--) {
- if (pprog && pattry(pprog, t) &&
- !--num)
- return r;
- }
- } else {
- for (t = d; beg && t <= de; beg--)
- t += MB_METACHARLEN(t);
- for (;;) {
- if (pprog && pattry(pprog, t) && !--num) {
- /* return pointer after matched char */
- t += (lastcharlen = MB_METACHARLEN(t));
- if (prevcharlen)
- *prevcharlen = lastcharlen;
- if (nextcharlen)
- *nextcharlen = MB_METACHARLEN(t);
- return t - d;
- }
- if (t == de)
- break;
- t += MB_METACHARLEN(t);
- }
- }
- }
- }
- return down ? 0 : slen + 1;
- }
- }
- return r;
-}
-
-/*
- * Parse a subscript.
- *
- * pptr: In/Out parameter. On entry, *ptr points to a "[foo]" string. On exit
- * it will point one past the closing bracket.
- *
- * v: In/Out parameter. Its .start and .end members (at least) will be updated
- * with the parsed indices.
- *
- * flags: can be either SCANPM_DQUOTED or zero. Other bits are not used.
- */
-
-/**/
-int
-getindex(char **pptr, Value v, int flags)
-{
- int start, end, inv = 0;
- char *s = *pptr, *tbrack;
-
- *s++ = '[';
- /* Error handled after untokenizing */
- s = parse_subscript(s, flags & SCANPM_DQUOTED, ']');
- /* Now we untokenize everything except inull() markers so we can check *
- * for the '*' and '@' special subscripts. The inull()s are removed *
- * in getarg() after we know whether we're doing reverse indexing. */
- for (tbrack = *pptr + 1; *tbrack && tbrack != s; tbrack++) {
- if (inull(*tbrack) && !*++tbrack)
- break;
- if (itok(*tbrack)) /* Need to check for Nularg here? */
- *tbrack = ztokens[*tbrack - Pound];
- }
- /* If we reached the end of the string (s == NULL) we have an error */
- if (*tbrack)
- *tbrack = Outbrack;
- else {
- zerr("invalid subscript");
- *pptr = tbrack;
- return 1;
- }
- s = *pptr + 1;
- if ((s[0] == '*' || s[0] == '@') && s + 1 == tbrack) {
- if ((v->isarr || IS_UNSET_VALUE(v)) && s[0] == '@')
- v->isarr |= SCANPM_ISVAR_AT;
- v->start = 0;
- v->end = -1;
- s += 2;
- } else {
- zlong we = 0, dummy;
- int startprevlen, startnextlen;
-
- start = getarg(&s, &inv, v, 0, &we, &startprevlen, &startnextlen,
- flags);
-
- if (inv) {
- if (!v->isarr && start != 0) {
- char *t, *p;
- t = getstrvalue(v);
- /*
- * Note for the confused (= pws): this is an inverse
- * offset so at this stage we need to convert from
- * the immediate offset into the value that we have
- * into a logical character position.
- */
- if (start > 0) {
- int nstart = 0;
- char *target = t + start - startprevlen;
-
- p = t;
- MB_METACHARINIT();
- while (*p) {
- /*
- * move up characters, counting how many we
- * found
- */
- p += MB_METACHARLEN(p);
- if (p < target)
- nstart++;
- else {
- if (p == target)
- nstart++;
- else
- p = target; /* pretend we hit exactly */
- break;
- }
- }
- /* if start was too big, keep the difference */
- start = nstart + (target - p) + 1;
- } else {
- zlong startoff = start + strlen(t);
-#ifdef DEBUG
- dputs("BUG: can't have negative inverse offsets???");
-#endif
- if (startoff < 0) {
- /* invalid: keep index but don't dereference */
- start = startoff;
- } else {
- /* find start in full characters */
- MB_METACHARINIT();
- for (p = t; p < t + startoff;)
- p += MB_METACHARLEN(p);
- start = - MB_METASTRLEN(p);
- }
- }
- }
- if (start > 0 && (isset(KSHARRAYS) || (v->pm->node.flags & PM_HASHED)))
- start--;
- if (v->isarr != SCANPM_WANTINDEX) {
- v->flags |= VALFLAG_INV;
- v->isarr = 0;
- v->start = start;
- v->end = start + 1;
- }
- if (*s == ',') {
- zerr("invalid subscript");
- *tbrack = ']';
- *pptr = tbrack+1;
- return 1;
- }
- if (s == tbrack)
- s++;
- } else {
- int com;
-
- if ((com = (*s == ','))) {
- s++;
- end = getarg(&s, &inv, v, 1, &dummy, NULL, NULL, flags);
- } else {
- end = we ? we : start;
- }
- if (start != end)
- com = 1;
- /*
- * Somehow the logic sometimes forces us to use the previous
- * or next character to what we would expect, which is
- * why we had to calculate them in getarg().
- */
- if (start > 0)
- start -= startprevlen;
- else if (start == 0 && end == 0)
- {
- /*
- * Strictly, this range is entirely off the
- * start of the available index range.
- * This can't happen with KSH_ARRAYS; we already
- * altered the start index in getarg().
- * Are we being strict?
- */
- if (isset(KSHZEROSUBSCRIPT)) {
- /*
- * We're not.
- * Treat this as accessing the first element of the
- * array.
- */
- end = startnextlen;
- } else {
- /*
- * We are. Flag that this range is invalid
- * for setting elements. Set the indexes
- * to a range that returns empty for other accesses.
- */
- v->flags |= VALFLAG_EMPTY;
- start = -1;
- com = 1;
- }
- }
- if (s == tbrack) {
- s++;
- if (v->isarr && !com &&
- (!(v->isarr & SCANPM_MATCHMANY) ||
- !(v->isarr & (SCANPM_MATCHKEY | SCANPM_MATCHVAL |
- SCANPM_KEYMATCH))))
- v->isarr = 0;
- v->start = start;
- v->end = end;
- } else
- s = *pptr;
- }
- }
- *tbrack = ']';
- *pptr = s;
- return 0;
-}
-
-
-/**/
-mod_export Value
-getvalue(Value v, char **pptr, int bracks)
-{
- return fetchvalue(v, pptr, bracks, 0);
-}
-
-/**/
-mod_export Value
-fetchvalue(Value v, char **pptr, int bracks, int flags)
-{
- char *s, *t, *ie;
- char sav, c;
- int ppar = 0;
-
- s = t = *pptr;
-
- if (idigit(c = *s)) {
- if (bracks >= 0)
- ppar = zstrtol(s, &s, 10);
- else
- ppar = *s++ - '0';
- }
- else if ((ie = itype_end(s, IIDENT, 0)) != s)
- s = ie;
- else if (c == Quest)
- *s++ = '?';
- else if (c == Pound)
- *s++ = '#';
- else if (c == String)
- *s++ = '$';
- else if (c == Qstring)
- *s++ = '$';
- else if (c == Star)
- *s++ = '*';
- else if (IS_DASH(c))
- *s++ = '-';
- else if (c == '#' || c == '?' || c == '$' ||
- c == '!' || c == '@' || c == '*')
- s++;
- else
- return NULL;
-
- if ((sav = *s))
- *s = '\0';
- if (ppar) {
- if (v)
- memset(v, 0, sizeof(*v));
- else
- v = (Value) hcalloc(sizeof *v);
- v->pm = argvparam;
- v->flags = 0;
- v->start = ppar - 1;
- v->end = ppar;
- if (sav)
- *s = sav;
- } else {
- Param pm;
- int isvarat;
-
- isvarat = (t[0] == '@' && !t[1]);
- pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
- if (sav)
- *s = sav;
- *pptr = s;
- if (!pm || (pm->node.flags & PM_UNSET))
- return NULL;
- if (v)
- memset(v, 0, sizeof(*v));
- else
- v = (Value) hcalloc(sizeof *v);
- if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
- /* Overload v->isarr as the flag bits for hashed arrays. */
- v->isarr = flags | (isvarat ? SCANPM_ISVAR_AT : 0);
- /* If no flags were passed, we need something to represent *
- * `true' yet differ from an explicit WANTVALS. Use a *
- * special flag for this case. */
- if (!v->isarr)
- v->isarr = SCANPM_ARRONLY;
- }
- v->pm = pm;
- v->flags = 0;
- v->start = 0;
- v->end = -1;
- if (bracks > 0 && (*s == '[' || *s == Inbrack)) {
- if (getindex(&s, v, flags)) {
- *pptr = s;
- return v;
- }
- } else if (!(flags & SCANPM_ASSIGNING) && v->isarr &&
- itype_end(t, IIDENT, 1) != t && isset(KSHARRAYS))
- v->end = 1, v->isarr = 0;
- }
- if (!bracks && *s)
- return NULL;
- *pptr = s;
-#if 0
- /*
- * Check for large subscripts that might be erroneous.
- * This code is too gross in several ways:
- * - the limit is completely arbitrary
- * - the test vetoes operations on existing arrays
- * - it's not at all clear a general test on large arrays of
- * this kind is any use.
- *
- * Until someone comes up with workable replacement code it's
- * therefore commented out.
- */
- if (v->start > MAX_ARRLEN) {
- zerr("subscript too %s: %d", "big", v->start + !isset(KSHARRAYS));
- return NULL;
- }
- if (v->start < -MAX_ARRLEN) {
- zerr("subscript too %s: %d", "small", v->start);
- return NULL;
- }
- if (v->end > MAX_ARRLEN+1) {
- zerr("subscript too %s: %d", "big", v->end - !!isset(KSHARRAYS));
- return NULL;
- }
- if (v->end < -MAX_ARRLEN) {
- zerr("subscript too %s: %d", "small", v->end);
- return NULL;
- }
-#endif
- return v;
-}
-
-/**/
-mod_export char *
-getstrvalue(Value v)
-{
- char *s, **ss;
- char buf[BDIGBUFSIZE];
- int len;
-
- if (!v)
- return hcalloc(1);
-
- if ((v->flags & VALFLAG_INV) && !(v->pm->node.flags & PM_HASHED)) {
- sprintf(buf, "%d", v->start);
- s = dupstring(buf);
- return s;
- }
-
- switch(PM_TYPE(v->pm->node.flags)) {
- case PM_HASHED:
- /* (!v->isarr) should be impossible unless emulating ksh */
- if (!v->isarr && EMULATION(EMULATE_KSH)) {
- s = dupstring("[0]");
- if (getindex(&s, v, 0) == 0)
- s = getstrvalue(v);
- return s;
- } /* else fall through */
- case PM_ARRAY:
- ss = getvaluearr(v);
- if (v->isarr)
- s = sepjoin(ss, NULL, 1);
- else {
- if (v->start < 0)
- v->start += arrlen(ss);
- s = (arrlen_le(ss, v->start) || v->start < 0) ?
- (char *) hcalloc(1) : ss[v->start];
- }
- return s;
- case PM_INTEGER:
- convbase(buf, v->pm->gsu.i->getfn(v->pm), v->pm->base);
- s = dupstring(buf);
- break;
- case PM_EFLOAT:
- case PM_FFLOAT:
- s = convfloat(v->pm->gsu.f->getfn(v->pm),
- v->pm->base, v->pm->node.flags, NULL);
- break;
- case PM_SCALAR:
- s = v->pm->gsu.s->getfn(v->pm);
- break;
- default:
- s = "";
- DPUTS(1, "BUG: param node without valid type");
- break;
- }
-
- if (v->flags & VALFLAG_SUBST) {
- if (v->pm->node.flags & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z)) {
- unsigned int fwidth = v->pm->width ? v->pm->width : MB_METASTRLEN(s);
- switch (v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
- char *t, *tend;
- unsigned int t0;
-
- case PM_LEFT:
- case PM_LEFT | PM_RIGHT_Z:
- t = s;
- if (v->pm->node.flags & PM_RIGHT_Z)
- while (*t == '0')
- t++;
- else
- while (iblank(*t))
- t++;
- MB_METACHARINIT();
- for (tend = t, t0 = 0; t0 < fwidth && *tend; t0++)
- tend += MB_METACHARLEN(tend);
- /*
- * t0 is the number of characters from t used,
- * hence (fwidth - t0) is the number of padding
- * characters. fwidth is a misnomer: we use
- * character counts, not character widths.
- *
- * (tend - t) is the number of bytes we need
- * to get fwidth characters or the entire string;
- * the characters may be multiple bytes.
- */
- fwidth -= t0; /* padding chars remaining */
- t0 = tend - t; /* bytes to copy from string */
- s = (char *) hcalloc(t0 + fwidth + 1);
- memcpy(s, t, t0);
- if (fwidth)
- memset(s + t0, ' ', fwidth);
- s[t0 + fwidth] = '\0';
- break;
- case PM_RIGHT_B:
- case PM_RIGHT_Z:
- case PM_RIGHT_Z | PM_RIGHT_B:
- {
- int zero = 1;
- /* Calculate length in possibly multibyte chars */
- unsigned int charlen = MB_METASTRLEN(s);
-
- if (charlen < fwidth) {
- char *valprefend = s;
- int preflen;
- if (v->pm->node.flags & PM_RIGHT_Z) {
- /*
- * This is a documented feature: when deciding
- * whether to pad with zeroes, ignore
- * leading blanks already in the value;
- * only look for numbers after that.
- * Not sure how useful this really is.
- * It's certainly confusing to code around.
- */
- for (t = s; iblank(*t); t++)
- ;
- /*
- * Allow padding after initial minus
- * for numeric variables.
- */
- if ((v->pm->node.flags &
- (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) &&
- *t == '-')
- t++;
- /*
- * Allow padding after initial 0x or
- * base# for integer variables.
- */
- if (v->pm->node.flags & PM_INTEGER) {
- if (isset(CBASES) &&
- t[0] == '0' && t[1] == 'x')
- t += 2;
- else if ((valprefend = strchr(t, '#')))
- t = valprefend + 1;
- }
- valprefend = t;
- if (!*t)
- zero = 0;
- else if (v->pm->node.flags &
- (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) {
- /* zero always OK */
- } else if (!idigit(*t))
- zero = 0;
- }
- /* number of characters needed for padding */
- fwidth -= charlen;
- /* bytes from original string */
- t0 = strlen(s);
- t = (char *) hcalloc(fwidth + t0 + 1);
- /* prefix guaranteed to be single byte chars */
- preflen = valprefend - s;
- memset(t + preflen,
- (((v->pm->node.flags & PM_RIGHT_B)
- || !zero) ? ' ' : '0'), fwidth);
- /*
- * Copy - or 0x or base# before any padding
- * zeroes.
- */
- if (preflen)
- memcpy(t, s, preflen);
- memcpy(t + preflen + fwidth,
- valprefend, t0 - preflen);
- t[fwidth + t0] = '\0';
- s = t;
- } else {
- /* Need to skip (charlen - fwidth) chars */
- for (t0 = charlen - fwidth; t0; t0--)
- s += MB_METACHARLEN(s);
- }
- }
- break;
- }
- }
- switch (v->pm->node.flags & (PM_LOWER | PM_UPPER)) {
- case PM_LOWER:
- s = casemodify(s, CASMOD_LOWER);
- break;
- case PM_UPPER:
- s = casemodify(s, CASMOD_UPPER);
- break;
- }
- }
- if (v->start == 0 && v->end == -1)
- return s;
-
- len = strlen(s);
- if (v->start < 0) {
- v->start += len;
- if (v->start < 0)
- v->start = 0;
- }
- if (v->end < 0) {
- v->end += len;
- if (v->end >= 0) {
- char *eptr = s + v->end;
- if (*eptr)
- v->end += MB_METACHARLEN(eptr);
- }
- }
-
- s = (v->start > len) ? dupstring("") :
- dupstring_wlen(s + v->start, len - v->start);
-
- if (v->end <= v->start)
- s[0] = '\0';
- else if (v->end - v->start <= len - v->start)
- s[v->end - v->start] = '\0';
-
- return s;
-}
-
-static char *nular[] = {"", NULL};
-
-/**/
-mod_export char **
-getarrvalue(Value v)
-{
- char **s;
-
- if (!v)
- return arrdup(nular);
- else if (IS_UNSET_VALUE(v))
- return arrdup(&nular[1]);
- if (v->flags & VALFLAG_INV) {
- char buf[DIGBUFSIZE];
-
- s = arrdup(nular);
- sprintf(buf, "%d", v->start);
- s[0] = dupstring(buf);
- return s;
- }
- s = getvaluearr(v);
- if (v->start == 0 && v->end == -1)
- return s;
- if (v->start < 0)
- v->start += arrlen(s);
- if (v->end < 0)
- v->end += arrlen(s) + 1;
-
- /* Null if 1) array too short, 2) index still negative */
- if (v->end <= v->start) {
- s = arrdup_max(nular, 0);
- }
- else if (v->start < 0) {
- s = arrdup_max(nular, 1);
- }
- else if (arrlen_le(s, v->start)) {
- /* Handle $ary[i,i] consistently for any $i > $#ary
- * and $ary[i,j] consistently for any $j > $i > $#ary
- */
- s = arrdup_max(nular, v->end - (v->start + 1));
- }
- else {
- /* Copy to a point before the end of the source array:
- * arrdup_max will copy at most v->end - v->start elements,
- * starting from v->start element. Original code said:
- * s[v->end - v->start] = NULL
- * which means that there are exactly the same number of
- * elements as the value of the above *0-based* index.
- */
- s = arrdup_max(s + v->start, v->end - v->start);
- }
-
- return s;
-}
-
-/**/
-mod_export zlong
-getintvalue(Value v)
-{
- if (!v)
- return 0;
- if (v->flags & VALFLAG_INV)
- return v->start;
- if (v->isarr) {
- char **arr = getarrvalue(v);
- if (arr) {
- char *scal = sepjoin(arr, NULL, 1);
- return mathevali(scal);
- } else
- return 0;
- }
- if (PM_TYPE(v->pm->node.flags) == PM_INTEGER)
- return v->pm->gsu.i->getfn(v->pm);
- if (v->pm->node.flags & (PM_EFLOAT|PM_FFLOAT))
- return (zlong)v->pm->gsu.f->getfn(v->pm);
- return mathevali(getstrvalue(v));
-}
-
-/**/
-mnumber
-getnumvalue(Value v)
-{
- mnumber mn;
- mn.type = MN_INTEGER;
-
-
- if (!v) {
- mn.u.l = 0;
- } else if (v->flags & VALFLAG_INV) {
- mn.u.l = v->start;
- } else if (v->isarr) {
- char **arr = getarrvalue(v);
- if (arr) {
- char *scal = sepjoin(arr, NULL, 1);
- return matheval(scal);
- } else
- mn.u.l = 0;
- } else if (PM_TYPE(v->pm->node.flags) == PM_INTEGER) {
- mn.u.l = v->pm->gsu.i->getfn(v->pm);
- } else if (v->pm->node.flags & (PM_EFLOAT|PM_FFLOAT)) {
- mn.type = MN_FLOAT;
- mn.u.d = v->pm->gsu.f->getfn(v->pm);
- } else
- return matheval(getstrvalue(v));
- return mn;
-}
-
-/**/
-void
-export_param(Param pm)
-{
- char buf[BDIGBUFSIZE], *val;
-
- if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
-#if 0 /* Requires changes elsewhere in params.c and builtin.c */
- if (EMULATION(EMULATE_KSH) /* isset(KSHARRAYS) */) {
- struct value v;
- v.isarr = 1;
- v.flags = 0;
- v.start = 0;
- v.end = -1;
- val = getstrvalue(&v);
- } else
-#endif
- return;
- } else if (PM_TYPE(pm->node.flags) == PM_INTEGER)
- convbase(val = buf, pm->gsu.i->getfn(pm), pm->base);
- else if (pm->node.flags & (PM_EFLOAT|PM_FFLOAT))
- val = convfloat(pm->gsu.f->getfn(pm), pm->base,
- pm->node.flags, NULL);
- else
- val = pm->gsu.s->getfn(pm);
-
- addenv(pm, val);
-}
-
-/**/
-mod_export void
-setstrvalue(Value v, char *val)
-{
- assignstrvalue(v, val, 0);
-}
-
-/**/
-mod_export void
-assignstrvalue(Value v, char *val, int flags)
-{
- if (unset(EXECOPT))
- return;
- if (v->pm->node.flags & PM_READONLY) {
- zerr("read-only variable: %s", v->pm->node.nam);
- zsfree(val);
- return;
- }
- if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerr("%s: restricted", v->pm->node.nam);
- zsfree(val);
- return;
- }
- if ((v->pm->node.flags & PM_HASHED) &&
- (v->isarr & (SCANPM_MATCHMANY|SCANPM_ARRONLY))) {
- zerr("%s: attempt to set slice of associative array", v->pm->node.nam);
- zsfree(val);
- return;
- }
- if (v->flags & VALFLAG_EMPTY) {
- zerr("%s: assignment to invalid subscript range", v->pm->node.nam);
- zsfree(val);
- return;
- }
- v->pm->node.flags &= ~PM_UNSET;
- switch (PM_TYPE(v->pm->node.flags)) {
- case PM_SCALAR:
- if (v->start == 0 && v->end == -1) {
- v->pm->gsu.s->setfn(v->pm, val);
- if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
- !v->pm->width)
- v->pm->width = strlen(val);
- } else {
- char *z, *x;
- int zlen, vlen, newsize;
-
- z = v->pm->gsu.s->getfn(v->pm);
- zlen = strlen(z);
-
- if ((v->flags & VALFLAG_INV) && unset(KSHARRAYS))
- v->start--, v->end--;
- if (v->start < 0) {
- v->start += zlen;
- if (v->start < 0)
- v->start = 0;
- }
- if (v->start > zlen)
- v->start = zlen;
- if (v->end < 0) {
- v->end += zlen;
- if (v->end < 0) {
- v->end = 0;
- } else if (v->end >= zlen) {
- v->end = zlen;
- } else {
-#ifdef MULTIBYTE_SUPPORT
- if (isset(MULTIBYTE)) {
- v->end += MB_METACHARLEN(z + v->end);
- } else {
- v->end++;
- }
-#else
- v->end++;
-#endif
- }
- }
- else if (v->end > zlen)
- v->end = zlen;
-
- vlen = strlen(val);
- /* Characters preceding start index +
- characters of what is assigned +
- characters following end index */
- newsize = v->start + vlen + (zlen - v->end);
-
- /* Does new size differ? */
- if (newsize != zlen || v->pm->gsu.s->setfn != strsetfn) {
- x = (char *) zalloc(newsize + 1);
- strncpy(x, z, v->start);
- strcpy(x + v->start, val);
- strcat(x + v->start, z + v->end);
- v->pm->gsu.s->setfn(v->pm, x);
- } else {
- Param pm = v->pm;
- /* Size doesn't change, can limit actions to only
- * overwriting bytes in already allocated string */
- strncpy(z + v->start, val, vlen);
- /* Implement remainder of strsetfn */
- if (!(pm->node.flags & PM_HASHELEM) &&
- ((pm->node.flags & PM_NAMEDDIR) ||
- isset(AUTONAMEDIRS))) {
- pm->node.flags |= PM_NAMEDDIR;
- adduserdir(pm->node.nam, z, 0, 0);
- }
- }
- zsfree(val);
- }
- break;
- case PM_INTEGER:
- if (val) {
- zlong ival;
- if (flags & ASSPM_ENV_IMPORT) {
- char *ptr;
- ival = zstrtol_underscore(val, &ptr, 0, 1);
- } else
- ival = mathevali(val);
- v->pm->gsu.i->setfn(v->pm, ival);
- if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
- !v->pm->width)
- v->pm->width = strlen(val);
- zsfree(val);
- }
- if (!v->pm->base && lastbase != -1)
- v->pm->base = lastbase;
- break;
- case PM_EFLOAT:
- case PM_FFLOAT:
- if (val) {
- mnumber mn;
- if (flags & ASSPM_ENV_IMPORT) {
- char *ptr;
- mn.type = MN_FLOAT;
- mn.u.d = strtod(val, &ptr);
- } else
- mn = matheval(val);
- v->pm->gsu.f->setfn(v->pm, (mn.type & MN_FLOAT) ? mn.u.d :
- (double)mn.u.l);
- if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
- !v->pm->width)
- v->pm->width = strlen(val);
- zsfree(val);
- }
- break;
- case PM_ARRAY:
- {
- char **ss = (char **) zalloc(2 * sizeof(char *));
-
- ss[0] = val;
- ss[1] = NULL;
- setarrvalue(v, ss);
- }
- break;
- case PM_HASHED:
- {
- if (foundparam == NULL)
- {
- zerr("%s: attempt to set associative array to scalar",
- v->pm->node.nam);
- zsfree(val);
- return;
- }
- else
- foundparam->gsu.s->setfn(foundparam, val);
- }
- break;
- }
- if ((!v->pm->env && !(v->pm->node.flags & PM_EXPORTED) &&
- !(isset(ALLEXPORT) && !(v->pm->node.flags & PM_HASHELEM))) ||
- (v->pm->node.flags & PM_ARRAY) || v->pm->ename)
- return;
- export_param(v->pm);
-}
-
-/**/
-void
-setnumvalue(Value v, mnumber val)
-{
- char buf[BDIGBUFSIZE], *p;
-
- if (unset(EXECOPT))
- return;
- if (v->pm->node.flags & PM_READONLY) {
- zerr("read-only variable: %s", v->pm->node.nam);
- return;
- }
- if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerr("%s: restricted", v->pm->node.nam);
- return;
- }
- switch (PM_TYPE(v->pm->node.flags)) {
- case PM_SCALAR:
- case PM_ARRAY:
- if ((val.type & MN_INTEGER) || outputradix) {
- if (!(val.type & MN_INTEGER))
- val.u.l = (zlong) val.u.d;
- p = convbase_underscore(buf, val.u.l, outputradix,
- outputunderscore);
- } else
- p = convfloat_underscore(val.u.d, outputunderscore);
- setstrvalue(v, ztrdup(p));
- break;
- case PM_INTEGER:
- v->pm->gsu.i->setfn(v->pm, (val.type & MN_INTEGER) ? val.u.l :
- (zlong) val.u.d);
- setstrvalue(v, NULL);
- break;
- case PM_EFLOAT:
- case PM_FFLOAT:
- v->pm->gsu.f->setfn(v->pm, (val.type & MN_INTEGER) ?
- (double)val.u.l : val.u.d);
- setstrvalue(v, NULL);
- break;
- }
-}
-
-/**/
-mod_export void
-setarrvalue(Value v, char **val)
-{
- if (unset(EXECOPT))
- return;
- if (v->pm->node.flags & PM_READONLY) {
- zerr("read-only variable: %s", v->pm->node.nam);
- freearray(val);
- return;
- }
- if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerr("%s: restricted", v->pm->node.nam);
- freearray(val);
- return;
- }
- if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED))) {
- freearray(val);
- zerr("%s: attempt to assign array value to non-array",
- v->pm->node.nam);
- return;
- }
- if (v->flags & VALFLAG_EMPTY) {
- zerr("%s: assignment to invalid subscript range", v->pm->node.nam);
- freearray(val);
- return;
- }
-
- if (v->start == 0 && v->end == -1) {
- if (PM_TYPE(v->pm->node.flags) == PM_HASHED)
- arrhashsetfn(v->pm, val, 0);
- else
- v->pm->gsu.a->setfn(v->pm, val);
- } else if (v->start == -1 && v->end == 0 &&
- PM_TYPE(v->pm->node.flags) == PM_HASHED) {
- arrhashsetfn(v->pm, val, ASSPM_AUGMENT);
- } else if ((PM_TYPE(v->pm->node.flags) == PM_HASHED)) {
- freearray(val);
- zerr("%s: attempt to set slice of associative array",
- v->pm->node.nam);
- return;
- } else {
- char **const old = v->pm->gsu.a->getfn(v->pm);
- char **new;
- char **p, **q, **r; /* index variables */
- const int pre_assignment_length = arrlen(old);
- int post_assignment_length;
- int i;
-
- q = old;
-
- if ((v->flags & VALFLAG_INV) && unset(KSHARRAYS)) {
- if (v->start > 0)
- v->start--;
- v->end--;
- }
- if (v->start < 0) {
- v->start += pre_assignment_length;
- if (v->start < 0)
- v->start = 0;
- }
- if (v->end < 0) {
- v->end += pre_assignment_length + 1;
- if (v->end < 0)
- v->end = 0;
- }
- if (v->end < v->start)
- v->end = v->start;
-
- post_assignment_length = v->start + arrlen(val);
- if (v->end < pre_assignment_length) {
- /*
- * Allocate room for array elements between the end of the slice `v'
- * and the original array's end.
- */
- post_assignment_length += pre_assignment_length - v->end;
- }
-
- if (pre_assignment_length == post_assignment_length
- && v->pm->gsu.a->setfn == arrsetfn
- /* ... and isn't something that arrsetfn() treats specially */
- && 0 == (v->pm->node.flags & (PM_SPECIAL|PM_UNIQUE))
- && NULL == v->pm->ename)
- {
- /* v->start is 0-based */
- p = old + v->start;
- for (r = val; *r;) {
- /* Free previous string */
- zsfree(*p);
- /* Give away ownership of the string */
- *p++ = *r++;
- }
- } else {
- /* arr+=( ... )
- * arr[${#arr}+x,...]=( ... ) */
- if (post_assignment_length > pre_assignment_length &&
- pre_assignment_length <= v->start &&
- pre_assignment_length > 0 &&
- v->pm->gsu.a->setfn == arrsetfn)
- {
- p = new = (char **) zrealloc(old, sizeof(char *)
- * (post_assignment_length + 1));
-
- p += pre_assignment_length; /* after old elements */
-
- /* Consider 1 < 0, case for a=( 1 ); a[1,..] =
- * 1 < 1, case for a=( 1 ); a[2,..] = */
- if (pre_assignment_length < v->start) {
- for (i = pre_assignment_length; i < v->start; i++) {
- *p++ = ztrdup("");
- }
- }
-
- for (r = val; *r;) {
- /* Give away ownership of the string */
- *p++ = *r++;
- }
-
- /* v->end doesn't matter:
- * a=( 1 2 ); a[4,100]=( a b ); echo "${(q@)a}"
- * 1 2 '' a b */
- *p = NULL;
-
- v->pm->u.arr = NULL;
- v->pm->gsu.a->setfn(v->pm, new);
- } else {
- p = new = (char **) zalloc(sizeof(char *)
- * (post_assignment_length + 1));
- for (i = 0; i < v->start; i++)
- *p++ = i < pre_assignment_length ? ztrdup(*q++) : ztrdup("");
- for (r = val; *r;) {
- /* Give away ownership of the string */
- *p++ = *r++;
- }
- if (v->end < pre_assignment_length)
- for (q = old + v->end; *q;)
- *p++ = ztrdup(*q++);
- *p = NULL;
-
- v->pm->gsu.a->setfn(v->pm, new);
- }
-
- DPUTS2(p - new != post_assignment_length, "setarrvalue: wrong allocation: %d 1= %lu",
- post_assignment_length, (unsigned long)(p - new));
- }
-
- /* Ownership of all strings has been
- * given away, can plainly free */
- free(val);
- }
-}
-
-/* Retrieve an integer parameter */
-
-/**/
-mod_export zlong
-getiparam(char *s)
-{
- struct value vbuf;
- Value v;
-
- if (!(v = getvalue(&vbuf, &s, 1)))
- return 0;
- return getintvalue(v);
-}
-
-/* Retrieve a numerical parameter, either integer or floating */
-
-/**/
-mnumber
-getnparam(char *s)
-{
- struct value vbuf;
- Value v;
-
- if (!(v = getvalue(&vbuf, &s, 1))) {
- mnumber mn;
- mn.type = MN_INTEGER;
- mn.u.l = 0;
- return mn;
- }
- return getnumvalue(v);
-}
-
-/* Retrieve a scalar (string) parameter */
-
-/**/
-mod_export char *
-getsparam(char *s)
-{
- struct value vbuf;
- Value v;
-
- if (!(v = getvalue(&vbuf, &s, 0)))
- return NULL;
- return getstrvalue(v);
-}
-
-/**/
-mod_export char *
-getsparam_u(char *s)
-{
- if ((s = getsparam(s)))
- return unmetafy(s, NULL);
- return s;
-}
-
-/* Retrieve an array parameter */
-
-/**/
-mod_export char **
-getaparam(char *s)
-{
- struct value vbuf;
- Value v;
-
- if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
- PM_TYPE(v->pm->node.flags) == PM_ARRAY)
- return v->pm->gsu.a->getfn(v->pm);
- return NULL;
-}
-
-/* Retrieve an assoc array parameter as an array */
-
-/**/
-mod_export char **
-gethparam(char *s)
-{
- struct value vbuf;
- Value v;
-
- if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
- PM_TYPE(v->pm->node.flags) == PM_HASHED)
- return paramvalarr(v->pm->gsu.h->getfn(v->pm), SCANPM_WANTVALS);
- return NULL;
-}
-
-/* Retrieve the keys of an assoc array parameter as an array */
-
-/**/
-mod_export char **
-gethkparam(char *s)
-{
- struct value vbuf;
- Value v;
-
- if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
- PM_TYPE(v->pm->node.flags) == PM_HASHED)
- return paramvalarr(v->pm->gsu.h->getfn(v->pm), SCANPM_WANTKEYS);
- return NULL;
-}
-
-/*
- * Function behind WARNCREATEGLOBAL and WARNNESTEDVAR option.
- *
- * For WARNNESTEDVAR:
- * Called when the variable is created.
- * Apply heuristics to see if this variable was just created
- * globally but in a local context.
- *
- * For WARNNESTEDVAR:
- * Called when the variable already exists and is set.
- * Apply heuristics to see if this variable is setting
- * a variable that was created in a less nested function
- * or globally.
- */
-
-/**/
-static void
-check_warn_pm(Param pm, const char *pmtype, int created,
- int may_warn_about_nested_vars)
-{
- Funcstack i;
-
- if (!may_warn_about_nested_vars && !created)
- return;
-
- if (created && isset(WARNCREATEGLOBAL)) {
- if (locallevel <= forklevel || pm->level != 0)
- return;
- } else if (!created && isset(WARNNESTEDVAR)) {
- if (pm->level >= locallevel)
- return;
- } else
- return;
-
- if (pm->node.flags & PM_SPECIAL)
- return;
-
- for (i = funcstack; i; i = i->prev) {
- if (i->tp == FS_FUNC) {
- char *msg;
- DPUTS(!i->name, "funcstack entry with no name");
- msg = created ?
- "%s parameter %s created globally in function %s" :
- "%s parameter %s set in enclosing scope in function %s";
- zwarn(msg, pmtype, pm->node.nam, i->name);
- break;
- }
- }
-}
-
-/**/
-mod_export Param
-assignsparam(char *s, char *val, int flags)
-{
- struct value vbuf;
- Value v;
- char *t = s;
- char *ss, *copy, *var;
- size_t lvar;
- mnumber lhs, rhs;
- int sstart, created = 0;
-
- if (!isident(s)) {
- zerr("not an identifier: %s", s);
- zsfree(val);
- errflag |= ERRFLAG_ERROR;
- return NULL;
- }
- queue_signals();
- if ((ss = strchr(s, '['))) {
- *ss = '\0';
- if (!(v = getvalue(&vbuf, &s, 1))) {
- createparam(t, PM_ARRAY);
- created = 1;
- } else {
- if (v->pm->node.flags & PM_READONLY) {
- zerr("read-only variable: %s", v->pm->node.nam);
- *ss = '[';
- zsfree(val);
- unqueue_signals();
- return NULL;
- }
- /*
- * Parameter defined here is a temporary bogus one.
- * Don't warn about anything.
- */
- flags &= ~ASSPM_WARN;
- }
- *ss = '[';
- v = NULL;
- } else {
- if (!(v = getvalue(&vbuf, &s, 1))) {
- createparam(t, PM_SCALAR);
- created = 1;
- } else if ((((v->pm->node.flags & PM_ARRAY) && !(flags & ASSPM_AUGMENT)) ||
- (v->pm->node.flags & PM_HASHED)) &&
- !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) &&
- unset(KSHARRAYS)) {
- unsetparam(t);
- createparam(t, PM_SCALAR);
- /* not regarded as a new creation */
- v = NULL;
- }
- }
- if (!v && !(v = getvalue(&vbuf, &t, 1))) {
- unqueue_signals();
- zsfree(val);
- /* errflag |= ERRFLAG_ERROR; */
- return NULL;
- }
- if (flags & ASSPM_WARN)
- check_warn_pm(v->pm, "scalar", created, 1);
- if (flags & ASSPM_AUGMENT) {
- if (v->start == 0 && v->end == -1) {
- switch (PM_TYPE(v->pm->node.flags)) {
- case PM_SCALAR:
- v->start = INT_MAX; /* just append to scalar value */
- break;
- case PM_INTEGER:
- case PM_EFLOAT:
- case PM_FFLOAT:
- rhs = matheval(val);
- lhs = getnumvalue(v);
- if (lhs.type == MN_FLOAT) {
- if ((rhs.type) == MN_FLOAT)
- lhs.u.d = lhs.u.d + rhs.u.d;
- else
- lhs.u.d = lhs.u.d + (double)rhs.u.l;
- } else {
- if ((rhs.type) == MN_INTEGER)
- lhs.u.l = lhs.u.l + rhs.u.l;
- else
- lhs.u.l = lhs.u.l + (zlong)rhs.u.d;
- }
- setnumvalue(v, lhs);
- unqueue_signals();
- zsfree(val);
- return v->pm; /* avoid later setstrvalue() call */
- case PM_ARRAY:
- if (unset(KSHARRAYS)) {
- v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
- v->end = v->start + 1;
- } else {
- /* ksh appends scalar to first element */
- v->end = 1;
- goto kshappend;
- }
- break;
- }
- } else {
- switch (PM_TYPE(v->pm->node.flags)) {
- case PM_SCALAR:
- if (v->end > 0)
- v->start = v->end;
- else
- v->start = v->end = strlen(v->pm->gsu.s->getfn(v->pm)) +
- v->end + 1;
- break;
- case PM_INTEGER:
- case PM_EFLOAT:
- case PM_FFLOAT:
- unqueue_signals();
- zerr("attempt to add to slice of a numeric variable");
- zsfree(val);
- return NULL;
- case PM_ARRAY:
- kshappend:
- /* treat slice as the end element */
- v->start = sstart = v->end > 0 ? v->end - 1 : v->end;
- v->isarr = 0;
- var = getstrvalue(v);
- v->start = sstart;
- copy = val;
- lvar = strlen(var);
- val = (char *)zalloc(lvar + strlen(val) + 1);
- strcpy(val, var);
- strcpy(val + lvar, copy);
- zsfree(copy);
- break;
- }
- }
- }
-
- assignstrvalue(v, val, flags);
- unqueue_signals();
- return v->pm;
-}
-
-/**/
-mod_export Param
-setsparam(char *s, char *val)
-{
- return assignsparam(s, val, ASSPM_WARN);
-}
-
-/**/
-mod_export Param
-assignaparam(char *s, char **val, int flags)
-{
- struct value vbuf;
- Value v;
- char *t = s;
- char *ss;
- int created = 0;
- int may_warn_about_nested_vars = 1;
-
- if (!isident(s)) {
- zerr("not an identifier: %s", s);
- freearray(val);
- errflag |= ERRFLAG_ERROR;
- return NULL;
- }
- queue_signals();
- if ((ss = strchr(s, '['))) {
- *ss = '\0';
- if (!(v = getvalue(&vbuf, &s, 1))) {
- createparam(t, PM_ARRAY);
- created = 1;
- } else {
- may_warn_about_nested_vars = 0;
- }
- *ss = '[';
- if (v && PM_TYPE(v->pm->node.flags) == PM_HASHED) {
- unqueue_signals();
- zerr("%s: attempt to set slice of associative array",
- v->pm->node.nam);
- freearray(val);
- errflag |= ERRFLAG_ERROR;
- return NULL;
- }
- v = NULL;
- } else {
- if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) {
- createparam(t, PM_ARRAY);
- created = 1;
- } else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) &&
- !(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) {
- int uniq = v->pm->node.flags & PM_UNIQUE;
- if (flags & ASSPM_AUGMENT) {
- /* insert old value at the beginning of the val array */
- char **new;
- int lv = arrlen(val);
-
- new = (char **) zalloc(sizeof(char *) * (lv + 2));
- *new = ztrdup(getstrvalue(v));
- memcpy(new+1, val, sizeof(char *) * (lv + 1));
- free(val);
- val = new;
- }
- unsetparam(t);
- createparam(t, PM_ARRAY | uniq);
- v = NULL;
- }
- }
- if (!v)
- if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
- unqueue_signals();
- freearray(val);
- /* errflag |= ERRFLAG_ERROR; */
- return NULL;
- }
-
- if (flags & ASSPM_WARN)
- check_warn_pm(v->pm, "array", created, may_warn_about_nested_vars);
-
- /*
- * At this point, we may have array entries consisting of
- * - a Marker element --- normally allocated array entry but
- * with just Marker char and null
- * - an array index element --- as normal for associative array,
- * but non-standard for normal array which we handle now.
- * - a value for the indexed element.
- * This only applies if the flag ASSPM_KEY_VALUE is passed in,
- * indicating prefork() detected this syntax.
- *
- * For associative arrays we just junk the Marker elements.
- */
- if (flags & ASSPM_KEY_VALUE) {
- char **aptr;
- if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
- /*
- * This is an ordinary array with key / value pairs.
- */
- int maxlen, origlen, nextind;
- char **fullval, **origptr;
- zlong *subscripts = (zlong *)zhalloc(arrlen(val) * sizeof(zlong));
- zlong *iptr = subscripts;
- if (flags & ASSPM_AUGMENT) {
- origptr = v->pm->gsu.a->getfn(v->pm);
- maxlen = origlen = arrlen(origptr);
- } else {
- maxlen = origlen = 0;
- origptr = NULL;
- }
- nextind = 0;
- for (aptr = val; *aptr; ) {
- if (**aptr == Marker) {
- *iptr = mathevali(*++aptr);
- if (*iptr < 0 ||
- (!isset(KSHARRAYS) && *iptr == 0)) {
- unqueue_signals();
- zerr("bad subscript for direct array assignment: %s", *aptr);
- freearray(val);
- return NULL;
- }
- if (!isset(KSHARRAYS))
- --*iptr;
- nextind = *iptr + 1;
- ++iptr;
- aptr += 2;
- } else {
- ++nextind;
- ++aptr;
- }
- if (nextind > maxlen)
- maxlen = nextind;
- }
- fullval = zshcalloc((maxlen+1) * sizeof(char *));
- if (!fullval) {
- zerr("array too large");
- freearray(val);
- return NULL;
- }
- fullval[maxlen] = NULL;
- if (flags & ASSPM_AUGMENT) {
- char **srcptr = origptr;
- for (aptr = fullval; aptr <= fullval + origlen; aptr++) {
- *aptr = ztrdup(*srcptr);
- srcptr++;
- }
- }
- iptr = subscripts;
- nextind = 0;
- for (aptr = val; *aptr; ++aptr) {
- char *old;
- if (**aptr == Marker) {
- int augment = ((*aptr)[1] == '+');
- zsfree(*aptr);
- zsfree(*++aptr); /* Index, no longer needed */
- old = fullval[*iptr];
- if (augment && old) {
- fullval[*iptr] = bicat(old, *++aptr);
- zsfree(*aptr);
- } else {
- fullval[*iptr] = *++aptr;
- }
- nextind = *iptr + 1;
- ++iptr;
- } else {
- old = fullval[nextind];
- fullval[nextind] = *aptr;
- ++nextind;
- }
- if (old)
- zsfree(old);
- /* aptr now on value in both cases */
- }
- if (*aptr) { /* Shouldn't be possible */
- DPUTS(1, "Extra element in key / value array");
- zsfree(*aptr);
- }
- free(val);
- for (aptr = fullval; aptr < fullval + maxlen; aptr++) {
- /*
- * Remember we don't have sparse arrays but and they're null
- * terminated --- so any value we don't set has to be an
- * empty string.
- */
- if (!*aptr)
- *aptr = ztrdup("");
- }
- setarrvalue(v, fullval);
- unqueue_signals();
- return v->pm;
- } else if (PM_TYPE(v->pm->node.flags & PM_HASHED)) {
- /*
- * We strictly enforce [key]=value syntax for associative
- * arrays. Marker can only indicate a Marker / key / value
- * triad; it cannot be there by accident.
- *
- * It's too inefficient to strip Markers here, and they
- * can't be there in the other form --- so just ignore
- * them willy nilly lower down.
- */
- for (aptr = val; *aptr; aptr += 3) {
- if (**aptr != Marker) {
- unqueue_signals();
- freearray(val);
- zerr("bad [key]=value syntax for associative array");
- return NULL;
- }
- }
- } else {
- unqueue_signals();
- freearray(val);
- zerr("invalid use of [key]=value assignment syntax");
- return NULL;
- }
- }
-
- if (flags & ASSPM_AUGMENT) {
- if (v->start == 0 && v->end == -1) {
- if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
- v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
- v->end = v->start + 1;
- } else if (PM_TYPE(v->pm->node.flags) & PM_HASHED)
- v->start = -1, v->end = 0;
- } else {
- if (v->end > 0)
- v->start = v->end--;
- else if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
- v->end = arrlen(v->pm->gsu.a->getfn(v->pm)) + v->end;
- v->start = v->end + 1;
- }
- }
- }
-
- setarrvalue(v, val);
- unqueue_signals();
- return v->pm;
-}
-
-
-/**/
-mod_export Param
-setaparam(char *s, char **aval)
-{
- return assignaparam(s, aval, ASSPM_WARN);
-}
-
-/**/
-mod_export Param
-sethparam(char *s, char **val)
-{
- struct value vbuf;
- Value v;
- char *t = s;
- int checkcreate = 0;
-
- if (!isident(s)) {
- zerr("not an identifier: %s", s);
- freearray(val);
- errflag |= ERRFLAG_ERROR;
- return NULL;
- }
- if (strchr(s, '[')) {
- freearray(val);
- zerr("nested associative arrays not yet supported");
- errflag |= ERRFLAG_ERROR;
- return NULL;
- }
- if (unset(EXECOPT))
- return NULL;
- queue_signals();
- if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) {
- createparam(t, PM_HASHED);
- checkcreate = 1;
- } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED)) {
- if (!(v->pm->node.flags & PM_SPECIAL)) {
- unsetparam(t);
- /* no WARNCREATEGLOBAL check here as parameter already existed */
- createparam(t, PM_HASHED);
- v = NULL;
- } else {
- zerr("%s: can't change type of a special parameter", t);
- unqueue_signals();
- return NULL;
- }
- }
- if (!v)
- if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
- unqueue_signals();
- /* errflag |= ERRFLAG_ERROR; */
- return NULL;
- }
- check_warn_pm(v->pm, "associative array", checkcreate, 1);
- setarrvalue(v, val);
- unqueue_signals();
- return v->pm;
-}
-
-
-/*
- * Set a generic shell number, floating point or integer.
- * Option to warn on setting.
- */
-
-/**/
-mod_export Param
-assignnparam(char *s, mnumber val, int flags)
-{
- struct value vbuf;
- Value v;
- char *t = s, *ss;
- Param pm;
- int was_unset = 0;
-
- if (!isident(s)) {
- zerr("not an identifier: %s", s);
- errflag |= ERRFLAG_ERROR;
- return NULL;
- }
- if (unset(EXECOPT))
- return NULL;
- queue_signals();
- ss = strchr(s, '[');
- v = getvalue(&vbuf, &s, 1);
- if (v && (v->pm->node.flags & (PM_ARRAY|PM_HASHED)) &&
- !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) &&
- /*
- * not sure what KSHARRAYS has got to do with this...
- * copied this from assignsparam().
- */
- unset(KSHARRAYS) && !ss) {
- unsetparam_pm(v->pm, 0, 1);
- was_unset = 1;
- s = t;
- v = NULL;
- }
- if (!v) {
- /* s has been updated by getvalue, so check again */
- ss = strchr(s, '[');
- if (ss)
- *ss = '\0';
- pm = createparam(t, ss ? PM_ARRAY :
- isset(POSIXIDENTIFIERS) ? PM_SCALAR :
- (val.type & MN_INTEGER) ? PM_INTEGER : PM_FFLOAT);
- if (!pm)
- pm = (Param) paramtab->getnode(paramtab, t);
- DPUTS(!pm, "BUG: parameter not created");
- if (ss) {
- *ss = '[';
- } else if (val.type & MN_INTEGER) {
- pm->base = outputradix;
- }
- if (!(v = getvalue(&vbuf, &t, 1))) {
- DPUTS(!v, "BUG: value not found for new parameter");
- /* errflag |= ERRFLAG_ERROR; */
- unqueue_signals();
- return NULL;
- }
- if (flags & ASSPM_WARN)
- check_warn_pm(v->pm, "numeric", !was_unset, 1);
- } else {
- if (flags & ASSPM_WARN)
- check_warn_pm(v->pm, "numeric", 0, 1);
- }
- setnumvalue(v, val);
- unqueue_signals();
- return v->pm;
-}
-
-/*
- * Set a generic shell number, floating point or integer.
- * Warn on setting based on option.
- */
-
-/**/
-mod_export Param
-setnparam(char *s, mnumber val)
-{
- return assignnparam(s, val, ASSPM_WARN);
-}
-
-/* Simplified interface to assignnparam */
-
-/**/
-mod_export Param
-assigniparam(char *s, zlong val, int flags)
-{
- mnumber mnval;
- mnval.type = MN_INTEGER;
- mnval.u.l = val;
- return assignnparam(s, mnval, flags);
-}
-
-/* Simplified interface to setnparam */
-
-/**/
-mod_export Param
-setiparam(char *s, zlong val)
-{
- mnumber mnval;
- mnval.type = MN_INTEGER;
- mnval.u.l = val;
- return assignnparam(s, mnval, ASSPM_WARN);
-}
-
-/*
- * Set an integer parameter without forcing creation of an integer type.
- * This is useful if the integer is going to be set to a parmaeter which
- * would usually be scalar but may not exist.
- */
-
-/**/
-mod_export Param
-setiparam_no_convert(char *s, zlong val)
-{
- /*
- * If the target is already an integer, thisgets converted
- * back. Low technology rules.
- */
- char buf[BDIGBUFSIZE];
- convbase(buf, val, 10);
- return assignsparam(s, ztrdup(buf), ASSPM_WARN);
-}
-
-/* Unset a parameter */
-
-/**/
-mod_export void
-unsetparam(char *s)
-{
- Param pm;
-
- queue_signals();
- if ((pm = (Param) (paramtab == realparamtab ?
- /* getnode2() to avoid autoloading */
- paramtab->getnode2(paramtab, s) :
- paramtab->getnode(paramtab, s))))
- unsetparam_pm(pm, 0, 1);
- unqueue_signals();
-}
-
-/* Unset a parameter
- *
- * altflag: if true, don't remove pm->ename from the environment
- * exp: See stdunsetfn()
- */
-
-/**/
-mod_export int
-unsetparam_pm(Param pm, int altflag, int exp)
-{
- Param oldpm, altpm;
- char *altremove;
-
- if ((pm->node.flags & PM_READONLY) && pm->level <= locallevel) {
- zerr("read-only variable: %s", pm->node.nam);
- return 1;
- }
- if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerr("%s: restricted", pm->node.nam);
- return 1;
- }
-
- if (pm->ename && !altflag)
- altremove = ztrdup(pm->ename);
- else
- altremove = NULL;
-
- if (!(pm->node.flags & PM_UNSET))
- pm->gsu.s->unsetfn(pm, exp);
- if (pm->env)
- delenv(pm);
-
- /* remove it under its alternate name if necessary */
- if (altremove) {
- altpm = (Param) paramtab->getnode(paramtab, altremove);
- /* tied parameters are at the same local level as each other */
- oldpm = NULL;
- while (altpm && altpm->level > pm->level) {
- /* param under alternate name hidden by a local */
- oldpm = altpm;
- altpm = altpm->old;
- }
- if (altpm) {
- if (oldpm && !altpm->level) {
- oldpm->old = NULL;
- /* fudge things so removenode isn't called */
- altpm->level = 1;
- }
- unsetparam_pm(altpm, 1, exp);
- }
-
- zsfree(altremove);
- }
-
- /*
- * If this was a local variable, we need to keep the old
- * struct so that it is resurrected at the right level.
- * This is partly because when an array/scalar value is set
- * and the parameter used to be the other sort, unsetparam()
- * is called. Beyond that, there is an ambiguity: should
- * foo() { local bar; unset bar; } make the global bar
- * available or not? The following makes the answer "no".
- *
- * Some specials, such as those used in zle, still need removing
- * from the parameter table; they have the PM_REMOVABLE flag.
- */
- if ((pm->level && locallevel >= pm->level) ||
- (pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
- return 0;
-
- /* remove parameter node from table */
- paramtab->removenode(paramtab, pm->node.nam);
-
- if (pm->old) {
- oldpm = pm->old;
- paramtab->addnode(paramtab, oldpm->node.nam, oldpm);
- if ((PM_TYPE(oldpm->node.flags) == PM_SCALAR) &&
- !(pm->node.flags & PM_HASHELEM) &&
- (oldpm->node.flags & PM_NAMEDDIR) &&
- oldpm->gsu.s == &stdscalar_gsu)
- adduserdir(oldpm->node.nam, oldpm->u.str, 0, 0);
- if (oldpm->node.flags & PM_EXPORTED) {
- /*
- * Re-export the old value which we removed in typeset_single().
- * I don't think we need to test for ALL_EXPORT here, since if
- * it was used to export the parameter originally the parameter
- * should still have the PM_EXPORTED flag.
- */
- export_param(oldpm);
- }
- }
-
- paramtab->freenode(&pm->node); /* free parameter node */
-
- return 0;
-}
-
-/* Standard function to unset a parameter. This is mostly delegated to *
- * the specific set function.
- *
- * This could usefully be made type-specific, but then we need
- * to be more careful when calling the unset method directly.
- *
- * The "exp"licit parameter should be nonzero for assignments and the
- * unset command, and zero for implicit unset (e.g., end of scope).
- * Currently this is used only by some modules.
- */
-
-/**/
-mod_export void
-stdunsetfn(Param pm, UNUSED(int exp))
-{
- switch (PM_TYPE(pm->node.flags)) {
- case PM_SCALAR:
- if (pm->gsu.s->setfn)
- pm->gsu.s->setfn(pm, NULL);
- break;
-
- case PM_ARRAY:
- if (pm->gsu.a->setfn)
- pm->gsu.a->setfn(pm, NULL);
- break;
-
- case PM_HASHED:
- if (pm->gsu.h->setfn)
- pm->gsu.h->setfn(pm, NULL);
- break;
-
- default:
- if (!(pm->node.flags & PM_SPECIAL))
- pm->u.str = NULL;
- break;
- }
- if ((pm->node.flags & (PM_SPECIAL|PM_TIED)) == PM_TIED) {
- if (pm->ename) {
- zsfree(pm->ename);
- pm->ename = NULL;
- }
- pm->node.flags &= ~PM_TIED;
- }
- pm->node.flags |= PM_UNSET;
-}
-
-/* Function to get value of an integer parameter */
-
-/**/
-mod_export zlong
-intgetfn(Param pm)
-{
- return pm->u.val;
-}
-
-/* Function to set value of an integer parameter */
-
-/**/
-static void
-intsetfn(Param pm, zlong x)
-{
- pm->u.val = x;
-}
-
-/* Function to get value of a floating point parameter */
-
-/**/
-static double
-floatgetfn(Param pm)
-{
- return pm->u.dval;
-}
-
-/* Function to set value of an integer parameter */
-
-/**/
-static void
-floatsetfn(Param pm, double x)
-{
- pm->u.dval = x;
-}
-
-/* Function to get value of a scalar (string) parameter */
-
-/**/
-mod_export char *
-strgetfn(Param pm)
-{
- return pm->u.str ? pm->u.str : (char *) hcalloc(1);
-}
-
-/* Function to set value of a scalar (string) parameter */
-
-/**/
-mod_export void
-strsetfn(Param pm, char *x)
-{
- zsfree(pm->u.str);
- pm->u.str = x;
- if (!(pm->node.flags & PM_HASHELEM) &&
- ((pm->node.flags & PM_NAMEDDIR) || isset(AUTONAMEDIRS))) {
- pm->node.flags |= PM_NAMEDDIR;
- adduserdir(pm->node.nam, x, 0, 0);
- }
- /* If you update this function, you may need to update the
- * `Implement remainder of strsetfn' block in assignstrvalue(). */
-}
-
-/* Function to get value of an array parameter */
-
-static char *nullarray = NULL;
-
-/**/
-char **
-arrgetfn(Param pm)
-{
- return pm->u.arr ? pm->u.arr : &nullarray;
-}
-
-/* Function to set value of an array parameter */
-
-/**/
-mod_export void
-arrsetfn(Param pm, char **x)
-{
- if (pm->u.arr && pm->u.arr != x)
- freearray(pm->u.arr);
- if (pm->node.flags & PM_UNIQUE)
- uniqarray(x);
- pm->u.arr = x;
- /* Arrays tied to colon-arrays may need to fix the environment */
- if (pm->ename && x)
- arrfixenv(pm->ename, x);
- /* If you extend this function, update the list of conditions in
- * setarrvalue(). */
-}
-
-/* Function to get value of an association parameter */
-
-/**/
-mod_export HashTable
-hashgetfn(Param pm)
-{
- return pm->u.hash;
-}
-
-/* Function to set value of an association parameter */
-
-/**/
-mod_export void
-hashsetfn(Param pm, HashTable x)
-{
- if (pm->u.hash && pm->u.hash != x)
- deleteparamtable(pm->u.hash);
- pm->u.hash = x;
-}
-
-/* Function to dispose of setting of an unsettable hash */
-
-/**/
-mod_export void
-nullsethashfn(UNUSED(Param pm), HashTable x)
-{
- deleteparamtable(x);
-}
-
-/* Function to set value of an association parameter using key/value pairs */
-
-/**/
-static void
-arrhashsetfn(Param pm, char **val, int flags)
-{
- /* Best not to shortcut this by using the existing hash table, *
- * since that could cause trouble for special hashes. This way, *
- * it's up to pm->gsu.h->setfn() what to do. */
- int alen = 0;
- HashTable opmtab = paramtab, ht = 0;
- char **aptr;
- Value v = (Value) hcalloc(sizeof *v);
- v->end = -1;
-
- for (aptr = val; *aptr; ++aptr) {
- if (**aptr != Marker)
- ++alen;
- }
-
- if (alen % 2) {
- freearray(val);
- zerr("bad set of key/value pairs for associative array");
- return;
- }
- if (flags & ASSPM_AUGMENT) {
- ht = paramtab = pm->gsu.h->getfn(pm);
- }
- if (alen && (!(flags & ASSPM_AUGMENT) || !paramtab)) {
- ht = paramtab = newparamtable(17, pm->node.nam);
- }
- for (aptr = val; *aptr; ) {
- int eltflags = 0;
- if (**aptr == Marker) {
- /* Either all elements have Marker or none. Checked in caller. */
- if ((*aptr)[1] == '+') {
- /* Actually, assignstrvalue currently doesn't handle this... */
- eltflags = ASSPM_AUGMENT;
- /* ...so we'll use the trick from setsparam(). */
- v->start = INT_MAX;
- } else {
- v->start = 0;
- }
- v->end = -1;
- zsfree(*aptr++);
- }
- /* The parameter name is ztrdup'd... */
- v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
- /*
- * createparam() doesn't return anything if the parameter
- * already existed.
- */
- if (!v->pm)
- v->pm = (Param) paramtab->getnode(paramtab, *aptr);
- zsfree(*aptr++);
- /* ...but we can use the value without copying. */
- assignstrvalue(v, *aptr++, eltflags);
- }
- paramtab = opmtab;
- pm->gsu.h->setfn(pm, ht);
- free(val); /* not freearray() */
-}
-
-/*
- * These functions are used as the set function for special parameters that
- * cannot be set by the user. The set is incomplete as the only such
- * parameters are scalar and integer.
- */
-
-/**/
-mod_export void
-nullstrsetfn(UNUSED(Param pm), char *x)
-{
- zsfree(x);
-}
-
-/**/
-mod_export void
-nullintsetfn(UNUSED(Param pm), UNUSED(zlong x))
-{}
-
-/**/
-mod_export void
-nullunsetfn(UNUSED(Param pm), UNUSED(int exp))
-{}
-
-
-/* Function to get value of generic special integer *
- * parameter. data is pointer to global variable *
- * containing the integer value. */
-
-/**/
-mod_export zlong
-intvargetfn(Param pm)
-{
- return *pm->u.valptr;
-}
-
-/* Function to set value of generic special integer *
- * parameter. data is pointer to global variable *
- * where the value is to be stored. */
-
-/**/
-mod_export void
-intvarsetfn(Param pm, zlong x)
-{
- *pm->u.valptr = x;
-}
-
-/* Function to set value of any ZLE-related integer *
- * parameter. data is pointer to global variable *
- * where the value is to be stored. */
-
-/**/
-void
-zlevarsetfn(Param pm, zlong x)
-{
- zlong *p = pm->u.valptr;
-
- *p = x;
- if (p == &zterm_lines || p == &zterm_columns)
- adjustwinsize(2 + (p == &zterm_columns));
-}
-
-
-/* Implements gsu_integer.unsetfn for ZLE_RPROMPT_INDENT; see stdunsetfn() */
-
-static void
-rprompt_indent_unsetfn(Param pm, int exp)
-{
- stdunsetfn(pm, exp);
- rprompt_indent = 1; /* Keep this in sync with init_term() */
-}
-
-/* Function to set value of generic special scalar *
- * parameter. data is pointer to a character pointer *
- * representing the scalar (string). */
-
-/**/
-mod_export void
-strvarsetfn(Param pm, char *x)
-{
- char **q = ((char **)pm->u.data);
-
- zsfree(*q);
- *q = x;
-}
-
-/* Function to get value of generic special scalar *
- * parameter. data is pointer to a character pointer *
- * representing the scalar (string). */
-
-/**/
-mod_export char *
-strvargetfn(Param pm)
-{
- char *s = *((char **)pm->u.data);
-
- if (!s)
- return hcalloc(1);
- return s;
-}
-
-/* Function to get value of generic special array *
- * parameter. data is a pointer to the pointer to *
- * a pointer (a pointer to a variable length array *
- * of pointers). */
-
-/**/
-mod_export char **
-arrvargetfn(Param pm)
-{
- char **arrptr = *((char ***)pm->u.data);
-
- return arrptr ? arrptr : &nullarray;
-}
-
-/* Function to set value of generic special array parameter. *
- * data is pointer to a variable length array of pointers which *
- * represents this array of scalars (strings). If pm->ename is *
- * non NULL, then it is a colon separated environment variable *
- * version of this array which will need to be updated. */
-
-/**/
-mod_export void
-arrvarsetfn(Param pm, char **x)
-{
- char ***dptr = (char ***)pm->u.data;
-
- if (*dptr != x)
- freearray(*dptr);
- if (pm->node.flags & PM_UNIQUE)
- uniqarray(x);
- /*
- * Special tied arrays point to variables accessible in other
- * ways which need to be set to NULL. We can't do this
- * with user tied variables since we can leak memory.
- */
- if ((pm->node.flags & PM_SPECIAL) && !x)
- *dptr = mkarray(NULL);
- else
- *dptr = x;
- if (pm->ename) {
- if (x)
- arrfixenv(pm->ename, x);
- else if (*dptr == path)
- pathchecked = path;
- }
-}
-
-/**/
-char *
-colonarrgetfn(Param pm)
-{
- char ***dptr = (char ***)pm->u.data;
- return *dptr ? zjoin(*dptr, ':', 1) : "";
-}
-
-/**/
-void
-colonarrsetfn(Param pm, char *x)
-{
- char ***dptr = (char ***)pm->u.data;
- /*
- * We have to make sure this is never NULL, since that
- * can cause problems.
- */
- if (*dptr)
- freearray(*dptr);
- if (x)
- *dptr = colonsplit(x, pm->node.flags & PM_UNIQUE);
- else
- *dptr = mkarray(NULL);
- arrfixenv(pm->node.nam, *dptr);
- zsfree(x);
-}
-
-/**/
-char *
-tiedarrgetfn(Param pm)
-{
- struct tieddata *dptr = (struct tieddata *)pm->u.data;
- return *dptr->arrptr ? zjoin(*dptr->arrptr, STOUC(dptr->joinchar), 1) : "";
-}
-
-/**/
-void
-tiedarrsetfn(Param pm, char *x)
-{
- struct tieddata *dptr = (struct tieddata *)pm->u.data;
-
- if (*dptr->arrptr)
- freearray(*dptr->arrptr);
- if (x) {
- char sepbuf[3];
- if (imeta(dptr->joinchar))
- {
- sepbuf[0] = Meta;
- sepbuf[1] = dptr->joinchar ^ 32;
- sepbuf[2] = '\0';
- }
- else
- {
- sepbuf[0] = dptr->joinchar;
- sepbuf[1] = '\0';
- }
- *dptr->arrptr = sepsplit(x, sepbuf, 0, 0);
- if (pm->node.flags & PM_UNIQUE)
- uniqarray(*dptr->arrptr);
- zsfree(x);
- } else
- *dptr->arrptr = NULL;
- if (pm->ename)
- arrfixenv(pm->node.nam, *dptr->arrptr);
-}
-
-/**/
-void
-tiedarrunsetfn(Param pm, UNUSED(int exp))
-{
- /*
- * Special unset function because we allocated a struct tieddata
- * in typeset_single to hold the special data which we now
- * need to delete.
- */
- pm->gsu.s->setfn(pm, NULL);
- zfree(pm->u.data, sizeof(struct tieddata));
- /* paranoia -- shouldn't need these, but in case we reuse the struct... */
- pm->u.data = NULL;
- zsfree(pm->ename);
- pm->ename = NULL;
- pm->node.flags &= ~PM_TIED;
- pm->node.flags |= PM_UNSET;
-}
-
-/**/
-static void
-simple_arrayuniq(char **x, int freeok)
-{
- char **t, **p = x;
- char *hole = "";
-
- /* Find duplicates and replace them with holes */
- while (*++p)
- for (t = x; t < p; t++)
- if (*t != hole && !strcmp(*p, *t)) {
- if (freeok)
- zsfree(*p);
- *p = hole;
- break;
- }
- /* Swap non-holes into holes in optimal jumps */
- for (p = t = x; *t != NULL; t++) {
- if (*t == hole) {
- while (*p == hole)
- ++p;
- if ((*t = *p) != NULL)
- *p++ = hole;
- } else if (p == t)
- p++;
- }
- /* Erase all the remaining holes, just in case */
- while (++t < p)
- *t = NULL;
-}
-
-/**/
-static void
-arrayuniq_freenode(HashNode hn)
-{
- (void)hn;
-}
-
-/**/
-HashTable
-newuniqtable(zlong size)
-{
- HashTable ht = newhashtable((int)size, "arrayuniq", NULL);
- /* ??? error checking */
-
- ht->hash = hasher;
- ht->emptytable = emptyhashtable;
- ht->filltable = NULL;
- ht->cmpnodes = strcmp;
- ht->addnode = addhashnode;
- ht->getnode = gethashnode2;
- ht->getnode2 = gethashnode2;
- ht->removenode = removehashnode;
- ht->disablenode = disablehashnode;
- ht->enablenode = enablehashnode;
- ht->freenode = arrayuniq_freenode;
- ht->printnode = NULL;
-
- return ht;
-}
-
-/**/
-static void
-arrayuniq(char **x, int freeok)
-{
- char **it, **write_it;
- zlong array_size = arrlen(x);
- HashTable ht;
-
- if (array_size == 0)
- return;
- if (array_size < 10 || !(ht = newuniqtable(array_size + 1))) {
- /* fallback to simpler routine */
- simple_arrayuniq(x, freeok);
- return;
- }
-
- for (it = x, write_it = x; *it;) {
- if (! gethashnode2(ht, *it)) {
- HashNode new_node = zhalloc(sizeof(struct hashnode));
- if (!new_node) {
- /* Oops, out of heap memory, no way to recover */
- zerr("out of memory in arrayuniq");
- break;
- }
- (void) addhashnode2(ht, *it, new_node);
- *write_it = *it;
- if (it != write_it)
- *it = NULL;
- ++write_it;
- }
- else {
- if (freeok)
- zsfree(*it);
- *it = NULL;
- }
- ++it;
- }
-
- deletehashtable(ht);
-}
-
-/**/
-void
-uniqarray(char **x)
-{
- if (!x || !*x)
- return;
- arrayuniq(x, !zheapptr(*x));
-}
-
-/**/
-void
-zhuniqarray(char **x)
-{
- if (!x || !*x)
- return;
- arrayuniq(x, 0);
-}
-
-/* Function to get value of special parameter `#' and `ARGC' */
-
-/**/
-zlong
-poundgetfn(UNUSED(Param pm))
-{
- return arrlen(pparams);
-}
-
-/* Function to get value for special parameter `RANDOM' */
-
-/**/
-zlong
-randomgetfn(UNUSED(Param pm))
-{
- return rand() & 0x7fff;
-}
-
-/* Function to set value of special parameter `RANDOM' */
-
-/**/
-void
-randomsetfn(UNUSED(Param pm), zlong v)
-{
- srand((unsigned int)v);
-}
-
-/* Function to get value for special parameter `SECONDS' */
-
-/**/
-zlong
-intsecondsgetfn(UNUSED(Param pm))
-{
- struct timeval now;
- struct timezone dummy_tz;
-
- gettimeofday(&now, &dummy_tz);
-
- return (zlong)(now.tv_sec - shtimer.tv_sec -
- (now.tv_usec < shtimer.tv_usec ? 1 : 0));
-}
-
-/* Function to set value of special parameter `SECONDS' */
-
-/**/
-void
-intsecondssetfn(UNUSED(Param pm), zlong x)
-{
- struct timeval now;
- struct timezone dummy_tz;
- zlong diff;
-
- gettimeofday(&now, &dummy_tz);
- diff = (zlong)now.tv_sec - x;
- shtimer.tv_sec = diff;
- if ((zlong)shtimer.tv_sec != diff)
- zwarn("SECONDS truncated on assignment");
- shtimer.tv_usec = now.tv_usec;
-}
-
-/**/
-double
-floatsecondsgetfn(UNUSED(Param pm))
-{
- struct timeval now;
- struct timezone dummy_tz;
-
- gettimeofday(&now, &dummy_tz);
-
- return (double)(now.tv_sec - shtimer.tv_sec) +
- (double)(now.tv_usec - shtimer.tv_usec) / 1000000.0;
-}
-
-/**/
-void
-floatsecondssetfn(UNUSED(Param pm), double x)
-{
- struct timeval now;
- struct timezone dummy_tz;
-
- gettimeofday(&now, &dummy_tz);
- shtimer.tv_sec = now.tv_sec - (zlong)x;
- shtimer.tv_usec = now.tv_usec - (zlong)((x - (zlong)x) * 1000000.0);
-}
-
-/**/
-double
-getrawseconds(void)
-{
- return (double)shtimer.tv_sec + (double)shtimer.tv_usec / 1000000.0;
-}
-
-/**/
-void
-setrawseconds(double x)
-{
- shtimer.tv_sec = (zlong)x;
- shtimer.tv_usec = (zlong)((x - (zlong)x) * 1000000.0);
-}
-
-/**/
-int
-setsecondstype(Param pm, int on, int off)
-{
- int newflags = (pm->node.flags | on) & ~off;
- int tp = PM_TYPE(newflags);
- /* Only one of the numeric types is allowed. */
- if (tp == PM_EFLOAT || tp == PM_FFLOAT)
- {
- pm->gsu.f = &floatseconds_gsu;
- }
- else if (tp == PM_INTEGER)
- {
- pm->gsu.i = &intseconds_gsu;
- }
- else
- return 1;
- pm->node.flags = newflags;
- return 0;
-}
-
-/* Function to get value for special parameter `USERNAME' */
-
-/**/
-char *
-usernamegetfn(UNUSED(Param pm))
-{
- return get_username();
-}
-
-/* Function to set value of special parameter `USERNAME' */
-
-/**/
-void
-usernamesetfn(UNUSED(Param pm), char *x)
-{
-#if defined(HAVE_SETUID) && defined(HAVE_GETPWNAM)
- struct passwd *pswd;
-
- if (x && (pswd = getpwnam(x)) && (pswd->pw_uid != cached_uid)) {
-# ifdef USE_INITGROUPS
- initgroups(x, pswd->pw_gid);
-# endif
- if (setgid(pswd->pw_gid))
- zwarn("failed to change group ID: %e", errno);
- else if (setuid(pswd->pw_uid))
- zwarn("failed to change user ID: %e", errno);
- else {
- zsfree(cached_username);
- cached_username = ztrdup(pswd->pw_name);
- cached_uid = pswd->pw_uid;
- }
- }
-#endif /* HAVE_SETUID && HAVE_GETPWNAM */
- zsfree(x);
-}
-
-/* Function to get value for special parameter `UID' */
-
-/**/
-zlong
-uidgetfn(UNUSED(Param pm))
-{
- return getuid();
-}
-
-/* Function to set value of special parameter `UID' */
-
-/**/
-void
-uidsetfn(UNUSED(Param pm), zlong x)
-{
-#ifdef HAVE_SETUID
- if (setuid((uid_t)x))
- zerr("failed to change user ID: %e", errno);
-#endif
-}
-
-/* Function to get value for special parameter `EUID' */
-
-/**/
-zlong
-euidgetfn(UNUSED(Param pm))
-{
- return geteuid();
-}
-
-/* Function to set value of special parameter `EUID' */
-
-/**/
-void
-euidsetfn(UNUSED(Param pm), zlong x)
-{
-#ifdef HAVE_SETEUID
- if (seteuid((uid_t)x))
- zerr("failed to change effective user ID: %e", errno);
-#endif
-}
-
-/* Function to get value for special parameter `GID' */
-
-/**/
-zlong
-gidgetfn(UNUSED(Param pm))
-{
- return getgid();
-}
-
-/* Function to set value of special parameter `GID' */
-
-/**/
-void
-gidsetfn(UNUSED(Param pm), zlong x)
-{
-#ifdef HAVE_SETUID
- if (setgid((gid_t)x))
- zerr("failed to change group ID: %e", errno);
-#endif
-}
-
-/* Function to get value for special parameter `EGID' */
-
-/**/
-zlong
-egidgetfn(UNUSED(Param pm))
-{
- return getegid();
-}
-
-/* Function to set value of special parameter `EGID' */
-
-/**/
-void
-egidsetfn(UNUSED(Param pm), zlong x)
-{
-#ifdef HAVE_SETEUID
- if (setegid((gid_t)x))
- zerr("failed to change effective group ID: %e", errno);
-#endif
-}
-
-/**/
-zlong
-ttyidlegetfn(UNUSED(Param pm))
-{
- struct stat ttystat;
-
- if (SHTTY == -1 || fstat(SHTTY, &ttystat))
- return -1;
- return time(NULL) - ttystat.st_atime;
-}
-
-/* Function to get value for special parameter `IFS' */
-
-/**/
-char *
-ifsgetfn(UNUSED(Param pm))
-{
- return ifs;
-}
-
-/* Function to set value of special parameter `IFS' */
-
-/**/
-void
-ifssetfn(UNUSED(Param pm), char *x)
-{
- zsfree(ifs);
- ifs = x;
- inittyptab();
-}
-
-/* Functions to set value of special parameters `LANG' and `LC_*' */
-
-#ifdef USE_LOCALE
-static struct localename {
- char *name;
- int category;
-} lc_names[] = {
-#ifdef LC_COLLATE
- {"LC_COLLATE", LC_COLLATE},
-#endif
-#ifdef LC_CTYPE
- {"LC_CTYPE", LC_CTYPE},
-#endif
-#ifdef LC_MESSAGES
- {"LC_MESSAGES", LC_MESSAGES},
-#endif
-#ifdef LC_NUMERIC
- {"LC_NUMERIC", LC_NUMERIC},
-#endif
-#ifdef LC_TIME
- {"LC_TIME", LC_TIME},
-#endif
- {NULL, 0}
-};
-
-/**/
-static void
-setlang(char *x)
-{
- struct localename *ln;
- char *x2;
-
- if ((x2 = getsparam_u("LC_ALL")) && *x2)
- return;
-
- /*
- * Set the global locale to the value passed, but override
- * this with any non-empty definitions for specific
- * categories.
- *
- * We only use non-empty definitions because empty values aren't
- * valid as locales; when passed to setlocale() they mean "use the
- * environment variable", but if that's what we're setting the value
- * from this is meaningless. So just all $LANG to show through in
- * that case.
- */
- setlocale(LC_ALL, x ? unmeta(x) : "");
- queue_signals();
- for (ln = lc_names; ln->name; ln++)
- if ((x = getsparam_u(ln->name)) && *x)
- setlocale(ln->category, x);
- unqueue_signals();
-}
-
-/**/
-void
-lc_allsetfn(Param pm, char *x)
-{
- strsetfn(pm, x);
- /*
- * Treat an empty LC_ALL the same as an unset one,
- * namely by using LANG as the default locale but overriding
- * that with any LC_* that are set.
- */
- if (!x || !*x) {
- x = getsparam_u("LANG");
- if (x && *x) {
- queue_signals();
- setlang(x);
- unqueue_signals();
- }
- }
- else
- setlocale(LC_ALL, unmeta(x));
-}
-
-/**/
-void
-langsetfn(Param pm, char *x)
-{
- strsetfn(pm, x);
- setlang(unmeta(x));
-}
-
-/**/
-void
-lcsetfn(Param pm, char *x)
-{
- char *x2;
- struct localename *ln;
-
- strsetfn(pm, x);
- if ((x2 = getsparam("LC_ALL")) && *x2)
- return;
- queue_signals();
- /* Treat empty LC_* the same as unset. */
- if (!x || !*x)
- x = getsparam("LANG");
-
- /*
- * If we've got no non-empty string at this
- * point (after checking $LANG, too),
- * we shouldn't bother setting anything.
- */
- if (x && *x) {
- for (ln = lc_names; ln->name; ln++)
- if (!strcmp(ln->name, pm->node.nam))
- setlocale(ln->category, unmeta(x));
- }
- unqueue_signals();
-}
-#endif /* USE_LOCALE */
-
-/* Function to set value for special parameter `0' */
-
-/**/
-static void
-argzerosetfn(UNUSED(Param pm), char *x)
-{
- if (x) {
- if (isset(POSIXARGZERO))
- zerr("read-only variable: 0");
- else {
- zsfree(argzero);
- argzero = ztrdup(x);
- }
- zsfree(x);
- }
-}
-
-/* Function to get value for special parameter `0' */
-
-/**/
-static char *
-argzerogetfn(UNUSED(Param pm))
-{
- if (isset(POSIXARGZERO))
- return posixzero;
- return argzero;
-}
-
-/* Function to get value for special parameter `HISTSIZE' */
-
-/**/
-zlong
-histsizegetfn(UNUSED(Param pm))
-{
- return histsiz;
-}
-
-/* Function to set value of special parameter `HISTSIZE' */
-
-/**/
-void
-histsizesetfn(UNUSED(Param pm), zlong v)
-{
- if ((histsiz = v) < 1)
- histsiz = 1;
- resizehistents();
-}
-
-/* Function to get value for special parameter `SAVEHIST' */
-
-/**/
-zlong
-savehistsizegetfn(UNUSED(Param pm))
-{
- return savehistsiz;
-}
-
-/* Function to set value of special parameter `SAVEHIST' */
-
-/**/
-void
-savehistsizesetfn(UNUSED(Param pm), zlong v)
-{
- if ((savehistsiz = v) < 0)
- savehistsiz = 0;
-}
-
-/* Function to set value for special parameter `ERRNO' */
-
-/**/
-void
-errnosetfn(UNUSED(Param pm), zlong x)
-{
- errno = (int)x;
- if ((zlong)errno != x)
- zwarn("errno truncated on assignment");
-}
-
-/* Function to get value for special parameter `ERRNO' */
-
-/**/
-zlong
-errnogetfn(UNUSED(Param pm))
-{
- return errno;
-}
-
-/* Function to get value for special parameter `KEYBOARD_HACK' */
-
-/**/
-char *
-keyboardhackgetfn(UNUSED(Param pm))
-{
- static char buf[2];
-
- buf[0] = keyboardhackchar;
- buf[1] = '\0';
- return buf;
-}
-
-
-/* Function to set value of special parameter `KEYBOARD_HACK' */
-
-/**/
-void
-keyboardhacksetfn(UNUSED(Param pm), char *x)
-{
- if (x) {
- int len, i;
-
- unmetafy(x, &len);
- if (len > 1) {
- len = 1;
- zwarn("Only one KEYBOARD_HACK character can be defined"); /* could be changed if needed */
- }
- for (i = 0; i < len; i++) {
- if (!isascii(STOUC(x[i]))) {
- zwarn("KEYBOARD_HACK can only contain ASCII characters");
- return;
- }
- }
- keyboardhackchar = len ? STOUC(x[0]) : '\0';
- free(x);
- } else
- keyboardhackchar = '\0';
-}
-
-/* Function to get value for special parameter `histchar' */
-
-/**/
-char *
-histcharsgetfn(UNUSED(Param pm))
-{
- static char buf[4];
-
- buf[0] = bangchar;
- buf[1] = hatchar;
- buf[2] = hashchar;
- buf[3] = '\0';
- return buf;
-}
-
-/* Function to set value of special parameter `histchar' */
-
-/**/
-void
-histcharssetfn(UNUSED(Param pm), char *x)
-{
- if (x) {
- int len, i;
-
- unmetafy(x, &len);
- if (len > 3)
- len = 3;
- for (i = 0; i < len; i++) {
- if (!isascii(STOUC(x[i]))) {
- zwarn("HISTCHARS can only contain ASCII characters");
- return;
- }
- }
- bangchar = len ? STOUC(x[0]) : '\0';
- hatchar = len > 1 ? STOUC(x[1]) : '\0';
- hashchar = len > 2 ? STOUC(x[2]) : '\0';
- free(x);
- } else {
- bangchar = '!';
- hashchar = '#';
- hatchar = '^';
- }
- inittyptab();
-}
-
-/* Function to get value for special parameter `HOME' */
-
-/**/
-char *
-homegetfn(UNUSED(Param pm))
-{
- return home;
-}
-
-/* Function to set value of special parameter `HOME' */
-
-/**/
-void
-homesetfn(UNUSED(Param pm), char *x)
-{
- zsfree(home);
- if (x && isset(CHASELINKS) && (home = xsymlink(x, 0)))
- zsfree(x);
- else
- home = x ? x : ztrdup("");
- finddir(NULL);
-}
-
-/* Function to get value for special parameter `WORDCHARS' */
-
-/**/
-char *
-wordcharsgetfn(UNUSED(Param pm))
-{
- return wordchars;
-}
-
-/* Function to set value of special parameter `WORDCHARS' */
-
-/**/
-void
-wordcharssetfn(UNUSED(Param pm), char *x)
-{
- zsfree(wordchars);
- wordchars = x;
- inittyptab();
-}
-
-/* Function to get value for special parameter `_' */
-
-/**/
-char *
-underscoregetfn(UNUSED(Param pm))
-{
- char *u = dupstring(zunderscore);
-
- untokenize(u);
- return u;
-}
-
-/* Function used when we need to reinitialise the terminal */
-
-static void
-term_reinit_from_pm(void)
-{
- /* If non-interactive, delay setting up term till we need it. */
- if (unset(INTERACTIVE) || !*term)
- termflags |= TERM_UNKNOWN;
- else
- init_term();
-}
-
-/* Function to get value for special parameter `TERM' */
-
-/**/
-char *
-termgetfn(UNUSED(Param pm))
-{
- return term;
-}
-
-/* Function to set value of special parameter `TERM' */
-
-/**/
-void
-termsetfn(UNUSED(Param pm), char *x)
-{
- zsfree(term);
- term = x ? x : ztrdup("");
- term_reinit_from_pm();
-}
-
-/* Function to get value of special parameter `TERMINFO' */
-
-/**/
-char *
-terminfogetfn(UNUSED(Param pm))
-{
- return zsh_terminfo ? zsh_terminfo : dupstring("");
-}
-
-/* Function to set value of special parameter `TERMINFO' */
-
-/**/
-void
-terminfosetfn(Param pm, char *x)
-{
- zsfree(zsh_terminfo);
- zsh_terminfo = x;
-
- /*
- * terminfo relies on the value being exported before
- * we reinitialise the terminal. This is a bit inefficient.
- */
- if ((pm->node.flags & PM_EXPORTED) && x)
- addenv(pm, x);
-
- term_reinit_from_pm();
-}
-
-/* Function to get value of special parameter `TERMINFO_DIRS' */
-
-/**/
-char *
-terminfodirsgetfn(UNUSED(Param pm))
-{
- return zsh_terminfodirs ? zsh_terminfodirs : dupstring("");
-}
-
-/* Function to set value of special parameter `TERMINFO_DIRS' */
-
-/**/
-void
-terminfodirssetfn(Param pm, char *x)
-{
- zsfree(zsh_terminfodirs);
- zsh_terminfodirs = x;
-
- /*
- * terminfo relies on the value being exported before
- * we reinitialise the terminal. This is a bit inefficient.
- */
- if ((pm->node.flags & PM_EXPORTED) && x)
- addenv(pm, x);
-
- term_reinit_from_pm();
-}
-/* Function to get value for special parameter `pipestatus' */
-
-/**/
-static char **
-pipestatgetfn(UNUSED(Param pm))
-{
- char **x = (char **) zhalloc((numpipestats + 1) * sizeof(char *));
- char buf[DIGBUFSIZE], **p;
- int *q, i;
-
- for (p = x, q = pipestats, i = numpipestats; i--; p++, q++) {
- sprintf(buf, "%d", *q);
- *p = dupstring(buf);
- }
- *p = NULL;
-
- return x;
-}
-
-/* Function to get value for special parameter `pipestatus' */
-
-/**/
-static void
-pipestatsetfn(UNUSED(Param pm), char **x)
-{
- if (x) {
- int i;
-
- for (i = 0; *x && i < MAX_PIPESTATS; i++, x++)
- pipestats[i] = atoi(*x);
- numpipestats = i;
- }
- else
- numpipestats = 0;
-}
-
-/**/
-void
-arrfixenv(char *s, char **t)
-{
- Param pm;
- int joinchar;
-
- if (t == path)
- cmdnamtab->emptytable(cmdnamtab);
-
- pm = (Param) paramtab->getnode(paramtab, s);
-
- /*
- * Only one level of a parameter can be exported. Unless
- * ALLEXPORT is set, this must be global.
- */
-
- if (pm->node.flags & PM_HASHELEM)
- return;
-
- if (isset(ALLEXPORT))
- pm->node.flags |= PM_EXPORTED;
-
- /*
- * Do not "fix" parameters that were not exported
- */
-
- if (!(pm->node.flags & PM_EXPORTED))
- return;
-
- if (pm->node.flags & PM_TIED)
- joinchar = STOUC(((struct tieddata *)pm->u.data)->joinchar);
- else
- joinchar = ':';
-
- addenv(pm, t ? zjoin(t, joinchar, 1) : "");
-}
-
-
-/**/
-int
-zputenv(char *str)
-{
- DPUTS(!str, "Attempt to put null string into environment.");
-#ifdef USE_SET_UNSET_ENV
- /*
- * If we are using unsetenv() to remove values from the
- * environment, which is the safe thing to do, we
- * need to use setenv() to put them there in the first place.
- * Unfortunately this is a slightly different interface
- * from what zputenv() assumes.
- */
- char *ptr;
- int ret;
-
- for (ptr = str; *ptr && STOUC(*ptr) < 128 && *ptr != '='; ptr++)
- ;
- if (STOUC(*ptr) >= 128) {
- /*
- * Environment variables not in the portable character
- * set are non-standard and we don't really know of
- * a use for them.
- *
- * We'll disable until someone complains.
- */
- return 1;
- } else if (*ptr) {
- *ptr = '\0';
- ret = setenv(str, ptr+1, 1);
- *ptr = '=';
- } else {
- /* safety first */
- DPUTS(1, "bad environment string");
- ret = setenv(str, ptr, 1);
- }
- return ret;
-#else
-#ifdef HAVE_PUTENV
- return putenv(str);
-#else
- char **ep;
- int num_env;
-
-
- /* First check if there is already an environment *
- * variable matching string `name'. */
- if (findenv(str, &num_env)) {
- environ[num_env] = str;
- } else {
- /* Else we have to make room and add it */
- num_env = arrlen(environ);
- environ = (char **) zrealloc(environ, (sizeof(char *)) * (num_env + 2));
-
- /* Now add it at the end */
- ep = environ + num_env;
- *ep = str;
- *(ep + 1) = NULL;
- }
- return 0;
-#endif
-#endif
-}
-
-/**/
-#ifndef USE_SET_UNSET_ENV
-/**/
-static int
-findenv(char *name, int *pos)
-{
- char **ep, *eq;
- int nlen;
-
-
- eq = strchr(name, '=');
- nlen = eq ? eq - name : (int)strlen(name);
- for (ep = environ; *ep; ep++)
- if (!strncmp (*ep, name, nlen) && *((*ep)+nlen) == '=') {
- if (pos)
- *pos = ep - environ;
- return 1;
- }
-
- return 0;
-}
-/**/
-#endif
-
-/* Given *name = "foo", it searches the environment for string *
- * "foo=bar", and returns a pointer to the beginning of "bar" */
-
-/**/
-mod_export char *
-zgetenv(char *name)
-{
-#ifdef HAVE_GETENV
- return getenv(name);
-#else
- char **ep, *s, *t;
-
- for (ep = environ; *ep; ep++) {
- for (s = *ep, t = name; *s && *s == *t; s++, t++);
- if (*s == '=' && !*t)
- return s + 1;
- }
- return NULL;
-#endif
-}
-
-/**/
-static void
-copyenvstr(char *s, char *value, int flags)
-{
- while (*s++) {
- if ((*s = *value++) == Meta)
- *s = *value++ ^ 32;
- if (flags & PM_LOWER)
- *s = tulower(*s);
- else if (flags & PM_UPPER)
- *s = tuupper(*s);
- }
-}
-
-/**/
-void
-addenv(Param pm, char *value)
-{
- char *newenv = 0;
-#ifndef USE_SET_UNSET_ENV
- char *oldenv = 0, *env = 0;
- int pos;
-
- /*
- * First check if there is already an environment
- * variable matching string `name'.
- */
- if (findenv(pm->node.nam, &pos))
- oldenv = environ[pos];
-#endif
-
- newenv = mkenvstr(pm->node.nam, value, pm->node.flags);
- if (zputenv(newenv)) {
- zsfree(newenv);
- pm->env = NULL;
- return;
- }
-#ifdef USE_SET_UNSET_ENV
- /*
- * If we are using setenv/unsetenv to manage the environment,
- * we simply store the string we created in pm->env since
- * memory management of the environment is handled entirely
- * by the system.
- *
- * TODO: is this good enough to fix problem cases from
- * the other branch? If so, we don't actually need to
- * store pm->env at all, just a flag that the value was set.
- */
- if (pm->env)
- zsfree(pm->env);
- pm->env = newenv;
- pm->node.flags |= PM_EXPORTED;
-#else
- /*
- * Under Cygwin we must use putenv() to maintain consistency.
- * Unfortunately, current version (1.1.2) copies argument and may
- * silently reuse existing environment string. This tries to
- * check for both cases
- */
- if (findenv(pm->node.nam, &pos)) {
- env = environ[pos];
- if (env != oldenv)
- zsfree(oldenv);
- if (env != newenv)
- zsfree(newenv);
- pm->node.flags |= PM_EXPORTED;
- pm->env = env;
- return;
- }
-
- DPUTS(1, "addenv should never reach the end");
- pm->env = NULL;
-#endif
-}
-
-
-/* Given strings *name = "foo", *value = "bar", *
- * return a new string *str = "foo=bar". */
-
-/**/
-static char *
-mkenvstr(char *name, char *value, int flags)
-{
- char *str, *s = value;
- int len_name, len_value = 0;
-
- len_name = strlen(name);
- if (s)
- while (*s && (*s++ != Meta || *s++ != 32))
- len_value++;
- s = str = (char *) zalloc(len_name + len_value + 2);
- strcpy(s, name);
- s += len_name;
- *s = '=';
- if (value)
- copyenvstr(s, value, flags);
- else
- *++s = '\0';
- return str;
-}
-
-/* Given *name = "foo", *value = "bar", add the *
- * string "foo=bar" to the environment. Return a *
- * pointer to the location of this new environment *
- * string. */
-
-
-#ifndef USE_SET_UNSET_ENV
-/**/
-void
-delenvvalue(char *x)
-{
- char **ep;
-
- for (ep = environ; *ep; ep++) {
- if (*ep == x)
- break;
- }
- if (*ep) {
- for (; (ep[0] = ep[1]); ep++);
- }
- zsfree(x);
-}
-#endif
-
-
-/* Delete a pointer from the list of pointers to environment *
- * variables by shifting all the other pointers up one slot. */
-
-/**/
-void
-delenv(Param pm)
-{
-#ifdef USE_SET_UNSET_ENV
- unsetenv(pm->node.nam);
- zsfree(pm->env);
-#else
- delenvvalue(pm->env);
-#endif
- pm->env = NULL;
- /*
- * Note we don't remove PM_EXPORT from the flags. This
- * may be asking for trouble but we need to know later
- * if we restore this parameter to its old value.
- */
-}
-
-/*
- * Guts of convbase: this version can return the number of digits
- * sans any base discriminator.
- */
-
-/**/
-void
-convbase_ptr(char *s, zlong v, int base, int *ndigits)
-{
- int digs = 0;
- zulong x;
-
- if (v < 0)
- *s++ = '-', v = -v;
- if (base >= -1 && base <= 1)
- base = -10;
-
- if (base > 0) {
- if (isset(CBASES) && base == 16)
- sprintf(s, "0x");
- else if (isset(CBASES) && base == 8 && isset(OCTALZEROES))
- sprintf(s, "0");
- else if (base != 10)
- sprintf(s, "%d#", base);
- else
- *s = 0;
- s += strlen(s);
- } else
- base = -base;
- for (x = v; x; digs++)
- x /= base;
- if (!digs)
- digs = 1;
- if (ndigits)
- *ndigits = digs;
- s[digs--] = '\0';
- x = v;
- while (digs >= 0) {
- int dig = x % base;
-
- s[digs--] = (dig < 10) ? '0' + dig : dig - 10 + 'A';
- x /= base;
- }
-}
-
-/*
- * Basic conversion of integer to a string given a base.
- * If 0 base is 10.
- * If negative no base discriminator is output.
- */
-
-/**/
-mod_export void
-convbase(char *s, zlong v, int base)
-{
- convbase_ptr(s, v, base, NULL);
-}
-
-/*
- * Add underscores to converted integer for readability with given spacing.
- * s is as for convbase: at least BDIGBUFSIZE.
- * If underscores were added, returned value with underscores comes from
- * heap, else the returned value is s.
- */
-
-/**/
-char *
-convbase_underscore(char *s, zlong v, int base, int underscore)
-{
- char *retptr, *sptr, *dptr;
- int ndigits, nunderscore, mod, len;
-
- convbase_ptr(s, v, base, &ndigits);
-
- if (underscore <= 0)
- return s;
-
- nunderscore = (ndigits - 1) / underscore;
- if (!nunderscore)
- return s;
- len = strlen(s);
- retptr = zhalloc(len + nunderscore + 1);
- mod = 0;
- memcpy(retptr, s, len - ndigits);
- sptr = s + len;
- dptr = retptr + len + nunderscore;
- /* copy the null */
- *dptr-- = *sptr--;
- for (;;) {
- *dptr = *sptr;
- if (!--ndigits)
- break;
- dptr--;
- sptr--;
- if (++mod == underscore) {
- mod = 0;
- *dptr-- = '_';
- }
- }
-
- return retptr;
-}
-
-/*
- * Convert a floating point value for output.
- * Unlike convbase(), this has its own internal storage and returns
- * a value from the heap.
- */
-
-/**/
-char *
-convfloat(double dval, int digits, int flags, FILE *fout)
-{
- char fmt[] = "%.*e";
- char *prev_locale, *ret;
-
- /*
- * The difficulty with the buffer size is that a %f conversion
- * prints all digits before the decimal point: with 64 bit doubles,
- * that's around 310. We can't check without doing some quite
- * serious floating point operations we'd like to avoid.
- * Then we are liable to get all the digits
- * we asked for after the decimal point, or we should at least
- * bargain for it. So we just allocate 512 + digits. This
- * should work until somebody decides on 128-bit doubles.
- */
- if (!(flags & (PM_EFLOAT|PM_FFLOAT))) {
- /*
- * Conversion from a floating point expression without using
- * a variable. The best bet in this case just seems to be
- * to use the general %g format with something like the maximum
- * double precision.
- */
- fmt[3] = 'g';
- if (!digits)
- digits = 17;
- } else {
- if (flags & PM_FFLOAT)
- fmt[3] = 'f';
- if (digits <= 0)
- digits = 10;
- if (flags & PM_EFLOAT) {
- /*
- * Here, we are given the number of significant figures, but
- * %e wants the number of decimal places (unlike %g)
- */
- digits--;
- }
- }
-#ifdef USE_LOCALE
- prev_locale = dupstring(setlocale(LC_NUMERIC, NULL));
- setlocale(LC_NUMERIC, "POSIX");
-#endif
- if (fout) {
- fprintf(fout, fmt, digits, dval);
- ret = NULL;
- } else {
- VARARR(char, buf, 512 + digits);
- if (isinf(dval))
- ret = dupstring((dval < 0.0) ? "-Inf" : "Inf");
- else if (isnan(dval))
- ret = dupstring("NaN");
- else {
- sprintf(buf, fmt, digits, dval);
- if (!strchr(buf, 'e') && !strchr(buf, '.'))
- strcat(buf, ".");
- ret = dupstring(buf);
- }
- }
-#ifdef USE_LOCALE
- if (prev_locale) setlocale(LC_NUMERIC, prev_locale);
-#endif
- return ret;
-}
-
-/*
- * convert float to string with basic options but inserting underscores
- * for readability.
- */
-
-/**/
-char *convfloat_underscore(double dval, int underscore)
-{
- int ndigits_int = 0, ndigits_frac = 0, nunderscore, len;
- char *s, *retptr, *sptr, *dptr;
-
- s = convfloat(dval, 0, 0, NULL);
- if (underscore <= 0)
- return s;
-
- /*
- * Count the number of digits before and after the decimal point, if any.
- */
- sptr = s;
- if (*sptr == '-')
- sptr++;
- while (idigit(*sptr)) {
- ndigits_int++;
- sptr++;
- }
- if (*sptr == '.') {
- sptr++;
- while (idigit(*sptr)) {
- ndigits_frac++;
- sptr++;
- }
- }
-
- /*
- * Work out how many underscores to insert --- remember we
- * put them in integer and fractional parts separately.
- */
- nunderscore = (ndigits_int-1) / underscore + (ndigits_frac-1) / underscore;
- if (!nunderscore)
- return s;
- len = strlen(s);
- dptr = retptr = zhalloc(len + nunderscore + 1);
-
- /*
- * Insert underscores in integer part.
- * Grouping starts from the point in both directions.
- */
- sptr = s;
- if (*sptr == '-')
- *dptr++ = *sptr++;
- while (ndigits_int) {
- *dptr++ = *sptr++;
- if (--ndigits_int && !(ndigits_int % underscore))
- *dptr++ = '_';
- }
- if (ndigits_frac) {
- /*
- * Insert underscores in the fractional part.
- */
- int mod = 0;
- /* decimal point, we already checked */
- *dptr++ = *sptr++;
- while (ndigits_frac) {
- *dptr++ = *sptr++;
- mod++;
- if (--ndigits_frac && mod == underscore) {
- *dptr++ = '_';
- mod = 0;
- }
- }
- }
- /* Copy exponent and anything else up to null */
- while ((*dptr++ = *sptr++))
- ;
- return retptr;
-}
-
-/* Start a parameter scope */
-
-/**/
-mod_export void
-startparamscope(void)
-{
- locallevel++;
-}
-
-/* End a parameter scope: delete the parameters local to the scope. */
-
-/**/
-mod_export void
-endparamscope(void)
-{
- queue_signals();
- locallevel--;
- /* This pops anything from a higher locallevel */
- saveandpophiststack(0, HFILE_USE_OPTIONS);
- scanhashtable(paramtab, 0, 0, 0, scanendscope, 0);
- unqueue_signals();
-}
-
-/**/
-static void
-scanendscope(HashNode hn, UNUSED(int flags))
-{
- Param pm = (Param)hn;
- if (pm->level > locallevel) {
- if ((pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL) {
- /*
- * Removable specials are normal in that they can be removed
- * to reveal an ordinary parameter beneath. Here we handle
- * non-removable specials, which were made local by stealth
- * (see newspecial code in typeset_single()). In fact the
- * visible pm is always the same struct; the pm->old is
- * just a place holder for old data and flags.
- */
- Param tpm = pm->old;
-
- if (!strcmp(pm->node.nam, "SECONDS"))
- {
- setsecondstype(pm, PM_TYPE(tpm->node.flags), PM_TYPE(pm->node.flags));
- /*
- * We restore SECONDS by restoring its raw internal value
- * that we cached off into tpm->u.dval.
- */
- setrawseconds(tpm->u.dval);
- tpm->node.flags |= PM_NORESTORE;
- }
- DPUTS(!tpm || PM_TYPE(pm->node.flags) != PM_TYPE(tpm->node.flags) ||
- !(tpm->node.flags & PM_SPECIAL),
- "BUG: in restoring scope of special parameter");
- pm->old = tpm->old;
- pm->node.flags = (tpm->node.flags & ~PM_NORESTORE);
- pm->level = tpm->level;
- pm->base = tpm->base;
- pm->width = tpm->width;
- if (pm->env)
- delenv(pm);
-
- if (!(tpm->node.flags & (PM_NORESTORE|PM_READONLY)))
- switch (PM_TYPE(pm->node.flags)) {
- case PM_SCALAR:
- pm->gsu.s->setfn(pm, tpm->u.str);
- break;
- case PM_INTEGER:
- pm->gsu.i->setfn(pm, tpm->u.val);
- break;
- case PM_EFLOAT:
- case PM_FFLOAT:
- pm->gsu.f->setfn(pm, tpm->u.dval);
- break;
- case PM_ARRAY:
- pm->gsu.a->setfn(pm, tpm->u.arr);
- break;
- case PM_HASHED:
- pm->gsu.h->setfn(pm, tpm->u.hash);
- break;
- }
- zfree(tpm, sizeof(*tpm));
-
- if (pm->node.flags & PM_EXPORTED)
- export_param(pm);
- } else
- unsetparam_pm(pm, 0, 0);
- }
-}
-
-
-/**********************************/
-/* Parameter Hash Table Functions */
-/**********************************/
-
-/**/
-void
-freeparamnode(HashNode hn)
-{
- Param pm = (Param) hn;
-
- /* The second argument of unsetfn() is used by modules to
- * differentiate "exp"licit unset from implicit unset, as when
- * a parameter is going out of scope. It's not clear which
- * of these applies here, but passing 1 has always worked.
- */
- if (delunset)
- pm->gsu.s->unsetfn(pm, 1);
- zsfree(pm->node.nam);
- /* If this variable was tied by the user, ename was ztrdup'd */
- if (pm->node.flags & PM_TIED)
- zsfree(pm->ename);
- zfree(pm, sizeof(struct param));
-}
-
-/* Print a parameter */
-
-enum paramtypes_flags {
- PMTF_USE_BASE = (1<<0),
- PMTF_USE_WIDTH = (1<<1),
- PMTF_TEST_LEVEL = (1<<2)
-};
-
-struct paramtypes {
- int binflag; /* The relevant PM_FLAG(S) */
- const char *string; /* String for verbose output */
- int typeflag; /* Flag for typeset -? */
- int flags; /* The enum above */
-};
-
-static const struct paramtypes pmtypes[] = {
- { PM_AUTOLOAD, "undefined", 0, 0},
- { PM_INTEGER, "integer", 'i', PMTF_USE_BASE},
- { PM_EFLOAT, "float", 'E', 0},
- { PM_FFLOAT, "float", 'F', 0},
- { PM_ARRAY, "array", 'a', 0},
- { PM_HASHED, "association", 'A', 0},
- { 0, "local", 0, PMTF_TEST_LEVEL},
- { PM_LEFT, "left justified", 'L', PMTF_USE_WIDTH},
- { PM_RIGHT_B, "right justified", 'R', PMTF_USE_WIDTH},
- { PM_RIGHT_Z, "zero filled", 'Z', PMTF_USE_WIDTH},
- { PM_LOWER, "lowercase", 'l', 0},
- { PM_UPPER, "uppercase", 'u', 0},
- { PM_READONLY, "readonly", 'r', 0},
- { PM_TAGGED, "tagged", 't', 0},
- { PM_EXPORTED, "exported", 'x', 0}
-};
-
-#define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
-
-static void
-printparamvalue(Param p, int printflags)
-{
- char *t, **u;
-
- if (!(printflags & PRINT_KV_PAIR))
- putchar('=');
-
- /* How the value is displayed depends *
- * on the type of the parameter */
- switch (PM_TYPE(p->node.flags)) {
- case PM_SCALAR:
- /* string: simple output */
- if (p->gsu.s->getfn && (t = p->gsu.s->getfn(p)))
- quotedzputs(t, stdout);
- break;
- case PM_INTEGER:
- /* integer */
-#ifdef ZSH_64_BIT_TYPE
- fputs(output64(p->gsu.i->getfn(p)), stdout);
-#else
- printf("%ld", p->gsu.i->getfn(p));
-#endif
- break;
- case PM_EFLOAT:
- case PM_FFLOAT:
- /* float */
- convfloat(p->gsu.f->getfn(p), p->base, p->node.flags, stdout);
- break;
- case PM_ARRAY:
- /* array */
- if (!(printflags & PRINT_KV_PAIR)) {
- putchar('(');
- if (!(printflags & PRINT_LINE))
- putchar(' ');
- }
- u = p->gsu.a->getfn(p);
- if(*u) {
- if (printflags & PRINT_LINE) {
- if (printflags & PRINT_KV_PAIR)
- printf(" ");
- else
- printf("\n ");
- }
- quotedzputs(*u++, stdout);
- while (*u) {
- if (printflags & PRINT_LINE)
- printf("\n ");
- else
- putchar(' ');
- quotedzputs(*u++, stdout);
- }
- if ((printflags & (PRINT_LINE|PRINT_KV_PAIR)) == PRINT_LINE)
- putchar('\n');
- }
- if (!(printflags & PRINT_KV_PAIR)) {
- if (!(printflags & PRINT_LINE))
- putchar(' ');
- putchar(')');
- }
- break;
- case PM_HASHED:
- /* association */
- {
- HashTable ht;
- int found = 0;
- if (!(printflags & PRINT_KV_PAIR)) {
- putchar('(');
- if (!(printflags & PRINT_LINE))
- putchar(' ');
- }
- ht = p->gsu.h->getfn(p);
- if (ht)
- found = scanhashtable(ht, 1, 0, PM_UNSET,
- ht->printnode, PRINT_KV_PAIR |
- (printflags & PRINT_LINE));
- if (!(printflags & PRINT_KV_PAIR)) {
- if (found && (printflags & PRINT_LINE))
- putchar('\n');
- putchar(')');
- }
- }
- break;
- }
- if ((printflags & (PRINT_KV_PAIR|PRINT_LINE)) == PRINT_KV_PAIR)
- putchar(' ');
- else if (!(printflags & PRINT_KV_PAIR))
- putchar('\n');
-}
-
-/**/
-mod_export void
-printparamnode(HashNode hn, int printflags)
-{
- Param p = (Param) hn;
-
- if (p->node.flags & PM_UNSET) {
- if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) &&
- (printflags & PRINT_TYPESET))
- {
- /*
- * Special POSIX rules: show the parameter as readonly
- * even though it's unset, but with no value.
- */
- printflags |= PRINT_NAMEONLY;
- }
- else if (p->node.flags & PM_EXPORTED)
- printflags |= PRINT_NAMEONLY;
- else
- return;
- }
- if (p->node.flags & PM_AUTOLOAD)
- printflags |= PRINT_NAMEONLY;
-
- if (printflags & PRINT_TYPESET) {
- if ((p->node.flags & (PM_READONLY|PM_SPECIAL)) ==
- (PM_READONLY|PM_SPECIAL) ||
- (p->node.flags & PM_AUTOLOAD)) {
- /*
- * It's not possible to restore the state of
- * these, so don't output.
- */
- return;
- }
- if (locallevel && p->level >= locallevel) {
- printf("typeset "); /* printf("local "); */
- } else if ((p->node.flags & PM_EXPORTED) &&
- !(p->node.flags & (PM_ARRAY|PM_HASHED))) {
- printf("export ");
- } else if (locallevel) {
- printf("typeset -g ");
- } else
- printf("typeset ");
- }
-
- /* Print the attributes of the parameter */
- if (printflags & (PRINT_TYPE|PRINT_TYPESET)) {
- int doneminus = 0, i;
- const struct paramtypes *pmptr;
-
- for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
- int doprint = 0;
- if (pmptr->flags & PMTF_TEST_LEVEL) {
- if (p->level)
- doprint = 1;
- } else if ((pmptr->binflag != PM_EXPORTED || p->level ||
- (p->node.flags & (PM_LOCAL|PM_ARRAY|PM_HASHED))) &&
- (p->node.flags & pmptr->binflag))
- doprint = 1;
-
- if (doprint) {
- if (printflags & PRINT_TYPESET) {
- if (pmptr->typeflag) {
- if (!doneminus) {
- putchar('-');
- doneminus = 1;
- }
- putchar(pmptr->typeflag);
- }
- } else
- printf("%s ", pmptr->string);
- if ((pmptr->flags & PMTF_USE_BASE) && p->base) {
- printf("%d ", p->base);
- doneminus = 0;
- }
- if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
- printf("%d ", p->width);
- doneminus = 0;
- }
- }
- }
- if (doneminus)
- putchar(' ');
- }
-
- if ((printflags & PRINT_NAMEONLY) ||
- ((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
- zputs(p->node.nam, stdout);
- putchar('\n');
- } else {
- if (printflags & PRINT_KV_PAIR) {
- if (printflags & PRINT_LINE)
- printf("\n ");
- putchar('[');
- }
- quotedzputs(p->node.nam, stdout);
- if (printflags & PRINT_KV_PAIR)
- printf("]=");
-
- printparamvalue(p, printflags);
- }
-}