2 * params.c - parameters
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1992-1997 Paul Falstad
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
34 #ifdef CUSTOM_PATCHLEVEL
35 #define ZSH_PATCHLEVEL CUSTOM_PATCHLEVEL
37 #include "patchlevel.h"
39 /* If removed from the ChangeLog for some reason */
40 #ifndef ZSH_PATCHLEVEL
41 #define ZSH_PATCHLEVEL "unknown"
45 /* what level of localness we are at */
48 mod_export
int locallevel
;
50 /* Variables holding values of special parameters */
54 char **pparams
, /* $argv */
55 **cdpath
, /* $cdpath */
57 **mailpath
, /* $mailpath */
58 **manpath
, /* $manpath */
61 **zsh_eval_context
; /* $zsh_eval_context */
64 char **path
, /* $path */
65 **fignore
; /* $fignore */
69 char *argzero
, /* $0 */
72 *nullcmd
, /* $NULLCMD */
73 *oldpwd
, /* $OLDPWD */
74 *zoptarg
, /* $OPTARG */
75 *prompt
, /* $PROMPT */
76 *prompt2
, /* $PROMPT2 */
77 *prompt3
, /* $PROMPT3 */
78 *prompt4
, /* $PROMPT4 */
79 *readnullcmd
, /* $READNULLCMD */
80 *rprompt
, /* $RPROMPT */
81 *rprompt2
, /* $RPROMPT2 */
82 *sprompt
, /* $SPROMPT */
83 *wordchars
, /* $WORDCHARS */
84 *zsh_name
; /* $ZSH_NAME */
88 *postedit
, /* $POSTEDIT */
90 *zsh_terminfo
, /* $TERMINFO */
91 *ttystrname
, /* $TTY */
96 zlong lastval
, /* $? */
99 zterm_columns
, /* $COLUMNS */
100 zterm_lines
, /* $LINES */
101 rprompt_indent
, /* $ZLE_RPROMPT_INDENT */
103 zsh_subshell
; /* $ZSH_SUBSHELL */
105 zlong lineno
, /* $LINENO */
106 zoptind
, /* $OPTIND */
112 mod_export
unsigned char bangchar
;
114 unsigned char hatchar
, hashchar
;
117 unsigned char keyboardhackchar
= '\0';
119 /* $SECONDS = now.tv_sec - shtimer.tv_sec
120 * + (now.tv_usec - shtimer.tv_usec) / 1000000.0
121 * (rounded to an integer if the parameter is not set to float) */
124 struct timeval shtimer
;
126 /* 0 if this $TERM setup is usable, otherwise it contains TERM_* flags */
129 mod_export
int termflags
;
131 /* Standard methods for get/set/unset pointers in parameters */
134 mod_export
const struct gsu_scalar stdscalar_gsu
=
135 { strgetfn
, strsetfn
, stdunsetfn
};
137 mod_export
const struct gsu_scalar varscalar_gsu
=
138 { strvargetfn
, strvarsetfn
, stdunsetfn
};
140 mod_export
const struct gsu_scalar nullsetscalar_gsu
=
141 { strgetfn
, nullstrsetfn
, NULL
};
144 mod_export
const struct gsu_integer stdinteger_gsu
=
145 { intgetfn
, intsetfn
, stdunsetfn
};
147 mod_export
const struct gsu_integer varinteger_gsu
=
148 { intvargetfn
, intvarsetfn
, stdunsetfn
};
150 mod_export
const struct gsu_integer nullsetinteger_gsu
=
151 { intgetfn
, NULL
, NULL
};
154 mod_export
const struct gsu_float stdfloat_gsu
=
155 { floatgetfn
, floatsetfn
, stdunsetfn
};
158 mod_export
const struct gsu_array stdarray_gsu
=
159 { arrgetfn
, arrsetfn
, stdunsetfn
};
161 mod_export
const struct gsu_array vararray_gsu
=
162 { arrvargetfn
, arrvarsetfn
, stdunsetfn
};
165 mod_export
const struct gsu_hash stdhash_gsu
=
166 { hashgetfn
, hashsetfn
, stdunsetfn
};
168 mod_export
const struct gsu_hash nullsethash_gsu
=
169 { hashgetfn
, nullsethashfn
, nullunsetfn
};
172 /* Non standard methods (not exported) */
173 static const struct gsu_integer pound_gsu
=
174 { poundgetfn
, nullintsetfn
, stdunsetfn
};
175 static const struct gsu_integer errno_gsu
=
176 { errnogetfn
, errnosetfn
, stdunsetfn
};
177 static const struct gsu_integer gid_gsu
=
178 { gidgetfn
, gidsetfn
, stdunsetfn
};
179 static const struct gsu_integer egid_gsu
=
180 { egidgetfn
, egidsetfn
, stdunsetfn
};
181 static const struct gsu_integer histsize_gsu
=
182 { histsizegetfn
, histsizesetfn
, stdunsetfn
};
183 static const struct gsu_integer random_gsu
=
184 { randomgetfn
, randomsetfn
, stdunsetfn
};
185 static const struct gsu_integer savehist_gsu
=
186 { savehistsizegetfn
, savehistsizesetfn
, stdunsetfn
};
187 static const struct gsu_integer intseconds_gsu
=
188 { intsecondsgetfn
, intsecondssetfn
, stdunsetfn
};
189 static const struct gsu_float floatseconds_gsu
=
190 { floatsecondsgetfn
, floatsecondssetfn
, stdunsetfn
};
191 static const struct gsu_integer uid_gsu
=
192 { uidgetfn
, uidsetfn
, stdunsetfn
};
193 static const struct gsu_integer euid_gsu
=
194 { euidgetfn
, euidsetfn
, stdunsetfn
};
195 static const struct gsu_integer ttyidle_gsu
=
196 { ttyidlegetfn
, nullintsetfn
, stdunsetfn
};
198 static const struct gsu_scalar argzero_gsu
=
199 { argzerogetfn
, argzerosetfn
, nullunsetfn
};
200 static const struct gsu_scalar username_gsu
=
201 { usernamegetfn
, usernamesetfn
, stdunsetfn
};
202 static const struct gsu_scalar dash_gsu
=
203 { dashgetfn
, nullstrsetfn
, stdunsetfn
};
204 static const struct gsu_scalar histchars_gsu
=
205 { histcharsgetfn
, histcharssetfn
, stdunsetfn
};
206 static const struct gsu_scalar home_gsu
=
207 { homegetfn
, homesetfn
, stdunsetfn
};
208 static const struct gsu_scalar term_gsu
=
209 { termgetfn
, termsetfn
, stdunsetfn
};
210 static const struct gsu_scalar terminfo_gsu
=
211 { terminfogetfn
, terminfosetfn
, stdunsetfn
};
212 static const struct gsu_scalar wordchars_gsu
=
213 { wordcharsgetfn
, wordcharssetfn
, stdunsetfn
};
214 static const struct gsu_scalar ifs_gsu
=
215 { ifsgetfn
, ifssetfn
, stdunsetfn
};
216 static const struct gsu_scalar underscore_gsu
=
217 { underscoregetfn
, nullstrsetfn
, stdunsetfn
};
218 static const struct gsu_scalar keyboard_hack_gsu
=
219 { keyboardhackgetfn
, keyboardhacksetfn
, stdunsetfn
};
221 static const struct gsu_scalar lc_blah_gsu
=
222 { strgetfn
, lcsetfn
, stdunsetfn
};
223 static const struct gsu_scalar lang_gsu
=
224 { strgetfn
, langsetfn
, stdunsetfn
};
225 static const struct gsu_scalar lc_all_gsu
=
226 { strgetfn
, lc_allsetfn
, stdunsetfn
};
229 static const struct gsu_integer varint_readonly_gsu
=
230 { intvargetfn
, nullintsetfn
, stdunsetfn
};
231 static const struct gsu_integer zlevar_gsu
=
232 { intvargetfn
, zlevarsetfn
, stdunsetfn
};
234 static const struct gsu_scalar colonarr_gsu
=
235 { colonarrgetfn
, colonarrsetfn
, stdunsetfn
};
237 static const struct gsu_integer argc_gsu
=
238 { poundgetfn
, nullintsetfn
, stdunsetfn
};
239 static const struct gsu_array pipestatus_gsu
=
240 { pipestatgetfn
, pipestatsetfn
, stdunsetfn
};
242 /* Nodes for special parameters for parameter hash table */
244 #ifdef HAVE_UNION_INIT
246 typedef struct param initparam
;
249 typedef struct iparam
{
250 struct hashnode
*next
;
251 char *nam
; /* hash data */
252 int flags
; /* PM_* flags (defined in zsh.h) */
254 void *gsu
; /* get/set/unset methods */
255 int base
; /* output base */
256 int width
; /* output field width */
257 char *env
; /* location in environment, if exported */
258 char *ename
; /* name of corresponding environment var */
259 Param old
; /* old struct for use with local */
260 int level
; /* if (old != NULL), level of localness */
264 static initparam special_params
[] ={
265 #define GSU(X) BR((GsuScalar)(void *)(&(X)))
266 #define NULL_GSU BR((GsuScalar)(void *)NULL)
267 #define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
268 IPDEF1("#", pound_gsu
, PM_READONLY
),
269 IPDEF1("ERRNO", errno_gsu
, PM_UNSET
),
270 IPDEF1("GID", gid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
271 IPDEF1("EGID", egid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
272 IPDEF1("HISTSIZE", histsize_gsu
, PM_RESTRICTED
),
273 IPDEF1("RANDOM", random_gsu
, 0),
274 IPDEF1("SAVEHIST", savehist_gsu
, PM_RESTRICTED
),
275 IPDEF1("SECONDS", intseconds_gsu
, 0),
276 IPDEF1("UID", uid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
277 IPDEF1("EUID", euid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
278 IPDEF1("TTYIDLE", ttyidle_gsu
, PM_READONLY
),
280 #define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
281 IPDEF2("USERNAME", username_gsu
, PM_DONTIMPORT
|PM_RESTRICTED
),
282 IPDEF2("-", dash_gsu
, PM_READONLY
),
283 IPDEF2("histchars", histchars_gsu
, PM_DONTIMPORT
),
284 IPDEF2("HOME", home_gsu
, PM_UNSET
),
285 IPDEF2("TERM", term_gsu
, PM_UNSET
),
286 IPDEF2("TERMINFO", terminfo_gsu
, PM_UNSET
),
287 IPDEF2("WORDCHARS", wordchars_gsu
, 0),
288 IPDEF2("IFS", ifs_gsu
, PM_DONTIMPORT
),
289 IPDEF2("_", underscore_gsu
, PM_DONTIMPORT
),
290 IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu
, PM_DONTIMPORT
),
291 IPDEF2("0", argzero_gsu
, 0),
294 # define LCIPDEF(name) IPDEF2(name, lc_blah_gsu, PM_UNSET)
295 IPDEF2("LANG", lang_gsu
, PM_UNSET
),
296 IPDEF2("LC_ALL", lc_all_gsu
, PM_UNSET
),
298 LCIPDEF("LC_COLLATE"),
304 LCIPDEF("LC_MESSAGES"),
307 LCIPDEF("LC_NUMERIC"),
312 #endif /* USE_LOCALE */
314 #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}
315 IPDEF4("!", &lastpid
),
317 IPDEF4("?", &lastval
),
318 IPDEF4("HISTCMD", &curhist
),
319 IPDEF4("LINENO", &lineno
),
320 IPDEF4("PPID", &ppid
),
321 IPDEF4("ZSH_SUBSHELL", &zsh_subshell
),
323 #define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
324 #define IPDEF5U(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
325 IPDEF5("COLUMNS", &zterm_columns
, zlevar_gsu
),
326 IPDEF5("LINES", &zterm_lines
, zlevar_gsu
),
327 IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent
, zlevar_gsu
),
328 IPDEF5("SHLVL", &shlvl
, varinteger_gsu
),
330 /* Don't import internal integer status variables. */
331 #define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
332 IPDEF6("OPTIND", &zoptind
, varinteger_gsu
),
333 IPDEF6("TRY_BLOCK_ERROR", &try_errflag
, varinteger_gsu
),
334 IPDEF6("TRY_BLOCK_INTERRUPT", &try_interrupt
, varinteger_gsu
),
336 #define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
337 #define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
338 IPDEF7("OPTARG", &zoptarg
),
339 IPDEF7("NULLCMD", &nullcmd
),
340 IPDEF7U("POSTEDIT", &postedit
),
341 IPDEF7("READNULLCMD", &readnullcmd
),
342 IPDEF7("PS1", &prompt
),
343 IPDEF7U("RPS1", &rprompt
),
344 IPDEF7U("RPROMPT", &rprompt
),
345 IPDEF7("PS2", &prompt2
),
346 IPDEF7U("RPS2", &rprompt2
),
347 IPDEF7U("RPROMPT2", &rprompt2
),
348 IPDEF7("PS3", &prompt3
),
349 IPDEF7("PS4", &prompt4
),
350 IPDEF7("SPROMPT", &sprompt
),
352 #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}
353 IPDEF8("CDPATH", &cdpath
, "cdpath", 0),
354 IPDEF8("FIGNORE", &fignore
, "fignore", 0),
355 IPDEF8("FPATH", &fpath
, "fpath", 0),
356 IPDEF8("MAILPATH", &mailpath
, "mailpath", 0),
357 IPDEF8("WATCH", &watch
, "watch", 0),
358 IPDEF8("PATH", &path
, "path", PM_RESTRICTED
),
359 IPDEF8("PSVAR", &psvar
, "psvar", 0),
360 IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context
, "zsh_eval_context", PM_READONLY
),
362 /* MODULE_PATH is not imported for security reasons */
363 IPDEF8("MODULE_PATH", &module_path
, "module_path", PM_DONTIMPORT
|PM_RESTRICTED
),
365 #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}
366 #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
367 IPDEF9F("*", &pparams
, NULL
, PM_ARRAY
|PM_SPECIAL
|PM_DONTIMPORT
|PM_READONLY
),
368 IPDEF9F("@", &pparams
, NULL
, PM_ARRAY
|PM_SPECIAL
|PM_DONTIMPORT
|PM_READONLY
),
371 * This empty row indicates the end of parameters available in
374 {{NULL
,NULL
,0},BR(NULL
),NULL_GSU
,0,0,NULL
,NULL
,NULL
,0},
376 #define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
379 * The following parameters are not available in sh/ksh compatibility *
383 /* All of these have sh compatible equivalents. */
384 IPDEF1("ARGC", argc_gsu
, PM_READONLY
),
385 IPDEF2("HISTCHARS", histchars_gsu
, PM_DONTIMPORT
),
386 IPDEF4("status", &lastval
),
387 IPDEF7("prompt", &prompt
),
388 IPDEF7("PROMPT", &prompt
),
389 IPDEF7("PROMPT2", &prompt2
),
390 IPDEF7("PROMPT3", &prompt3
),
391 IPDEF7("PROMPT4", &prompt4
),
392 IPDEF8("MANPATH", &manpath
, "manpath", 0),
393 IPDEF9("argv", &pparams
, NULL
),
394 IPDEF9("fignore", &fignore
, "FIGNORE"),
395 IPDEF9("cdpath", &cdpath
, "CDPATH"),
396 IPDEF9("fpath", &fpath
, "FPATH"),
397 IPDEF9("mailpath", &mailpath
, "MAILPATH"),
398 IPDEF9("manpath", &manpath
, "MANPATH"),
399 IPDEF9("psvar", &psvar
, "PSVAR"),
400 IPDEF9("watch", &watch
, "WATCH"),
402 IPDEF9F("zsh_eval_context", &zsh_eval_context
, "ZSH_EVAL_CONTEXT", PM_READONLY
),
404 IPDEF9F("module_path", &module_path
, "MODULE_PATH", PM_RESTRICTED
),
405 IPDEF9F("path", &path
, "PATH", PM_RESTRICTED
),
407 /* These are known to zsh alone. */
409 IPDEF10("pipestatus", pipestatus_gsu
),
411 {{NULL
,NULL
,0},BR(NULL
),NULL_GSU
,0,0,NULL
,NULL
,NULL
,0},
415 * Special way of referring to the positional parameters. Unlike $*
416 * and $@, this is not readonly. This parameter is not directly
417 * visible in user space.
419 initparam argvparam_pm
= IPDEF9F("", &pparams
, NULL
, \
420 PM_ARRAY
|PM_SPECIAL
|PM_DONTIMPORT
);
424 #define IS_UNSET_VALUE(V) \
425 ((V) && (!(V)->pm || ((V)->pm->node.flags & PM_UNSET) || \
426 !(V)->pm->node.nam || !*(V)->pm->node.nam))
428 static Param argvparam
;
430 /* hash table containing the parameters */
433 mod_export HashTable paramtab
, realparamtab
;
437 newparamtable(int size
, char const *name
)
442 ht
= newhashtable(size
, name
, NULL
);
445 ht
->emptytable
= emptyhashtable
;
446 ht
->filltable
= NULL
;
447 ht
->cmpnodes
= strcmp
;
448 ht
->addnode
= addhashnode
;
449 ht
->getnode
= getparamnode
;
450 ht
->getnode2
= getparamnode
;
451 ht
->removenode
= removehashnode
;
452 ht
->disablenode
= NULL
;
453 ht
->enablenode
= NULL
;
454 ht
->freenode
= freeparamnode
;
455 ht
->printnode
= printparamnode
;
462 getparamnode(HashTable ht
, const char *nam
)
464 HashNode hn
= gethashnode2(ht
, nam
);
465 Param pm
= (Param
) hn
;
467 if (pm
&& pm
->u
.str
&& (pm
->node
.flags
& PM_AUTOLOAD
)) {
468 char *mn
= dupstring(pm
->u
.str
);
470 (void)ensurefeature(mn
, "p:", (pm
->node
.flags
& PM_AUTOALL
) ? NULL
:
472 hn
= gethashnode2(ht
, nam
);
475 * This used to be a warning, but surely if we allow
476 * stuff to go ahead with the autoload stub with
477 * no error status we're in for all sorts of mayhem?
479 zerr("autoloading module %s failed to define parameter: %s", mn
,
486 /* Copy a parameter hash table */
488 static HashTable outtable
;
492 scancopyparams(HashNode hn
, UNUSED(int flags
))
494 /* Going into a real parameter, so always use permanent storage */
495 Param pm
= (Param
)hn
;
496 Param tpm
= (Param
) zshcalloc(sizeof *tpm
);
497 tpm
->node
.nam
= ztrdup(pm
->node
.nam
);
498 copyparam(tpm
, pm
, 0);
499 addhashnode(outtable
, tpm
->node
.nam
, tpm
);
504 copyparamtable(HashTable ht
, char *name
)
506 HashTable nht
= newparamtable(ht
->hsize
, name
);
508 scanhashtable(ht
, 0, 0, 0, scancopyparams
, 0);
513 /* Flag to freeparamnode to unset the struct */
517 /* Function to delete a parameter table. */
521 deleteparamtable(HashTable t
)
523 /* The parameters in the hash table need to be unset *
524 * before being deleted. */
525 int odelunset
= delunset
;
528 delunset
= odelunset
;
531 static unsigned numparamvals
;
535 scancountparams(UNUSED(HashNode hn
), int flags
)
538 if ((flags
& SCANPM_WANTKEYS
) && (flags
& SCANPM_WANTVALS
))
542 static Patprog scanprog
;
543 static char *scanstr
;
544 static char **paramvals
;
545 static Param foundparam
;
549 scanparamvals(HashNode hn
, int flags
)
554 if (numparamvals
&& !(flags
& SCANPM_MATCHMANY
) &&
555 (flags
& (SCANPM_MATCHVAL
|SCANPM_MATCHKEY
|SCANPM_KEYMATCH
)))
558 if ((flags
& SCANPM_KEYMATCH
)) {
559 char *tmp
= dupstring(v
.pm
->node
.nam
);
564 if (!(prog
= patcompile(tmp
, 0, NULL
)) || !pattry(prog
, scanstr
))
566 } else if ((flags
& SCANPM_MATCHKEY
) && !pattry(scanprog
, v
.pm
->node
.nam
)) {
570 if (flags
& SCANPM_WANTKEYS
) {
571 paramvals
[numparamvals
++] = v
.pm
->node
.nam
;
572 if (!(flags
& (SCANPM_WANTVALS
|SCANPM_MATCHVAL
)))
575 v
.isarr
= (PM_TYPE(v
.pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
));
579 paramvals
[numparamvals
] = getstrvalue(&v
);
580 if (flags
& SCANPM_MATCHVAL
) {
581 if (pattry(scanprog
, paramvals
[numparamvals
])) {
582 numparamvals
+= ((flags
& SCANPM_WANTVALS
) ? 1 :
583 !(flags
& SCANPM_WANTKEYS
));
584 } else if (flags
& SCANPM_WANTKEYS
)
585 --numparamvals
; /* Value didn't match, discard key */
593 paramvalarr(HashTable ht
, int flags
)
595 DPUTS((flags
& (SCANPM_MATCHKEY
|SCANPM_MATCHVAL
)) && !scanprog
,
596 "BUG: scanning hash without scanprog set");
599 scanhashtable(ht
, 0, 0, PM_UNSET
, scancountparams
, flags
);
600 paramvals
= (char **) zhalloc((numparamvals
+ 1) * sizeof(char *));
603 scanhashtable(ht
, 0, 0, PM_UNSET
, scanparamvals
, flags
);
605 paramvals
[numparamvals
] = 0;
609 /* Return the full array (no indexing) referred to by a Value. *
610 * The array value is cached for the lifetime of the Value. */
618 else if (PM_TYPE(v
->pm
->node
.flags
) == PM_ARRAY
)
619 return v
->arr
= v
->pm
->gsu
.a
->getfn(v
->pm
);
620 else if (PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
) {
621 v
->arr
= paramvalarr(v
->pm
->gsu
.h
->getfn(v
->pm
), v
->isarr
);
622 /* Can't take numeric slices of associative arrays */
624 v
->end
= numparamvals
+ 1;
631 * Split environment string into (name, value) pair.
632 * this is used to avoid in-place editing of environment table
633 * that results in core dump on some systems
637 split_env_string(char *env
, char **name
, char **value
)
641 if (!env
|| !name
|| !value
)
644 tenv
= strcpy(zhalloc(strlen(env
) + 1), env
);
645 for (str
= tenv
; *str
&& *str
!= '='; str
++) {
646 if (STOUC(*str
) >= 128) {
648 * We'll ignore environment variables with names not
649 * from the portable character set since we don't
650 * know of a good reason to accept them.
655 if (str
!= tenv
&& *str
== '=') {
664 /* Set up parameter hash table. This will add predefined *
665 * parameter entries as well as setting up parameter table *
666 * entries for environment variables we inherit. */
670 createparamtable(void)
673 #if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV)
677 #ifndef USE_SET_UNSET_ENV
680 char **envp2
, **sigptr
, **t
;
681 char buf
[50], *str
, *iname
, *ivalue
, *hostnam
;
682 int oae
= opts
[ALLEXPORT
];
684 struct utsname unamebuf
;
688 paramtab
= realparamtab
= newparamtable(151, "paramtab");
690 /* Add the special parameters to the hash table */
691 for (ip
= special_params
; ip
->node
.nam
; ip
++)
692 paramtab
->addnode(paramtab
, ztrdup(ip
->node
.nam
), ip
);
693 if (!EMULATION(EMULATE_SH
|EMULATE_KSH
))
694 while ((++ip
)->node
.nam
)
695 paramtab
->addnode(paramtab
, ztrdup(ip
->node
.nam
), ip
);
697 argvparam
= (Param
) &argvparam_pm
;
701 /* Add the standard non-special parameters which have to *
702 * be initialized before we copy the environment variables. *
703 * We don't want to override whatever values the user has *
704 * given them in the environment. */
706 setiparam("MAILCHECK", 60);
707 setiparam("LOGCHECK", 60);
708 setiparam("KEYTIMEOUT", 40);
709 setiparam("LISTMAX", 100);
711 * We used to get the output baud rate here. However, that's
712 * pretty irrelevant to a terminal on an X display and can lead
713 * to unnecessary delays if it's wrong (which it probably is).
714 * Furthermore, even if the output is slow it's very likely
715 * to be because of WAN delays, not covered by the output
717 * So allow the user to set it in the special cases where it's
720 setsparam("TMPPREFIX", ztrdup_metafy(DEFAULT_TMPPREFIX
));
721 setsparam("TIMEFMT", ztrdup_metafy(DEFAULT_TIMEFMT
));
722 setsparam("WATCHFMT", ztrdup_metafy(default_watchfmt
));
724 hostnam
= (char *)zalloc(256);
725 gethostname(hostnam
, 256);
726 setsparam("HOST", ztrdup_metafy(hostnam
));
730 ztrdup_metafy((str
= getlogin()) && *str
?
731 str
: cached_username
));
733 #if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV)
734 /* Copy the environment variables we are inheriting to dynamic *
735 * memory, so we can do mallocs and frees on it. */
736 envsize
= sizeof(char *)*(1 + arrlen(environ
));
737 new_environ
= (char **) zalloc(envsize
);
738 memcpy(new_environ
, environ
, envsize
);
739 environ
= new_environ
;
742 /* Use heap allocation to avoid many small alloc/free calls */
745 /* Now incorporate environment variables we are inheriting *
746 * into the parameter hash table. Copy them into dynamic *
747 * memory so that we can free them if needed */
749 #ifndef USE_SET_UNSET_ENV
752 envp2
= environ
; *envp2
; envp2
++) {
753 if (split_env_string(*envp2
, &iname
, &ivalue
)) {
754 if (!idigit(*iname
) && isident(iname
) && !strchr(iname
, '[')) {
755 if ((!(pm
= (Param
) paramtab
->getnode(paramtab
, iname
)) ||
756 !(pm
->node
.flags
& PM_DONTIMPORT
|| pm
->node
.flags
& PM_EXPORTED
)) &&
757 (pm
= assignsparam(iname
, metafy(ivalue
, -1, META_DUP
),
758 ASSPM_ENV_IMPORT
))) {
759 pm
->node
.flags
|= PM_EXPORTED
;
760 if (pm
->node
.flags
& PM_SPECIAL
)
761 pm
->env
= mkenvstr (pm
->node
.nam
,
762 getsparam(pm
->node
.nam
), pm
->node
.flags
);
764 pm
->env
= ztrdup(*envp2
);
765 #ifndef USE_SET_UNSET_ENV
773 #ifndef USE_SET_UNSET_ENV
776 opts
[ALLEXPORT
] = oae
;
778 if (EMULATION(EMULATE_ZSH
))
781 * For native emulation we always set the variable home
784 pm
= (Param
) paramtab
->getnode(paramtab
, "HOME");
785 pm
->node
.flags
&= ~PM_UNSET
;
786 if (!(pm
->node
.flags
& PM_EXPORTED
))
789 pm
= (Param
) paramtab
->getnode(paramtab
, "LOGNAME");
790 if (!(pm
->node
.flags
& PM_EXPORTED
))
791 addenv(pm
, pm
->u
.str
);
792 pm
= (Param
) paramtab
->getnode(paramtab
, "SHLVL");
793 sprintf(buf
, "%d", (int)++shlvl
);
794 /* shlvl value in environment needs updating unconditionally */
797 /* Add the standard non-special parameters */
800 if(uname(&unamebuf
)) setsparam("CPUTYPE", ztrdup("unknown"));
803 machinebuf
= ztrdup_metafy(unamebuf
.machine
);
804 setsparam("CPUTYPE", machinebuf
);
808 setsparam("CPUTYPE", ztrdup_metafy("unknown"));
810 setsparam("MACHTYPE", ztrdup_metafy(MACHTYPE
));
811 setsparam("OSTYPE", ztrdup_metafy(OSTYPE
));
812 setsparam("TTY", ztrdup_metafy(ttystrname
));
813 setsparam("VENDOR", ztrdup_metafy(VENDOR
));
814 setsparam("ZSH_NAME", ztrdup_metafy(zsh_name
));
815 setsparam("ZSH_VERSION", ztrdup_metafy(ZSH_VERSION
));
816 setsparam("ZSH_PATCHLEVEL", ztrdup_metafy(ZSH_PATCHLEVEL
));
817 setaparam("signals", sigptr
= zalloc((SIGCOUNT
+4) * sizeof(char *)));
818 for (t
= sigs
; (*sigptr
++ = ztrdup_metafy(*t
++)); );
823 /* assign various functions used for non-special parameters */
827 assigngetset(Param pm
)
829 switch (PM_TYPE(pm
->node
.flags
)) {
831 pm
->gsu
.s
= &stdscalar_gsu
;
834 pm
->gsu
.i
= &stdinteger_gsu
;
838 pm
->gsu
.f
= &stdfloat_gsu
;
841 pm
->gsu
.a
= &stdarray_gsu
;
844 pm
->gsu
.h
= &stdhash_gsu
;
847 DPUTS(1, "BUG: tried to create param node without valid flag");
852 /* Create a parameter, so that it can be assigned to. Returns NULL if the *
853 * parameter already exists or can't be created, otherwise returns the *
854 * parameter node. If a parameter of the same name exists in an outer *
855 * scope, it is hidden by a newly created parameter. An already existing *
856 * parameter node at the current level may be `created' and returned *
857 * provided it is unset and not special. If the parameter can't be *
858 * created because it already exists, the PM_UNSET flag is cleared. */
862 createparam(char *name
, int flags
)
866 if (paramtab
!= realparamtab
)
867 flags
= (flags
& ~PM_EXPORTED
) | PM_HASHELEM
;
869 if (name
!= nulstring
) {
870 oldpm
= (Param
) (paramtab
== realparamtab
?
871 gethashnode2(paramtab
, name
) :
872 paramtab
->getnode(paramtab
, name
));
874 DPUTS(oldpm
&& oldpm
->level
> locallevel
,
875 "BUG: old local parameter not deleted");
876 if (oldpm
&& (oldpm
->level
== locallevel
|| !(flags
& PM_LOCAL
))) {
877 if (isset(POSIXBUILTINS
) && (oldpm
->node
.flags
& PM_READONLY
)) {
878 zerr("read-only variable: %s", name
);
881 if (!(oldpm
->node
.flags
& PM_UNSET
) || (oldpm
->node
.flags
& PM_SPECIAL
)) {
882 oldpm
->node
.flags
&= ~PM_UNSET
;
883 if ((oldpm
->node
.flags
& PM_SPECIAL
) && oldpm
->ename
) {
885 (Param
) paramtab
->getnode(paramtab
, oldpm
->ename
);
887 altpm
->node
.flags
&= ~PM_UNSET
;
891 if ((oldpm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
892 zerr("%s: restricted", name
);
897 pm
->base
= pm
->width
= 0;
900 pm
= (Param
) zshcalloc(sizeof *pm
);
901 if ((pm
->old
= oldpm
)) {
903 * needed to avoid freeing oldpm, but we do take it
904 * out of the environment when it's hidden.
908 paramtab
->removenode(paramtab
, name
);
910 paramtab
->addnode(paramtab
, ztrdup(name
), pm
);
913 if (isset(ALLEXPORT
) && !(flags
& PM_HASHELEM
))
914 flags
|= PM_EXPORTED
;
916 pm
= (Param
) hcalloc(sizeof *pm
);
917 pm
->node
.nam
= nulstring
;
919 pm
->node
.flags
= flags
& ~PM_LOCAL
;
921 if(!(pm
->node
.flags
& PM_SPECIAL
))
926 /* Empty dummy function for special hash parameters. */
935 * Create a simple special hash parameter.
937 * This is for hashes added internally --- it's not possible to add
938 * special hashes from shell commands. It's currently used
939 * - by addparamdef() for special parameters in the zsh/parameter
941 * - by ztie for special parameters tied to databases.
946 createspecialhash(char *name
, GetNodeFunc get
, ScanTabFunc scan
, int flags
)
951 if (!(pm
= createparam(name
, PM_SPECIAL
|PM_HASHED
|flags
)))
955 * If there's an old parameter, we'll put the new one at
956 * the current locallevel, so that the old parameter is
957 * exposed again after leaving the function. Otherwise,
958 * we'll leave it alone. Usually this means the parameter
959 * will stay in place until explicitly unloaded, however
960 * if the parameter was previously unset within a function
961 * we'll inherit the level of that function and follow the
962 * standard convention that the parameter remains local
965 * These semantics are similar to those of a normal parameter set
966 * within a function without a local definition.
969 pm
->level
= locallevel
;
970 pm
->gsu
.h
= (flags
& PM_READONLY
) ? &stdhash_gsu
:
972 pm
->u
.hash
= ht
= newhashtable(0, name
, NULL
);
975 ht
->emptytable
= (TableFunc
) shempty
;
976 ht
->filltable
= NULL
;
977 ht
->addnode
= (AddNodeFunc
) shempty
;
978 ht
->getnode
= ht
->getnode2
= get
;
979 ht
->removenode
= (RemoveNodeFunc
) shempty
;
980 ht
->disablenode
= NULL
;
981 ht
->enablenode
= NULL
;
982 ht
->freenode
= (FreeNodeFunc
) shempty
;
983 ht
->printnode
= printparamnode
;
993 * If fakecopy is set, we are just saving the details of a special
994 * parameter. Otherwise, the result will be used as a real parameter
995 * and we need to do more work.
1000 copyparam(Param tpm
, Param pm
, int fakecopy
)
1003 * Note that tpm, into which we're copying, may not be in permanent
1004 * storage. However, the values themselves are later used directly
1005 * to set the parameter, so must be permanently allocated (in accordance
1006 * with sets.?fn() usage).
1008 tpm
->node
.flags
= pm
->node
.flags
;
1009 tpm
->base
= pm
->base
;
1010 tpm
->width
= pm
->width
;
1011 tpm
->level
= pm
->level
;
1013 tpm
->node
.flags
&= ~PM_SPECIAL
;
1014 switch (PM_TYPE(pm
->node
.flags
)) {
1016 tpm
->u
.str
= ztrdup(pm
->gsu
.s
->getfn(pm
));
1019 tpm
->u
.val
= pm
->gsu
.i
->getfn(pm
);
1023 tpm
->u
.dval
= pm
->gsu
.f
->getfn(pm
);
1026 tpm
->u
.arr
= zarrdup(pm
->gsu
.a
->getfn(pm
));
1029 tpm
->u
.hash
= copyparamtable(pm
->gsu
.h
->getfn(pm
), pm
->node
.nam
);
1033 * If the value is going to be passed as a real parameter (e.g. this is
1034 * called from inside an associative array), we need the gets and sets
1035 * functions to be useful.
1037 * In this case we assume the saved parameter is not itself special,
1038 * so we just use the standard functions. This is also why we switch off
1045 /* Return 1 if the string s is a valid identifier, else return 0. */
1053 if (!*s
) /* empty string is definitely not valid */
1057 /* If the first character is `s' is a digit, then all must be */
1058 for (ss
= ++s
; *ss
; ss
++)
1062 /* Find the first character in `s' not in the iident type table */
1063 ss
= itype_end(s
, IIDENT
, 0);
1066 /* If the next character is not [, then it is *
1067 * definitely not a valid identifier. */
1075 /* Require balanced [ ] pairs with something between */
1076 if (!(ss
= parse_subscript(++ss
, 1, ']')))
1083 * Parse a single argument to a parameter subscript.
1084 * The subscripts starts at *str; *str is updated (input/output)
1086 * *inv is set to indicate if the subscript is reversed (output)
1087 * v is the Value for the parameter being accessed (input; note
1088 * v->isarr may be modified, and if v is a hash the parameter will
1089 * be updated to the element of the hash)
1090 * a2 is 1 if this is the second subscript of a range (input)
1091 * *w is only set if we need to find the end of a word (input; should
1092 * be set to 0 by the caller).
1094 * The final two arguments are to support multibyte characters.
1095 * If supplied they are set to the length of the character before
1096 * the index position and the one at the index position. If
1097 * multibyte characters are not in use they are set to 1 for
1098 * consistency. Note they aren't fully handled if a2 is non-zero,
1099 * since they aren't needed.
1101 * Returns a raw offset into the value from the start or end (i.e.
1102 * after the arithmetic for Meta and possible multibyte characters has
1103 * been taken into account). This actually gives the offset *after*
1104 * the character in question; subtract *prevcharlen if necessary.
1109 getarg(char **str
, int *inv
, Value v
, int a2
, zlong
*w
,
1110 int *prevcharlen
, int *nextcharlen
)
1112 int hasbeg
= 0, word
= 0, rev
= 0, ind
= 0, down
= 0, l
, i
, ishash
;
1113 int keymatch
= 0, needtok
= 0, arglen
, len
;
1114 char *s
= *str
, *sep
= NULL
, *t
, sav
, *d
, **ta
, **p
, *tt
, c
;
1115 zlong num
= 1, beg
= 0, r
= 0, quote_arg
= 0;
1116 Patprog pprog
= NULL
;
1119 * If in NO_EXEC mode, the parameters won't be set up properly,
1120 * so just pretend everything is a hash for subscript parsing
1123 ishash
= (unset(EXECOPT
) ||
1124 (v
->pm
&& PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
));
1130 /* first parse any subscription flags */
1131 if (v
->pm
&& (*s
== '(' || *s
== Inpar
)) {
1134 for (s
++; *s
!= ')' && *s
!= Outpar
&& s
!= *str
; s
++) {
1138 keymatch
= down
= ind
= 0;
1156 down
= keymatch
= 0;
1159 rev
= ind
= down
= 1;
1163 /* If the parameter is a scalar, then make subscription *
1164 * work on a per-word basis instead of characters. */
1175 t
= get_strarg(++s
, &arglen
);
1180 num
= mathevalarg(s
+ arglen
, &d
);
1188 t
= get_strarg(++s
, &arglen
);
1193 if ((beg
= mathevalarg(s
+ arglen
, &d
)) > 0)
1202 /* This gives the string that separates words *
1203 * (for use with the `w' flag). */
1204 t
= get_strarg(++s
, &arglen
);
1210 sep
= escapes
? getkeystring(s
, &waste
, GETKEYS_SEP
, NULL
)
1218 word
= rev
= ind
= down
= keymatch
= 0;
1230 if (v
->isarr
& SCANPM_WANTKEYS
)
1231 *inv
= (ind
|| !(v
->isarr
& SCANPM_WANTVALS
));
1232 else if (v
->isarr
& SCANPM_WANTVALS
)
1237 v
->isarr
|= SCANPM_WANTKEYS
;
1238 v
->isarr
&= ~SCANPM_WANTVALS
;
1240 v
->isarr
|= SCANPM_WANTVALS
;
1242 * This catches the case where we are using "k" (rather
1243 * than "K") on a hash.
1245 if (!down
&& keymatch
&& ishash
)
1246 v
->isarr
&= ~SCANPM_MATCHMANY
;
1252 (c
= *t
) && ((c
!= Outbrack
&&
1253 (ishash
|| c
!= ',')) || i
); t
++) {
1254 /* Untokenize inull() except before brackets and double-quotes */
1257 if (c
== '[' || c
== ']' ||
1258 c
== '(' || c
== ')' ||
1259 c
== '{' || c
== '}') {
1260 /* This test handles nested subscripts in hash keys */
1262 *t
= ztokens
[*t
- Pound
];
1265 } else if (c
!= '"')
1266 *t
= ztokens
[*t
- Pound
];
1269 /* Inbrack and Outbrack are probably never found here ... */
1270 if (c
== '[' || c
== Inbrack
)
1272 else if (c
== ']' || c
== Outbrack
)
1282 * If in NO_EXEC mode, the parameters won't be set up properly,
1283 * so there's no additional sanity checking we can do.
1284 * Just return 0 now.
1289 s
= dupstrpfx(s
, t
- s
);
1291 /* If we're NOT reverse subscripting, strip the inull()s so brackets *
1292 * are not backslashed after parsestr(). Otherwise leave them alone *
1293 * so that the brackets will be escaped when we patcompile() or when *
1294 * subscript arithmetic is performed (for nested subscripts). */
1295 if (ishash
&& (keymatch
|| !rev
))
1303 remnulargs(s
); /* This is probably always a no-op, but ... */
1306 HashTable ht
= v
->pm
->gsu
.h
->getfn(v
->pm
);
1308 ht
= newparamtable(17, v
->pm
->node
.nam
);
1309 v
->pm
->gsu
.h
->setfn(v
->pm
, ht
);
1312 if (!(v
->pm
= (Param
) ht
->getnode(ht
, s
))) {
1313 HashTable tht
= paramtab
;
1315 v
->pm
= createparam(s
, PM_SCALAR
|PM_UNSET
);
1318 v
->isarr
= (*inv
? SCANPM_WANTINDEX
: 0);
1320 *inv
= 0; /* We've already obtained the "index" (key) */
1322 r
= isset(KSHARRAYS
) ? 1 : 0;
1324 r
= mathevalarg(s
, &s
);
1325 if (isset(KSHARRAYS
) && r
>= 0)
1328 if (word
&& !v
->isarr
) {
1329 s
= t
= getstrvalue(v
);
1330 i
= wordcount(s
, sep
, 0);
1339 while ((d
= findword(&s
, sep
)) && --r
);
1343 if (!a2
&& *tt
!= ',')
1344 *w
= (zlong
)(s
- t
);
1346 return (a2
? s
: d
+ 1) - t
;
1347 } else if (!v
->isarr
&& !word
) {
1348 int lastcharlen
= 1;
1351 * Note for the confused (= pws): the index r we
1352 * have so far is that specified by the user. The value
1353 * passed back is an offset from the start or end of
1354 * the string. Hence it needs correcting at least
1355 * for Meta characters and maybe for multibyte characters.
1361 for (t
= s
; nchars
&& *t
; nchars
--)
1362 t
+= (lastcharlen
= MB_METACHARLEN(t
));
1363 /* for consistency, keep any remainder off the end */
1364 r
= (zlong
)(t
- s
) + nchars
;
1365 if (prevcharlen
&& !nchars
/* ignore if off the end */)
1366 *prevcharlen
= lastcharlen
;
1367 if (nextcharlen
&& *t
)
1368 *nextcharlen
= MB_METACHARLEN(t
);
1369 } else if (r
== 0) {
1372 if (nextcharlen
&& *s
) {
1374 *nextcharlen
= MB_METACHARLEN(s
);
1377 zlong nchars
= (zlong
)MB_METASTRLEN(s
) + r
;
1380 /* make sure this isn't valid as a raw pointer */
1381 r
-= (zlong
)strlen(s
);
1384 for (t
= s
; nchars
&& *t
; nchars
--)
1385 t
+= (lastcharlen
= MB_METACHARLEN(t
));
1386 r
= - (zlong
)strlen(t
); /* keep negative */
1388 *prevcharlen
= lastcharlen
;
1389 if (nextcharlen
&& *t
)
1390 *nextcharlen
= MB_METACHARLEN(t
);
1395 if (!v
->isarr
&& !word
) {
1398 if (!l
|| *s
!= '*') {
1399 d
= (char *) hcalloc(l
+ 2);
1405 if (!l
|| s
[l
- 1] != '*' || (l
> 1 && s
[l
- 2] == '\\')) {
1406 d
= (char *) hcalloc(l
+ 2);
1419 pprog
= patcompile(s
, 0, NULL
);
1428 v
->isarr
|= SCANPM_KEYMATCH
;
1433 v
->isarr
|= SCANPM_MATCHKEY
;
1435 v
->isarr
|= SCANPM_MATCHVAL
;
1438 v
->isarr
|= SCANPM_MATCHMANY
;
1439 if ((ta
= getvaluearr(v
)) &&
1440 (*ta
|| ((v
->isarr
& SCANPM_MATCHMANY
) &&
1441 (v
->isarr
& (SCANPM_MATCHKEY
| SCANPM_MATCHVAL
|
1442 SCANPM_KEYMATCH
))))) {
1443 *inv
= (v
->flags
& VALFLAG_INV
) ? 1 : 0;
1450 ta
= getarrvalue(v
);
1459 } else if (beg
>= len
)
1461 if (beg
>= 0 && beg
< len
) {
1465 for (r
= 1 + beg
, p
= ta
+ beg
; p
>= ta
; r
--, p
--) {
1466 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1470 for (r
= 1 + beg
, p
= ta
+ beg
; *p
; r
++, p
++)
1471 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1475 ta
= sepsplit(d
= s
= getstrvalue(v
), sep
, 1, 1);
1482 } else if (beg
>= len
)
1484 if (beg
>= 0 && beg
< len
) {
1488 for (r
= 1 + beg
, p
= ta
+ beg
; p
>= ta
; p
--, r
--)
1489 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1494 for (r
= 1 + beg
, p
= ta
+ beg
; *p
; r
++, p
++)
1495 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1503 for (i
= 0; (t
= findword(&d
, sep
)) && *t
; i
++)
1505 r
= (zlong
)(t
- s
+ (a2
? -1 : 1));
1506 if (!a2
&& *tt
!= ',')
1507 *w
= r
+ strlen(ta
[i
]) - 1;
1512 /* Searching characters */
1518 * beg and len are character counts, not raw offsets.
1519 * Remember we need to return a raw offset.
1521 len
= MB_METASTRLEN(d
);
1526 if (beg
>= 0 && beg
< len
) {
1527 char *de
= d
+ slen
;
1531 * Second argument: we don't need to
1532 * handle prevcharlen or nextcharlen, but
1533 * we do need to handle characters appropriately.
1537 char *lastpos
= NULL
;
1543 * See below: we have to move forward,
1544 * but need to count from the end.
1546 for (t
= d
, r
= 0; r
<= beg
; r
++) {
1549 if (pprog
&& pattry(pprog
, d
)) {
1556 t
+= MB_METACHARLEN(t
);
1559 if (nmatches
>= num
) {
1563 for (t
= d
, r
= 0; ; r
++) {
1566 if (pprog
&& pattry(pprog
, d
) &&
1573 t
+= MB_METACHARLEN(t
);
1576 /* else lastpos is already OK */
1582 * This handling of the b flag
1583 * gives odd results, but this is the
1584 * way it's always worked.
1586 for (t
= d
; beg
&& t
<= de
; beg
--)
1587 t
+= MB_METACHARLEN(t
);
1591 if (pprog
&& pattry(pprog
, d
) && !--num
) {
1594 * This time, don't increment
1595 * pointer, since it's already
1596 * after everything we matched.
1603 t
+= MB_METACHARLEN(t
);
1608 * First argument: this is the only case
1609 * where we need prevcharlen and nextcharlen.
1615 char *lastpos
= NULL
;
1621 * We can only move forward through
1622 * multibyte strings, so record the
1624 * Unfortunately the count num works
1625 * from the end, so it's easy to get the
1626 * last one but we need to repeat if
1627 * we want another one.
1629 for (t
= d
, r
= 0; r
<= beg
; r
++) {
1630 if (pprog
&& pattry(pprog
, t
)) {
1636 t
+= MB_METACHARLEN(t
);
1639 if (nmatches
>= num
) {
1642 * Need to start again and repeat
1643 * to get the right match.
1647 for (t
= d
, r
= 0; ; r
++) {
1648 if (pprog
&& pattry(pprog
, t
) &&
1653 t
+= MB_METACHARLEN(t
);
1656 /* else lastpos is already OK */
1658 /* return pointer after matched char */
1660 (lastcharlen
= MB_METACHARLEN(lastpos
));
1662 *prevcharlen
= lastcharlen
;
1664 *nextcharlen
= MB_METACHARLEN(lastpos
);
1668 for (r
= beg
+ 1, t
= d
+ beg
; t
>= d
; r
--, t
--) {
1669 if (pprog
&& pattry(pprog
, t
) &&
1674 for (t
= d
; beg
&& t
<= de
; beg
--)
1675 t
+= MB_METACHARLEN(t
);
1677 if (pprog
&& pattry(pprog
, t
) && !--num
) {
1678 /* return pointer after matched char */
1679 t
+= (lastcharlen
= MB_METACHARLEN(t
));
1681 *prevcharlen
= lastcharlen
;
1683 *nextcharlen
= MB_METACHARLEN(t
);
1688 t
+= MB_METACHARLEN(t
);
1693 return down
? 0 : slen
+ 1;
1701 getindex(char **pptr
, Value v
, int flags
)
1703 int start
, end
, inv
= 0;
1704 char *s
= *pptr
, *tbrack
;
1707 /* Error handled after untokenizing */
1708 s
= parse_subscript(s
, flags
& SCANPM_DQUOTED
, ']');
1709 /* Now we untokenize everything except inull() markers so we can check *
1710 * for the '*' and '@' special subscripts. The inull()s are removed *
1711 * in getarg() after we know whether we're doing reverse indexing. */
1712 for (tbrack
= *pptr
+ 1; *tbrack
&& tbrack
!= s
; tbrack
++) {
1713 if (inull(*tbrack
) && !*++tbrack
)
1715 if (itok(*tbrack
)) /* Need to check for Nularg here? */
1716 *tbrack
= ztokens
[*tbrack
- Pound
];
1718 /* If we reached the end of the string (s == NULL) we have an error */
1722 zerr("invalid subscript");
1727 if ((s
[0] == '*' || s
[0] == '@') && s
+ 1 == tbrack
) {
1728 if ((v
->isarr
|| IS_UNSET_VALUE(v
)) && s
[0] == '@')
1729 v
->isarr
|= SCANPM_ISVAR_AT
;
1734 zlong we
= 0, dummy
;
1735 int startprevlen
, startnextlen
;
1737 start
= getarg(&s
, &inv
, v
, 0, &we
, &startprevlen
, &startnextlen
);
1740 if (!v
->isarr
&& start
!= 0) {
1744 * Note for the confused (= pws): this is an inverse
1745 * offset so at this stage we need to convert from
1746 * the immediate offset into the value that we have
1747 * into a logical character position.
1751 char *target
= t
+ start
- startprevlen
;
1757 * move up characters, counting how many we
1760 p
+= MB_METACHARLEN(p
);
1767 p
= target
; /* pretend we hit exactly */
1771 /* if start was too big, keep the difference */
1772 start
= nstart
+ (target
- p
) + 1;
1774 zlong startoff
= start
+ strlen(t
);
1776 dputs("BUG: can't have negative inverse offsets???");
1779 /* invalid: keep index but don't dereference */
1782 /* find start in full characters */
1784 for (p
= t
; p
< t
+ startoff
;)
1785 p
+= MB_METACHARLEN(p
);
1786 start
= - MB_METASTRLEN(p
);
1790 if (start
> 0 && (isset(KSHARRAYS
) || (v
->pm
->node
.flags
& PM_HASHED
)))
1792 if (v
->isarr
!= SCANPM_WANTINDEX
) {
1793 v
->flags
|= VALFLAG_INV
;
1799 zerr("invalid subscript");
1809 if ((com
= (*s
== ','))) {
1811 end
= getarg(&s
, &inv
, v
, 1, &dummy
, NULL
, NULL
);
1813 end
= we
? we
: start
;
1818 * Somehow the logic sometimes forces us to use the previous
1819 * or next character to what we would expect, which is
1820 * why we had to calculate them in getarg().
1823 start
-= startprevlen
;
1824 else if (start
== 0 && end
== 0)
1827 * Strictly, this range is entirely off the
1828 * start of the available index range.
1829 * This can't happen with KSH_ARRAYS; we already
1830 * altered the start index in getarg().
1831 * Are we being strict?
1833 if (isset(KSHZEROSUBSCRIPT
)) {
1836 * Treat this as accessing the first element of the
1842 * We are. Flag that this range is invalid
1843 * for setting elements. Set the indexes
1844 * to a range that returns empty for other accesses.
1846 v
->flags
|= VALFLAG_EMPTY
;
1853 if (v
->isarr
&& !com
&&
1854 (!(v
->isarr
& SCANPM_MATCHMANY
) ||
1855 !(v
->isarr
& (SCANPM_MATCHKEY
| SCANPM_MATCHVAL
|
1872 getvalue(Value v
, char **pptr
, int bracks
)
1874 return fetchvalue(v
, pptr
, bracks
, 0);
1879 fetchvalue(Value v
, char **pptr
, int bracks
, int flags
)
1887 if (idigit(c
= *s
)) {
1889 ppar
= zstrtol(s
, &s
, 10);
1893 else if ((ie
= itype_end(s
, IIDENT
, 0)) != s
)
1895 else if (c
== Quest
)
1897 else if (c
== Pound
)
1899 else if (c
== String
)
1901 else if (c
== Qstring
)
1905 else if (c
== '#' || c
== '-' || c
== '?' || c
== '$' ||
1906 c
== '!' || c
== '@' || c
== '*')
1915 memset(v
, 0, sizeof(*v
));
1917 v
= (Value
) hcalloc(sizeof *v
);
1920 v
->start
= ppar
- 1;
1928 isvarat
= (t
[0] == '@' && !t
[1]);
1929 pm
= (Param
) paramtab
->getnode(paramtab
, *t
== '0' ? "0" : t
);
1933 if (!pm
|| (pm
->node
.flags
& PM_UNSET
))
1936 memset(v
, 0, sizeof(*v
));
1938 v
= (Value
) hcalloc(sizeof *v
);
1939 if (PM_TYPE(pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
)) {
1940 /* Overload v->isarr as the flag bits for hashed arrays. */
1941 v
->isarr
= flags
| (isvarat
? SCANPM_ISVAR_AT
: 0);
1942 /* If no flags were passed, we need something to represent *
1943 * `true' yet differ from an explicit WANTVALS. Use a *
1944 * special flag for this case. */
1946 v
->isarr
= SCANPM_ARRONLY
;
1952 if (bracks
> 0 && (*s
== '[' || *s
== Inbrack
)) {
1953 if (getindex(&s
, v
, flags
)) {
1957 } else if (!(flags
& SCANPM_ASSIGNING
) && v
->isarr
&&
1958 itype_end(t
, IIDENT
, 1) != t
&& isset(KSHARRAYS
))
1959 v
->end
= 1, v
->isarr
= 0;
1966 * Check for large subscripts that might be erroneous.
1967 * This code is too gross in several ways:
1968 * - the limit is completely arbitrary
1969 * - the test vetoes operations on existing arrays
1970 * - it's not at all clear a general test on large arrays of
1971 * this kind is any use.
1973 * Until someone comes up with workable replacement code it's
1974 * therefore commented out.
1976 if (v
->start
> MAX_ARRLEN
) {
1977 zerr("subscript too %s: %d", "big", v
->start
+ !isset(KSHARRAYS
));
1980 if (v
->start
< -MAX_ARRLEN
) {
1981 zerr("subscript too %s: %d", "small", v
->start
);
1984 if (v
->end
> MAX_ARRLEN
+1) {
1985 zerr("subscript too %s: %d", "big", v
->end
- !!isset(KSHARRAYS
));
1988 if (v
->end
< -MAX_ARRLEN
) {
1989 zerr("subscript too %s: %d", "small", v
->end
);
1998 getstrvalue(Value v
)
2001 char buf
[BDIGBUFSIZE
];
2006 if ((v
->flags
& VALFLAG_INV
) && !(v
->pm
->node
.flags
& PM_HASHED
)) {
2007 sprintf(buf
, "%d", v
->start
);
2012 switch(PM_TYPE(v
->pm
->node
.flags
)) {
2014 /* (!v->isarr) should be impossible unless emulating ksh */
2015 if (!v
->isarr
&& EMULATION(EMULATE_KSH
)) {
2016 s
= dupstring("[0]");
2017 if (getindex(&s
, v
, 0) == 0)
2020 } /* else fall through */
2022 ss
= getvaluearr(v
);
2024 s
= sepjoin(ss
, NULL
, 1);
2027 v
->start
+= arrlen(ss
);
2028 s
= (v
->start
>= arrlen(ss
) || v
->start
< 0) ?
2029 (char *) hcalloc(1) : ss
[v
->start
];
2033 convbase(buf
, v
->pm
->gsu
.i
->getfn(v
->pm
), v
->pm
->base
);
2038 s
= convfloat(v
->pm
->gsu
.f
->getfn(v
->pm
),
2039 v
->pm
->base
, v
->pm
->node
.flags
, NULL
);
2042 s
= v
->pm
->gsu
.s
->getfn(v
->pm
);
2046 DPUTS(1, "BUG: param node without valid type");
2050 if (v
->flags
& VALFLAG_SUBST
) {
2051 if (v
->pm
->node
.flags
& (PM_LEFT
|PM_RIGHT_B
|PM_RIGHT_Z
)) {
2052 unsigned int fwidth
= v
->pm
->width
? v
->pm
->width
: MB_METASTRLEN(s
);
2053 switch (v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) {
2058 case PM_LEFT
| PM_RIGHT_Z
:
2060 if (v
->pm
->node
.flags
& PM_RIGHT_Z
)
2067 for (tend
= t
, t0
= 0; t0
< fwidth
&& *tend
; t0
++)
2068 tend
+= MB_METACHARLEN(tend
);
2070 * t0 is the number of characters from t used,
2071 * hence (fwidth - t0) is the number of padding
2072 * characters. fwidth is a misnomer: we use
2073 * character counts, not character widths.
2075 * (tend - t) is the number of bytes we need
2076 * to get fwidth characters or the entire string;
2077 * the characters may be multiple bytes.
2079 fwidth
-= t0
; /* padding chars remaining */
2080 t0
= tend
- t
; /* bytes to copy from string */
2081 s
= (char *) hcalloc(t0
+ fwidth
+ 1);
2084 memset(s
+ t0
, ' ', fwidth
);
2085 s
[t0
+ fwidth
] = '\0';
2089 case PM_RIGHT_Z
| PM_RIGHT_B
:
2092 /* Calculate length in possibly multibyte chars */
2093 unsigned int charlen
= MB_METASTRLEN(s
);
2095 if (charlen
< fwidth
) {
2096 char *valprefend
= s
;
2098 if (v
->pm
->node
.flags
& PM_RIGHT_Z
) {
2100 * This is a documented feature: when deciding
2101 * whether to pad with zeroes, ignore
2102 * leading blanks already in the value;
2103 * only look for numbers after that.
2104 * Not sure how useful this really is.
2105 * It's certainly confusing to code around.
2107 for (t
= s
; iblank(*t
); t
++)
2110 * Allow padding after initial minus
2111 * for numeric variables.
2113 if ((v
->pm
->node
.flags
&
2114 (PM_INTEGER
|PM_EFLOAT
|PM_FFLOAT
)) &&
2118 * Allow padding after initial 0x or
2119 * base# for integer variables.
2121 if (v
->pm
->node
.flags
& PM_INTEGER
) {
2122 if (isset(CBASES
) &&
2123 t
[0] == '0' && t
[1] == 'x')
2125 else if ((valprefend
= strchr(t
, '#')))
2131 else if (v
->pm
->node
.flags
&
2132 (PM_INTEGER
|PM_EFLOAT
|PM_FFLOAT
)) {
2133 /* zero always OK */
2134 } else if (!idigit(*t
))
2137 /* number of characters needed for padding */
2139 /* bytes from original string */
2141 t
= (char *) hcalloc(fwidth
+ t0
+ 1);
2142 /* prefix guaranteed to be single byte chars */
2143 preflen
= valprefend
- s
;
2145 (((v
->pm
->node
.flags
& PM_RIGHT_B
)
2146 || !zero
) ? ' ' : '0'), fwidth
);
2148 * Copy - or 0x or base# before any padding
2152 memcpy(t
, s
, preflen
);
2153 memcpy(t
+ preflen
+ fwidth
,
2154 valprefend
, t0
- preflen
);
2155 t
[fwidth
+ t0
] = '\0';
2158 /* Need to skip (charlen - fwidth) chars */
2159 for (t0
= charlen
- fwidth
; t0
; t0
--)
2160 s
+= MB_METACHARLEN(s
);
2166 switch (v
->pm
->node
.flags
& (PM_LOWER
| PM_UPPER
)) {
2168 s
= casemodify(s
, CASMOD_LOWER
);
2171 s
= casemodify(s
, CASMOD_UPPER
);
2175 if (v
->start
== 0 && v
->end
== -1)
2179 v
->start
+= strlen(s
);
2184 v
->end
+= strlen(s
);
2186 char *eptr
= s
+ v
->end
;
2188 v
->end
+= MB_METACHARLEN(eptr
);
2191 s
= (v
->start
> (int)strlen(s
)) ? dupstring("") : dupstring(s
+ v
->start
);
2192 if (v
->end
<= v
->start
)
2194 else if (v
->end
- v
->start
<= (int)strlen(s
))
2195 s
[v
->end
- v
->start
] = '\0';
2200 static char *nular
[] = {"", NULL
};
2204 getarrvalue(Value v
)
2209 return arrdup(nular
);
2210 else if (IS_UNSET_VALUE(v
))
2211 return arrdup(&nular
[1]);
2212 if (v
->flags
& VALFLAG_INV
) {
2213 char buf
[DIGBUFSIZE
];
2216 sprintf(buf
, "%d", v
->start
);
2217 s
[0] = dupstring(buf
);
2221 if (v
->start
== 0 && v
->end
== -1)
2224 v
->start
+= arrlen(s
);
2226 v
->end
+= arrlen(s
) + 1;
2227 if (v
->start
> arrlen(s
) || v
->start
< 0)
2230 s
= arrdup(s
+ v
->start
);
2231 if (v
->end
<= v
->start
)
2233 else if (v
->end
- v
->start
<= arrlen(s
))
2234 s
[v
->end
- v
->start
] = NULL
;
2240 getintvalue(Value v
)
2244 if (v
->flags
& VALFLAG_INV
)
2247 char **arr
= getarrvalue(v
);
2249 char *scal
= sepjoin(arr
, NULL
, 1);
2250 return mathevali(scal
);
2254 if (PM_TYPE(v
->pm
->node
.flags
) == PM_INTEGER
)
2255 return v
->pm
->gsu
.i
->getfn(v
->pm
);
2256 if (v
->pm
->node
.flags
& (PM_EFLOAT
|PM_FFLOAT
))
2257 return (zlong
)v
->pm
->gsu
.f
->getfn(v
->pm
);
2258 return mathevali(getstrvalue(v
));
2263 getnumvalue(Value v
)
2266 mn
.type
= MN_INTEGER
;
2271 } else if (v
->flags
& VALFLAG_INV
) {
2273 } else if (v
->isarr
) {
2274 char **arr
= getarrvalue(v
);
2276 char *scal
= sepjoin(arr
, NULL
, 1);
2277 return matheval(scal
);
2280 } else if (PM_TYPE(v
->pm
->node
.flags
) == PM_INTEGER
) {
2281 mn
.u
.l
= v
->pm
->gsu
.i
->getfn(v
->pm
);
2282 } else if (v
->pm
->node
.flags
& (PM_EFLOAT
|PM_FFLOAT
)) {
2284 mn
.u
.d
= v
->pm
->gsu
.f
->getfn(v
->pm
);
2286 return matheval(getstrvalue(v
));
2292 export_param(Param pm
)
2294 char buf
[BDIGBUFSIZE
], *val
;
2296 if (PM_TYPE(pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
)) {
2297 #if 0 /* Requires changes elsewhere in params.c and builtin.c */
2298 if (EMULATION(EMULATE_KSH
) /* isset(KSHARRAYS) */) {
2304 val
= getstrvalue(&v
);
2308 } else if (PM_TYPE(pm
->node
.flags
) == PM_INTEGER
)
2309 convbase(val
= buf
, pm
->gsu
.i
->getfn(pm
), pm
->base
);
2310 else if (pm
->node
.flags
& (PM_EFLOAT
|PM_FFLOAT
))
2311 val
= convfloat(pm
->gsu
.f
->getfn(pm
), pm
->base
,
2312 pm
->node
.flags
, NULL
);
2314 val
= pm
->gsu
.s
->getfn(pm
);
2321 setstrvalue(Value v
, char *val
)
2323 assignstrvalue(v
, val
, 0);
2328 assignstrvalue(Value v
, char *val
, int flags
)
2332 if (v
->pm
->node
.flags
& PM_READONLY
) {
2333 zerr("read-only variable: %s", v
->pm
->node
.nam
);
2337 if ((v
->pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
2338 zerr("%s: restricted", v
->pm
->node
.nam
);
2342 if ((v
->pm
->node
.flags
& PM_HASHED
) &&
2343 (v
->isarr
& (SCANPM_MATCHMANY
|SCANPM_ARRONLY
))) {
2344 zerr("%s: attempt to set slice of associative array", v
->pm
->node
.nam
);
2348 if (v
->flags
& VALFLAG_EMPTY
) {
2349 zerr("%s: assignment to invalid subscript range", v
->pm
->node
.nam
);
2353 v
->pm
->node
.flags
&= ~PM_UNSET
;
2354 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2356 if (v
->start
== 0 && v
->end
== -1) {
2357 v
->pm
->gsu
.s
->setfn(v
->pm
, val
);
2358 if ((v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) &&
2360 v
->pm
->width
= strlen(val
);
2365 z
= dupstring(v
->pm
->gsu
.s
->getfn(v
->pm
));
2367 if ((v
->flags
& VALFLAG_INV
) && unset(KSHARRAYS
))
2368 v
->start
--, v
->end
--;
2374 if (v
->start
> zlen
)
2380 } else if (v
->end
>= zlen
) {
2383 #ifdef MULTIBYTE_SUPPORT
2384 if (isset(MULTIBYTE
)) {
2385 v
->end
+= MB_METACHARLEN(z
+ v
->end
);
2394 else if (v
->end
> zlen
)
2396 x
= (char *) zalloc(v
->start
+ strlen(val
) + zlen
- v
->end
+ 1);
2397 strncpy(x
, z
, v
->start
);
2398 strcpy(x
+ v
->start
, val
);
2399 strcat(x
+ v
->start
, z
+ v
->end
);
2400 v
->pm
->gsu
.s
->setfn(v
->pm
, x
);
2407 if (flags
& ASSPM_ENV_IMPORT
) {
2409 ival
= zstrtol_underscore(val
, &ptr
, 0, 1);
2411 ival
= mathevali(val
);
2412 v
->pm
->gsu
.i
->setfn(v
->pm
, ival
);
2413 if ((v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) &&
2415 v
->pm
->width
= strlen(val
);
2418 if (!v
->pm
->base
&& lastbase
!= -1)
2419 v
->pm
->base
= lastbase
;
2425 if (flags
& ASSPM_ENV_IMPORT
) {
2428 mn
.u
.d
= strtod(val
, &ptr
);
2431 v
->pm
->gsu
.f
->setfn(v
->pm
, (mn
.type
& MN_FLOAT
) ? mn
.u
.d
:
2433 if ((v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) &&
2435 v
->pm
->width
= strlen(val
);
2441 char **ss
= (char **) zalloc(2 * sizeof(char *));
2450 if (foundparam
== NULL
)
2452 zerr("%s: attempt to set associative array to scalar",
2458 foundparam
->gsu
.s
->setfn(foundparam
, val
);
2462 if ((!v
->pm
->env
&& !(v
->pm
->node
.flags
& PM_EXPORTED
) &&
2463 !(isset(ALLEXPORT
) && !(v
->pm
->node
.flags
& PM_HASHELEM
))) ||
2464 (v
->pm
->node
.flags
& PM_ARRAY
) || v
->pm
->ename
)
2466 export_param(v
->pm
);
2471 setnumvalue(Value v
, mnumber val
)
2473 char buf
[BDIGBUFSIZE
], *p
;
2477 if (v
->pm
->node
.flags
& PM_READONLY
) {
2478 zerr("read-only variable: %s", v
->pm
->node
.nam
);
2481 if ((v
->pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
2482 zerr("%s: restricted", v
->pm
->node
.nam
);
2485 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2488 if ((val
.type
& MN_INTEGER
) || outputradix
) {
2489 if (!(val
.type
& MN_INTEGER
))
2490 val
.u
.l
= (zlong
) val
.u
.d
;
2491 p
= convbase_underscore(buf
, val
.u
.l
, outputradix
,
2494 p
= convfloat_underscore(val
.u
.d
, outputunderscore
);
2495 setstrvalue(v
, ztrdup(p
));
2498 v
->pm
->gsu
.i
->setfn(v
->pm
, (val
.type
& MN_INTEGER
) ? val
.u
.l
:
2500 setstrvalue(v
, NULL
);
2504 v
->pm
->gsu
.f
->setfn(v
->pm
, (val
.type
& MN_INTEGER
) ?
2505 (double)val
.u
.l
: val
.u
.d
);
2506 setstrvalue(v
, NULL
);
2513 setarrvalue(Value v
, char **val
)
2517 if (v
->pm
->node
.flags
& PM_READONLY
) {
2518 zerr("read-only variable: %s", v
->pm
->node
.nam
);
2522 if ((v
->pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
2523 zerr("%s: restricted", v
->pm
->node
.nam
);
2527 if (!(PM_TYPE(v
->pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
))) {
2529 zerr("%s: attempt to assign array value to non-array",
2533 if (v
->flags
& VALFLAG_EMPTY
) {
2534 zerr("%s: assignment to invalid subscript range", v
->pm
->node
.nam
);
2538 if (v
->start
== 0 && v
->end
== -1) {
2539 if (PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)
2540 arrhashsetfn(v
->pm
, val
, 0);
2542 v
->pm
->gsu
.a
->setfn(v
->pm
, val
);
2543 } else if (v
->start
== -1 && v
->end
== 0 &&
2544 PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
) {
2545 arrhashsetfn(v
->pm
, val
, 1);
2547 char **old
, **new, **p
, **q
, **r
;
2550 if ((PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)) {
2552 zerr("%s: attempt to set slice of associative array",
2556 if ((v
->flags
& VALFLAG_INV
) && unset(KSHARRAYS
)) {
2561 q
= old
= v
->pm
->gsu
.a
->getfn(v
->pm
);
2573 if (v
->end
< v
->start
)
2576 ll
= v
->start
+ arrlen(val
);
2578 ll
+= n
- v
->end
+ 1;
2580 p
= new = (char **) zshcalloc(sizeof(char *) * (ll
+ 1));
2582 for (i
= 0; i
< v
->start
; i
++)
2583 *p
++ = i
< n
? ztrdup(*q
++) : ztrdup("");
2585 *p
++ = ztrdup(*r
++);
2587 for (q
= old
+ v
->end
; *q
;)
2588 *p
++ = ztrdup(*q
++);
2591 v
->pm
->gsu
.a
->setfn(v
->pm
, new);
2596 /* Retrieve an integer parameter */
2605 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2607 return getintvalue(v
);
2610 /* Retrieve a numerical parameter, either integer or floating */
2619 if (!(v
= getvalue(&vbuf
, &s
, 1))) {
2621 mn
.type
= MN_INTEGER
;
2625 return getnumvalue(v
);
2628 /* Retrieve a scalar (string) parameter */
2637 if (!(v
= getvalue(&vbuf
, &s
, 0)))
2639 return getstrvalue(v
);
2642 /* Retrieve an array parameter */
2651 if (!idigit(*s
) && (v
= getvalue(&vbuf
, &s
, 0)) &&
2652 PM_TYPE(v
->pm
->node
.flags
) == PM_ARRAY
)
2653 return v
->pm
->gsu
.a
->getfn(v
->pm
);
2657 /* Retrieve an assoc array parameter as an array */
2666 if (!idigit(*s
) && (v
= getvalue(&vbuf
, &s
, 0)) &&
2667 PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)
2668 return paramvalarr(v
->pm
->gsu
.h
->getfn(v
->pm
), SCANPM_WANTVALS
);
2672 /* Retrieve the keys of an assoc array parameter as an array */
2681 if (!idigit(*s
) && (v
= getvalue(&vbuf
, &s
, 0)) &&
2682 PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)
2683 return paramvalarr(v
->pm
->gsu
.h
->getfn(v
->pm
), SCANPM_WANTKEYS
);
2689 assignsparam(char *s
, char *val
, int flags
)
2694 char *ss
, *copy
, *var
;
2700 zerr("not an identifier: %s", s
);
2702 errflag
|= ERRFLAG_ERROR
;
2706 if ((ss
= strchr(s
, '['))) {
2708 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2709 createparam(t
, PM_ARRAY
);
2711 if (v
->pm
->node
.flags
& PM_READONLY
) {
2712 zerr("read-only variable: %s", v
->pm
->node
.nam
);
2717 flags
&= ~ASSPM_WARN_CREATE
;
2722 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2723 createparam(t
, PM_SCALAR
);
2724 else if ((((v
->pm
->node
.flags
& PM_ARRAY
) && !(flags
& ASSPM_AUGMENT
)) ||
2725 (v
->pm
->node
.flags
& PM_HASHED
)) &&
2726 !(v
->pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
)) &&
2729 createparam(t
, PM_SCALAR
);
2733 flags
&= ~ASSPM_WARN_CREATE
;
2735 if (!v
&& !(v
= getvalue(&vbuf
, &t
, 1))) {
2740 if ((flags
& ASSPM_WARN_CREATE
) && v
->pm
->level
== 0)
2741 zwarn("scalar parameter %s created globally in function",
2743 if (flags
& ASSPM_AUGMENT
) {
2744 if (v
->start
== 0 && v
->end
== -1) {
2745 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2747 v
->start
= INT_MAX
; /* just append to scalar value */
2752 rhs
= matheval(val
);
2753 lhs
= getnumvalue(v
);
2754 if (lhs
.type
== MN_FLOAT
) {
2755 if ((rhs
.type
) == MN_FLOAT
)
2756 lhs
.u
.d
= lhs
.u
.d
+ rhs
.u
.d
;
2758 lhs
.u
.d
= lhs
.u
.d
+ (double)rhs
.u
.l
;
2760 if ((rhs
.type
) == MN_INTEGER
)
2761 lhs
.u
.l
= lhs
.u
.l
+ rhs
.u
.l
;
2763 lhs
.u
.l
= lhs
.u
.l
+ (zlong
)rhs
.u
.d
;
2765 setnumvalue(v
, lhs
);
2768 return v
->pm
; /* avoid later setstrvalue() call */
2770 if (unset(KSHARRAYS
)) {
2771 v
->start
= arrlen(v
->pm
->gsu
.a
->getfn(v
->pm
));
2772 v
->end
= v
->start
+ 1;
2774 /* ksh appends scalar to first element */
2781 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2786 v
->start
= v
->end
= strlen(v
->pm
->gsu
.s
->getfn(v
->pm
)) +
2793 zerr("attempt to add to slice of a numeric variable");
2798 /* treat slice as the end element */
2799 v
->start
= sstart
= v
->end
> 0 ? v
->end
- 1 : v
->end
;
2801 var
= getstrvalue(v
);
2805 val
= (char *)zalloc(lvar
+ strlen(val
) + 1);
2807 strcpy(val
+ lvar
, copy
);
2814 assignstrvalue(v
, val
, flags
);
2821 assignaparam(char *s
, char **val
, int flags
)
2829 zerr("not an identifier: %s", s
);
2831 errflag
|= ERRFLAG_ERROR
;
2835 if ((ss
= strchr(s
, '['))) {
2837 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2838 createparam(t
, PM_ARRAY
);
2840 flags
&= ~ASSPM_WARN_CREATE
;
2842 if (v
&& PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
) {
2844 zerr("%s: attempt to set slice of associative array",
2847 errflag
|= ERRFLAG_ERROR
;
2852 if (!(v
= fetchvalue(&vbuf
, &s
, 1, SCANPM_ASSIGNING
)))
2853 createparam(t
, PM_ARRAY
);
2854 else if (!(PM_TYPE(v
->pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
)) &&
2855 !(v
->pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
))) {
2856 int uniq
= v
->pm
->node
.flags
& PM_UNIQUE
;
2857 if (flags
& ASSPM_AUGMENT
) {
2858 /* insert old value at the beginning of the val array */
2860 int lv
= arrlen(val
);
2862 new = (char **) zalloc(sizeof(char *) * (lv
+ 2));
2863 *new = ztrdup(getstrvalue(v
));
2864 memcpy(new+1, val
, sizeof(char *) * (lv
+ 1));
2869 createparam(t
, PM_ARRAY
| uniq
);
2873 flags
&= ~ASSPM_WARN_CREATE
;
2876 if (!(v
= fetchvalue(&vbuf
, &t
, 1, SCANPM_ASSIGNING
))) {
2882 if ((flags
& ASSPM_WARN_CREATE
) && v
->pm
->level
== 0)
2883 zwarn("array parameter %s created globally in function",
2885 if (flags
& ASSPM_AUGMENT
) {
2886 if (v
->start
== 0 && v
->end
== -1) {
2887 if (PM_TYPE(v
->pm
->node
.flags
) & PM_ARRAY
) {
2888 v
->start
= arrlen(v
->pm
->gsu
.a
->getfn(v
->pm
));
2889 v
->end
= v
->start
+ 1;
2890 } else if (PM_TYPE(v
->pm
->node
.flags
) & PM_HASHED
)
2891 v
->start
= -1, v
->end
= 0;
2894 v
->start
= v
->end
--;
2895 else if (PM_TYPE(v
->pm
->node
.flags
) & PM_ARRAY
) {
2896 v
->end
= arrlen(v
->pm
->gsu
.a
->getfn(v
->pm
)) + v
->end
;
2897 v
->start
= v
->end
+ 1;
2902 setarrvalue(v
, val
);
2909 sethparam(char *s
, char **val
)
2916 zerr("not an identifier: %s", s
);
2918 errflag
|= ERRFLAG_ERROR
;
2921 if (strchr(s
, '[')) {
2923 zerr("nested associative arrays not yet supported");
2924 errflag
|= ERRFLAG_ERROR
;
2930 if (!(v
= fetchvalue(&vbuf
, &s
, 1, SCANPM_ASSIGNING
)))
2931 createparam(t
, PM_HASHED
);
2932 else if (!(PM_TYPE(v
->pm
->node
.flags
) & PM_HASHED
) &&
2933 !(v
->pm
->node
.flags
& PM_SPECIAL
)) {
2935 createparam(t
, PM_HASHED
);
2939 if (!(v
= fetchvalue(&vbuf
, &t
, 1, SCANPM_ASSIGNING
))) {
2943 setarrvalue(v
, val
);
2950 * Set a generic shell number, floating point or integer.
2955 setnparam(char *s
, mnumber val
)
2963 zerr("not an identifier: %s", s
);
2964 errflag
|= ERRFLAG_ERROR
;
2970 ss
= strchr(s
, '[');
2971 v
= getvalue(&vbuf
, &s
, 1);
2972 if (v
&& (v
->pm
->node
.flags
& (PM_ARRAY
|PM_HASHED
)) &&
2973 !(v
->pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
)) &&
2975 * not sure what KSHARRAYS has got to do with this...
2976 * copied this from assignsparam().
2978 unset(KSHARRAYS
) && !ss
) {
2979 unsetparam_pm(v
->pm
, 0, 1);
2984 /* s has been updated by getvalue, so check again */
2985 ss
= strchr(s
, '[');
2988 pm
= createparam(t
, ss
? PM_ARRAY
:
2989 (val
.type
& MN_INTEGER
) ? PM_INTEGER
: PM_FFLOAT
);
2991 pm
= (Param
) paramtab
->getnode(paramtab
, t
);
2992 DPUTS(!pm
, "BUG: parameter not created");
2995 } else if (val
.type
& MN_INTEGER
) {
2996 pm
->base
= outputradix
;
2998 v
= getvalue(&vbuf
, &t
, 1);
2999 DPUTS(!v
, "BUG: value not found for new parameter");
3001 setnumvalue(v
, val
);
3006 /* Simplified interface to setnparam */
3010 setiparam(char *s
, zlong val
)
3013 mnval
.type
= MN_INTEGER
;
3015 return setnparam(s
, mnval
);
3019 /* Unset a parameter */
3028 if ((pm
= (Param
) (paramtab
== realparamtab
?
3029 gethashnode2(paramtab
, s
) :
3030 paramtab
->getnode(paramtab
, s
))))
3031 unsetparam_pm(pm
, 0, 1);
3035 /* Unset a parameter */
3039 unsetparam_pm(Param pm
, int altflag
, int exp
)
3044 if ((pm
->node
.flags
& PM_READONLY
) && pm
->level
<= locallevel
) {
3045 zerr("read-only variable: %s", pm
->node
.nam
);
3048 if ((pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
3049 zerr("%s: restricted", pm
->node
.nam
);
3053 if (pm
->ename
&& !altflag
)
3054 altremove
= ztrdup(pm
->ename
);
3058 if (!(pm
->node
.flags
& PM_UNSET
))
3059 pm
->gsu
.s
->unsetfn(pm
, exp
);
3063 /* remove it under its alternate name if necessary */
3065 altpm
= (Param
) paramtab
->getnode(paramtab
, altremove
);
3066 /* tied parameters are at the same local level as each other */
3068 while (altpm
&& altpm
->level
> pm
->level
) {
3069 /* param under alternate name hidden by a local */
3074 if (oldpm
&& !altpm
->level
) {
3076 /* fudge things so removenode isn't called */
3079 unsetparam_pm(altpm
, 1, exp
);
3086 * If this was a local variable, we need to keep the old
3087 * struct so that it is resurrected at the right level.
3088 * This is partly because when an array/scalar value is set
3089 * and the parameter used to be the other sort, unsetparam()
3090 * is called. Beyond that, there is an ambiguity: should
3091 * foo() { local bar; unset bar; } make the global bar
3092 * available or not? The following makes the answer "no".
3094 * Some specials, such as those used in zle, still need removing
3095 * from the parameter table; they have the PM_REMOVABLE flag.
3097 if ((pm
->level
&& locallevel
>= pm
->level
) ||
3098 (pm
->node
.flags
& (PM_SPECIAL
|PM_REMOVABLE
)) == PM_SPECIAL
)
3101 /* remove parameter node from table */
3102 paramtab
->removenode(paramtab
, pm
->node
.nam
);
3106 paramtab
->addnode(paramtab
, oldpm
->node
.nam
, oldpm
);
3107 if ((PM_TYPE(oldpm
->node
.flags
) == PM_SCALAR
) &&
3108 !(pm
->node
.flags
& PM_HASHELEM
) &&
3109 (oldpm
->node
.flags
& PM_NAMEDDIR
) &&
3110 oldpm
->gsu
.s
== &stdscalar_gsu
)
3111 adduserdir(oldpm
->node
.nam
, oldpm
->u
.str
, 0, 0);
3112 if (oldpm
->node
.flags
& PM_EXPORTED
) {
3114 * Re-export the old value which we removed in typeset_single().
3115 * I don't think we need to test for ALL_EXPORT here, since if
3116 * it was used to export the parameter originally the parameter
3117 * should still have the PM_EXPORTED flag.
3119 export_param(oldpm
);
3123 paramtab
->freenode(&pm
->node
); /* free parameter node */
3128 /* Standard function to unset a parameter. This is mostly delegated to *
3129 * the specific set function.
3131 * This could usefully be made type-specific, but then we need
3132 * to be more careful when calling the unset method directly.
3137 stdunsetfn(Param pm
, UNUSED(int exp
))
3139 switch (PM_TYPE(pm
->node
.flags
)) {
3141 if (pm
->gsu
.s
->setfn
)
3142 pm
->gsu
.s
->setfn(pm
, NULL
);
3146 if (pm
->gsu
.a
->setfn
)
3147 pm
->gsu
.a
->setfn(pm
, NULL
);
3151 if (pm
->gsu
.h
->setfn
)
3152 pm
->gsu
.h
->setfn(pm
, NULL
);
3156 if (!(pm
->node
.flags
& PM_SPECIAL
))
3160 if ((pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
)) == PM_TIED
) {
3165 pm
->node
.flags
&= ~PM_TIED
;
3167 pm
->node
.flags
|= PM_UNSET
;
3170 /* Function to get value of an integer parameter */
3179 /* Function to set value of an integer parameter */
3183 intsetfn(Param pm
, zlong x
)
3188 /* Function to get value of a floating point parameter */
3192 floatgetfn(Param pm
)
3197 /* Function to set value of an integer parameter */
3201 floatsetfn(Param pm
, double x
)
3206 /* Function to get value of a scalar (string) parameter */
3212 return pm
->u
.str
? pm
->u
.str
: (char *) hcalloc(1);
3215 /* Function to set value of a scalar (string) parameter */
3219 strsetfn(Param pm
, char *x
)
3223 if (!(pm
->node
.flags
& PM_HASHELEM
) &&
3224 ((pm
->node
.flags
& PM_NAMEDDIR
) || isset(AUTONAMEDIRS
))) {
3225 pm
->node
.flags
|= PM_NAMEDDIR
;
3226 adduserdir(pm
->node
.nam
, x
, 0, 0);
3230 /* Function to get value of an array parameter */
3232 static char *nullarray
= NULL
;
3238 return pm
->u
.arr
? pm
->u
.arr
: &nullarray
;
3241 /* Function to set value of an array parameter */
3245 arrsetfn(Param pm
, char **x
)
3247 if (pm
->u
.arr
&& pm
->u
.arr
!= x
)
3248 freearray(pm
->u
.arr
);
3249 if (pm
->node
.flags
& PM_UNIQUE
)
3252 /* Arrays tied to colon-arrays may need to fix the environment */
3254 arrfixenv(pm
->ename
, x
);
3257 /* Function to get value of an association parameter */
3260 mod_export HashTable
3266 /* Function to set value of an association parameter */
3270 hashsetfn(Param pm
, HashTable x
)
3272 if (pm
->u
.hash
&& pm
->u
.hash
!= x
)
3273 deleteparamtable(pm
->u
.hash
);
3277 /* Function to dispose of setting of an unsettable hash */
3281 nullsethashfn(UNUSED(Param pm
), HashTable x
)
3283 deleteparamtable(x
);
3286 /* Function to set value of an association parameter using key/value pairs */
3290 arrhashsetfn(Param pm
, char **val
, int augment
)
3292 /* Best not to shortcut this by using the existing hash table, *
3293 * since that could cause trouble for special hashes. This way, *
3294 * it's up to pm->gsu.h->setfn() what to do. */
3295 int alen
= arrlen(val
);
3296 HashTable opmtab
= paramtab
, ht
= 0;
3298 Value v
= (Value
) hcalloc(sizeof *v
);
3303 zerr("bad set of key/value pairs for associative array");
3307 if (!(augment
&& (ht
= paramtab
= pm
->gsu
.h
->getfn(pm
))))
3308 ht
= paramtab
= newparamtable(17, pm
->node
.nam
);
3310 /* The parameter name is ztrdup'd... */
3311 v
->pm
= createparam(*aptr
, PM_SCALAR
|PM_UNSET
);
3313 * createparam() doesn't return anything if the parameter
3317 v
->pm
= (Param
) paramtab
->getnode(paramtab
, *aptr
);
3319 /* ...but we can use the value without copying. */
3320 setstrvalue(v
, *aptr
++);
3323 pm
->gsu
.h
->setfn(pm
, ht
);
3324 free(val
); /* not freearray() */
3328 * These functions are used as the set function for special parameters that
3329 * cannot be set by the user. The set is incomplete as the only such
3330 * parameters are scalar and integer.
3335 nullstrsetfn(UNUSED(Param pm
), char *x
)
3342 nullintsetfn(UNUSED(Param pm
), UNUSED(zlong x
))
3347 nullunsetfn(UNUSED(Param pm
), UNUSED(int exp
))
3351 /* Function to get value of generic special integer *
3352 * parameter. data is pointer to global variable *
3353 * containing the integer value. */
3357 intvargetfn(Param pm
)
3359 return *pm
->u
.valptr
;
3362 /* Function to set value of generic special integer *
3363 * parameter. data is pointer to global variable *
3364 * where the value is to be stored. */
3368 intvarsetfn(Param pm
, zlong x
)
3373 /* Function to set value of any ZLE-related integer *
3374 * parameter. data is pointer to global variable *
3375 * where the value is to be stored. */
3379 zlevarsetfn(Param pm
, zlong x
)
3381 zlong
*p
= pm
->u
.valptr
;
3384 if (p
== &zterm_lines
|| p
== &zterm_columns
)
3385 adjustwinsize(2 + (p
== &zterm_columns
));
3388 /* Function to set value of generic special scalar *
3389 * parameter. data is pointer to a character pointer *
3390 * representing the scalar (string). */
3394 strvarsetfn(Param pm
, char *x
)
3396 char **q
= ((char **)pm
->u
.data
);
3402 /* Function to get value of generic special scalar *
3403 * parameter. data is pointer to a character pointer *
3404 * representing the scalar (string). */
3408 strvargetfn(Param pm
)
3410 char *s
= *((char **)pm
->u
.data
);
3417 /* Function to get value of generic special array *
3418 * parameter. data is a pointer to the pointer to *
3419 * a pointer (a pointer to a variable length array *
3424 arrvargetfn(Param pm
)
3426 char **arrptr
= *((char ***)pm
->u
.data
);
3428 return arrptr
? arrptr
: &nullarray
;
3431 /* Function to set value of generic special array parameter. *
3432 * data is pointer to a variable length array of pointers which *
3433 * represents this array of scalars (strings). If pm->ename is *
3434 * non NULL, then it is a colon separated environment variable *
3435 * version of this array which will need to be updated. */
3439 arrvarsetfn(Param pm
, char **x
)
3441 char ***dptr
= (char ***)pm
->u
.data
;
3445 if (pm
->node
.flags
& PM_UNIQUE
)
3448 * Special tied arrays point to variables accessible in other
3449 * ways which need to be set to NULL. We can't do this
3450 * with user tied variables since we can leak memory.
3452 if ((pm
->node
.flags
& PM_SPECIAL
) && !x
)
3453 *dptr
= mkarray(NULL
);
3458 arrfixenv(pm
->ename
, x
);
3459 else if (*dptr
== path
)
3466 colonarrgetfn(Param pm
)
3468 char ***dptr
= (char ***)pm
->u
.data
;
3469 return *dptr
? zjoin(*dptr
, ':', 1) : "";
3474 colonarrsetfn(Param pm
, char *x
)
3476 char ***dptr
= (char ***)pm
->u
.data
;
3478 * We have to make sure this is never NULL, since that
3479 * can cause problems.
3484 *dptr
= colonsplit(x
, pm
->node
.flags
& PM_UNIQUE
);
3486 *dptr
= mkarray(NULL
);
3488 arrfixenv(pm
->node
.nam
, *dptr
);
3494 tiedarrgetfn(Param pm
)
3496 struct tieddata
*dptr
= (struct tieddata
*)pm
->u
.data
;
3497 return *dptr
->arrptr
? zjoin(*dptr
->arrptr
, STOUC(dptr
->joinchar
), 1) : "";
3502 tiedarrsetfn(Param pm
, char *x
)
3504 struct tieddata
*dptr
= (struct tieddata
*)pm
->u
.data
;
3507 freearray(*dptr
->arrptr
);
3510 if (imeta(dptr
->joinchar
))
3513 sepbuf
[1] = dptr
->joinchar
^ 32;
3518 sepbuf
[0] = dptr
->joinchar
;
3521 *dptr
->arrptr
= sepsplit(x
, sepbuf
, 0, 0);
3522 if (pm
->node
.flags
& PM_UNIQUE
)
3523 uniqarray(*dptr
->arrptr
);
3526 *dptr
->arrptr
= NULL
;
3528 arrfixenv(pm
->node
.nam
, *dptr
->arrptr
);
3533 tiedarrunsetfn(Param pm
, UNUSED(int exp
))
3536 * Special unset function because we allocated a struct tieddata
3537 * in typeset_single to hold the special data which we now
3540 pm
->gsu
.s
->setfn(pm
, NULL
);
3541 zfree(pm
->u
.data
, sizeof(struct tieddata
));
3542 /* paranoia -- shouldn't need these, but in case we reuse the struct... */
3546 pm
->node
.flags
&= ~PM_TIED
;
3547 pm
->node
.flags
|= PM_UNSET
;
3552 simple_arrayuniq(char **x
, int freeok
)
3557 /* Find duplicates and replace them with holes */
3559 for (t
= x
; t
< p
; t
++)
3560 if (*t
!= hole
&& !strcmp(*p
, *t
)) {
3566 /* Swap non-holes into holes in optimal jumps */
3567 for (p
= t
= x
; *t
!= NULL
; t
++) {
3571 if ((*t
= *p
) != NULL
)
3576 /* Erase all the remaining holes, just in case */
3583 arrayuniq_freenode(HashNode hn
)
3590 newuniqtable(zlong size
)
3592 HashTable ht
= newhashtable((int)size
, "arrayuniq", NULL
);
3593 /* ??? error checking */
3596 ht
->emptytable
= emptyhashtable
;
3597 ht
->filltable
= NULL
;
3598 ht
->cmpnodes
= strcmp
;
3599 ht
->addnode
= addhashnode
;
3600 ht
->getnode
= gethashnode2
;
3601 ht
->getnode2
= gethashnode2
;
3602 ht
->removenode
= removehashnode
;
3603 ht
->disablenode
= disablehashnode
;
3604 ht
->enablenode
= enablehashnode
;
3605 ht
->freenode
= arrayuniq_freenode
;
3606 ht
->printnode
= NULL
;
3613 arrayuniq(char **x
, int freeok
)
3615 char **it
, **write_it
;
3616 zlong array_size
= arrlen(x
);
3619 if (array_size
== 0)
3621 if (array_size
< 10 || !(ht
= newuniqtable(array_size
+ 1))) {
3622 /* fallback to simpler routine */
3623 simple_arrayuniq(x
, freeok
);
3627 for (it
= x
, write_it
= x
; *it
;) {
3628 if (! gethashnode2(ht
, *it
)) {
3629 HashNode new_node
= zhalloc(sizeof(struct hashnode
));
3631 /* Oops, out of heap memory, no way to recover */
3632 zerr("out of memory in arrayuniq");
3635 (void) addhashnode2(ht
, *it
, new_node
);
3649 deletehashtable(ht
);
3658 arrayuniq(x
, !zheapptr(*x
));
3663 zhuniqarray(char **x
)
3670 /* Function to get value of special parameter `#' and `ARGC' */
3674 poundgetfn(UNUSED(Param pm
))
3676 return arrlen(pparams
);
3679 /* Function to get value for special parameter `RANDOM' */
3683 randomgetfn(UNUSED(Param pm
))
3685 return rand() & 0x7fff;
3688 /* Function to set value of special parameter `RANDOM' */
3692 randomsetfn(UNUSED(Param pm
), zlong v
)
3694 srand((unsigned int)v
);
3697 /* Function to get value for special parameter `SECONDS' */
3701 intsecondsgetfn(UNUSED(Param pm
))
3704 struct timezone dummy_tz
;
3706 gettimeofday(&now
, &dummy_tz
);
3708 return (zlong
)(now
.tv_sec
- shtimer
.tv_sec
) +
3709 (zlong
)(now
.tv_usec
- shtimer
.tv_usec
) / (zlong
)1000000;
3712 /* Function to set value of special parameter `SECONDS' */
3716 intsecondssetfn(UNUSED(Param pm
), zlong x
)
3719 struct timezone dummy_tz
;
3722 gettimeofday(&now
, &dummy_tz
);
3723 diff
= (zlong
)now
.tv_sec
- x
;
3724 shtimer
.tv_sec
= diff
;
3725 if ((zlong
)shtimer
.tv_sec
!= diff
)
3726 zwarn("SECONDS truncated on assignment");
3727 shtimer
.tv_usec
= 0;
3732 floatsecondsgetfn(UNUSED(Param pm
))
3735 struct timezone dummy_tz
;
3737 gettimeofday(&now
, &dummy_tz
);
3739 return (double)(now
.tv_sec
- shtimer
.tv_sec
) +
3740 (double)(now
.tv_usec
- shtimer
.tv_usec
) / 1000000.0;
3745 floatsecondssetfn(UNUSED(Param pm
), double x
)
3748 struct timezone dummy_tz
;
3750 gettimeofday(&now
, &dummy_tz
);
3751 shtimer
.tv_sec
= now
.tv_sec
- (zlong
)x
;
3752 shtimer
.tv_usec
= now
.tv_usec
- (zlong
)((x
- (zlong
)x
) * 1000000.0);
3759 return (double)shtimer
.tv_sec
+ (double)shtimer
.tv_usec
/ 1000000.0;
3764 setrawseconds(double x
)
3766 shtimer
.tv_sec
= (zlong
)x
;
3767 shtimer
.tv_usec
= (zlong
)((x
- (zlong
)x
) * 1000000.0);
3772 setsecondstype(Param pm
, int on
, int off
)
3774 int newflags
= (pm
->node
.flags
| on
) & ~off
;
3775 int tp
= PM_TYPE(newflags
);
3776 /* Only one of the numeric types is allowed. */
3777 if (tp
== PM_EFLOAT
|| tp
== PM_FFLOAT
)
3779 pm
->gsu
.f
= &floatseconds_gsu
;
3781 else if (tp
== PM_INTEGER
)
3783 pm
->gsu
.i
= &intseconds_gsu
;
3787 pm
->node
.flags
= newflags
;
3791 /* Function to get value for special parameter `USERNAME' */
3795 usernamegetfn(UNUSED(Param pm
))
3797 return get_username();
3800 /* Function to set value of special parameter `USERNAME' */
3804 usernamesetfn(UNUSED(Param pm
), char *x
)
3806 #if defined(HAVE_SETUID) && defined(HAVE_GETPWNAM)
3807 struct passwd
*pswd
;
3809 if (x
&& (pswd
= getpwnam(x
)) && (pswd
->pw_uid
!= cached_uid
)) {
3810 # ifdef USE_INITGROUPS
3811 initgroups(x
, pswd
->pw_gid
);
3813 if (setgid(pswd
->pw_gid
))
3814 zwarn("failed to change group ID: %e", errno
);
3815 else if (setuid(pswd
->pw_uid
))
3816 zwarn("failed to change user ID: %e", errno
);
3818 zsfree(cached_username
);
3819 cached_username
= ztrdup(pswd
->pw_name
);
3820 cached_uid
= pswd
->pw_uid
;
3823 #endif /* HAVE_SETUID && HAVE_GETPWNAM */
3827 /* Function to get value for special parameter `UID' */
3831 uidgetfn(UNUSED(Param pm
))
3836 /* Function to set value of special parameter `UID' */
3840 uidsetfn(UNUSED(Param pm
), zlong x
)
3843 if (setuid((uid_t
)x
))
3844 zwarn("failed to change user ID: %e", errno
);
3848 /* Function to get value for special parameter `EUID' */
3852 euidgetfn(UNUSED(Param pm
))
3857 /* Function to set value of special parameter `EUID' */
3861 euidsetfn(UNUSED(Param pm
), zlong x
)
3864 if (seteuid((uid_t
)x
))
3865 zwarn("failed to change effective user ID: %e", errno
);
3869 /* Function to get value for special parameter `GID' */
3873 gidgetfn(UNUSED(Param pm
))
3878 /* Function to set value of special parameter `GID' */
3882 gidsetfn(UNUSED(Param pm
), zlong x
)
3885 if (setgid((gid_t
)x
))
3886 zwarn("failed to change group ID: %e", errno
);
3890 /* Function to get value for special parameter `EGID' */
3894 egidgetfn(UNUSED(Param pm
))
3899 /* Function to set value of special parameter `EGID' */
3903 egidsetfn(UNUSED(Param pm
), zlong x
)
3906 if (setegid((gid_t
)x
))
3907 zwarn("failed to change effective group ID: %e", errno
);
3913 ttyidlegetfn(UNUSED(Param pm
))
3915 struct stat ttystat
;
3917 if (SHTTY
== -1 || fstat(SHTTY
, &ttystat
))
3919 return time(NULL
) - ttystat
.st_atime
;
3922 /* Function to get value for special parameter `IFS' */
3926 ifsgetfn(UNUSED(Param pm
))
3931 /* Function to set value of special parameter `IFS' */
3935 ifssetfn(UNUSED(Param pm
), char *x
)
3942 /* Functions to set value of special parameters `LANG' and `LC_*' */
3945 static struct localename
{
3950 {"LC_COLLATE", LC_COLLATE
},
3953 {"LC_CTYPE", LC_CTYPE
},
3956 {"LC_MESSAGES", LC_MESSAGES
},
3959 {"LC_NUMERIC", LC_NUMERIC
},
3962 {"LC_TIME", LC_TIME
},
3971 struct localename
*ln
;
3974 if ((x2
= getsparam("LC_ALL")) && *x2
)
3978 * Set the global locale to the value passed, but override
3979 * this with any non-empty definitions for specific
3982 * We only use non-empty definitions because empty values aren't
3983 * valid as locales; when passed to setlocale() they mean "use the
3984 * environment variable", but if that's what we're setting the value
3985 * from this is meaningless. So just all $LANG to show through in
3988 setlocale(LC_ALL
, x
? x
: "");
3990 for (ln
= lc_names
; ln
->name
; ln
++)
3991 if ((x
= getsparam(ln
->name
)) && *x
)
3992 setlocale(ln
->category
, x
);
3998 lc_allsetfn(Param pm
, char *x
)
4002 * Treat an empty LC_ALL the same as an unset one,
4003 * namely by using LANG as the default locale but overriding
4004 * that with any LC_* that are set.
4007 x
= getsparam("LANG");
4015 setlocale(LC_ALL
, x
);
4020 langsetfn(Param pm
, char *x
)
4028 lcsetfn(Param pm
, char *x
)
4031 struct localename
*ln
;
4034 if ((x2
= getsparam("LC_ALL")) && *x2
)
4037 /* Treat empty LC_* the same as unset. */
4039 x
= getsparam("LANG");
4042 * If we've got no non-empty string at this
4043 * point (after checking $LANG, too),
4044 * we shouldn't bother setting anything.
4047 for (ln
= lc_names
; ln
->name
; ln
++)
4048 if (!strcmp(ln
->name
, pm
->node
.nam
))
4049 setlocale(ln
->category
, x
);
4053 #endif /* USE_LOCALE */
4055 /* Function to set value for special parameter `0' */
4059 argzerosetfn(UNUSED(Param pm
), char *x
)
4062 if (!isset(POSIXARGZERO
)) {
4064 argzero
= ztrdup(x
);
4070 /* Function to get value for special parameter `0' */
4074 argzerogetfn(UNUSED(Param pm
))
4076 if (isset(POSIXARGZERO
))
4081 /* Function to get value for special parameter `HISTSIZE' */
4085 histsizegetfn(UNUSED(Param pm
))
4090 /* Function to set value of special parameter `HISTSIZE' */
4094 histsizesetfn(UNUSED(Param pm
), zlong v
)
4096 if ((histsiz
= v
) < 1)
4101 /* Function to get value for special parameter `SAVEHIST' */
4105 savehistsizegetfn(UNUSED(Param pm
))
4110 /* Function to set value of special parameter `SAVEHIST' */
4114 savehistsizesetfn(UNUSED(Param pm
), zlong v
)
4116 if ((savehistsiz
= v
) < 0)
4120 /* Function to set value for special parameter `ERRNO' */
4124 errnosetfn(UNUSED(Param pm
), zlong x
)
4127 if ((zlong
)errno
!= x
)
4128 zwarn("errno truncated on assignment");
4131 /* Function to get value for special parameter `ERRNO' */
4135 errnogetfn(UNUSED(Param pm
))
4140 /* Function to get value for special parameter `KEYBOARD_HACK' */
4144 keyboardhackgetfn(UNUSED(Param pm
))
4148 buf
[0] = keyboardhackchar
;
4154 /* Function to set value of special parameter `KEYBOARD_HACK' */
4158 keyboardhacksetfn(UNUSED(Param pm
), char *x
)
4166 zwarn("Only one KEYBOARD_HACK character can be defined"); /* could be changed if needed */
4168 for (i
= 0; i
< len
; i
++) {
4169 if (!isascii(STOUC(x
[i
]))) {
4170 zwarn("KEYBOARD_HACK can only contain ASCII characters");
4174 keyboardhackchar
= len
? STOUC(x
[0]) : '\0';
4177 keyboardhackchar
= '\0';
4180 /* Function to get value for special parameter `histchar' */
4184 histcharsgetfn(UNUSED(Param pm
))
4195 /* Function to set value of special parameter `histchar' */
4199 histcharssetfn(UNUSED(Param pm
), char *x
)
4207 for (i
= 0; i
< len
; i
++) {
4208 if (!isascii(STOUC(x
[i
]))) {
4209 zwarn("HISTCHARS can only contain ASCII characters");
4213 bangchar
= len
? STOUC(x
[0]) : '\0';
4214 hatchar
= len
> 1 ? STOUC(x
[1]) : '\0';
4215 hashchar
= len
> 2 ? STOUC(x
[2]) : '\0';
4225 /* Function to get value for special parameter `HOME' */
4229 homegetfn(UNUSED(Param pm
))
4234 /* Function to set value of special parameter `HOME' */
4238 homesetfn(UNUSED(Param pm
), char *x
)
4241 if (x
&& isset(CHASELINKS
) && (home
= xsymlink(x
)))
4244 home
= x
? x
: ztrdup("");
4248 /* Function to get value for special parameter `WORDCHARS' */
4252 wordcharsgetfn(UNUSED(Param pm
))
4257 /* Function to set value of special parameter `WORDCHARS' */
4261 wordcharssetfn(UNUSED(Param pm
), char *x
)
4268 /* Function to get value for special parameter `_' */
4272 underscoregetfn(UNUSED(Param pm
))
4274 char *u
= dupstring(zunderscore
);
4280 /* Function used when we need to reinitialise the terminal */
4283 term_reinit_from_pm(void)
4285 /* If non-interactive, delay setting up term till we need it. */
4286 if (unset(INTERACTIVE
) || !*term
)
4287 termflags
|= TERM_UNKNOWN
;
4292 /* Function to get value for special parameter `TERM' */
4296 termgetfn(UNUSED(Param pm
))
4301 /* Function to set value of special parameter `TERM' */
4305 termsetfn(UNUSED(Param pm
), char *x
)
4308 term
= x
? x
: ztrdup("");
4309 term_reinit_from_pm();
4312 /* Function to get value of special parameter `TERMINFO' */
4316 terminfogetfn(UNUSED(Param pm
))
4318 return zsh_terminfo
? zsh_terminfo
: dupstring("");
4321 /* Function to set value of special parameter `TERMINFO' */
4325 terminfosetfn(Param pm
, char *x
)
4327 zsfree(zsh_terminfo
);
4331 * terminfo relies on the value being exported before
4332 * we reinitialise the terminal. This is a bit inefficient.
4334 if ((pm
->node
.flags
& PM_EXPORTED
) && x
)
4337 term_reinit_from_pm();
4340 /* Function to get value for special parameter `pipestatus' */
4344 pipestatgetfn(UNUSED(Param pm
))
4346 char **x
= (char **) zhalloc((numpipestats
+ 1) * sizeof(char *));
4347 char buf
[DIGBUFSIZE
], **p
;
4350 for (p
= x
, q
= pipestats
, i
= numpipestats
; i
--; p
++, q
++) {
4351 sprintf(buf
, "%d", *q
);
4352 *p
= dupstring(buf
);
4359 /* Function to get value for special parameter `pipestatus' */
4363 pipestatsetfn(UNUSED(Param pm
), char **x
)
4368 for (i
= 0; *x
&& i
< MAX_PIPESTATS
; i
++, x
++)
4369 pipestats
[i
] = atoi(*x
);
4378 arrfixenv(char *s
, char **t
)
4384 cmdnamtab
->emptytable(cmdnamtab
);
4386 pm
= (Param
) paramtab
->getnode(paramtab
, s
);
4389 * Only one level of a parameter can be exported. Unless
4390 * ALLEXPORT is set, this must be global.
4393 if (pm
->node
.flags
& PM_HASHELEM
)
4396 if (isset(ALLEXPORT
))
4397 pm
->node
.flags
|= PM_EXPORTED
;
4400 * Do not "fix" parameters that were not exported
4403 if (!(pm
->node
.flags
& PM_EXPORTED
))
4406 if (pm
->node
.flags
& PM_TIED
)
4407 joinchar
= STOUC(((struct tieddata
*)pm
->u
.data
)->joinchar
);
4411 addenv(pm
, t
? zjoin(t
, joinchar
, 1) : "");
4419 DPUTS(!str
, "Attempt to put null string into environment.");
4420 #ifdef USE_SET_UNSET_ENV
4422 * If we are using unsetenv() to remove values from the
4423 * environment, which is the safe thing to do, we
4424 * need to use setenv() to put them there in the first place.
4425 * Unfortunately this is a slightly different interface
4426 * from what zputenv() assumes.
4431 for (ptr
= str
; *ptr
&& STOUC(*ptr
) < 128 && *ptr
!= '='; ptr
++)
4433 if (STOUC(*ptr
) >= 128) {
4435 * Environment variables not in the portable character
4436 * set are non-standard and we don't really know of
4439 * We'll disable until someone complains.
4444 ret
= setenv(str
, ptr
+1, 1);
4448 DPUTS(1, "bad environment string");
4449 ret
= setenv(str
, ptr
, 1);
4460 /* First check if there is already an environment *
4461 * variable matching string `name'. */
4462 if (findenv(str
, &num_env
)) {
4463 environ
[num_env
] = str
;
4465 /* Else we have to make room and add it */
4466 num_env
= arrlen(environ
);
4467 environ
= (char **) zrealloc(environ
, (sizeof(char *)) * (num_env
+ 2));
4469 /* Now add it at the end */
4470 ep
= environ
+ num_env
;
4480 #ifndef USE_SET_UNSET_ENV
4483 findenv(char *name
, int *pos
)
4489 eq
= strchr(name
, '=');
4490 nlen
= eq
? eq
- name
: (int)strlen(name
);
4491 for (ep
= environ
; *ep
; ep
++)
4492 if (!strncmp (*ep
, name
, nlen
) && *((*ep
)+nlen
) == '=') {
4494 *pos
= ep
- environ
;
4503 /* Given *name = "foo", it searches the environment for string *
4504 * "foo=bar", and returns a pointer to the beginning of "bar" */
4511 return getenv(name
);
4515 for (ep
= environ
; *ep
; ep
++) {
4516 for (s
= *ep
, t
= name
; *s
&& *s
== *t
; s
++, t
++);
4517 if (*s
== '=' && !*t
)
4526 copyenvstr(char *s
, char *value
, int flags
)
4529 if ((*s
= *value
++) == Meta
)
4531 if (flags
& PM_LOWER
)
4533 else if (flags
& PM_UPPER
)
4540 addenv(Param pm
, char *value
)
4543 #ifndef USE_SET_UNSET_ENV
4544 char *oldenv
= 0, *env
= 0;
4548 * First check if there is already an environment
4549 * variable matching string `name'.
4551 if (findenv(pm
->node
.nam
, &pos
))
4552 oldenv
= environ
[pos
];
4555 newenv
= mkenvstr(pm
->node
.nam
, value
, pm
->node
.flags
);
4556 if (zputenv(newenv
)) {
4561 #ifdef USE_SET_UNSET_ENV
4563 * If we are using setenv/unsetenv to manage the environment,
4564 * we simply store the string we created in pm->env since
4565 * memory management of the environment is handled entirely
4568 * TODO: is this good enough to fix problem cases from
4569 * the other branch? If so, we don't actually need to
4570 * store pm->env at all, just a flag that the value was set.
4577 * Under Cygwin we must use putenv() to maintain consistency.
4578 * Unfortunately, current version (1.1.2) copies argument and may
4579 * silently reuse existing environment string. This tries to
4580 * check for both cases
4582 if (findenv(pm
->node
.nam
, &pos
)) {
4588 pm
->node
.flags
|= PM_EXPORTED
;
4593 DPUTS(1, "addenv should never reach the end");
4599 /* Given strings *name = "foo", *value = "bar", *
4600 * return a new string *str = "foo=bar". */
4604 mkenvstr(char *name
, char *value
, int flags
)
4606 char *str
, *s
= value
;
4607 int len_name
, len_value
= 0;
4609 len_name
= strlen(name
);
4611 while (*s
&& (*s
++ != Meta
|| *s
++ != 32))
4613 s
= str
= (char *) zalloc(len_name
+ len_value
+ 2);
4618 copyenvstr(s
, value
, flags
);
4624 /* Given *name = "foo", *value = "bar", add the *
4625 * string "foo=bar" to the environment. Return a *
4626 * pointer to the location of this new environment *
4630 #ifndef USE_SET_UNSET_ENV
4633 delenvvalue(char *x
)
4637 for (ep
= environ
; *ep
; ep
++) {
4642 for (; (ep
[0] = ep
[1]); ep
++);
4649 /* Delete a pointer from the list of pointers to environment *
4650 * variables by shifting all the other pointers up one slot. */
4656 #ifdef USE_SET_UNSET_ENV
4657 unsetenv(pm
->node
.nam
);
4660 delenvvalue(pm
->env
);
4664 * Note we don't remove PM_EXPORT from the flags. This
4665 * may be asking for trouble but we need to know later
4666 * if we restore this parameter to its old value.
4671 * Guts of convbase: this version can return the number of digits
4672 * sans any base discriminator.
4677 convbase_ptr(char *s
, zlong v
, int base
, int *ndigits
)
4684 if (base
>= -1 && base
<= 1)
4688 if (isset(CBASES
) && base
== 16)
4690 else if (isset(CBASES
) && base
== 8 && isset(OCTALZEROES
))
4692 else if (base
!= 10)
4693 sprintf(s
, "%d#", base
);
4699 for (x
= v
; x
; digs
++)
4710 s
[digs
--] = (dig
< 10) ? '0' + dig
: dig
- 10 + 'A';
4716 * Basic conversion of integer to a string given a base.
4718 * If negative no base discriminator is output.
4723 convbase(char *s
, zlong v
, int base
)
4725 convbase_ptr(s
, v
, base
, NULL
);
4729 * Add underscores to converted integer for readability with given spacing.
4730 * s is as for convbase: at least BDIGBUFSIZE.
4731 * If underscores were added, returned value with underscores comes from
4732 * heap, else the returned value is s.
4737 convbase_underscore(char *s
, zlong v
, int base
, int underscore
)
4739 char *retptr
, *sptr
, *dptr
;
4740 int ndigits
, nunderscore
, mod
, len
;
4742 convbase_ptr(s
, v
, base
, &ndigits
);
4744 if (underscore
<= 0)
4747 nunderscore
= (ndigits
- 1) / underscore
;
4751 retptr
= zhalloc(len
+ nunderscore
+ 1);
4753 memcpy(retptr
, s
, len
- ndigits
);
4755 dptr
= retptr
+ len
+ nunderscore
;
4764 if (++mod
== underscore
) {
4774 * Convert a floating point value for output.
4775 * Unlike convbase(), this has its own internal storage and returns
4776 * a value from the heap.
4781 convfloat(double dval
, int digits
, int flags
, FILE *fout
)
4783 char fmt
[] = "%.*e";
4784 char *prev_locale
, *ret
;
4787 * The difficulty with the buffer size is that a %f conversion
4788 * prints all digits before the decimal point: with 64 bit doubles,
4789 * that's around 310. We can't check without doing some quite
4790 * serious floating point operations we'd like to avoid.
4791 * Then we are liable to get all the digits
4792 * we asked for after the decimal point, or we should at least
4793 * bargain for it. So we just allocate 512 + digits. This
4794 * should work until somebody decides on 128-bit doubles.
4796 if (!(flags
& (PM_EFLOAT
|PM_FFLOAT
))) {
4798 * Conversion from a floating point expression without using
4799 * a variable. The best bet in this case just seems to be
4800 * to use the general %g format with something like the maximum
4807 if (flags
& PM_FFLOAT
)
4811 if (flags
& PM_EFLOAT
) {
4813 * Here, we are given the number of significant figures, but
4814 * %e wants the number of decimal places (unlike %g)
4820 prev_locale
= dupstring(setlocale(LC_NUMERIC
, NULL
));
4821 setlocale(LC_NUMERIC
, "POSIX");
4824 fprintf(fout
, fmt
, digits
, dval
);
4827 VARARR(char, buf
, 512 + digits
);
4828 sprintf(buf
, fmt
, digits
, dval
);
4829 if (!strchr(buf
, 'e') && !strchr(buf
, '.'))
4831 ret
= dupstring(buf
);
4834 if (prev_locale
) setlocale(LC_NUMERIC
, prev_locale
);
4840 * convert float to string with basic options but inserting underscores
4845 char *convfloat_underscore(double dval
, int underscore
)
4847 int ndigits_int
= 0, ndigits_frac
= 0, nunderscore
, len
;
4848 char *s
, *retptr
, *sptr
, *dptr
;
4850 s
= convfloat(dval
, 0, 0, NULL
);
4851 if (underscore
<= 0)
4855 * Count the number of digits before and after the decimal point, if any.
4860 while (idigit(*sptr
)) {
4866 while (idigit(*sptr
)) {
4873 * Work out how many underscores to insert --- remember we
4874 * put them in integer and fractional parts separately.
4876 nunderscore
= (ndigits_int
-1) / underscore
+ (ndigits_frac
-1) / underscore
;
4880 dptr
= retptr
= zhalloc(len
+ nunderscore
+ 1);
4883 * Insert underscores in integer part.
4884 * Grouping starts from the point in both directions.
4889 while (ndigits_int
) {
4891 if (--ndigits_int
&& !(ndigits_int
% underscore
))
4896 * Insert underscores in the fractional part.
4899 /* decimal point, we already checked */
4901 while (ndigits_frac
) {
4904 if (--ndigits_frac
&& mod
== underscore
) {
4910 /* Copy exponent and anything else up to null */
4911 while ((*dptr
++ = *sptr
++))
4916 /* Start a parameter scope */
4920 startparamscope(void)
4925 /* End a parameter scope: delete the parameters local to the scope. */
4933 /* This pops anything from a higher locallevel */
4934 saveandpophiststack(0, HFILE_USE_OPTIONS
);
4935 scanhashtable(paramtab
, 0, 0, 0, scanendscope
, 0);
4941 scanendscope(HashNode hn
, UNUSED(int flags
))
4943 Param pm
= (Param
)hn
;
4944 if (pm
->level
> locallevel
) {
4945 if ((pm
->node
.flags
& (PM_SPECIAL
|PM_REMOVABLE
)) == PM_SPECIAL
) {
4947 * Removable specials are normal in that they can be removed
4948 * to reveal an ordinary parameter beneath. Here we handle
4949 * non-removable specials, which were made local by stealth
4950 * (see newspecial code in typeset_single()). In fact the
4951 * visible pm is always the same struct; the pm->old is
4952 * just a place holder for old data and flags.
4954 Param tpm
= pm
->old
;
4956 if (!strcmp(pm
->node
.nam
, "SECONDS"))
4958 setsecondstype(pm
, PM_TYPE(tpm
->node
.flags
), PM_TYPE(pm
->node
.flags
));
4960 * We restore SECONDS by restoring its raw internal value
4961 * that we cached off into tpm->u.dval.
4963 setrawseconds(tpm
->u
.dval
);
4964 tpm
->node
.flags
|= PM_NORESTORE
;
4966 DPUTS(!tpm
|| PM_TYPE(pm
->node
.flags
) != PM_TYPE(tpm
->node
.flags
) ||
4967 !(tpm
->node
.flags
& PM_SPECIAL
),
4968 "BUG: in restoring scope of special parameter");
4970 pm
->node
.flags
= (tpm
->node
.flags
& ~PM_NORESTORE
);
4971 pm
->level
= tpm
->level
;
4972 pm
->base
= tpm
->base
;
4973 pm
->width
= tpm
->width
;
4977 if (!(tpm
->node
.flags
& (PM_NORESTORE
|PM_READONLY
)))
4978 switch (PM_TYPE(pm
->node
.flags
)) {
4980 pm
->gsu
.s
->setfn(pm
, tpm
->u
.str
);
4983 pm
->gsu
.i
->setfn(pm
, tpm
->u
.val
);
4987 pm
->gsu
.f
->setfn(pm
, tpm
->u
.dval
);
4990 pm
->gsu
.a
->setfn(pm
, tpm
->u
.arr
);
4993 pm
->gsu
.h
->setfn(pm
, tpm
->u
.hash
);
4996 zfree(tpm
, sizeof(*tpm
));
4998 if (pm
->node
.flags
& PM_EXPORTED
)
5001 unsetparam_pm(pm
, 0, 0);
5006 /**********************************/
5007 /* Parameter Hash Table Functions */
5008 /**********************************/
5012 freeparamnode(HashNode hn
)
5014 Param pm
= (Param
) hn
;
5016 /* Since the second flag to unsetfn isn't used, I don't *
5017 * know what its value should be. */
5019 pm
->gsu
.s
->unsetfn(pm
, 1);
5020 zsfree(pm
->node
.nam
);
5021 /* If this variable was tied by the user, ename was ztrdup'd */
5022 if (pm
->node
.flags
& PM_TIED
)
5024 zfree(pm
, sizeof(struct param
));
5027 /* Print a parameter */
5029 enum paramtypes_flags
{
5030 PMTF_USE_BASE
= (1<<0),
5031 PMTF_USE_WIDTH
= (1<<1),
5032 PMTF_TEST_LEVEL
= (1<<2)
5036 int binflag
; /* The relevant PM_FLAG(S) */
5037 const char *string
; /* String for verbose output */
5038 int typeflag
; /* Flag for typeset -? */
5039 int flags
; /* The enum above */
5042 static const struct paramtypes pmtypes
[] = {
5043 { PM_AUTOLOAD
, "undefined", 0, 0},
5044 { PM_INTEGER
, "integer", 'i', PMTF_USE_BASE
},
5045 { PM_EFLOAT
, "float", 'E', 0},
5046 { PM_FFLOAT
, "float", 'F', 0},
5047 { PM_ARRAY
, "array", 'a', 0},
5048 { PM_HASHED
, "association", 'A', 0},
5049 { 0, "local", 0, PMTF_TEST_LEVEL
},
5050 { PM_LEFT
, "left justified", 'L', PMTF_USE_WIDTH
},
5051 { PM_RIGHT_B
, "right justified", 'R', PMTF_USE_WIDTH
},
5052 { PM_RIGHT_Z
, "zero filled", 'Z', PMTF_USE_WIDTH
},
5053 { PM_LOWER
, "lowercase", 'l', 0},
5054 { PM_UPPER
, "uppercase", 'u', 0},
5055 { PM_READONLY
, "readonly", 'r', 0},
5056 { PM_TAGGED
, "tagged", 't', 0},
5057 { PM_EXPORTED
, "exported", 'x', 0}
5060 #define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
5063 printparamvalue(Param p
, int printflags
)
5067 if (p
->node
.flags
& PM_AUTOLOAD
) {
5071 if (printflags
& PRINT_KV_PAIR
)
5073 else if ((printflags
& PRINT_TYPESET
) &&
5074 (PM_TYPE(p
->node
.flags
) == PM_ARRAY
|| PM_TYPE(p
->node
.flags
) == PM_HASHED
))
5075 printf("%s=", p
->node
.nam
);
5079 /* How the value is displayed depends *
5080 * on the type of the parameter */
5081 switch (PM_TYPE(p
->node
.flags
)) {
5083 /* string: simple output */
5084 if (p
->gsu
.s
->getfn
&& (t
= p
->gsu
.s
->getfn(p
)))
5085 quotedzputs(t
, stdout
);
5089 #ifdef ZSH_64_BIT_TYPE
5090 fputs(output64(p
->gsu
.i
->getfn(p
)), stdout
);
5092 printf("%ld", p
->gsu
.i
->getfn(p
));
5098 convfloat(p
->gsu
.f
->getfn(p
), p
->base
, p
->node
.flags
, stdout
);
5102 if (!(printflags
& PRINT_KV_PAIR
))
5104 u
= p
->gsu
.a
->getfn(p
);
5106 quotedzputs(*u
++, stdout
);
5109 quotedzputs(*u
++, stdout
);
5112 if (!(printflags
& PRINT_KV_PAIR
))
5117 if (!(printflags
& PRINT_KV_PAIR
))
5120 HashTable ht
= p
->gsu
.h
->getfn(p
);
5122 scanhashtable(ht
, 1, 0, PM_UNSET
,
5123 ht
->printnode
, PRINT_KV_PAIR
);
5125 if (!(printflags
& PRINT_KV_PAIR
))
5129 if (printflags
& PRINT_KV_PAIR
)
5137 printparamnode(HashNode hn
, int printflags
)
5139 Param p
= (Param
) hn
;
5142 if (p
->node
.flags
& PM_UNSET
) {
5143 if (isset(POSIXBUILTINS
) && (p
->node
.flags
& PM_READONLY
) &&
5144 (printflags
& PRINT_TYPESET
))
5147 * Special POSIX rules: show the parameter as readonly
5148 * even though it's unset, but with no value.
5150 printflags
|= PRINT_NAMEONLY
;
5156 if (printflags
& PRINT_TYPESET
) {
5157 if ((p
->node
.flags
& (PM_READONLY
|PM_SPECIAL
)) ==
5158 (PM_READONLY
|PM_SPECIAL
)) {
5160 * It's not possible to restore the state of
5161 * these, so don't output.
5166 * Printing the value of array: this needs to be on
5167 * a separate line so more care is required.
5169 array_typeset
= (PM_TYPE(p
->node
.flags
) == PM_ARRAY
||
5170 PM_TYPE(p
->node
.flags
) == PM_HASHED
) &&
5171 !(printflags
& PRINT_NAMEONLY
);
5172 if (array_typeset
&& (p
->node
.flags
& PM_READONLY
)) {
5174 * We need to create the array before making it
5177 printf("typeset -a ");
5178 zputs(p
->node
.nam
, stdout
);
5180 printparamvalue(p
, printflags
);
5181 printflags
|= PRINT_NAMEONLY
;
5188 /* Print the attributes of the parameter */
5189 if (printflags
& (PRINT_TYPE
|PRINT_TYPESET
)) {
5190 int doneminus
= 0, i
;
5191 const struct paramtypes
*pmptr
;
5193 for (pmptr
= pmtypes
, i
= 0; i
< PMTYPES_SIZE
; i
++, pmptr
++) {
5195 if (pmptr
->flags
& PMTF_TEST_LEVEL
) {
5198 } else if (p
->node
.flags
& pmptr
->binflag
)
5202 if (printflags
& PRINT_TYPESET
) {
5203 if (pmptr
->typeflag
) {
5208 putchar(pmptr
->typeflag
);
5211 printf("%s ", pmptr
->string
);
5213 if ((pmptr
->flags
& PMTF_USE_BASE
) && p
->base
) {
5214 printf("%d ", p
->base
);
5217 if ((pmptr
->flags
& PMTF_USE_WIDTH
) && p
->width
) {
5218 printf("%d ", p
->width
);
5227 if ((printflags
& PRINT_NAMEONLY
) ||
5228 ((p
->node
.flags
& PM_HIDEVAL
) && !(printflags
& PRINT_INCLUDEVALUE
))) {
5229 zputs(p
->node
.nam
, stdout
);
5232 quotedzputs(p
->node
.nam
, stdout
);
5236 printparamvalue(p
, printflags
);