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 */
63 char **path
, /* $path */
64 **fignore
; /* $fignore */
68 char *argzero
, /* $0 */
70 *nullcmd
, /* $NULLCMD */
71 *oldpwd
, /* $OLDPWD */
72 *zoptarg
, /* $OPTARG */
73 *prompt
, /* $PROMPT */
74 *prompt2
, /* $PROMPT2 */
75 *prompt3
, /* $PROMPT3 */
76 *prompt4
, /* $PROMPT4 */
77 *readnullcmd
, /* $READNULLCMD */
78 *rprompt
, /* $RPROMPT */
79 *rprompt2
, /* $RPROMPT2 */
80 *sprompt
, /* $SPROMPT */
81 *wordchars
, /* $WORDCHARS */
82 *zsh_name
; /* $ZSH_NAME */
86 *postedit
, /* $POSTEDIT */
88 *ttystrname
, /* $TTY */
93 zlong lastval
, /* $? */
96 columns
, /* $COLUMNS */
99 zsh_subshell
; /* $ZSH_SUBSHELL */
101 zlong lineno
, /* $LINENO */
102 zoptind
, /* $OPTIND */
108 mod_export
unsigned char bangchar
;
110 unsigned char hatchar
, hashchar
;
112 /* $SECONDS = now.tv_sec - shtimer.tv_sec
113 * + (now.tv_usec - shtimer.tv_usec) / 1000000.0
114 * (rounded to an integer if the parameter is not set to float) */
117 struct timeval shtimer
;
119 /* 0 if this $TERM setup is usable, otherwise it contains TERM_* flags */
122 mod_export
int termflags
;
124 /* Standard methods for get/set/unset pointers in parameters */
127 mod_export
const struct gsu_scalar stdscalar_gsu
=
128 { strgetfn
, strsetfn
, stdunsetfn
};
130 mod_export
const struct gsu_scalar varscalar_gsu
=
131 { strvargetfn
, strvarsetfn
, stdunsetfn
};
133 mod_export
const struct gsu_scalar nullsetscalar_gsu
=
134 { strgetfn
, nullstrsetfn
, NULL
};
137 mod_export
const struct gsu_integer stdinteger_gsu
=
138 { intgetfn
, intsetfn
, stdunsetfn
};
140 mod_export
const struct gsu_integer varinteger_gsu
=
141 { intvargetfn
, intvarsetfn
, stdunsetfn
};
143 mod_export
const struct gsu_integer nullsetinteger_gsu
=
144 { intgetfn
, NULL
, NULL
};
147 mod_export
const struct gsu_float stdfloat_gsu
=
148 { floatgetfn
, floatsetfn
, stdunsetfn
};
151 mod_export
const struct gsu_array stdarray_gsu
=
152 { arrgetfn
, arrsetfn
, stdunsetfn
};
154 mod_export
const struct gsu_array vararray_gsu
=
155 { arrvargetfn
, arrvarsetfn
, stdunsetfn
};
158 mod_export
const struct gsu_hash stdhash_gsu
=
159 { hashgetfn
, hashsetfn
, stdunsetfn
};
161 mod_export
const struct gsu_hash nullsethash_gsu
=
162 { hashgetfn
, nullsethashfn
, nullunsetfn
};
165 /* Non standard methods (not exported) */
166 static const struct gsu_integer pound_gsu
=
167 { poundgetfn
, nullintsetfn
, stdunsetfn
};
168 static const struct gsu_integer errno_gsu
=
169 { errnogetfn
, errnosetfn
, stdunsetfn
};
170 static const struct gsu_integer gid_gsu
=
171 { gidgetfn
, gidsetfn
, stdunsetfn
};
172 static const struct gsu_integer egid_gsu
=
173 { egidgetfn
, egidsetfn
, stdunsetfn
};
174 static const struct gsu_integer histsize_gsu
=
175 { histsizegetfn
, histsizesetfn
, stdunsetfn
};
176 static const struct gsu_integer random_gsu
=
177 { randomgetfn
, randomsetfn
, stdunsetfn
};
178 static const struct gsu_integer savehist_gsu
=
179 { savehistsizegetfn
, savehistsizesetfn
, stdunsetfn
};
180 static const struct gsu_integer intseconds_gsu
=
181 { intsecondsgetfn
, intsecondssetfn
, stdunsetfn
};
182 static const struct gsu_float floatseconds_gsu
=
183 { floatsecondsgetfn
, floatsecondssetfn
, stdunsetfn
};
184 static const struct gsu_integer uid_gsu
=
185 { uidgetfn
, uidsetfn
, stdunsetfn
};
186 static const struct gsu_integer euid_gsu
=
187 { euidgetfn
, euidsetfn
, stdunsetfn
};
188 static const struct gsu_integer ttyidle_gsu
=
189 { ttyidlegetfn
, nullintsetfn
, stdunsetfn
};
191 static const struct gsu_scalar username_gsu
=
192 { usernamegetfn
, usernamesetfn
, stdunsetfn
};
193 static const struct gsu_scalar dash_gsu
=
194 { dashgetfn
, nullstrsetfn
, stdunsetfn
};
195 static const struct gsu_scalar histchars_gsu
=
196 { histcharsgetfn
, histcharssetfn
, stdunsetfn
};
197 static const struct gsu_scalar home_gsu
=
198 { homegetfn
, homesetfn
, stdunsetfn
};
199 static const struct gsu_scalar term_gsu
=
200 { termgetfn
, termsetfn
, stdunsetfn
};
201 static const struct gsu_scalar wordchars_gsu
=
202 { wordcharsgetfn
, wordcharssetfn
, stdunsetfn
};
203 static const struct gsu_scalar ifs_gsu
=
204 { ifsgetfn
, ifssetfn
, stdunsetfn
};
205 static const struct gsu_scalar underscore_gsu
=
206 { underscoregetfn
, nullstrsetfn
, stdunsetfn
};
208 static const struct gsu_scalar lc_blah_gsu
=
209 { strgetfn
, lcsetfn
, stdunsetfn
};
210 static const struct gsu_scalar lang_gsu
=
211 { strgetfn
, langsetfn
, stdunsetfn
};
212 static const struct gsu_scalar lc_all_gsu
=
213 { strgetfn
, lc_allsetfn
, stdunsetfn
};
216 static const struct gsu_integer varint_readonly_gsu
=
217 { intvargetfn
, nullintsetfn
, stdunsetfn
};
218 static const struct gsu_integer zlevar_gsu
=
219 { intvargetfn
, zlevarsetfn
, stdunsetfn
};
221 static const struct gsu_scalar colonarr_gsu
=
222 { colonarrgetfn
, colonarrsetfn
, stdunsetfn
};
224 static const struct gsu_integer argc_gsu
=
225 { poundgetfn
, nullintsetfn
, stdunsetfn
};
226 static const struct gsu_array pipestatus_gsu
=
227 { pipestatgetfn
, pipestatsetfn
, stdunsetfn
};
229 /* Nodes for special parameters for parameter hash table */
231 #ifdef HAVE_UNION_INIT
233 typedef struct param initparam
;
236 typedef struct iparam
{
237 struct hashnode
*next
;
238 char *nam
; /* hash data */
239 int flags
; /* PM_* flags (defined in zsh.h) */
241 void *gsu
; /* get/set/unset methods */
242 int base
; /* output base */
243 int width
; /* output field width */
244 char *env
; /* location in environment, if exported */
245 char *ename
; /* name of corresponding environment var */
246 Param old
; /* old struct for use with local */
247 int level
; /* if (old != NULL), level of localness */
251 static initparam special_params
[] ={
252 #define GSU(X) BR((GsuScalar)(void *)(&(X)))
253 #define NULL_GSU BR((GsuScalar)(void *)NULL)
254 #define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
255 IPDEF1("#", pound_gsu
, PM_READONLY
),
256 IPDEF1("ERRNO", errno_gsu
, 0),
257 IPDEF1("GID", gid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
258 IPDEF1("EGID", egid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
259 IPDEF1("HISTSIZE", histsize_gsu
, PM_RESTRICTED
),
260 IPDEF1("RANDOM", random_gsu
, 0),
261 IPDEF1("SAVEHIST", savehist_gsu
, PM_RESTRICTED
),
262 IPDEF1("SECONDS", intseconds_gsu
, 0),
263 IPDEF1("UID", uid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
264 IPDEF1("EUID", euid_gsu
, PM_DONTIMPORT
| PM_RESTRICTED
),
265 IPDEF1("TTYIDLE", ttyidle_gsu
, PM_READONLY
),
267 #define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
268 IPDEF2("USERNAME", username_gsu
, PM_DONTIMPORT
|PM_RESTRICTED
),
269 IPDEF2("-", dash_gsu
, PM_READONLY
),
270 IPDEF2("histchars", histchars_gsu
, PM_DONTIMPORT
),
271 IPDEF2("HOME", home_gsu
, PM_UNSET
),
272 IPDEF2("TERM", term_gsu
, 0),
273 IPDEF2("WORDCHARS", wordchars_gsu
, 0),
274 IPDEF2("IFS", ifs_gsu
, PM_DONTIMPORT
),
275 IPDEF2("_", underscore_gsu
, PM_READONLY
),
278 # define LCIPDEF(name) IPDEF2(name, lc_blah_gsu, PM_UNSET)
279 IPDEF2("LANG", lang_gsu
, PM_UNSET
),
280 IPDEF2("LC_ALL", lc_all_gsu
, PM_UNSET
),
282 LCIPDEF("LC_COLLATE"),
288 LCIPDEF("LC_MESSAGES"),
291 LCIPDEF("LC_NUMERIC"),
296 #endif /* USE_LOCALE */
298 #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}
299 IPDEF4("!", &lastpid
),
301 IPDEF4("?", &lastval
),
302 IPDEF4("HISTCMD", &curhist
),
303 IPDEF4("LINENO", &lineno
),
304 IPDEF4("PPID", &ppid
),
305 IPDEF4("ZSH_SUBSHELL", &zsh_subshell
),
307 #define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(varinteger_gsu),10,0,NULL,NULL,NULL,0}
308 IPDEF5("COLUMNS", &columns
, zlevar_gsu
),
309 IPDEF5("LINES", &lines
, zlevar_gsu
),
310 IPDEF5("OPTIND", &zoptind
, varinteger_gsu
),
311 IPDEF5("SHLVL", &shlvl
, varinteger_gsu
),
312 IPDEF5("TRY_BLOCK_ERROR", &try_errflag
, varinteger_gsu
),
314 #define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
315 IPDEF7("OPTARG", &zoptarg
),
316 IPDEF7("NULLCMD", &nullcmd
),
317 IPDEF7("POSTEDIT", &postedit
),
318 IPDEF7("READNULLCMD", &readnullcmd
),
319 IPDEF7("PS1", &prompt
),
320 IPDEF7("RPS1", &rprompt
),
321 IPDEF7("RPROMPT", &rprompt
),
322 IPDEF7("PS2", &prompt2
),
323 IPDEF7("RPS2", &rprompt2
),
324 IPDEF7("RPROMPT2", &rprompt2
),
325 IPDEF7("PS3", &prompt3
),
326 IPDEF7("PS4", &prompt4
),
327 IPDEF7("SPROMPT", &sprompt
),
328 IPDEF7("0", &argzero
),
330 #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}
331 IPDEF8("CDPATH", &cdpath
, "cdpath", 0),
332 IPDEF8("FIGNORE", &fignore
, "fignore", 0),
333 IPDEF8("FPATH", &fpath
, "fpath", 0),
334 IPDEF8("MAILPATH", &mailpath
, "mailpath", 0),
335 IPDEF8("WATCH", &watch
, "watch", 0),
336 IPDEF8("PATH", &path
, "path", PM_RESTRICTED
),
337 IPDEF8("PSVAR", &psvar
, "psvar", 0),
339 /* MODULE_PATH is not imported for security reasons */
340 IPDEF8("MODULE_PATH", &module_path
, "module_path", PM_DONTIMPORT
|PM_RESTRICTED
),
342 #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}
343 #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
344 IPDEF9F("*", &pparams
, NULL
, PM_ARRAY
|PM_SPECIAL
|PM_DONTIMPORT
|PM_READONLY
),
345 IPDEF9F("@", &pparams
, NULL
, PM_ARRAY
|PM_SPECIAL
|PM_DONTIMPORT
|PM_READONLY
),
346 {{NULL
,NULL
,0},BR(NULL
),NULL_GSU
,0,0,NULL
,NULL
,NULL
,0},
348 #define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
350 /* The following parameters are not available in sh/ksh compatibility *
351 * mode. All of these have sh compatible equivalents. */
352 IPDEF1("ARGC", argc_gsu
, PM_READONLY
),
353 IPDEF2("HISTCHARS", histchars_gsu
, PM_DONTIMPORT
),
354 IPDEF4("status", &lastval
),
355 IPDEF7("prompt", &prompt
),
356 IPDEF7("PROMPT", &prompt
),
357 IPDEF7("PROMPT2", &prompt2
),
358 IPDEF7("PROMPT3", &prompt3
),
359 IPDEF7("PROMPT4", &prompt4
),
360 IPDEF8("MANPATH", &manpath
, "manpath", 0),
361 IPDEF9("argv", &pparams
, NULL
),
362 IPDEF9("fignore", &fignore
, "FIGNORE"),
363 IPDEF9("cdpath", &cdpath
, "CDPATH"),
364 IPDEF9("fpath", &fpath
, "FPATH"),
365 IPDEF9("mailpath", &mailpath
, "MAILPATH"),
366 IPDEF9("manpath", &manpath
, "MANPATH"),
367 IPDEF9("psvar", &psvar
, "PSVAR"),
368 IPDEF9("watch", &watch
, "WATCH"),
370 IPDEF9F("module_path", &module_path
, "MODULE_PATH", PM_RESTRICTED
),
371 IPDEF9F("path", &path
, "PATH", PM_RESTRICTED
),
373 IPDEF10("pipestatus", pipestatus_gsu
),
375 {{NULL
,NULL
,0},BR(NULL
),NULL_GSU
,0,0,NULL
,NULL
,NULL
,0},
379 * Special way of referring to the positional parameters. Unlike $*
380 * and $@, this is not readonly. This parameter is not directly
381 * visible in user space.
383 initparam argvparam_pm
= IPDEF9F("", &pparams
, NULL
, \
384 PM_ARRAY
|PM_SPECIAL
|PM_DONTIMPORT
);
388 #define IS_UNSET_VALUE(V) \
389 ((V) && (!(V)->pm || ((V)->pm->node.flags & PM_UNSET) || \
390 !(V)->pm->node.nam || !*(V)->pm->node.nam))
392 static Param argvparam
;
394 /* hash table containing the parameters */
397 mod_export HashTable paramtab
, realparamtab
;
401 newparamtable(int size
, char const *name
)
406 ht
= newhashtable(size
, name
, NULL
);
409 ht
->emptytable
= emptyhashtable
;
410 ht
->filltable
= NULL
;
411 ht
->cmpnodes
= strcmp
;
412 ht
->addnode
= addhashnode
;
413 ht
->getnode
= getparamnode
;
414 ht
->getnode2
= getparamnode
;
415 ht
->removenode
= removehashnode
;
416 ht
->disablenode
= NULL
;
417 ht
->enablenode
= NULL
;
418 ht
->freenode
= freeparamnode
;
419 ht
->printnode
= printparamnode
;
426 getparamnode(HashTable ht
, const char *nam
)
428 HashNode hn
= gethashnode2(ht
, nam
);
429 Param pm
= (Param
) hn
;
431 if (pm
&& pm
->u
.str
&& (pm
->node
.flags
& PM_AUTOLOAD
)) {
432 char *mn
= dupstring(pm
->u
.str
);
434 (void)ensurefeature(mn
, "p:", (pm
->node
.flags
& PM_AUTOALL
) ? NULL
:
436 hn
= gethashnode2(ht
, nam
);
439 * This used to be a warning, but surely if we allow
440 * stuff to go ahead with the autoload stub with
441 * no error status we're in for all sorts of mayhem?
443 zerr("unknown parameter: %s", nam
);
449 /* Copy a parameter hash table */
451 static HashTable outtable
;
455 scancopyparams(HashNode hn
, UNUSED(int flags
))
457 /* Going into a real parameter, so always use permanent storage */
458 Param pm
= (Param
)hn
;
459 Param tpm
= (Param
) zshcalloc(sizeof *tpm
);
460 tpm
->node
.nam
= ztrdup(pm
->node
.nam
);
461 copyparam(tpm
, pm
, 0);
462 addhashnode(outtable
, tpm
->node
.nam
, tpm
);
467 copyparamtable(HashTable ht
, char *name
)
469 HashTable nht
= newparamtable(ht
->hsize
, name
);
471 scanhashtable(ht
, 0, 0, 0, scancopyparams
, 0);
476 /* Flag to freeparamnode to unset the struct */
480 /* Function to delete a parameter table. */
484 deleteparamtable(HashTable t
)
486 /* The parameters in the hash table need to be unset *
487 * before being deleted. */
488 int odelunset
= delunset
;
491 delunset
= odelunset
;
494 static unsigned numparamvals
;
498 scancountparams(UNUSED(HashNode hn
), int flags
)
501 if ((flags
& SCANPM_WANTKEYS
) && (flags
& SCANPM_WANTVALS
))
505 static Patprog scanprog
;
506 static char *scanstr
;
507 static char **paramvals
;
508 static Param foundparam
;
512 scanparamvals(HashNode hn
, int flags
)
517 if (numparamvals
&& !(flags
& SCANPM_MATCHMANY
) &&
518 (flags
& (SCANPM_MATCHVAL
|SCANPM_MATCHKEY
|SCANPM_KEYMATCH
)))
521 if ((flags
& SCANPM_KEYMATCH
)) {
522 char *tmp
= dupstring(v
.pm
->node
.nam
);
527 if (!(prog
= patcompile(tmp
, 0, NULL
)) || !pattry(prog
, scanstr
))
529 } else if ((flags
& SCANPM_MATCHKEY
) && !pattry(scanprog
, v
.pm
->node
.nam
)) {
533 if (flags
& SCANPM_WANTKEYS
) {
534 paramvals
[numparamvals
++] = v
.pm
->node
.nam
;
535 if (!(flags
& (SCANPM_WANTVALS
|SCANPM_MATCHVAL
)))
538 v
.isarr
= (PM_TYPE(v
.pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
));
542 paramvals
[numparamvals
] = getstrvalue(&v
);
543 if (flags
& SCANPM_MATCHVAL
) {
544 if (pattry(scanprog
, paramvals
[numparamvals
])) {
545 numparamvals
+= ((flags
& SCANPM_WANTVALS
) ? 1 :
546 !(flags
& SCANPM_WANTKEYS
));
547 } else if (flags
& SCANPM_WANTKEYS
)
548 --numparamvals
; /* Value didn't match, discard key */
556 paramvalarr(HashTable ht
, int flags
)
558 DPUTS((flags
& (SCANPM_MATCHKEY
|SCANPM_MATCHVAL
)) && !scanprog
,
559 "BUG: scanning hash without scanprog set");
562 scanhashtable(ht
, 0, 0, PM_UNSET
, scancountparams
, flags
);
563 paramvals
= (char **) zhalloc((numparamvals
+ 1) * sizeof(char *));
566 scanhashtable(ht
, 0, 0, PM_UNSET
, scanparamvals
, flags
);
568 paramvals
[numparamvals
] = 0;
572 /* Return the full array (no indexing) referred to by a Value. *
573 * The array value is cached for the lifetime of the Value. */
581 else if (PM_TYPE(v
->pm
->node
.flags
) == PM_ARRAY
)
582 return v
->arr
= v
->pm
->gsu
.a
->getfn(v
->pm
);
583 else if (PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
) {
584 v
->arr
= paramvalarr(v
->pm
->gsu
.h
->getfn(v
->pm
), v
->isarr
);
585 /* Can't take numeric slices of associative arrays */
587 v
->end
= numparamvals
+ 1;
594 * Split environment string into (name, value) pair.
595 * this is used to avoid in-place editing of environment table
596 * that results in core dump on some systems
600 split_env_string(char *env
, char **name
, char **value
)
604 if (!env
|| !name
|| !value
)
607 tenv
= strcpy(zhalloc(strlen(env
) + 1), env
);
608 for (str
= tenv
; *str
&& *str
!= '='; str
++)
610 if (str
!= tenv
&& *str
== '=') {
619 /* Set up parameter hash table. This will add predefined *
620 * parameter entries as well as setting up parameter table *
621 * entries for environment variables we inherit. */
625 createparamtable(void)
628 #if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV)
632 char **envp
, **envp2
, **sigptr
, **t
;
633 char buf
[50], *str
, *iname
, *ivalue
, *hostnam
;
634 int oae
= opts
[ALLEXPORT
];
636 struct utsname unamebuf
;
640 paramtab
= realparamtab
= newparamtable(151, "paramtab");
642 /* Add the special parameters to the hash table */
643 for (ip
= special_params
; ip
->node
.nam
; ip
++)
644 paramtab
->addnode(paramtab
, ztrdup(ip
->node
.nam
), ip
);
645 if (!EMULATION(EMULATE_SH
|EMULATE_KSH
))
646 while ((++ip
)->node
.nam
)
647 paramtab
->addnode(paramtab
, ztrdup(ip
->node
.nam
), ip
);
649 argvparam
= (Param
) &argvparam_pm
;
653 /* Add the standard non-special parameters which have to *
654 * be initialized before we copy the environment variables. *
655 * We don't want to override whatever values the user has *
656 * given them in the environment. */
658 setiparam("MAILCHECK", 60);
659 setiparam("LOGCHECK", 60);
660 setiparam("KEYTIMEOUT", 40);
661 setiparam("LISTMAX", 100);
663 * We used to get the output baud rate here. However, that's
664 * pretty irrelevant to a terminal on an X display and can lead
665 * to unnecessary delays if it's wrong (which it probably is).
666 * Furthermore, even if the output is slow it's very likely
667 * to be because of WAN delays, not covered by the output
669 * So allow the user to set it in the special cases where it's
672 setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX
));
673 setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT
));
674 setsparam("WATCHFMT", ztrdup(default_watchfmt
));
676 hostnam
= (char *)zalloc(256);
677 gethostname(hostnam
, 256);
678 setsparam("HOST", ztrdup(hostnam
));
681 setsparam("LOGNAME", ztrdup((str
= getlogin()) && *str
? str
: cached_username
));
683 #if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV)
684 /* Copy the environment variables we are inheriting to dynamic *
685 * memory, so we can do mallocs and frees on it. */
686 envsize
= sizeof(char *)*(1 + arrlen(environ
));
687 new_environ
= (char **) zalloc(envsize
);
688 memcpy(new_environ
, environ
, envsize
);
689 environ
= new_environ
;
692 /* Use heap allocation to avoid many small alloc/free calls */
695 /* Now incorporate environment variables we are inheriting *
696 * into the parameter hash table. Copy them into dynamic *
697 * memory so that we can free them if needed */
698 for (envp
= envp2
= environ
; *envp2
; envp2
++) {
699 if (split_env_string(*envp2
, &iname
, &ivalue
)) {
700 if (!idigit(*iname
) && isident(iname
) && !strchr(iname
, '[')) {
701 if ((!(pm
= (Param
) paramtab
->getnode(paramtab
, iname
)) ||
702 !(pm
->node
.flags
& PM_DONTIMPORT
|| pm
->node
.flags
& PM_EXPORTED
)) &&
703 (pm
= setsparam(iname
, metafy(ivalue
, -1, META_DUP
)))) {
704 pm
->node
.flags
|= PM_EXPORTED
;
705 if (pm
->node
.flags
& PM_SPECIAL
)
706 pm
->env
= mkenvstr (pm
->node
.nam
,
707 getsparam(pm
->node
.nam
), pm
->node
.flags
);
709 pm
->env
= ztrdup(*envp2
);
710 #ifndef USE_SET_UNSET_ENV
718 #ifndef USE_SET_UNSET_ENV
721 opts
[ALLEXPORT
] = oae
;
723 if (EMULATION(EMULATE_ZSH
))
726 * For native emulation we always set the variable home
729 pm
= (Param
) paramtab
->getnode(paramtab
, "HOME");
730 pm
->node
.flags
&= ~PM_UNSET
;
731 if (!(pm
->node
.flags
& PM_EXPORTED
))
734 pm
= (Param
) paramtab
->getnode(paramtab
, "LOGNAME");
735 if (!(pm
->node
.flags
& PM_EXPORTED
))
736 addenv(pm
, pm
->u
.str
);
737 pm
= (Param
) paramtab
->getnode(paramtab
, "SHLVL");
738 sprintf(buf
, "%d", (int)++shlvl
);
739 /* shlvl value in environment needs updating unconditionally */
742 /* Add the standard non-special parameters */
745 if(uname(&unamebuf
)) setsparam("CPUTYPE", ztrdup("unknown"));
748 machinebuf
= ztrdup(unamebuf
.machine
);
749 setsparam("CPUTYPE", machinebuf
);
753 setsparam("CPUTYPE", ztrdup("unknown"));
755 setsparam("MACHTYPE", ztrdup(MACHTYPE
));
756 setsparam("OSTYPE", ztrdup(OSTYPE
));
757 setsparam("TTY", ztrdup(ttystrname
));
758 setsparam("VENDOR", ztrdup(VENDOR
));
759 setsparam("ZSH_NAME", ztrdup(zsh_name
));
760 setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION
));
761 setsparam("ZSH_PATCHLEVEL", ztrdup(ZSH_PATCHLEVEL
));
762 setaparam("signals", sigptr
= zalloc((SIGCOUNT
+4) * sizeof(char *)));
763 for (t
= sigs
; (*sigptr
++ = ztrdup(*t
++)); );
768 /* assign various functions used for non-special parameters */
772 assigngetset(Param pm
)
774 switch (PM_TYPE(pm
->node
.flags
)) {
776 pm
->gsu
.s
= &stdscalar_gsu
;
779 pm
->gsu
.i
= &stdinteger_gsu
;
783 pm
->gsu
.f
= &stdfloat_gsu
;
786 pm
->gsu
.a
= &stdarray_gsu
;
789 pm
->gsu
.h
= &stdhash_gsu
;
792 DPUTS(1, "BUG: tried to create param node without valid flag");
797 /* Create a parameter, so that it can be assigned to. Returns NULL if the *
798 * parameter already exists or can't be created, otherwise returns the *
799 * parameter node. If a parameter of the same name exists in an outer *
800 * scope, it is hidden by a newly created parameter. An already existing *
801 * parameter node at the current level may be `created' and returned *
802 * provided it is unset and not special. If the parameter can't be *
803 * created because it already exists, the PM_UNSET flag is cleared. */
807 createparam(char *name
, int flags
)
811 if (paramtab
!= realparamtab
)
812 flags
= (flags
& ~PM_EXPORTED
) | PM_HASHELEM
;
814 if (name
!= nulstring
) {
815 oldpm
= (Param
) (paramtab
== realparamtab
?
816 gethashnode2(paramtab
, name
) :
817 paramtab
->getnode(paramtab
, name
));
819 DPUTS(oldpm
&& oldpm
->level
> locallevel
,
820 "BUG: old local parameter not deleted");
821 if (oldpm
&& (oldpm
->level
== locallevel
|| !(flags
& PM_LOCAL
))) {
822 if (!(oldpm
->node
.flags
& PM_UNSET
) || (oldpm
->node
.flags
& PM_SPECIAL
)) {
823 oldpm
->node
.flags
&= ~PM_UNSET
;
824 if ((oldpm
->node
.flags
& PM_SPECIAL
) && oldpm
->ename
) {
826 (Param
) paramtab
->getnode(paramtab
, oldpm
->ename
);
828 altpm
->node
.flags
&= ~PM_UNSET
;
832 if ((oldpm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
833 zerr("%s: restricted", name
);
838 pm
->base
= pm
->width
= 0;
841 pm
= (Param
) zshcalloc(sizeof *pm
);
842 if ((pm
->old
= oldpm
)) {
844 * needed to avoid freeing oldpm, but we do take it
845 * out of the environment when it's hidden.
849 paramtab
->removenode(paramtab
, name
);
851 paramtab
->addnode(paramtab
, ztrdup(name
), pm
);
854 if (isset(ALLEXPORT
) && !(flags
& PM_HASHELEM
))
855 flags
|= PM_EXPORTED
;
857 pm
= (Param
) hcalloc(sizeof *pm
);
858 pm
->node
.nam
= nulstring
;
860 pm
->node
.flags
= flags
& ~PM_LOCAL
;
862 if(!(pm
->node
.flags
& PM_SPECIAL
))
867 /* Empty dummy function for special hash parameters. */
875 /* Create a simple special hash parameter. */
879 createspecialhash(char *name
, GetNodeFunc get
, ScanTabFunc scan
, int flags
)
884 if (!(pm
= createparam(name
, PM_SPECIAL
|PM_HASHED
|flags
)))
887 pm
->level
= pm
->old
? locallevel
: 0;
888 pm
->gsu
.h
= (flags
& PM_READONLY
) ? &stdhash_gsu
:
890 pm
->u
.hash
= ht
= newhashtable(0, name
, NULL
);
893 ht
->emptytable
= (TableFunc
) shempty
;
894 ht
->filltable
= NULL
;
895 ht
->addnode
= (AddNodeFunc
) shempty
;
896 ht
->getnode
= ht
->getnode2
= get
;
897 ht
->removenode
= (RemoveNodeFunc
) shempty
;
898 ht
->disablenode
= NULL
;
899 ht
->enablenode
= NULL
;
900 ht
->freenode
= (FreeNodeFunc
) shempty
;
901 ht
->printnode
= printparamnode
;
908 /* Copy a parameter */
912 copyparam(Param tpm
, Param pm
, int toplevel
)
915 * Note that tpm, into which we're copying, may not be in permanent
916 * storage. However, the values themselves are later used directly
917 * to set the parameter, so must be permanently allocated (in accordance
918 * with sets.?fn() usage).
920 tpm
->node
.flags
= pm
->node
.flags
;
921 tpm
->base
= pm
->base
;
922 tpm
->width
= pm
->width
;
924 tpm
->node
.flags
&= ~PM_SPECIAL
;
925 switch (PM_TYPE(pm
->node
.flags
)) {
927 tpm
->u
.str
= ztrdup(pm
->gsu
.s
->getfn(pm
));
930 tpm
->u
.val
= pm
->gsu
.i
->getfn(pm
);
934 tpm
->u
.dval
= pm
->gsu
.f
->getfn(pm
);
937 tpm
->u
.arr
= zarrdup(pm
->gsu
.a
->getfn(pm
));
940 tpm
->u
.hash
= copyparamtable(pm
->gsu
.h
->getfn(pm
), pm
->node
.nam
);
944 * If called from inside an associative array, that array is later going
945 * to be passed as a real parameter, so we need the gets and sets
946 * functions to be useful. However, the saved associated array is
947 * not itself special, so we just use the standard ones.
948 * This is also why we switch off PM_SPECIAL.
954 /* Return 1 if the string s is a valid identifier, else return 0. */
963 ne
= noeval
; /* save the current value of noeval */
964 if (!*s
) /* empty string is definitely not valid */
968 /* If the first character is `s' is a digit, then all must be */
969 for (ss
= ++s
; *ss
; ss
++)
973 /* Find the first character in `s' not in the iident type table */
974 ss
= itype_end(s
, IIDENT
, 0);
977 /* If the next character is not [, then it is *
978 * definitely not a valid identifier. */
984 /* Require balanced [ ] pairs with something between */
985 if (!(ss
= parse_subscript(++ss
, 1)))
992 * Parse a single argument to a parameter subscript.
993 * The subscripts starts at *str; *str is updated (input/output)
995 * *inv is set to indicate if the subscript is reversed (output)
996 * v is the Value for the parameter being accessed (input; note
997 * v->isarr may be modified, and if v is a hash the parameter will
998 * be updated to the element of the hash)
999 * a2 is 1 if this is the second subscript of a range (input)
1000 * *w is only set if we need to find the end of a word (input; should
1001 * be set to 0 by the caller).
1003 * The final two arguments are to support multibyte characters.
1004 * If supplied they are set to the length of the character before
1005 * the index position and the one at the index position. If
1006 * multibyte characters are not in use they are set to 1 for
1007 * consistency. Note they aren't fully handled if a2 is non-zero,
1008 * since they aren't needed.
1010 * Returns a raw offset into the value from the start or end (i.e.
1011 * after the arithmetic for Meta and possible multibyte characters has
1012 * been taken into account). This actually gives the offset *after*
1013 * the character in question; subtract *prevcharlen if necessary.
1018 getarg(char **str
, int *inv
, Value v
, int a2
, zlong
*w
,
1019 int *prevcharlen
, int *nextcharlen
)
1021 int hasbeg
= 0, word
= 0, rev
= 0, ind
= 0, down
= 0, l
, i
, ishash
;
1022 int keymatch
= 0, needtok
= 0, arglen
, len
;
1023 char *s
= *str
, *sep
= NULL
, *t
, sav
, *d
, **ta
, **p
, *tt
, c
;
1024 zlong num
= 1, beg
= 0, r
= 0, quote_arg
= 0;
1025 Patprog pprog
= NULL
;
1027 ishash
= (v
->pm
&& PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
);
1033 /* first parse any subscription flags */
1034 if (v
->pm
&& (*s
== '(' || *s
== Inpar
)) {
1037 for (s
++; *s
!= ')' && *s
!= Outpar
&& s
!= *str
; s
++) {
1041 keymatch
= down
= ind
= 0;
1059 down
= keymatch
= 0;
1062 rev
= ind
= down
= 1;
1066 /* If the parameter is a scalar, then make subscription *
1067 * work on a per-word basis instead of characters. */
1078 t
= get_strarg(++s
, &arglen
);
1083 num
= mathevalarg(s
+ arglen
, &d
);
1091 t
= get_strarg(++s
, &arglen
);
1096 if ((beg
= mathevalarg(s
+ arglen
, &d
)) > 0)
1105 /* This gives the string that separates words *
1106 * (for use with the `w' flag). */
1107 t
= get_strarg(++s
, &arglen
);
1113 sep
= escapes
? getkeystring(s
, &waste
, GETKEYS_SEP
, NULL
)
1121 word
= rev
= ind
= down
= keymatch
= 0;
1133 if (v
->isarr
& SCANPM_WANTKEYS
)
1134 *inv
= (ind
|| !(v
->isarr
& SCANPM_WANTVALS
));
1135 else if (v
->isarr
& SCANPM_WANTVALS
)
1140 v
->isarr
|= SCANPM_WANTKEYS
;
1141 v
->isarr
&= ~SCANPM_WANTVALS
;
1143 v
->isarr
|= SCANPM_WANTVALS
;
1145 * This catches the case where we are using "k" (rather
1146 * than "K") on a hash.
1148 if (!down
&& keymatch
&& ishash
)
1149 v
->isarr
&= ~SCANPM_MATCHMANY
;
1155 (c
= *t
) && ((c
!= Outbrack
&&
1156 (ishash
|| c
!= ',')) || i
); t
++) {
1157 /* Untokenize inull() except before brackets and double-quotes */
1160 if (c
== '[' || c
== ']' ||
1161 c
== '(' || c
== ')' ||
1162 c
== '{' || c
== '}') {
1163 /* This test handles nested subscripts in hash keys */
1165 *t
= ztokens
[*t
- Pound
];
1168 } else if (c
!= '"')
1169 *t
= ztokens
[*t
- Pound
];
1172 /* Inbrack and Outbrack are probably never found here ... */
1173 if (c
== '[' || c
== Inbrack
)
1175 else if (c
== ']' || c
== Outbrack
)
1182 s
= dupstrpfx(s
, t
- s
);
1184 /* If we're NOT reverse subscripting, strip the inull()s so brackets *
1185 * are not backslashed after parsestr(). Otherwise leave them alone *
1186 * so that the brackets will be escaped when we patcompile() or when *
1187 * subscript arithmetic is performed (for nested subscripts). */
1188 if (ishash
&& (keymatch
|| !rev
))
1195 remnulargs(s
); /* This is probably always a no-op, but ... */
1198 HashTable ht
= v
->pm
->gsu
.h
->getfn(v
->pm
);
1200 ht
= newparamtable(17, v
->pm
->node
.nam
);
1201 v
->pm
->gsu
.h
->setfn(v
->pm
, ht
);
1204 if (!(v
->pm
= (Param
) ht
->getnode(ht
, s
))) {
1205 HashTable tht
= paramtab
;
1207 v
->pm
= createparam(s
, PM_SCALAR
|PM_UNSET
);
1210 v
->isarr
= (*inv
? SCANPM_WANTINDEX
: 0);
1212 *inv
= 0; /* We've already obtained the "index" (key) */
1214 r
= isset(KSHARRAYS
) ? 1 : 0;
1216 r
= mathevalarg(s
, &s
);
1217 if (isset(KSHARRAYS
) && r
>= 0)
1220 if (word
&& !v
->isarr
) {
1221 s
= t
= getstrvalue(v
);
1222 i
= wordcount(s
, sep
, 0);
1231 while ((d
= findword(&s
, sep
)) && --r
);
1235 if (!a2
&& *tt
!= ',')
1236 *w
= (zlong
)(s
- t
);
1238 return (a2
? s
: d
+ 1) - t
;
1239 } else if (!v
->isarr
&& !word
) {
1240 int lastcharlen
= 1;
1243 * Note for the confused (= pws): the index r we
1244 * have so far is that specified by the user. The value
1245 * passed back is an offset from the start or end of
1246 * the string. Hence it needs correcting at least
1247 * for Meta characters and maybe for multibyte characters.
1253 for (t
= s
; nchars
&& *t
; nchars
--)
1254 t
+= (lastcharlen
= MB_METACHARLEN(t
));
1255 /* for consistency, keep any remainder off the end */
1256 r
= (zlong
)(t
- s
) + nchars
;
1257 if (prevcharlen
&& !nchars
/* ignore if off the end */)
1258 *prevcharlen
= lastcharlen
;
1259 if (nextcharlen
&& *t
)
1260 *nextcharlen
= MB_METACHARLEN(t
);
1261 } else if (r
== 0) {
1264 if (nextcharlen
&& *s
) {
1266 *nextcharlen
= MB_METACHARLEN(s
);
1269 zlong nchars
= (zlong
)MB_METASTRLEN(s
) + r
;
1272 /* make sure this isn't valid as a raw pointer */
1273 r
-= (zlong
)strlen(s
);
1276 for (t
= s
; nchars
&& *t
; nchars
--)
1277 t
+= (lastcharlen
= MB_METACHARLEN(t
));
1278 r
= - (zlong
)strlen(t
); /* keep negative */
1280 *prevcharlen
= lastcharlen
;
1281 if (nextcharlen
&& *t
)
1282 *nextcharlen
= MB_METACHARLEN(t
);
1287 if (!v
->isarr
&& !word
) {
1290 if (!l
|| *s
!= '*') {
1291 d
= (char *) hcalloc(l
+ 2);
1297 if (!l
|| s
[l
- 1] != '*' || (l
> 1 && s
[l
- 2] == '\\')) {
1298 d
= (char *) hcalloc(l
+ 2);
1311 pprog
= patcompile(s
, 0, NULL
);
1320 v
->isarr
|= SCANPM_KEYMATCH
;
1325 v
->isarr
|= SCANPM_MATCHKEY
;
1327 v
->isarr
|= SCANPM_MATCHVAL
;
1330 v
->isarr
|= SCANPM_MATCHMANY
;
1331 if ((ta
= getvaluearr(v
)) &&
1332 (*ta
|| ((v
->isarr
& SCANPM_MATCHMANY
) &&
1333 (v
->isarr
& (SCANPM_MATCHKEY
| SCANPM_MATCHVAL
|
1334 SCANPM_KEYMATCH
))))) {
1335 *inv
= (v
->flags
& VALFLAG_INV
) ? 1 : 0;
1342 ta
= getarrvalue(v
);
1348 if (beg
>= 0 && beg
< len
) {
1352 for (r
= 1 + beg
, p
= ta
+ beg
; p
>= ta
; r
--, p
--) {
1353 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1357 for (r
= 1 + beg
, p
= ta
+ beg
; *p
; r
++, p
++)
1358 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1362 ta
= sepsplit(d
= s
= getstrvalue(v
), sep
, 1, 1);
1366 if (beg
>= 0 && beg
< len
) {
1370 for (r
= 1 + beg
, p
= ta
+ beg
; p
>= ta
; p
--, r
--)
1371 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1376 for (r
= 1 + beg
, p
= ta
+ beg
; *p
; r
++, p
++)
1377 if (pprog
&& pattry(pprog
, *p
) && !--num
)
1385 for (i
= 0; (t
= findword(&d
, sep
)) && *t
; i
++)
1387 r
= (zlong
)(t
- s
+ (a2
? -1 : 1));
1388 if (!a2
&& *tt
!= ',')
1389 *w
= r
+ strlen(ta
[i
]) - 1;
1394 /* Searching characters */
1400 * beg and len are character counts, not raw offsets.
1401 * Remember we need to return a raw offset.
1403 len
= MB_METASTRLEN(d
);
1408 if (beg
>= 0 && beg
< len
) {
1409 char *de
= d
+ slen
;
1413 * Second argument: we don't need to
1414 * handle prevcharlen or nextcharlen, but
1415 * we do need to handle characters appropriately.
1419 char *lastpos
= NULL
;
1425 * See below: we have to move forward,
1426 * but need to count from the end.
1428 for (t
= d
, r
= 0; r
<= beg
; r
++) {
1431 if (pprog
&& pattry(pprog
, d
)) {
1438 t
+= MB_METACHARLEN(t
);
1441 if (nmatches
>= num
) {
1445 for (t
= d
, r
= 0; ; r
++) {
1448 if (pprog
&& pattry(pprog
, d
) &&
1455 t
+= MB_METACHARLEN(t
);
1458 /* else lastpos is already OK */
1464 * This handling of the b flag
1465 * gives odd results, but this is the
1466 * way it's always worked.
1468 for (t
= d
; beg
&& t
<= de
; beg
--)
1469 t
+= MB_METACHARLEN(t
);
1473 if (pprog
&& pattry(pprog
, d
) && !--num
) {
1476 * This time, don't increment
1477 * pointer, since it's already
1478 * after everything we matched.
1485 t
+= MB_METACHARLEN(t
);
1490 * First argument: this is the only case
1491 * where we need prevcharlen and nextcharlen.
1497 char *lastpos
= NULL
;
1503 * We can only move forward through
1504 * multibyte strings, so record the
1506 * Unfortunately the count num works
1507 * from the end, so it's easy to get the
1508 * last one but we need to repeat if
1509 * we want another one.
1511 for (t
= d
, r
= 0; r
<= beg
; r
++) {
1512 if (pprog
&& pattry(pprog
, t
)) {
1518 t
+= MB_METACHARLEN(t
);
1521 if (nmatches
>= num
) {
1524 * Need to start again and repeat
1525 * to get the right match.
1529 for (t
= d
, r
= 0; ; r
++) {
1530 if (pprog
&& pattry(pprog
, t
) &&
1535 t
+= MB_METACHARLEN(t
);
1538 /* else lastpos is already OK */
1540 /* return pointer after matched char */
1542 (lastcharlen
= MB_METACHARLEN(lastpos
));
1544 *prevcharlen
= lastcharlen
;
1546 *nextcharlen
= MB_METACHARLEN(lastpos
);
1550 for (r
= beg
+ 1, t
= d
+ beg
; t
>= d
; r
--, t
--) {
1551 if (pprog
&& pattry(pprog
, t
) &&
1556 for (t
= d
; beg
&& t
<= de
; beg
--)
1557 t
+= MB_METACHARLEN(t
);
1559 if (pprog
&& pattry(pprog
, t
) && !--num
) {
1560 /* return pointer after matched char */
1561 t
+= (lastcharlen
= MB_METACHARLEN(t
));
1563 *prevcharlen
= lastcharlen
;
1565 *nextcharlen
= MB_METACHARLEN(t
);
1570 t
+= MB_METACHARLEN(t
);
1575 return down
? 0 : slen
+ 1;
1583 getindex(char **pptr
, Value v
, int flags
)
1585 int start
, end
, inv
= 0;
1586 char *s
= *pptr
, *tbrack
;
1589 /* Error handled after untokenizing */
1590 s
= parse_subscript(s
, flags
& SCANPM_DQUOTED
);
1591 /* Now we untokenize everything except inull() markers so we can check *
1592 * for the '*' and '@' special subscripts. The inull()s are removed *
1593 * in getarg() after we know whether we're doing reverse indexing. */
1594 for (tbrack
= *pptr
+ 1; *tbrack
&& tbrack
!= s
; tbrack
++) {
1595 if (inull(*tbrack
) && !*++tbrack
)
1597 if (itok(*tbrack
)) /* Need to check for Nularg here? */
1598 *tbrack
= ztokens
[*tbrack
- Pound
];
1600 /* If we reached the end of the string (s == NULL) we have an error */
1604 zerr("invalid subscript");
1609 if ((s
[0] == '*' || s
[0] == '@') && s
+ 1 == tbrack
) {
1610 if ((v
->isarr
|| IS_UNSET_VALUE(v
)) && s
[0] == '@')
1611 v
->isarr
|= SCANPM_ISVAR_AT
;
1616 zlong we
= 0, dummy
;
1617 int startprevlen
, startnextlen
;
1619 start
= getarg(&s
, &inv
, v
, 0, &we
, &startprevlen
, &startnextlen
);
1622 if (!v
->isarr
&& start
!= 0) {
1626 * Note for the confused (= pws): this is an inverse
1627 * offset so at this stage we need to convert from
1628 * the immediate offset into the value that we have
1629 * into a logical character position.
1633 char *target
= t
+ start
- startprevlen
;
1639 * move up characters, counting how many we
1642 p
+= MB_METACHARLEN(p
);
1649 p
= target
; /* pretend we hit exactly */
1653 /* if start was too big, keep the difference */
1654 start
= nstart
+ (target
- p
) + 1;
1656 zlong startoff
= start
+ strlen(t
);
1658 dputs("BUG: can't have negative inverse offsets???");
1661 /* invalid: keep index but don't dereference */
1664 /* find start in full characters */
1666 for (p
= t
; p
< t
+ startoff
;)
1667 p
+= MB_METACHARLEN(p
);
1668 start
= - MB_METASTRLEN(p
);
1672 if (start
> 0 && (isset(KSHARRAYS
) || (v
->pm
->node
.flags
& PM_HASHED
)))
1674 if (v
->isarr
!= SCANPM_WANTINDEX
) {
1675 v
->flags
|= VALFLAG_INV
;
1681 zerr("invalid subscript");
1691 if ((com
= (*s
== ','))) {
1693 end
= getarg(&s
, &inv
, v
, 1, &dummy
, NULL
, NULL
);
1695 end
= we
? we
: start
;
1700 * Somehow the logic sometimes forces us to use the previous
1701 * or next character to what we would expect, which is
1702 * why we had to calculate them in getarg().
1705 start
-= startprevlen
;
1706 else if (start
== 0 && end
== 0)
1709 * Strictly, this range is entirely off the
1710 * start of the available index range.
1711 * This can't happen with KSH_ARRAYS; we already
1712 * altered the start index in getarg().
1713 * Are we being strict?
1715 if (isset(KSHZEROSUBSCRIPT
)) {
1718 * Treat this as accessing the first element of the
1724 * We are. Flag that this range is invalid
1725 * for setting elements. Set the indexes
1726 * to a range that returns empty for other accesses.
1728 v
->flags
|= VALFLAG_EMPTY
;
1735 if (v
->isarr
&& !com
&&
1736 (!(v
->isarr
& SCANPM_MATCHMANY
) ||
1737 !(v
->isarr
& (SCANPM_MATCHKEY
| SCANPM_MATCHVAL
|
1754 getvalue(Value v
, char **pptr
, int bracks
)
1756 return fetchvalue(v
, pptr
, bracks
, 0);
1761 fetchvalue(Value v
, char **pptr
, int bracks
, int flags
)
1769 if (idigit(c
= *s
)) {
1771 ppar
= zstrtol(s
, &s
, 10);
1775 else if ((ie
= itype_end(s
, IIDENT
, 0)) != s
)
1777 else if (c
== Quest
)
1779 else if (c
== Pound
)
1781 else if (c
== String
)
1783 else if (c
== Qstring
)
1787 else if (c
== '#' || c
== '-' || c
== '?' || c
== '$' ||
1788 c
== '!' || c
== '@' || c
== '*')
1797 memset(v
, 0, sizeof(*v
));
1799 v
= (Value
) hcalloc(sizeof *v
);
1802 v
->start
= ppar
- 1;
1810 isvarat
= (t
[0] == '@' && !t
[1]);
1811 pm
= (Param
) paramtab
->getnode(paramtab
, *t
== '0' ? "0" : t
);
1815 if (!pm
|| (pm
->node
.flags
& PM_UNSET
))
1818 memset(v
, 0, sizeof(*v
));
1820 v
= (Value
) hcalloc(sizeof *v
);
1821 if (PM_TYPE(pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
)) {
1822 /* Overload v->isarr as the flag bits for hashed arrays. */
1823 v
->isarr
= flags
| (isvarat
? SCANPM_ISVAR_AT
: 0);
1824 /* If no flags were passed, we need something to represent *
1825 * `true' yet differ from an explicit WANTVALS. Use a *
1826 * special flag for this case. */
1828 v
->isarr
= SCANPM_ARRONLY
;
1834 if (bracks
> 0 && (*s
== '[' || *s
== Inbrack
)) {
1835 if (getindex(&s
, v
, flags
)) {
1839 } else if (!(flags
& SCANPM_ASSIGNING
) && v
->isarr
&&
1840 itype_end(t
, IIDENT
, 1) != t
&& isset(KSHARRAYS
))
1841 v
->end
= 1, v
->isarr
= 0;
1846 if (v
->start
> MAX_ARRLEN
) {
1847 zerr("subscript too %s: %d", "big", v
->start
+ !isset(KSHARRAYS
));
1850 if (v
->start
< -MAX_ARRLEN
) {
1851 zerr("subscript too %s: %d", "small", v
->start
);
1854 if (v
->end
> MAX_ARRLEN
+1) {
1855 zerr("subscript too %s: %d", "big", v
->end
- !!isset(KSHARRAYS
));
1858 if (v
->end
< -MAX_ARRLEN
) {
1859 zerr("subscript too %s: %d", "small", v
->end
);
1867 getstrvalue(Value v
)
1870 char buf
[BDIGBUFSIZE
];
1875 if ((v
->flags
& VALFLAG_INV
) && !(v
->pm
->node
.flags
& PM_HASHED
)) {
1876 sprintf(buf
, "%d", v
->start
);
1881 switch(PM_TYPE(v
->pm
->node
.flags
)) {
1883 /* (!v->isarr) should be impossible unless emulating ksh */
1884 if (!v
->isarr
&& EMULATION(EMULATE_KSH
)) {
1885 s
= dupstring("[0]");
1886 if (getindex(&s
, v
, 0) == 0)
1889 } /* else fall through */
1891 ss
= getvaluearr(v
);
1893 s
= sepjoin(ss
, NULL
, 1);
1896 v
->start
+= arrlen(ss
);
1897 s
= (v
->start
>= arrlen(ss
) || v
->start
< 0) ?
1898 (char *) hcalloc(1) : ss
[v
->start
];
1902 convbase(buf
, v
->pm
->gsu
.i
->getfn(v
->pm
), v
->pm
->base
);
1907 s
= convfloat(v
->pm
->gsu
.f
->getfn(v
->pm
),
1908 v
->pm
->base
, v
->pm
->node
.flags
, NULL
);
1911 s
= v
->pm
->gsu
.s
->getfn(v
->pm
);
1915 DPUTS(1, "BUG: param node without valid type");
1919 if (v
->flags
& VALFLAG_SUBST
) {
1920 if (v
->pm
->node
.flags
& (PM_LEFT
|PM_RIGHT_B
|PM_RIGHT_Z
)) {
1921 unsigned int fwidth
= v
->pm
->width
? v
->pm
->width
: MB_METASTRLEN(s
);
1922 switch (v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) {
1927 case PM_LEFT
| PM_RIGHT_Z
:
1929 if (v
->pm
->node
.flags
& PM_RIGHT_Z
)
1936 for (tend
= t
, t0
= 0; t0
< fwidth
&& *tend
; t0
++)
1937 tend
+= MB_METACHARLEN(tend
);
1939 * t0 is the number of characters from t used,
1940 * hence (fwidth - t0) is the number of padding
1941 * characters. fwidth is a misnomer: we use
1942 * character counts, not character widths.
1944 * (tend - t) is the number of bytes we need
1945 * to get fwidth characters or the entire string;
1946 * the characters may be multiple bytes.
1948 fwidth
-= t0
; /* padding chars remaining */
1949 t0
= tend
- t
; /* bytes to copy from string */
1950 s
= (char *) hcalloc(t0
+ fwidth
+ 1);
1953 memset(s
+ t0
, ' ', fwidth
);
1954 s
[t0
+ fwidth
] = '\0';
1958 case PM_RIGHT_Z
| PM_RIGHT_B
:
1961 /* Calculate length in possibly multibyte chars */
1962 unsigned int charlen
= MB_METASTRLEN(s
);
1964 if (charlen
< fwidth
) {
1965 char *valprefend
= s
;
1967 if (v
->pm
->node
.flags
& PM_RIGHT_Z
) {
1969 * This is a documented feature: when deciding
1970 * whether to pad with zeroes, ignore
1971 * leading blanks already in the value;
1972 * only look for numbers after that.
1973 * Not sure how useful this really is.
1974 * It's certainly confusing to code around.
1976 for (t
= s
; iblank(*t
); t
++)
1979 * Allow padding after initial minus
1980 * for numeric variables.
1982 if ((v
->pm
->node
.flags
&
1983 (PM_INTEGER
|PM_EFLOAT
|PM_FFLOAT
)) &&
1987 * Allow padding after initial 0x or
1988 * base# for integer variables.
1990 if (v
->pm
->node
.flags
& PM_INTEGER
) {
1991 if (isset(CBASES
) &&
1992 t
[0] == '0' && t
[1] == 'x')
1994 else if ((valprefend
= strchr(t
, '#')))
2000 else if (v
->pm
->node
.flags
&
2001 (PM_INTEGER
|PM_EFLOAT
|PM_FFLOAT
)) {
2002 /* zero always OK */
2003 } else if (!idigit(*t
))
2006 /* number of characters needed for padding */
2008 /* bytes from original string */
2010 t
= (char *) hcalloc(fwidth
+ t0
+ 1);
2011 /* prefix guaranteed to be single byte chars */
2012 preflen
= valprefend
- s
;
2014 (((v
->pm
->node
.flags
& PM_RIGHT_B
)
2015 || !zero
) ? ' ' : '0'), fwidth
);
2017 * Copy - or 0x or base# before any padding
2021 memcpy(t
, s
, preflen
);
2022 memcpy(t
+ preflen
+ fwidth
,
2023 valprefend
, t0
- preflen
);
2024 t
[fwidth
+ t0
] = '\0';
2027 /* Need to skip (charlen - fwidth) chars */
2028 for (t0
= charlen
- fwidth
; t0
; t0
--)
2029 s
+= MB_METACHARLEN(s
);
2035 switch (v
->pm
->node
.flags
& (PM_LOWER
| PM_UPPER
)) {
2037 s
= casemodify(s
, CASMOD_LOWER
);
2040 s
= casemodify(s
, CASMOD_UPPER
);
2044 if (v
->start
== 0 && v
->end
== -1)
2048 v
->start
+= strlen(s
);
2053 v
->end
+= strlen(s
);
2055 char *eptr
= s
+ v
->end
;
2057 v
->end
+= MB_METACHARLEN(eptr
);
2060 s
= (v
->start
> (int)strlen(s
)) ? dupstring("") : dupstring(s
+ v
->start
);
2061 if (v
->end
<= v
->start
)
2063 else if (v
->end
- v
->start
<= (int)strlen(s
))
2064 s
[v
->end
- v
->start
] = '\0';
2069 static char *nular
[] = {"", NULL
};
2073 getarrvalue(Value v
)
2078 return arrdup(nular
);
2079 else if (IS_UNSET_VALUE(v
))
2080 return arrdup(&nular
[1]);
2081 if (v
->flags
& VALFLAG_INV
) {
2082 char buf
[DIGBUFSIZE
];
2085 sprintf(buf
, "%d", v
->start
);
2086 s
[0] = dupstring(buf
);
2090 if (v
->start
== 0 && v
->end
== -1)
2093 v
->start
+= arrlen(s
);
2095 v
->end
+= arrlen(s
) + 1;
2096 if (v
->start
> arrlen(s
) || v
->start
< 0)
2099 s
= arrdup(s
+ v
->start
);
2100 if (v
->end
<= v
->start
)
2102 else if (v
->end
- v
->start
<= arrlen(s
))
2103 s
[v
->end
- v
->start
] = NULL
;
2109 getintvalue(Value v
)
2113 if (v
->flags
& VALFLAG_INV
)
2116 char **arr
= getarrvalue(v
);
2118 char *scal
= sepjoin(arr
, NULL
, 1);
2119 return mathevali(scal
);
2123 if (PM_TYPE(v
->pm
->node
.flags
) == PM_INTEGER
)
2124 return v
->pm
->gsu
.i
->getfn(v
->pm
);
2125 if (v
->pm
->node
.flags
& (PM_EFLOAT
|PM_FFLOAT
))
2126 return (zlong
)v
->pm
->gsu
.f
->getfn(v
->pm
);
2127 return mathevali(getstrvalue(v
));
2132 getnumvalue(Value v
)
2135 mn
.type
= MN_INTEGER
;
2140 } else if (v
->flags
& VALFLAG_INV
) {
2142 } else if (v
->isarr
) {
2143 char **arr
= getarrvalue(v
);
2145 char *scal
= sepjoin(arr
, NULL
, 1);
2146 return matheval(scal
);
2149 } else if (PM_TYPE(v
->pm
->node
.flags
) == PM_INTEGER
) {
2150 mn
.u
.l
= v
->pm
->gsu
.i
->getfn(v
->pm
);
2151 } else if (v
->pm
->node
.flags
& (PM_EFLOAT
|PM_FFLOAT
)) {
2153 mn
.u
.d
= v
->pm
->gsu
.f
->getfn(v
->pm
);
2155 return matheval(getstrvalue(v
));
2161 export_param(Param pm
)
2163 char buf
[BDIGBUFSIZE
], *val
;
2165 if (PM_TYPE(pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
)) {
2166 #if 0 /* Requires changes elsewhere in params.c and builtin.c */
2167 if (EMULATION(EMULATE_KSH
) /* isset(KSHARRAYS) */) {
2173 val
= getstrvalue(&v
);
2177 } else if (PM_TYPE(pm
->node
.flags
) == PM_INTEGER
)
2178 convbase(val
= buf
, pm
->gsu
.i
->getfn(pm
), pm
->base
);
2179 else if (pm
->node
.flags
& (PM_EFLOAT
|PM_FFLOAT
))
2180 val
= convfloat(pm
->gsu
.f
->getfn(pm
), pm
->base
,
2181 pm
->node
.flags
, NULL
);
2183 val
= pm
->gsu
.s
->getfn(pm
);
2190 setstrvalue(Value v
, char *val
)
2192 if (v
->pm
->node
.flags
& PM_READONLY
) {
2193 zerr("read-only variable: %s", v
->pm
->node
.nam
);
2197 if ((v
->pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
2198 zerr("%s: restricted", v
->pm
->node
.nam
);
2202 if ((v
->pm
->node
.flags
& PM_HASHED
) &&
2203 (v
->isarr
& (SCANPM_MATCHMANY
|SCANPM_ARRONLY
))) {
2204 zerr("%s: attempt to set slice of associative array", v
->pm
->node
.nam
);
2208 if (v
->flags
& VALFLAG_EMPTY
) {
2209 zerr("%s: assignment to invalid subscript range", v
->pm
->node
.nam
);
2213 v
->pm
->node
.flags
&= ~PM_UNSET
;
2214 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2216 if (v
->start
== 0 && v
->end
== -1) {
2217 v
->pm
->gsu
.s
->setfn(v
->pm
, val
);
2218 if ((v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) &&
2220 v
->pm
->width
= strlen(val
);
2225 z
= dupstring(v
->pm
->gsu
.s
->getfn(v
->pm
));
2227 if ((v
->flags
& VALFLAG_INV
) && unset(KSHARRAYS
))
2228 v
->start
--, v
->end
--;
2234 if (v
->start
> zlen
)
2241 else if (v
->end
> zlen
)
2243 x
= (char *) zalloc(v
->start
+ strlen(val
) + zlen
- v
->end
+ 1);
2244 strncpy(x
, z
, v
->start
);
2245 strcpy(x
+ v
->start
, val
);
2246 strcat(x
+ v
->start
, z
+ v
->end
);
2247 v
->pm
->gsu
.s
->setfn(v
->pm
, x
);
2253 v
->pm
->gsu
.i
->setfn(v
->pm
, mathevali(val
));
2254 if ((v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) &&
2256 v
->pm
->width
= strlen(val
);
2259 if (!v
->pm
->base
&& lastbase
!= -1)
2260 v
->pm
->base
= lastbase
;
2265 mnumber mn
= matheval(val
);
2266 v
->pm
->gsu
.f
->setfn(v
->pm
, (mn
.type
& MN_FLOAT
) ? mn
.u
.d
:
2268 if ((v
->pm
->node
.flags
& (PM_LEFT
| PM_RIGHT_B
| PM_RIGHT_Z
)) &&
2270 v
->pm
->width
= strlen(val
);
2276 char **ss
= (char **) zalloc(2 * sizeof(char *));
2285 if (foundparam
== NULL
)
2287 zerr("%s: attempt to set associative array to scalar",
2293 foundparam
->gsu
.s
->setfn(foundparam
, val
);
2297 if ((!v
->pm
->env
&& !(v
->pm
->node
.flags
& PM_EXPORTED
) &&
2298 !(isset(ALLEXPORT
) && !(v
->pm
->node
.flags
& PM_HASHELEM
))) ||
2299 (v
->pm
->node
.flags
& PM_ARRAY
) || v
->pm
->ename
)
2301 export_param(v
->pm
);
2306 setnumvalue(Value v
, mnumber val
)
2308 char buf
[BDIGBUFSIZE
], *p
;
2310 if (v
->pm
->node
.flags
& PM_READONLY
) {
2311 zerr("read-only variable: %s", v
->pm
->node
.nam
);
2314 if ((v
->pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
2315 zerr("%s: restricted", v
->pm
->node
.nam
);
2318 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2321 if ((val
.type
& MN_INTEGER
) || outputradix
) {
2322 if (!(val
.type
& MN_INTEGER
))
2323 val
.u
.l
= (zlong
) val
.u
.d
;
2324 convbase(p
= buf
, val
.u
.l
, outputradix
);
2326 p
= convfloat(val
.u
.d
, 0, 0, NULL
);
2327 setstrvalue(v
, ztrdup(p
));
2330 v
->pm
->gsu
.i
->setfn(v
->pm
, (val
.type
& MN_INTEGER
) ? val
.u
.l
:
2332 setstrvalue(v
, NULL
);
2336 v
->pm
->gsu
.f
->setfn(v
->pm
, (val
.type
& MN_INTEGER
) ?
2337 (double)val
.u
.l
: val
.u
.d
);
2338 setstrvalue(v
, NULL
);
2345 setarrvalue(Value v
, char **val
)
2347 if (v
->pm
->node
.flags
& PM_READONLY
) {
2348 zerr("read-only variable: %s", v
->pm
->node
.nam
);
2352 if ((v
->pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
2353 zerr("%s: restricted", v
->pm
->node
.nam
);
2357 if (!(PM_TYPE(v
->pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
))) {
2359 zerr("%s: attempt to assign array value to non-array",
2363 if (v
->flags
& VALFLAG_EMPTY
) {
2364 zerr("%s: assignment to invalid subscript range", v
->pm
->node
.nam
);
2368 if (v
->start
== 0 && v
->end
== -1) {
2369 if (PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)
2370 arrhashsetfn(v
->pm
, val
, 0);
2372 v
->pm
->gsu
.a
->setfn(v
->pm
, val
);
2373 } else if (v
->start
== -1 && v
->end
== 0 &&
2374 PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
) {
2375 arrhashsetfn(v
->pm
, val
, 1);
2377 char **old
, **new, **p
, **q
, **r
;
2380 if ((PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)) {
2382 zerr("%s: attempt to set slice of associative array",
2386 if ((v
->flags
& VALFLAG_INV
) && unset(KSHARRAYS
)) {
2391 if (v
->end
< v
->start
)
2393 q
= old
= v
->pm
->gsu
.a
->getfn(v
->pm
);
2406 ll
= v
->start
+ arrlen(val
);
2408 ll
+= n
- v
->end
+ 1;
2410 p
= new = (char **) zshcalloc(sizeof(char *) * (ll
+ 1));
2412 for (i
= 0; i
< v
->start
; i
++)
2413 *p
++ = i
< n
? ztrdup(*q
++) : ztrdup("");
2415 *p
++ = ztrdup(*r
++);
2417 for (q
= old
+ v
->end
; *q
;)
2418 *p
++ = ztrdup(*q
++);
2421 v
->pm
->gsu
.a
->setfn(v
->pm
, new);
2426 /* Retrieve an integer parameter */
2435 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2437 return getintvalue(v
);
2440 /* Retrieve a numerical parameter, either integer or floating */
2449 if (!(v
= getvalue(&vbuf
, &s
, 1))) {
2451 mn
.type
= MN_INTEGER
;
2455 return getnumvalue(v
);
2458 /* Retrieve a scalar (string) parameter */
2467 if (!(v
= getvalue(&vbuf
, &s
, 0)))
2469 return getstrvalue(v
);
2472 /* Retrieve an array parameter */
2481 if (!idigit(*s
) && (v
= getvalue(&vbuf
, &s
, 0)) &&
2482 PM_TYPE(v
->pm
->node
.flags
) == PM_ARRAY
)
2483 return v
->pm
->gsu
.a
->getfn(v
->pm
);
2487 /* Retrieve an assoc array parameter as an array */
2496 if (!idigit(*s
) && (v
= getvalue(&vbuf
, &s
, 0)) &&
2497 PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)
2498 return paramvalarr(v
->pm
->gsu
.h
->getfn(v
->pm
), SCANPM_WANTVALS
);
2502 /* Retrieve the keys of an assoc array parameter as an array */
2511 if (!idigit(*s
) && (v
= getvalue(&vbuf
, &s
, 0)) &&
2512 PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
)
2513 return paramvalarr(v
->pm
->gsu
.h
->getfn(v
->pm
), SCANPM_WANTKEYS
);
2519 assignsparam(char *s
, char *val
, int flags
)
2524 char *ss
, *copy
, *var
;
2530 zerr("not an identifier: %s", s
);
2536 if ((ss
= strchr(s
, '['))) {
2538 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2539 createparam(t
, PM_ARRAY
);
2541 flags
&= ~ASSPM_WARN_CREATE
;
2545 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2546 createparam(t
, PM_SCALAR
);
2547 else if ((((v
->pm
->node
.flags
& PM_ARRAY
) && !(flags
& ASSPM_AUGMENT
)) ||
2548 (v
->pm
->node
.flags
& PM_HASHED
)) &&
2549 !(v
->pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
)) &&
2552 createparam(t
, PM_SCALAR
);
2556 flags
&= ~ASSPM_WARN_CREATE
;
2558 if (!v
&& !(v
= getvalue(&vbuf
, &t
, 1))) {
2563 if ((flags
& ASSPM_WARN_CREATE
) && v
->pm
->level
== 0)
2564 zwarn("scalar parameter %s created globally in function",
2566 if (flags
& ASSPM_AUGMENT
) {
2567 if (v
->start
== 0 && v
->end
== -1) {
2568 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2570 v
->start
= INT_MAX
; /* just append to scalar value */
2575 rhs
= matheval(val
);
2576 lhs
= getnumvalue(v
);
2577 if (lhs
.type
== MN_FLOAT
) {
2578 if ((rhs
.type
) == MN_FLOAT
)
2579 lhs
.u
.d
= lhs
.u
.d
+ rhs
.u
.d
;
2581 lhs
.u
.d
= lhs
.u
.d
+ (double)rhs
.u
.l
;
2583 if ((rhs
.type
) == MN_INTEGER
)
2584 lhs
.u
.l
= lhs
.u
.l
+ rhs
.u
.l
;
2586 lhs
.u
.l
= lhs
.u
.l
+ (zlong
)rhs
.u
.d
;
2588 setnumvalue(v
, lhs
);
2591 return v
->pm
; /* avoid later setstrvalue() call */
2593 if (unset(KSHARRAYS
)) {
2594 v
->start
= arrlen(v
->pm
->gsu
.a
->getfn(v
->pm
));
2595 v
->end
= v
->start
+ 1;
2597 /* ksh appends scalar to first element */
2604 switch (PM_TYPE(v
->pm
->node
.flags
)) {
2609 v
->start
= v
->end
= strlen(v
->pm
->gsu
.s
->getfn(v
->pm
)) +
2616 zerr("attempt to add to slice of a numeric variable");
2621 /* treat slice as the end element */
2622 v
->start
= sstart
= v
->end
> 0 ? v
->end
- 1 : v
->end
;
2624 var
= getstrvalue(v
);
2628 val
= (char *)zalloc(lvar
+ strlen(val
) + 1);
2630 strcpy(val
+ lvar
, copy
);
2637 setstrvalue(v
, val
);
2644 assignaparam(char *s
, char **val
, int flags
)
2652 zerr("not an identifier: %s", s
);
2658 if ((ss
= strchr(s
, '['))) {
2660 if (!(v
= getvalue(&vbuf
, &s
, 1)))
2661 createparam(t
, PM_ARRAY
);
2663 flags
&= ~ASSPM_WARN_CREATE
;
2665 if (v
&& PM_TYPE(v
->pm
->node
.flags
) == PM_HASHED
) {
2667 zerr("%s: attempt to set slice of associative array",
2675 if (!(v
= fetchvalue(&vbuf
, &s
, 1, SCANPM_ASSIGNING
)))
2676 createparam(t
, PM_ARRAY
);
2677 else if (!(PM_TYPE(v
->pm
->node
.flags
) & (PM_ARRAY
|PM_HASHED
)) &&
2678 !(v
->pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
))) {
2679 int uniq
= v
->pm
->node
.flags
& PM_UNIQUE
;
2680 if (flags
& ASSPM_AUGMENT
) {
2681 /* insert old value at the beginning of the val array */
2683 int lv
= arrlen(val
);
2685 new = (char **) zalloc(sizeof(char *) * (lv
+ 2));
2686 *new = ztrdup(getstrvalue(v
));
2687 memcpy(new+1, val
, sizeof(char *) * (lv
+ 1));
2692 createparam(t
, PM_ARRAY
| uniq
);
2696 flags
&= ~ASSPM_WARN_CREATE
;
2699 if (!(v
= fetchvalue(&vbuf
, &t
, 1, SCANPM_ASSIGNING
))) {
2705 if ((flags
& ASSPM_WARN_CREATE
) && v
->pm
->level
== 0)
2706 zwarn("array parameter %s created globally in function",
2708 if (flags
& ASSPM_AUGMENT
) {
2709 if (v
->start
== 0 && v
->end
== -1) {
2710 if (PM_TYPE(v
->pm
->node
.flags
) & PM_ARRAY
) {
2711 v
->start
= arrlen(v
->pm
->gsu
.a
->getfn(v
->pm
));
2712 v
->end
= v
->start
+ 1;
2713 } else if (PM_TYPE(v
->pm
->node
.flags
) & PM_HASHED
)
2714 v
->start
= -1, v
->end
= 0;
2717 v
->start
= v
->end
--;
2718 else if (PM_TYPE(v
->pm
->node
.flags
) & PM_ARRAY
) {
2719 v
->end
= arrlen(v
->pm
->gsu
.a
->getfn(v
->pm
)) + v
->end
;
2720 v
->start
= v
->end
+ 1;
2725 setarrvalue(v
, val
);
2732 sethparam(char *s
, char **val
)
2739 zerr("not an identifier: %s", s
);
2744 if (strchr(s
, '[')) {
2746 zerr("nested associative arrays not yet supported");
2751 if (!(v
= fetchvalue(&vbuf
, &s
, 1, SCANPM_ASSIGNING
)))
2752 createparam(t
, PM_HASHED
);
2753 else if (!(PM_TYPE(v
->pm
->node
.flags
) & PM_HASHED
) &&
2754 !(v
->pm
->node
.flags
& PM_SPECIAL
)) {
2756 createparam(t
, PM_HASHED
);
2760 if (!(v
= fetchvalue(&vbuf
, &t
, 1, SCANPM_ASSIGNING
))) {
2764 setarrvalue(v
, val
);
2771 * Set a generic shell number, floating point or integer.
2776 setnparam(char *s
, mnumber val
)
2784 zerr("not an identifier: %s", s
);
2789 ss
= strchr(s
, '[');
2790 v
= getvalue(&vbuf
, &s
, 1);
2791 if (v
&& (v
->pm
->node
.flags
& (PM_ARRAY
|PM_HASHED
)) &&
2792 !(v
->pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
)) &&
2794 * not sure what KSHARRAYS has got to do with this...
2795 * copied this from assignsparam().
2797 unset(KSHARRAYS
) && !ss
) {
2798 unsetparam_pm(v
->pm
, 0, 1);
2803 /* s has been updated by getvalue, so check again */
2804 ss
= strchr(s
, '[');
2807 pm
= createparam(t
, ss
? PM_ARRAY
:
2808 (val
.type
& MN_INTEGER
) ? PM_INTEGER
: PM_FFLOAT
);
2810 pm
= (Param
) paramtab
->getnode(paramtab
, t
);
2811 DPUTS(!pm
, "BUG: parameter not created");
2814 } else if (val
.type
& MN_INTEGER
) {
2815 pm
->base
= outputradix
;
2817 v
= getvalue(&vbuf
, &t
, 1);
2818 DPUTS(!v
, "BUG: value not found for new parameter");
2820 setnumvalue(v
, val
);
2825 /* Simplified interface to setnparam */
2829 setiparam(char *s
, zlong val
)
2832 mnval
.type
= MN_INTEGER
;
2834 return setnparam(s
, mnval
);
2838 /* Unset a parameter */
2847 if ((pm
= (Param
) (paramtab
== realparamtab
?
2848 gethashnode2(paramtab
, s
) :
2849 paramtab
->getnode(paramtab
, s
))))
2850 unsetparam_pm(pm
, 0, 1);
2854 /* Unset a parameter */
2858 unsetparam_pm(Param pm
, int altflag
, int exp
)
2863 if ((pm
->node
.flags
& PM_READONLY
) && pm
->level
<= locallevel
) {
2864 zerr("read-only variable: %s", pm
->node
.nam
);
2867 if ((pm
->node
.flags
& PM_RESTRICTED
) && isset(RESTRICTED
)) {
2868 zerr("%s: restricted", pm
->node
.nam
);
2872 if (pm
->ename
&& !altflag
)
2873 altremove
= ztrdup(pm
->ename
);
2877 if (!(pm
->node
.flags
& PM_UNSET
))
2878 pm
->gsu
.s
->unsetfn(pm
, exp
);
2882 /* remove it under its alternate name if necessary */
2884 altpm
= (Param
) paramtab
->getnode(paramtab
, altremove
);
2885 /* tied parameters are at the same local level as each other */
2887 while (altpm
&& altpm
->level
> pm
->level
) {
2888 /* param under alternate name hidden by a local */
2893 if (oldpm
&& !altpm
->level
) {
2895 /* fudge things so removenode isn't called */
2898 unsetparam_pm(altpm
, 1, exp
);
2905 * If this was a local variable, we need to keep the old
2906 * struct so that it is resurrected at the right level.
2907 * This is partly because when an array/scalar value is set
2908 * and the parameter used to be the other sort, unsetparam()
2909 * is called. Beyond that, there is an ambiguity: should
2910 * foo() { local bar; unset bar; } make the global bar
2911 * available or not? The following makes the answer "no".
2913 * Some specials, such as those used in zle, still need removing
2914 * from the parameter table; they have the PM_REMOVABLE flag.
2916 if ((pm
->level
&& locallevel
>= pm
->level
) ||
2917 (pm
->node
.flags
& (PM_SPECIAL
|PM_REMOVABLE
)) == PM_SPECIAL
)
2920 /* remove parameter node from table */
2921 paramtab
->removenode(paramtab
, pm
->node
.nam
);
2925 paramtab
->addnode(paramtab
, oldpm
->node
.nam
, oldpm
);
2926 if ((PM_TYPE(oldpm
->node
.flags
) == PM_SCALAR
) &&
2927 !(pm
->node
.flags
& PM_HASHELEM
) &&
2928 (oldpm
->node
.flags
& PM_NAMEDDIR
) &&
2929 oldpm
->gsu
.s
== &stdscalar_gsu
)
2930 adduserdir(oldpm
->node
.nam
, oldpm
->u
.str
, 0, 0);
2931 if (oldpm
->node
.flags
& PM_EXPORTED
) {
2933 * Re-export the old value which we removed in typeset_single().
2934 * I don't think we need to test for ALL_EXPORT here, since if
2935 * it was used to export the parameter originally the parameter
2936 * should still have the PM_EXPORTED flag.
2938 export_param(oldpm
);
2942 paramtab
->freenode(&pm
->node
); /* free parameter node */
2947 /* Standard function to unset a parameter. This is mostly delegated to *
2948 * the specific set function.
2950 * This could usefully be made type-specific, but then we need
2951 * to be more careful when calling the unset method directly.
2956 stdunsetfn(Param pm
, UNUSED(int exp
))
2958 switch (PM_TYPE(pm
->node
.flags
)) {
2959 case PM_SCALAR
: pm
->gsu
.s
->setfn(pm
, NULL
); break;
2960 case PM_ARRAY
: pm
->gsu
.a
->setfn(pm
, NULL
); break;
2961 case PM_HASHED
: pm
->gsu
.h
->setfn(pm
, NULL
); break;
2963 if (!(pm
->node
.flags
& PM_SPECIAL
))
2967 if ((pm
->node
.flags
& (PM_SPECIAL
|PM_TIED
)) == PM_TIED
) {
2972 pm
->node
.flags
&= ~PM_TIED
;
2974 pm
->node
.flags
|= PM_UNSET
;
2977 /* Function to get value of an integer parameter */
2986 /* Function to set value of an integer parameter */
2990 intsetfn(Param pm
, zlong x
)
2995 /* Function to get value of a floating point parameter */
2999 floatgetfn(Param pm
)
3004 /* Function to set value of an integer parameter */
3008 floatsetfn(Param pm
, double x
)
3013 /* Function to get value of a scalar (string) parameter */
3019 return pm
->u
.str
? pm
->u
.str
: (char *) hcalloc(1);
3022 /* Function to set value of a scalar (string) parameter */
3026 strsetfn(Param pm
, char *x
)
3030 if (!(pm
->node
.flags
& PM_HASHELEM
) &&
3031 ((pm
->node
.flags
& PM_NAMEDDIR
) || isset(AUTONAMEDIRS
))) {
3032 pm
->node
.flags
|= PM_NAMEDDIR
;
3033 adduserdir(pm
->node
.nam
, x
, 0, 0);
3037 /* Function to get value of an array parameter */
3039 static char *nullarray
= NULL
;
3045 return pm
->u
.arr
? pm
->u
.arr
: &nullarray
;
3048 /* Function to set value of an array parameter */
3052 arrsetfn(Param pm
, char **x
)
3054 if (pm
->u
.arr
&& pm
->u
.arr
!= x
)
3055 freearray(pm
->u
.arr
);
3056 if (pm
->node
.flags
& PM_UNIQUE
)
3059 /* Arrays tied to colon-arrays may need to fix the environment */
3061 arrfixenv(pm
->ename
, x
);
3064 /* Function to get value of an association parameter */
3067 mod_export HashTable
3073 /* Function to set value of an association parameter */
3077 hashsetfn(Param pm
, HashTable x
)
3079 if (pm
->u
.hash
&& pm
->u
.hash
!= x
)
3080 deleteparamtable(pm
->u
.hash
);
3084 /* Function to dispose of setting of an unsettable hash */
3088 nullsethashfn(UNUSED(Param pm
), HashTable x
)
3090 deleteparamtable(x
);
3093 /* Function to set value of an association parameter using key/value pairs */
3097 arrhashsetfn(Param pm
, char **val
, int augment
)
3099 /* Best not to shortcut this by using the existing hash table, *
3100 * since that could cause trouble for special hashes. This way, *
3101 * it's up to pm->gsu.h->setfn() what to do. */
3102 int alen
= arrlen(val
);
3103 HashTable opmtab
= paramtab
, ht
= 0;
3105 Value v
= (Value
) hcalloc(sizeof *v
);
3110 zerr("bad set of key/value pairs for associative array");
3114 if (!(augment
&& (ht
= paramtab
= pm
->gsu
.h
->getfn(pm
))))
3115 ht
= paramtab
= newparamtable(17, pm
->node
.nam
);
3117 /* The parameter name is ztrdup'd... */
3118 v
->pm
= createparam(*aptr
, PM_SCALAR
|PM_UNSET
);
3120 * createparam() doesn't return anything if the parameter
3124 v
->pm
= (Param
) paramtab
->getnode(paramtab
, *aptr
);
3126 /* ...but we can use the value without copying. */
3127 setstrvalue(v
, *aptr
++);
3130 pm
->gsu
.h
->setfn(pm
, ht
);
3131 free(val
); /* not freearray() */
3135 * These functions are used as the set function for special parameters that
3136 * cannot be set by the user. The set is incomplete as the only such
3137 * parameters are scalar and integer.
3142 nullstrsetfn(UNUSED(Param pm
), char *x
)
3149 nullintsetfn(UNUSED(Param pm
), UNUSED(zlong x
))
3154 nullunsetfn(UNUSED(Param pm
), UNUSED(int exp
))
3158 /* Function to get value of generic special integer *
3159 * parameter. data is pointer to global variable *
3160 * containing the integer value. */
3164 intvargetfn(Param pm
)
3166 return *pm
->u
.valptr
;
3169 /* Function to set value of generic special integer *
3170 * parameter. data is pointer to global variable *
3171 * where the value is to be stored. */
3175 intvarsetfn(Param pm
, zlong x
)
3180 /* Function to set value of any ZLE-related integer *
3181 * parameter. data is pointer to global variable *
3182 * where the value is to be stored. */
3186 zlevarsetfn(Param pm
, zlong x
)
3188 zlong
*p
= pm
->u
.valptr
;
3191 if (p
== &lines
|| p
== &columns
)
3192 adjustwinsize(2 + (p
== &columns
));
3195 /* Function to set value of generic special scalar *
3196 * parameter. data is pointer to a character pointer *
3197 * representing the scalar (string). */
3201 strvarsetfn(Param pm
, char *x
)
3203 char **q
= ((char **)pm
->u
.data
);
3209 /* Function to get value of generic special scalar *
3210 * parameter. data is pointer to a character pointer *
3211 * representing the scalar (string). */
3215 strvargetfn(Param pm
)
3217 char *s
= *((char **)pm
->u
.data
);
3224 /* Function to get value of generic special array *
3225 * parameter. data is a pointer to the pointer to *
3226 * a pointer (a pointer to a variable length array *
3231 arrvargetfn(Param pm
)
3233 char **arrptr
= *((char ***)pm
->u
.data
);
3235 return arrptr
? arrptr
: &nullarray
;
3238 /* Function to set value of generic special array parameter. *
3239 * data is pointer to a variable length array of pointers which *
3240 * represents this array of scalars (strings). If pm->ename is *
3241 * non NULL, then it is a colon separated environment variable *
3242 * version of this array which will need to be updated. */
3246 arrvarsetfn(Param pm
, char **x
)
3248 char ***dptr
= (char ***)pm
->u
.data
;
3252 if (pm
->node
.flags
& PM_UNIQUE
)
3255 * Special tied arrays point to variables accessible in other
3256 * ways which need to be set to NULL. We can't do this
3257 * with user tied variables since we can leak memory.
3259 if ((pm
->node
.flags
& PM_SPECIAL
) && !x
)
3260 *dptr
= mkarray(NULL
);
3264 arrfixenv(pm
->ename
, x
);
3269 colonarrgetfn(Param pm
)
3271 char ***dptr
= (char ***)pm
->u
.data
;
3272 return *dptr
? zjoin(*dptr
, ':', 1) : "";
3277 colonarrsetfn(Param pm
, char *x
)
3279 char ***dptr
= (char ***)pm
->u
.data
;
3281 * We have to make sure this is never NULL, since that
3282 * can cause problems.
3287 *dptr
= colonsplit(x
, pm
->node
.flags
& PM_UNIQUE
);
3289 *dptr
= mkarray(NULL
);
3291 arrfixenv(pm
->node
.nam
, *dptr
);
3297 tiedarrgetfn(Param pm
)
3299 struct tieddata
*dptr
= (struct tieddata
*)pm
->u
.data
;
3300 return *dptr
->arrptr
? zjoin(*dptr
->arrptr
, STOUC(dptr
->joinchar
), 1) : "";
3305 tiedarrsetfn(Param pm
, char *x
)
3307 struct tieddata
*dptr
= (struct tieddata
*)pm
->u
.data
;
3310 freearray(*dptr
->arrptr
);
3313 if (imeta(dptr
->joinchar
))
3316 sepbuf
[1] = dptr
->joinchar
^ 32;
3321 sepbuf
[0] = dptr
->joinchar
;
3324 *dptr
->arrptr
= sepsplit(x
, sepbuf
, 0, 0);
3325 if (pm
->node
.flags
& PM_UNIQUE
)
3326 uniqarray(*dptr
->arrptr
);
3329 *dptr
->arrptr
= NULL
;
3331 arrfixenv(pm
->node
.nam
, *dptr
->arrptr
);
3336 tiedarrunsetfn(Param pm
, UNUSED(int exp
))
3339 * Special unset function because we allocated a struct tieddata
3340 * in typeset_single to hold the special data which we now
3343 pm
->gsu
.s
->setfn(pm
, NULL
);
3344 zfree(pm
->u
.data
, sizeof(struct tieddata
));
3345 /* paranoia -- shouldn't need these, but in case we reuse the struct... */
3349 pm
->node
.flags
&= ~PM_TIED
;
3350 pm
->node
.flags
|= PM_UNSET
;
3355 arrayuniq(char **x
, int freeok
)
3360 for (t
= x
; t
< p
; t
++)
3361 if (!strcmp(*p
, *t
)) {
3364 for (t
= p
--; (*t
= t
[1]) != NULL
; t
++);
3375 arrayuniq(x
, !zheapptr(*x
));
3380 zhuniqarray(char **x
)
3387 /* Function to get value of special parameter `#' and `ARGC' */
3391 poundgetfn(UNUSED(Param pm
))
3393 return arrlen(pparams
);
3396 /* Function to get value for special parameter `RANDOM' */
3400 randomgetfn(UNUSED(Param pm
))
3402 return rand() & 0x7fff;
3405 /* Function to set value of special parameter `RANDOM' */
3409 randomsetfn(UNUSED(Param pm
), zlong v
)
3411 srand((unsigned int)v
);
3414 /* Function to get value for special parameter `SECONDS' */
3418 intsecondsgetfn(UNUSED(Param pm
))
3421 struct timezone dummy_tz
;
3423 gettimeofday(&now
, &dummy_tz
);
3425 return (zlong
)(now
.tv_sec
- shtimer
.tv_sec
) +
3426 (zlong
)(now
.tv_usec
- shtimer
.tv_usec
) / (zlong
)1000000;
3429 /* Function to set value of special parameter `SECONDS' */
3433 intsecondssetfn(UNUSED(Param pm
), zlong x
)
3436 struct timezone dummy_tz
;
3439 gettimeofday(&now
, &dummy_tz
);
3440 diff
= (zlong
)now
.tv_sec
- x
;
3441 shtimer
.tv_sec
= diff
;
3442 if ((zlong
)shtimer
.tv_sec
!= diff
)
3443 zwarn("SECONDS truncated on assignment");
3444 shtimer
.tv_usec
= 0;
3449 floatsecondsgetfn(UNUSED(Param pm
))
3452 struct timezone dummy_tz
;
3454 gettimeofday(&now
, &dummy_tz
);
3456 return (double)(now
.tv_sec
- shtimer
.tv_sec
) +
3457 (double)(now
.tv_usec
- shtimer
.tv_usec
) / 1000000.0;
3462 floatsecondssetfn(UNUSED(Param pm
), double x
)
3465 struct timezone dummy_tz
;
3467 gettimeofday(&now
, &dummy_tz
);
3468 shtimer
.tv_sec
= now
.tv_sec
- (zlong
)x
;
3469 shtimer
.tv_usec
= now
.tv_usec
- (zlong
)((x
- (zlong
)x
) * 1000000.0);
3476 return (double)shtimer
.tv_sec
+ (double)shtimer
.tv_usec
/ 1000000.0;
3481 setrawseconds(double x
)
3483 shtimer
.tv_sec
= (zlong
)x
;
3484 shtimer
.tv_usec
= (zlong
)((x
- (zlong
)x
) * 1000000.0);
3489 setsecondstype(Param pm
, int on
, int off
)
3491 int newflags
= (pm
->node
.flags
| on
) & ~off
;
3492 int tp
= PM_TYPE(newflags
);
3493 /* Only one of the numeric types is allowed. */
3494 if (tp
== PM_EFLOAT
|| tp
== PM_FFLOAT
)
3496 pm
->gsu
.f
= &floatseconds_gsu
;
3498 else if (tp
== PM_INTEGER
)
3500 pm
->gsu
.i
= &intseconds_gsu
;
3504 pm
->node
.flags
= newflags
;
3508 /* Function to get value for special parameter `USERNAME' */
3512 usernamegetfn(UNUSED(Param pm
))
3514 return get_username();
3517 /* Function to set value of special parameter `USERNAME' */
3521 usernamesetfn(UNUSED(Param pm
), char *x
)
3523 #if defined(HAVE_SETUID) && defined(HAVE_GETPWNAM)
3524 struct passwd
*pswd
;
3526 if (x
&& (pswd
= getpwnam(x
)) && (pswd
->pw_uid
!= cached_uid
)) {
3527 # ifdef USE_INITGROUPS
3528 initgroups(x
, pswd
->pw_gid
);
3530 if(!setgid(pswd
->pw_gid
) && !setuid(pswd
->pw_uid
)) {
3531 zsfree(cached_username
);
3532 cached_username
= ztrdup(pswd
->pw_name
);
3533 cached_uid
= pswd
->pw_uid
;
3536 #endif /* HAVE_SETUID && HAVE_GETPWNAM */
3540 /* Function to get value for special parameter `UID' */
3544 uidgetfn(UNUSED(Param pm
))
3549 /* Function to set value of special parameter `UID' */
3553 uidsetfn(UNUSED(Param pm
), zlong x
)
3560 /* Function to get value for special parameter `EUID' */
3564 euidgetfn(UNUSED(Param pm
))
3569 /* Function to set value of special parameter `EUID' */
3573 euidsetfn(UNUSED(Param pm
), zlong x
)
3580 /* Function to get value for special parameter `GID' */
3584 gidgetfn(UNUSED(Param pm
))
3589 /* Function to set value of special parameter `GID' */
3593 gidsetfn(UNUSED(Param pm
), zlong x
)
3600 /* Function to get value for special parameter `EGID' */
3604 egidgetfn(UNUSED(Param pm
))
3609 /* Function to set value of special parameter `EGID' */
3613 egidsetfn(UNUSED(Param pm
), zlong x
)
3622 ttyidlegetfn(UNUSED(Param pm
))
3624 struct stat ttystat
;
3626 if (SHTTY
== -1 || fstat(SHTTY
, &ttystat
))
3628 return time(NULL
) - ttystat
.st_atime
;
3631 /* Function to get value for special parameter `IFS' */
3635 ifsgetfn(UNUSED(Param pm
))
3640 /* Function to set value of special parameter `IFS' */
3644 ifssetfn(UNUSED(Param pm
), char *x
)
3651 /* Functions to set value of special parameters `LANG' and `LC_*' */
3654 static struct localename
{
3659 {"LC_COLLATE", LC_COLLATE
},
3662 {"LC_CTYPE", LC_CTYPE
},
3665 {"LC_MESSAGES", LC_MESSAGES
},
3668 {"LC_NUMERIC", LC_NUMERIC
},
3671 {"LC_TIME", LC_TIME
},
3680 struct localename
*ln
;
3683 * Set the global locale to the value passed, but override
3684 * this with any non-empty definitions for specific
3687 * We only use non-empty definitions because empty values aren't
3688 * valid as locales; when passed to setlocale() they mean "use the
3689 * environment variable", but if that's what we're setting the value
3690 * from this is meaningless. So just all $LANG to show through in
3693 setlocale(LC_ALL
, x
? x
: "");
3695 for (ln
= lc_names
; ln
->name
; ln
++)
3696 if ((x
= getsparam(ln
->name
)) && *x
)
3697 setlocale(ln
->category
, x
);
3703 lc_allsetfn(Param pm
, char *x
)
3707 * Treat an empty LC_ALL the same as an unset one,
3708 * namely by using LANG as the default locale but overriding
3709 * that with any LC_* that are set.
3712 x
= getsparam("LANG");
3720 setlocale(LC_ALL
, x
);
3725 langsetfn(Param pm
, char *x
)
3733 lcsetfn(Param pm
, char *x
)
3736 struct localename
*ln
;
3739 if ((x2
= getsparam("LC_ALL")) && *x2
)
3742 /* Treat empty LC_* the same as unset. */
3744 x
= getsparam("LANG");
3747 * If we've got no non-empty string at this
3748 * point (after checking $LANG, too),
3749 * we shouldn't bother setting anything.
3752 for (ln
= lc_names
; ln
->name
; ln
++)
3753 if (!strcmp(ln
->name
, pm
->node
.nam
))
3754 setlocale(ln
->category
, x
);
3758 #endif /* USE_LOCALE */
3760 /* Function to get value for special parameter `HISTSIZE' */
3764 histsizegetfn(UNUSED(Param pm
))
3769 /* Function to set value of special parameter `HISTSIZE' */
3773 histsizesetfn(UNUSED(Param pm
), zlong v
)
3775 if ((histsiz
= v
) < 1)
3780 /* Function to get value for special parameter `SAVEHIST' */
3784 savehistsizegetfn(UNUSED(Param pm
))
3789 /* Function to set value of special parameter `SAVEHIST' */
3793 savehistsizesetfn(UNUSED(Param pm
), zlong v
)
3795 if ((savehistsiz
= v
) < 0)
3799 /* Function to set value for special parameter `ERRNO' */
3803 errnosetfn(UNUSED(Param pm
), zlong x
)
3806 if ((zlong
)errno
!= x
)
3807 zwarn("errno truncated on assignment");
3810 /* Function to get value for special parameter `ERRNO' */
3814 errnogetfn(UNUSED(Param pm
))
3819 /* Function to get value for special parameter `histchar' */
3823 histcharsgetfn(UNUSED(Param pm
))
3834 /* Function to set value of special parameter `histchar' */
3838 histcharssetfn(UNUSED(Param pm
), char *x
)
3846 for (i
= 0; i
< len
; i
++) {
3847 if (!isascii(STOUC(x
[i
]))) {
3848 zwarn("HISTCHARS can only contain ASCII characters");
3852 bangchar
= len
? STOUC(x
[0]) : '\0';
3853 hatchar
= len
> 1 ? STOUC(x
[1]) : '\0';
3854 hashchar
= len
> 2 ? STOUC(x
[2]) : '\0';
3864 /* Function to get value for special parameter `HOME' */
3868 homegetfn(UNUSED(Param pm
))
3873 /* Function to set value of special parameter `HOME' */
3877 homesetfn(UNUSED(Param pm
), char *x
)
3880 if (x
&& isset(CHASELINKS
) && (home
= xsymlink(x
)))
3883 home
= x
? x
: ztrdup("");
3887 /* Function to get value for special parameter `WORDCHARS' */
3891 wordcharsgetfn(UNUSED(Param pm
))
3896 /* Function to set value of special parameter `WORDCHARS' */
3900 wordcharssetfn(UNUSED(Param pm
), char *x
)
3907 /* Function to get value for special parameter `_' */
3911 underscoregetfn(UNUSED(Param pm
))
3913 char *u
= dupstring(underscore
);
3919 /* Function to get value for special parameter `TERM' */
3923 termgetfn(UNUSED(Param pm
))
3928 /* Function to set value of special parameter `TERM' */
3932 termsetfn(UNUSED(Param pm
), char *x
)
3935 term
= x
? x
: ztrdup("");
3937 /* If non-interactive, delay setting up term till we need it. */
3938 if (unset(INTERACTIVE
) || !*term
)
3939 termflags
|= TERM_UNKNOWN
;
3944 /* Function to get value for special parameter `pipestatus' */
3948 pipestatgetfn(UNUSED(Param pm
))
3950 char **x
= (char **) zhalloc((numpipestats
+ 1) * sizeof(char *));
3954 for (p
= x
, q
= pipestats
, i
= numpipestats
; i
--; p
++, q
++) {
3955 sprintf(buf
, "%d", *q
);
3956 *p
= dupstring(buf
);
3963 /* Function to get value for special parameter `pipestatus' */
3967 pipestatsetfn(UNUSED(Param pm
), char **x
)
3972 for (i
= 0; *x
&& i
< MAX_PIPESTATS
; i
++, x
++)
3973 pipestats
[i
] = atoi(*x
);
3982 arrfixenv(char *s
, char **t
)
3988 cmdnamtab
->emptytable(cmdnamtab
);
3990 pm
= (Param
) paramtab
->getnode(paramtab
, s
);
3993 * Only one level of a parameter can be exported. Unless
3994 * ALLEXPORT is set, this must be global.
3997 if (pm
->node
.flags
& PM_HASHELEM
)
4000 if (isset(ALLEXPORT
))
4001 pm
->node
.flags
|= PM_EXPORTED
;
4004 * Do not "fix" parameters that were not exported
4007 if (!(pm
->node
.flags
& PM_EXPORTED
))
4010 if (pm
->node
.flags
& PM_TIED
)
4011 joinchar
= STOUC(((struct tieddata
*)pm
->u
.data
)->joinchar
);
4015 addenv(pm
, t
? zjoin(t
, joinchar
, 1) : "");
4023 #ifdef USE_SET_UNSET_ENV
4025 * If we are using unsetenv() to remove values from the
4026 * environment, which is the safe thing to do, we
4027 * need to use setenv() to put them there in the first place.
4028 * Unfortunately this is a slightly different interface
4029 * from what zputenv() assumes.
4034 for (ptr
= str
; *ptr
&& *ptr
!= '='; ptr
++)
4038 ret
= setenv(str
, ptr
+1, 1);
4042 DPUTS(1, "bad environment string");
4043 ret
= setenv(str
, ptr
, 1);
4054 /* First check if there is already an environment *
4055 * variable matching string `name'. */
4056 if (findenv(str
, &num_env
)) {
4057 environ
[num_env
] = str
;
4059 /* Else we have to make room and add it */
4060 num_env
= arrlen(environ
);
4061 environ
= (char **) zrealloc(environ
, (sizeof(char *)) * (num_env
+ 2));
4063 /* Now add it at the end */
4064 ep
= environ
+ num_env
;
4074 #ifndef USE_SET_UNSET_ENV
4077 findenv(char *name
, int *pos
)
4083 eq
= strchr(name
, '=');
4084 nlen
= eq
? eq
- name
: (int)strlen(name
);
4085 for (ep
= environ
; *ep
; ep
++)
4086 if (!strncmp (*ep
, name
, nlen
) && *((*ep
)+nlen
) == '=') {
4088 *pos
= ep
- environ
;
4097 /* Given *name = "foo", it searches the environment for string *
4098 * "foo=bar", and returns a pointer to the beginning of "bar" */
4105 return getenv(name
);
4109 for (ep
= environ
; *ep
; ep
++) {
4110 for (s
= *ep
, t
= name
; *s
&& *s
== *t
; s
++, t
++);
4111 if (*s
== '=' && !*t
)
4120 copyenvstr(char *s
, char *value
, int flags
)
4123 if ((*s
= *value
++) == Meta
)
4125 if (flags
& PM_LOWER
)
4127 else if (flags
& PM_UPPER
)
4134 addenv(Param pm
, char *value
)
4137 #ifndef USE_SET_UNSET_ENV
4138 char *oldenv
= 0, *env
= 0;
4142 * First check if there is already an environment
4143 * variable matching string `name'.
4145 if (findenv(pm
->node
.nam
, &pos
))
4146 oldenv
= environ
[pos
];
4149 newenv
= mkenvstr(pm
->node
.nam
, value
, pm
->node
.flags
);
4150 if (zputenv(newenv
)) {
4155 #ifdef USE_SET_UNSET_ENV
4157 * If we are using setenv/unsetenv to manage the environment,
4158 * we simply store the string we created in pm->env since
4159 * memory management of the environment is handled entirely
4162 * TODO: is this good enough to fix problem cases from
4163 * the other branch? If so, we don't actually need to
4164 * store pm->env at all, just a flag that the value was set.
4171 * Under Cygwin we must use putenv() to maintain consistency.
4172 * Unfortunately, current version (1.1.2) copies argument and may
4173 * silently reuse existing environment string. This tries to
4174 * check for both cases
4176 if (findenv(pm
->node
.nam
, &pos
)) {
4182 pm
->node
.flags
|= PM_EXPORTED
;
4187 DPUTS(1, "addenv should never reach the end");
4193 /* Given strings *name = "foo", *value = "bar", *
4194 * return a new string *str = "foo=bar". */
4198 mkenvstr(char *name
, char *value
, int flags
)
4201 int len_name
, len_value
;
4203 len_name
= strlen(name
);
4204 for (len_value
= 0, s
= value
;
4205 *s
&& (*s
++ != Meta
|| *s
++ != 32); len_value
++);
4206 s
= str
= (char *) zalloc(len_name
+ len_value
+ 2);
4210 copyenvstr(s
, value
, flags
);
4214 /* Given *name = "foo", *value = "bar", add the *
4215 * string "foo=bar" to the environment. Return a *
4216 * pointer to the location of this new environment *
4220 #ifndef USE_SET_UNSET_ENV
4223 delenvvalue(char *x
)
4227 for (ep
= environ
; *ep
; ep
++) {
4232 for (; (ep
[0] = ep
[1]); ep
++);
4239 /* Delete a pointer from the list of pointers to environment *
4240 * variables by shifting all the other pointers up one slot. */
4246 #ifdef USE_SET_UNSET_ENV
4247 unsetenv(pm
->node
.nam
);
4250 delenvvalue(pm
->env
);
4254 * Note we don't remove PM_EXPORT from the flags. This
4255 * may be asking for trouble but we need to know later
4256 * if we restore this parameter to its old value.
4262 convbase(char *s
, zlong v
, int base
)
4269 if (base
>= -1 && base
<= 1)
4273 if (isset(CBASES
) && base
== 16)
4275 else if (isset(CBASES
) && base
== 8 && isset(OCTALZEROES
))
4277 else if (base
!= 10)
4278 sprintf(s
, "%d#", base
);
4284 for (x
= v
; x
; digs
++)
4293 s
[digs
--] = (dig
< 10) ? '0' + dig
: dig
- 10 + 'A';
4299 * Convert a floating point value for output.
4300 * Unlike convbase(), this has its own internal storage and returns
4301 * a value from the heap.
4306 convfloat(double dval
, int digits
, int flags
, FILE *fout
)
4308 char fmt
[] = "%.*e";
4309 char *prev_locale
, *ret
;
4312 * The difficulty with the buffer size is that a %f conversion
4313 * prints all digits before the decimal point: with 64 bit doubles,
4314 * that's around 310. We can't check without doing some quite
4315 * serious floating point operations we'd like to avoid.
4316 * Then we are liable to get all the digits
4317 * we asked for after the decimal point, or we should at least
4318 * bargain for it. So we just allocate 512 + digits. This
4319 * should work until somebody decides on 128-bit doubles.
4321 if (!(flags
& (PM_EFLOAT
|PM_FFLOAT
))) {
4323 * Conversion from a floating point expression without using
4324 * a variable. The best bet in this case just seems to be
4325 * to use the general %g format with something like the maximum
4332 if (flags
& PM_FFLOAT
)
4336 if (flags
& PM_EFLOAT
) {
4338 * Here, we are given the number of significant figures, but
4339 * %e wants the number of decimal places (unlike %g)
4345 prev_locale
= dupstring(setlocale(LC_NUMERIC
, NULL
));
4346 setlocale(LC_NUMERIC
, "POSIX");
4349 fprintf(fout
, fmt
, digits
, dval
);
4352 VARARR(char, buf
, 512 + digits
);
4353 sprintf(buf
, fmt
, digits
, dval
);
4354 if (!strchr(buf
, 'e') && !strchr(buf
, '.'))
4356 ret
= dupstring(buf
);
4359 if (prev_locale
) setlocale(LC_NUMERIC
, prev_locale
);
4364 /* Start a parameter scope */
4368 startparamscope(void)
4373 /* End a parameter scope: delete the parameters local to the scope. */
4380 /* This pops anything from a higher locallevel */
4381 saveandpophiststack(0, HFILE_USE_OPTIONS
);
4382 scanhashtable(paramtab
, 0, 0, 0, scanendscope
, 0);
4387 scanendscope(HashNode hn
, UNUSED(int flags
))
4389 Param pm
= (Param
)hn
;
4390 if (pm
->level
> locallevel
) {
4391 if ((pm
->node
.flags
& (PM_SPECIAL
|PM_REMOVABLE
)) == PM_SPECIAL
) {
4393 * Removable specials are normal in that they can be removed
4394 * to reveal an ordinary parameter beneath. Here we handle
4395 * non-removable specials, which were made local by stealth
4396 * (see newspecial code in typeset_single()). In fact the
4397 * visible pm is always the same struct; the pm->old is
4398 * just a place holder for old data and flags.
4400 Param tpm
= pm
->old
;
4402 if (!strcmp(pm
->node
.nam
, "SECONDS"))
4404 setsecondstype(pm
, PM_TYPE(tpm
->node
.flags
), PM_TYPE(pm
->node
.flags
));
4406 * We restore SECONDS by restoring its raw internal value
4407 * that we cached off into tpm->u.dval.
4409 setrawseconds(tpm
->u
.dval
);
4410 tpm
->node
.flags
|= PM_NORESTORE
;
4412 DPUTS(!tpm
|| PM_TYPE(pm
->node
.flags
) != PM_TYPE(tpm
->node
.flags
) ||
4413 !(tpm
->node
.flags
& PM_SPECIAL
),
4414 "BUG: in restoring scope of special parameter");
4416 pm
->node
.flags
= (tpm
->node
.flags
& ~PM_NORESTORE
);
4417 pm
->level
= tpm
->level
;
4418 pm
->base
= tpm
->base
;
4419 pm
->width
= tpm
->width
;
4423 if (!(tpm
->node
.flags
& (PM_NORESTORE
|PM_READONLY
)))
4424 switch (PM_TYPE(pm
->node
.flags
)) {
4426 pm
->gsu
.s
->setfn(pm
, tpm
->u
.str
);
4429 pm
->gsu
.i
->setfn(pm
, tpm
->u
.val
);
4433 pm
->gsu
.f
->setfn(pm
, tpm
->u
.dval
);
4436 pm
->gsu
.a
->setfn(pm
, tpm
->u
.arr
);
4439 pm
->gsu
.h
->setfn(pm
, tpm
->u
.hash
);
4442 zfree(tpm
, sizeof(*tpm
));
4444 if (pm
->node
.flags
& PM_EXPORTED
)
4447 unsetparam_pm(pm
, 0, 0);
4452 /**********************************/
4453 /* Parameter Hash Table Functions */
4454 /**********************************/
4458 freeparamnode(HashNode hn
)
4460 Param pm
= (Param
) hn
;
4462 /* Since the second flag to unsetfn isn't used, I don't *
4463 * know what its value should be. */
4465 pm
->gsu
.s
->unsetfn(pm
, 1);
4466 zsfree(pm
->node
.nam
);
4467 /* If this variable was tied by the user, ename was ztrdup'd */
4468 if (pm
->node
.flags
& PM_TIED
)
4470 zfree(pm
, sizeof(struct param
));
4473 /* Print a parameter */
4475 enum paramtypes_flags
{
4476 PMTF_USE_BASE
= (1<<0),
4477 PMTF_USE_WIDTH
= (1<<1),
4478 PMTF_TEST_LEVEL
= (1<<2)
4482 int binflag
; /* The relevant PM_FLAG(S) */
4483 const char *string
; /* String for verbose output */
4484 int typeflag
; /* Flag for typeset -? */
4485 int flags
; /* The enum above */
4488 static const struct paramtypes pmtypes
[] = {
4489 { PM_AUTOLOAD
, "undefined", 0, 0},
4490 { PM_INTEGER
, "integer", 'i', PMTF_USE_BASE
},
4491 { PM_EFLOAT
, "float", 'E', 0},
4492 { PM_FFLOAT
, "float", 'F', 0},
4493 { PM_ARRAY
, "array", 'a', 0},
4494 { PM_HASHED
, "association", 'A', 0},
4495 { 0, "local", 0, PMTF_TEST_LEVEL
},
4496 { PM_LEFT
, "left justified", 'L', PMTF_USE_WIDTH
},
4497 { PM_RIGHT_B
, "right justified", 'R', PMTF_USE_WIDTH
},
4498 { PM_RIGHT_Z
, "zero filled", 'Z', PMTF_USE_WIDTH
},
4499 { PM_LOWER
, "lowercase", 'l', 0},
4500 { PM_UPPER
, "uppercase", 'u', 0},
4501 { PM_READONLY
, "readonly", 'r', 0},
4502 { PM_TAGGED
, "tagged", 't', 0},
4503 { PM_EXPORTED
, "exported", 'x', 0}
4506 #define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
4510 printparamnode(HashNode hn
, int printflags
)
4512 Param p
= (Param
) hn
;
4515 if (p
->node
.flags
& PM_UNSET
)
4518 if (printflags
& PRINT_TYPESET
)
4521 /* Print the attributes of the parameter */
4522 if (printflags
& (PRINT_TYPE
|PRINT_TYPESET
)) {
4523 int doneminus
= 0, i
;
4524 const struct paramtypes
*pmptr
;
4526 for (pmptr
= pmtypes
, i
= 0; i
< PMTYPES_SIZE
; i
++, pmptr
++) {
4528 if (pmptr
->flags
& PMTF_TEST_LEVEL
) {
4531 } else if (p
->node
.flags
& pmptr
->binflag
)
4535 if (printflags
& PRINT_TYPESET
) {
4536 if (pmptr
->typeflag
) {
4541 putchar(pmptr
->typeflag
);
4544 printf("%s ", pmptr
->string
);
4546 if ((pmptr
->flags
& PMTF_USE_BASE
) && p
->base
) {
4547 printf("%d ", p
->base
);
4550 if ((pmptr
->flags
& PMTF_USE_WIDTH
) && p
->width
) {
4551 printf("%d ", p
->width
);
4560 if ((printflags
& PRINT_NAMEONLY
) ||
4561 ((p
->node
.flags
& PM_HIDEVAL
) && !(printflags
& PRINT_INCLUDEVALUE
))) {
4562 zputs(p
->node
.nam
, stdout
);
4567 quotedzputs(p
->node
.nam
, stdout
);
4569 if (p
->node
.flags
& PM_AUTOLOAD
) {
4573 if (printflags
& PRINT_KV_PAIR
)
4575 else if ((printflags
& PRINT_TYPESET
) &&
4576 (PM_TYPE(p
->node
.flags
) == PM_ARRAY
|| PM_TYPE(p
->node
.flags
) == PM_HASHED
))
4577 printf("\n%s=", p
->node
.nam
);
4581 /* How the value is displayed depends *
4582 * on the type of the parameter */
4583 switch (PM_TYPE(p
->node
.flags
)) {
4585 /* string: simple output */
4586 if (p
->gsu
.s
->getfn
&& (t
= p
->gsu
.s
->getfn(p
)))
4587 quotedzputs(t
, stdout
);
4591 #ifdef ZSH_64_BIT_TYPE
4592 fputs(output64(p
->gsu
.i
->getfn(p
)), stdout
);
4594 printf("%ld", p
->gsu
.i
->getfn(p
));
4600 convfloat(p
->gsu
.f
->getfn(p
), p
->base
, p
->node
.flags
, stdout
);
4604 if (!(printflags
& PRINT_KV_PAIR
))
4606 u
= p
->gsu
.a
->getfn(p
);
4608 quotedzputs(*u
++, stdout
);
4611 quotedzputs(*u
++, stdout
);
4614 if (!(printflags
& PRINT_KV_PAIR
))
4619 if (!(printflags
& PRINT_KV_PAIR
))
4622 HashTable ht
= p
->gsu
.h
->getfn(p
);
4624 scanhashtable(ht
, 1, 0, PM_UNSET
,
4625 ht
->printnode
, PRINT_KV_PAIR
);
4627 if (!(printflags
& PRINT_KV_PAIR
))
4631 if (printflags
& PRINT_KV_PAIR
)