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