1 /*
2 * parameter.c - parameter interface to zsh internals
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 1999 Sven Wischnowsky
7 * All rights reserved.
8 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
14 *
15 * In no event shall Sven Wischnowsky or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Sven Wischnowsky and the Zsh Development Group have been advised of
19 * the possibility of such damage.
20 *
21 * Sven Wischnowsky and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
27 *
28 */
29
30 #include "parameter.mdh"
31 #include "parameter.pro"
32
33 /* This says if we are cleaning up when the module is unloaded. */
34
35 static int incleanup;
36
37 /* Functions for the parameters special parameter. */
38
39 /* Return a string describing the type of a parameter. */
40
41 /**/
42 static char *
paramtypestr(Param pm)43 paramtypestr(Param pm)
44 {
45 char *val = NULL;
46 int f = pm->node.flags;
47
48 if (!(f & PM_UNSET)) {
49 if (pm->node.flags & PM_AUTOLOAD)
50 return dupstring("undefined");
51
52 switch (PM_TYPE(f)) {
53 case PM_SCALAR: val = "scalar"; break;
54 case PM_ARRAY: val = "array"; break;
55 case PM_INTEGER: val = "integer"; break;
56 case PM_EFLOAT:
57 case PM_FFLOAT: val = "float"; break;
58 case PM_HASHED: val = "association"; break;
59 }
60 DPUTS(!val, "BUG: type not handled in parameter");
61 val = dupstring(val);
62 if (pm->level)
63 val = dyncat(val, "-local");
64 if (f & PM_LEFT)
65 val = dyncat(val, "-left");
66 if (f & PM_RIGHT_B)
67 val = dyncat(val, "-right_blanks");
68 if (f & PM_RIGHT_Z)
69 val = dyncat(val, "-right_zeros");
70 if (f & PM_LOWER)
71 val = dyncat(val, "-lower");
72 if (f & PM_UPPER)
73 val = dyncat(val, "-upper");
74 if (f & PM_READONLY)
75 val = dyncat(val, "-readonly");
76 if (f & PM_TAGGED)
77 val = dyncat(val, "-tag");
78 if (f & PM_TIED)
79 val = dyncat(val, "-tied");
80 if (f & PM_EXPORTED)
81 val = dyncat(val, "-export");
82 if (f & PM_UNIQUE)
83 val = dyncat(val, "-unique");
84 if (f & PM_HIDE)
85 val = dyncat(val, "-hide");
86 if (f & PM_HIDEVAL)
87 val = dyncat(val, "-hideval");
88 if (f & PM_SPECIAL)
89 val = dyncat(val, "-special");
90 } else
91 val = dupstring("");
92
93 return val;
94 }
95
96 /**/
97 static HashNode
getpmparameter(UNUSED (HashTable ht),const char * name)98 getpmparameter(UNUSED(HashTable ht), const char *name)
99 {
100 Param rpm, pm = NULL;
101
102 pm = (Param) hcalloc(sizeof(struct param));
103 pm->node.nam = dupstring(name);
104 pm->node.flags = PM_SCALAR | PM_READONLY;
105 pm->gsu.s = &nullsetscalar_gsu;
106 if ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
107 !(rpm->node.flags & PM_UNSET))
108 pm->u.str = paramtypestr(rpm);
109 else {
110 pm->u.str = dupstring("");
111 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
112 }
113 return &pm->node;
114 }
115
116 /**/
117 static void
scanpmparameters(UNUSED (HashTable ht),ScanFunc func,int flags)118 scanpmparameters(UNUSED(HashTable ht), ScanFunc func, int flags)
119 {
120 struct param pm;
121 int i;
122 HashNode hn;
123
124 memset((void *)&pm, 0, sizeof(struct param));
125 pm.node.flags = PM_SCALAR | PM_READONLY;
126 pm.gsu.s = &nullsetscalar_gsu;
127
128 for (i = 0; i < realparamtab->hsize; i++)
129 for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
130 if (((Param)hn)->node.flags & PM_UNSET)
131 continue;
132 pm.node.nam = hn->nam;
133 if (func != scancountparams &&
134 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
135 !(flags & SCANPM_WANTKEYS)))
136 pm.u.str = paramtypestr((Param) hn);
137 func(&pm.node, flags);
138 }
139 }
140
141 /* Functions for the commands special parameter. */
142
143 /**/
144 static void
setpmcommand(Param pm,char * value)145 setpmcommand(Param pm, char *value)
146 {
147 if (isset(RESTRICTED)) {
148 zwarn("restricted: %s", value);
149 zsfree(value);
150 } else {
151 Cmdnam cn = zshcalloc(sizeof(*cn));
152
153 cn->node.flags = HASHED;
154 cn->u.cmd = value;
155
156 cmdnamtab->addnode(cmdnamtab, ztrdup(pm->node.nam), &cn->node);
157 }
158 }
159
160 /**/
161 static void
unsetpmcommand(Param pm,UNUSED (int exp))162 unsetpmcommand(Param pm, UNUSED(int exp))
163 {
164 HashNode hn = cmdnamtab->removenode(cmdnamtab, pm->node.nam);
165
166 if (hn)
167 cmdnamtab->freenode(hn);
168 }
169
170 /**/
171 static void
setpmcommands(Param pm,HashTable ht)172 setpmcommands(Param pm, HashTable ht)
173 {
174 int i;
175 HashNode hn;
176
177 if (!ht)
178 return;
179
180 for (i = 0; i < ht->hsize; i++)
181 for (hn = ht->nodes[i]; hn; hn = hn->next) {
182 Cmdnam cn = zshcalloc(sizeof(*cn));
183 struct value v;
184
185 v.isarr = v.flags = v.start = 0;
186 v.end = -1;
187 v.arr = NULL;
188 v.pm = (Param) hn;
189
190 cn->node.flags = HASHED;
191 cn->u.cmd = ztrdup(getstrvalue(&v));
192
193 cmdnamtab->addnode(cmdnamtab, ztrdup(hn->nam), &cn->node);
194 }
195 /*
196 * On full-array assignment ht is a temporary hash with the default
197 * get/set functions, whereas pm->u.hash has the special $commands
198 * get/set functions. Do not assign ht to pm, just delete it.
199 *
200 * On append, ht and pm->u.hash are the same table, don't delete.
201 */
202 if (ht != pm->u.hash)
203 deleteparamtable(ht);
204 }
205
206 static const struct gsu_scalar pmcommand_gsu =
207 { strgetfn, setpmcommand, unsetpmcommand };
208
209
210 /**/
211 static HashNode
getpmcommand(UNUSED (HashTable ht),const char * name)212 getpmcommand(UNUSED(HashTable ht), const char *name)
213 {
214 Cmdnam cmd;
215 Param pm = NULL;
216
217 if (!(cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name)) &&
218 isset(HASHLISTALL)) {
219 cmdnamtab->filltable(cmdnamtab);
220 cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name);
221 }
222 pm = (Param) hcalloc(sizeof(struct param));
223 pm->node.nam = dupstring(name);
224 pm->node.flags = PM_SCALAR;
225 pm->gsu.s = &pmcommand_gsu;
226 if (cmd) {
227 if (cmd->node.flags & HASHED)
228 pm->u.str = cmd->u.cmd;
229 else {
230 pm->u.str = zhalloc(strlen(*(cmd->u.name)) + strlen(name) + 2);
231 strcpy(pm->u.str, *(cmd->u.name));
232 strcat(pm->u.str, "/");
233 strcat(pm->u.str, name);
234 }
235 } else {
236 pm->u.str = dupstring("");
237 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
238 }
239 return &pm->node;
240 }
241
242 /**/
243 static void
scanpmcommands(UNUSED (HashTable ht),ScanFunc func,int flags)244 scanpmcommands(UNUSED(HashTable ht), ScanFunc func, int flags)
245 {
246 struct param pm;
247 int i;
248 HashNode hn;
249 Cmdnam cmd;
250
251 if (isset(HASHLISTALL))
252 cmdnamtab->filltable(cmdnamtab);
253
254 memset((void *)&pm, 0, sizeof(struct param));
255 pm.node.flags = PM_SCALAR;
256 pm.gsu.s = &pmcommand_gsu;
257
258 for (i = 0; i < cmdnamtab->hsize; i++)
259 for (hn = cmdnamtab->nodes[i]; hn; hn = hn->next) {
260 pm.node.nam = hn->nam;
261 cmd = (Cmdnam) hn;
262 if (func != scancountparams &&
263 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
264 !(flags & SCANPM_WANTKEYS))) {
265 if (cmd->node.flags & HASHED)
266 pm.u.str = cmd->u.cmd;
267 else {
268 pm.u.str = zhalloc(strlen(*(cmd->u.name)) +
269 strlen(cmd->node.nam) + 2);
270 strcpy(pm.u.str, *(cmd->u.name));
271 strcat(pm.u.str, "/");
272 strcat(pm.u.str, cmd->node.nam);
273 }
274 }
275 func(&pm.node, flags);
276 }
277 }
278
279 /* Functions for the functions special parameter. */
280
281 /**/
282 static void
setfunction(char * name,char * val,int dis)283 setfunction(char *name, char *val, int dis)
284 {
285 char *value = dupstring(val);
286 Shfunc shf;
287 Eprog prog;
288 int sn;
289
290 val = metafy(val, strlen(val), META_REALLOC);
291
292 prog = parse_string(val, 1);
293
294 if (!prog || prog == &dummy_eprog) {
295 zwarn("invalid function definition", value);
296 zsfree(val);
297 return;
298 }
299 shf = (Shfunc) zshcalloc(sizeof(*shf));
300 shf->funcdef = dupeprog(prog, 0);
301 shf->node.flags = dis;
302 shfunc_set_sticky(shf);
303
304 if (!strncmp(name, "TRAP", 4) &&
305 (sn = getsignum(name + 4)) != -1) {
306 if (settrap(sn, NULL, ZSIG_FUNC)) {
307 freeeprog(shf->funcdef);
308 zfree(shf, sizeof(*shf));
309 zsfree(val);
310 return;
311 }
312 }
313 shfunctab->addnode(shfunctab, ztrdup(name), shf);
314 zsfree(val);
315 }
316
317 /**/
318 static void
setpmfunction(Param pm,char * value)319 setpmfunction(Param pm, char *value)
320 {
321 setfunction(pm->node.nam, value, 0);
322 }
323
324 /**/
325 static void
setpmdisfunction(Param pm,char * value)326 setpmdisfunction(Param pm, char *value)
327 {
328 setfunction(pm->node.nam, value, DISABLED);
329 }
330
331 /**/
332 static void
unsetpmfunction(Param pm,UNUSED (int exp))333 unsetpmfunction(Param pm, UNUSED(int exp))
334 {
335 HashNode hn = shfunctab->removenode(shfunctab, pm->node.nam);
336
337 if (hn)
338 shfunctab->freenode(hn);
339 }
340
341 /**/
342 static void
setfunctions(Param pm,HashTable ht,int dis)343 setfunctions(Param pm, HashTable ht, int dis)
344 {
345 int i;
346 HashNode hn;
347
348 if (!ht)
349 return;
350
351 for (i = 0; i < ht->hsize; i++)
352 for (hn = ht->nodes[i]; hn; hn = hn->next) {
353 struct value v;
354
355 v.isarr = v.flags = v.start = 0;
356 v.end = -1;
357 v.arr = NULL;
358 v.pm = (Param) hn;
359
360 setfunction(hn->nam, ztrdup(getstrvalue(&v)), dis);
361 }
362 /* See setpmcommands() above */
363 if (ht != pm->u.hash)
364 deleteparamtable(ht);
365 }
366
367 /**/
368 static void
setpmfunctions(Param pm,HashTable ht)369 setpmfunctions(Param pm, HashTable ht)
370 {
371 setfunctions(pm, ht, 0);
372 }
373
374 /**/
375 static void
setpmdisfunctions(Param pm,HashTable ht)376 setpmdisfunctions(Param pm, HashTable ht)
377 {
378 setfunctions(pm, ht, DISABLED);
379 }
380
381 static const struct gsu_scalar pmfunction_gsu =
382 { strgetfn, setpmfunction, unsetpmfunction };
383 static const struct gsu_scalar pmdisfunction_gsu =
384 { strgetfn, setpmdisfunction, unsetpmfunction };
385
386 /**/
387 static HashNode
getfunction(UNUSED (HashTable ht),const char * name,int dis)388 getfunction(UNUSED(HashTable ht), const char *name, int dis)
389 {
390 Shfunc shf;
391 Param pm = NULL;
392
393 pm = (Param) hcalloc(sizeof(struct param));
394 pm->node.nam = dupstring(name);
395 pm->node.flags = PM_SCALAR;
396 pm->gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
397
398 if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
399 (dis ? (shf->node.flags & DISABLED) : !(shf->node.flags & DISABLED))) {
400 if (shf->node.flags & PM_UNDEFINED) {
401 pm->u.str = dyncat("builtin autoload -X",
402 ((shf->node.flags & PM_UNALIASED) ?
403 ((shf->node.flags & PM_TAGGED) ? "Ut" : "U") :
404 ((shf->node.flags & PM_TAGGED) ? "t" : "")));
405 } else {
406 char *t = getpermtext(shf->funcdef, NULL, 1), *n, *h;
407 char *start;
408
409 if (shf->redir)
410 start = "{\n\t";
411 else
412 start = "\t";
413
414 if (shf->funcdef->flags & EF_RUN) {
415 n = nicedupstring(name);
416 h = (char *) zhalloc(strlen(start) + strlen(t) + strlen(n) + 8);
417 strcpy(h, start);
418 strcat(h, t);
419 strcat(h, "\n\t");
420 strcat(h, n);
421 strcat(h, " \"$@\"");
422 } else
423 h = dyncat(start, t);
424 zsfree(t);
425
426 if (shf->redir) {
427 t = getpermtext(shf->redir, NULL, 1);
428 h = zhtricat(h, "\n}", t);
429 zsfree(t);
430 }
431
432 pm->u.str = h;
433 }
434 } else {
435 pm->u.str = dupstring("");
436 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
437 }
438 return &pm->node;
439 }
440
441 /**/
442 static HashNode
getpmfunction(HashTable ht,const char * name)443 getpmfunction(HashTable ht, const char *name)
444 {
445 return getfunction(ht, name, 0);
446 }
447
448 /**/
449 static HashNode
getpmdisfunction(HashTable ht,const char * name)450 getpmdisfunction(HashTable ht, const char *name)
451 {
452 return getfunction(ht, name, DISABLED);
453 }
454
455 /**/
456 static void
scanfunctions(UNUSED (HashTable ht),ScanFunc func,int flags,int dis)457 scanfunctions(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
458 {
459 struct param pm;
460 int i;
461 HashNode hn;
462
463 memset((void *)&pm, 0, sizeof(struct param));
464 pm.node.flags = PM_SCALAR;
465 pm.gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
466
467 for (i = 0; i < shfunctab->hsize; i++)
468 for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
469 if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
470 pm.node.nam = hn->nam;
471 if (func != scancountparams &&
472 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
473 !(flags & SCANPM_WANTKEYS))) {
474 if (((Shfunc) hn)->node.flags & PM_UNDEFINED) {
475 Shfunc shf = (Shfunc) hn;
476 pm.u.str =
477 dyncat("builtin autoload -X",
478 ((shf->node.flags & PM_UNALIASED) ?
479 ((shf->node.flags & PM_TAGGED) ? "Ut" : "U") :
480 ((shf->node.flags & PM_TAGGED) ? "t" : "")));
481 } else {
482 Shfunc shf = (Shfunc)hn;
483 char *t = getpermtext(shf->funcdef, NULL, 1);
484 char *n, *start;
485
486 if (shf->redir)
487 start = "{\n\t";
488 else
489 start = "\t";
490
491 if (shf->funcdef->flags & EF_RUN) {
492 n = nicedupstring(hn->nam);
493 pm.u.str = (char *) zhalloc(
494 strlen(start) + strlen(t) + strlen(n) + 8);
495 strcpy(pm.u.str, start);
496 strcat(pm.u.str, t);
497 strcat(pm.u.str, "\n\t");
498 strcat(pm.u.str, n);
499 strcat(pm.u.str, " \"$@\"");
500 } else
501 pm.u.str = dyncat(start, t);
502 zsfree(t);
503
504 if (shf->redir) {
505 t = getpermtext(shf->redir, NULL, 1);
506 pm.u.str = zhtricat(pm.u.str, "\n}", t);
507 zsfree(t);
508 }
509 }
510 }
511 func(&pm.node, flags);
512 }
513 }
514 }
515
516 /**/
517 static void
scanpmfunctions(HashTable ht,ScanFunc func,int flags)518 scanpmfunctions(HashTable ht, ScanFunc func, int flags)
519 {
520 scanfunctions(ht, func, flags, 0);
521 }
522
523 /**/
524 static void
scanpmdisfunctions(HashTable ht,ScanFunc func,int flags)525 scanpmdisfunctions(HashTable ht, ScanFunc func, int flags)
526 {
527 scanfunctions(ht, func, flags, DISABLED);
528 }
529
530 /* Functions for the functions_source special parameter. */
531
532 /* Retrieve the source file for a function by explicit name */
533
534 /**/
535 static HashNode
getfunction_source(UNUSED (HashTable ht),const char * name,int dis)536 getfunction_source(UNUSED(HashTable ht), const char *name, int dis)
537 {
538 Shfunc shf;
539 Param pm = NULL;
540
541 pm = (Param) hcalloc(sizeof(struct param));
542 pm->node.nam = dupstring(name);
543 pm->node.flags = PM_SCALAR|PM_READONLY;
544 pm->gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
545
546 if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
547 (dis ? (shf->node.flags & DISABLED) : !(shf->node.flags & DISABLED))) {
548 pm->u.str = getshfuncfile(shf);
549 if (!pm->u.str)
550 pm->u.str = dupstring("");
551 }
552 return &pm->node;
553 }
554
555 /* Retrieve the source file for functions by scanning the table */
556
557 /**/
558 static void
scanfunctions_source(UNUSED (HashTable ht),ScanFunc func,int flags,int dis)559 scanfunctions_source(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
560 {
561 struct param pm;
562 int i;
563 HashNode hn;
564
565 memset((void *)&pm, 0, sizeof(struct param));
566 pm.node.flags = PM_SCALAR|PM_READONLY;
567 pm.gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
568
569 for (i = 0; i < shfunctab->hsize; i++) {
570 for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
571 if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
572 pm.node.nam = hn->nam;
573 if (func != scancountparams &&
574 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
575 !(flags & SCANPM_WANTKEYS))) {
576 pm.u.str = getshfuncfile((Shfunc)hn);
577 if (!pm.u.str)
578 pm.u.str = dupstring("");
579 }
580 func(&pm.node, flags);
581 }
582 }
583 }
584 }
585
586 /* Param table entry for retrieving functions_source element */
587
588 /**/
589 static HashNode
getpmfunction_source(HashTable ht,const char * name)590 getpmfunction_source(HashTable ht, const char *name)
591 {
592 return getfunction_source(ht, name, 0);
593 }
594
595 /* Param table entry for retrieving ds_functions_source element */
596
597 /**/
598 static HashNode
getpmdisfunction_source(HashTable ht,const char * name)599 getpmdisfunction_source(HashTable ht, const char *name)
600 {
601 return getfunction_source(ht, name, 1);
602 }
603
604 /* Param table entry for scanning functions_source table */
605
606 /**/
607 static void
scanpmfunction_source(HashTable ht,ScanFunc func,int flags)608 scanpmfunction_source(HashTable ht, ScanFunc func, int flags)
609 {
610 scanfunctions_source(ht, func, flags, 0);
611 }
612
613 /* Param table entry for scanning dis_functions_source table */
614
615 /**/
616 static void
scanpmdisfunction_source(HashTable ht,ScanFunc func,int flags)617 scanpmdisfunction_source(HashTable ht, ScanFunc func, int flags)
618 {
619 scanfunctions_source(ht, func, flags, 1);
620 }
621
622 /* Functions for the funcstack special parameter. */
623
624 /**/
625 static char **
funcstackgetfn(UNUSED (Param pm))626 funcstackgetfn(UNUSED(Param pm))
627 {
628 Funcstack f;
629 int num;
630 char **ret, **p;
631
632 for (f = funcstack, num = 0; f; f = f->prev, num++);
633
634 ret = (char **) zhalloc((num + 1) * sizeof(char *));
635
636 for (f = funcstack, p = ret; f; f = f->prev, p++)
637 *p = f->name;
638 *p = NULL;
639
640 return ret;
641 }
642
643 /* Functions for the functrace special parameter. */
644
645 /**/
646 static char **
functracegetfn(UNUSED (Param pm))647 functracegetfn(UNUSED(Param pm))
648 {
649 Funcstack f;
650 int num;
651 char **ret, **p;
652
653 for (f = funcstack, num = 0; f; f = f->prev, num++);
654
655 ret = (char **) zhalloc((num + 1) * sizeof(char *));
656
657 for (f = funcstack, p = ret; f; f = f->prev, p++) {
658 char *colonpair;
659
660 colonpair = zhalloc(strlen(f->caller) + (f->lineno > 9999 ? 24 : 6));
661 #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
662 sprintf(colonpair, "%s:%lld", f->caller, f->lineno);
663 #else
664 sprintf(colonpair, "%s:%ld", f->caller, (long)f->lineno);
665 #endif
666
667 *p = colonpair;
668 }
669 *p = NULL;
670
671 return ret;
672 }
673
674 /* Functions for the funcsourcetrace special parameter. */
675
676 /**/
677 static char **
funcsourcetracegetfn(UNUSED (Param pm))678 funcsourcetracegetfn(UNUSED(Param pm))
679 {
680 Funcstack f;
681 int num;
682 char **ret, **p;
683
684 for (f = funcstack, num = 0; f; f = f->prev, num++);
685
686 ret = (char **) zhalloc((num + 1) * sizeof(char *));
687
688 for (f = funcstack, p = ret; f; f = f->prev, p++) {
689 char *colonpair;
690 char *fname = f->filename ? f->filename : "";
691
692 colonpair = zhalloc(strlen(fname) + (f->flineno > 9999 ? 24 : 6));
693 #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
694 sprintf(colonpair, "%s:%lld", fname, f->flineno);
695 #else
696 sprintf(colonpair, "%s:%ld", fname, (long)f->flineno);
697 #endif
698
699 *p = colonpair;
700 }
701 *p = NULL;
702
703 return ret;
704 }
705
706 /* Functions for the funcfiletrace special parameter. */
707
708 /**/
709 static char **
funcfiletracegetfn(UNUSED (Param pm))710 funcfiletracegetfn(UNUSED(Param pm))
711 {
712 Funcstack f;
713 int num;
714 char **ret, **p;
715
716 for (f = funcstack, num = 0; f; f = f->prev, num++);
717
718 ret = (char **) zhalloc((num + 1) * sizeof(char *));
719
720 for (f = funcstack, p = ret; f; f = f->prev, p++) {
721 char *colonpair, *fname;
722
723 if (!f->prev || f->prev->tp == FS_SOURCE) {
724 /*
725 * Calling context is a file---either the parent
726 * script or interactive shell, or a sourced
727 * script. Just print the file information for the caller
728 * (same as $functrace)
729 */
730 colonpair = zhalloc(strlen(f->caller) +
731 (f->lineno > 9999 ? 24 : 6));
732 #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
733 sprintf(colonpair, "%s:%lld", f->caller, f->lineno);
734 #else
735 sprintf(colonpair, "%s:%ld", f->caller, (long)f->lineno);
736 #endif
737 } else {
738 /*
739 * Calling context is a function or eval; we need to find
740 * the line number in the file where that function was
741 * defined or the eval was called. For this we need the
742 * $funcsourcetrace information for the context above,
743 * together with the $functrace line number for the current
744 * context.
745 */
746 zlong flineno = f->prev->flineno + f->lineno;
747 /*
748 * Line numbers in eval start from 1, not zero,
749 * so offset by one to get line in file.
750 */
751 if (f->prev->tp == FS_EVAL)
752 flineno--;
753 fname = f->prev->filename ? f->prev->filename : "";
754
755 colonpair = zhalloc(strlen(fname) + (flineno > 9999 ? 24 : 6));
756 #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
757 sprintf(colonpair, "%s:%lld", fname, flineno);
758 #else
759 sprintf(colonpair, "%s:%ld", fname, (long)flineno);
760 #endif
761 }
762
763 *p = colonpair;
764 }
765 *p = NULL;
766
767 return ret;
768 }
769
770 /* Functions for the builtins special parameter. */
771
772 /**/
773 static HashNode
getbuiltin(UNUSED (HashTable ht),const char * name,int dis)774 getbuiltin(UNUSED(HashTable ht), const char *name, int dis)
775 {
776 Param pm = NULL;
777 Builtin bn;
778
779 pm = (Param) hcalloc(sizeof(struct param));
780 pm->node.nam = dupstring(name);
781 pm->node.flags = PM_SCALAR | PM_READONLY;
782 pm->gsu.s = &nullsetscalar_gsu;
783 if ((bn = (Builtin) builtintab->getnode2(builtintab, name)) &&
784 (dis ? (bn->node.flags & DISABLED) : !(bn->node.flags & DISABLED))) {
785 char *t = ((bn->handlerfunc || (bn->node.flags & BINF_PREFIX)) ?
786 "defined" : "undefined");
787
788 pm->u.str = dupstring(t);
789 } else {
790 pm->u.str = dupstring("");
791 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
792 }
793 return &pm->node;
794 }
795
796 /**/
797 static HashNode
getpmbuiltin(HashTable ht,const char * name)798 getpmbuiltin(HashTable ht, const char *name)
799 {
800 return getbuiltin(ht, name, 0);
801 }
802
803 /**/
804 static HashNode
getpmdisbuiltin(HashTable ht,const char * name)805 getpmdisbuiltin(HashTable ht, const char *name)
806 {
807 return getbuiltin(ht, name, DISABLED);
808 }
809
810 /**/
811 static void
scanbuiltins(UNUSED (HashTable ht),ScanFunc func,int flags,int dis)812 scanbuiltins(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
813 {
814 struct param pm;
815 int i;
816 HashNode hn;
817
818 memset((void *)&pm, 0, sizeof(struct param));
819 pm.node.flags = PM_SCALAR | PM_READONLY;
820 pm.gsu.s = &nullsetscalar_gsu;
821
822 for (i = 0; i < builtintab->hsize; i++)
823 for (hn = builtintab->nodes[i]; hn; hn = hn->next) {
824 if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
825 pm.node.nam = hn->nam;
826 if (func != scancountparams &&
827 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
828 !(flags & SCANPM_WANTKEYS))) {
829 char *t = ((((Builtin) hn)->handlerfunc ||
830 (hn->flags & BINF_PREFIX)) ?
831 "defined" : "undefined");
832
833 pm.u.str = dupstring(t);
834 }
835 func(&pm.node, flags);
836 }
837 }
838 }
839
840 /**/
841 static void
scanpmbuiltins(HashTable ht,ScanFunc func,int flags)842 scanpmbuiltins(HashTable ht, ScanFunc func, int flags)
843 {
844 scanbuiltins(ht, func, flags, 0);
845 }
846
847 /**/
848 static void
scanpmdisbuiltins(HashTable ht,ScanFunc func,int flags)849 scanpmdisbuiltins(HashTable ht, ScanFunc func, int flags)
850 {
851 scanbuiltins(ht, func, flags, DISABLED);
852 }
853
854 /* Functions for the reswords special parameter. */
855
856 /**/
857 static char **
getreswords(int dis)858 getreswords(int dis)
859 {
860 int i;
861 HashNode hn;
862 char **ret, **p;
863
864 p = ret = (char **) zhalloc((reswdtab->ct + 1) * sizeof(char *));
865
866 for (i = 0; i < reswdtab->hsize; i++)
867 for (hn = reswdtab->nodes[i]; hn; hn = hn->next)
868 if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED))
869 *p++ = dupstring(hn->nam);
870 *p = NULL;
871
872 return ret;
873 }
874
875 /**/
876 static char **
reswordsgetfn(UNUSED (Param pm))877 reswordsgetfn(UNUSED(Param pm))
878 {
879 return getreswords(0);
880 }
881
882 /**/
883 static char **
disreswordsgetfn(UNUSED (Param pm))884 disreswordsgetfn(UNUSED(Param pm))
885 {
886 return getreswords(DISABLED);
887 }
888
889 /* Functions for the patchars special parameter. */
890
891 /**/
892 static char **
getpatchars(int dis)893 getpatchars(int dis)
894 {
895 int i;
896 char **ret, **p;
897
898 p = ret = (char **) zhalloc(ZPC_COUNT * sizeof(char *));
899
900 for (i = 0; i < ZPC_COUNT; i++)
901 if (zpc_strings[i] && !dis == !zpc_disables[i])
902 *p++ = dupstring(zpc_strings[i]);
903
904 *p = NULL;
905
906 return ret;
907 }
908
909 static char **
patcharsgetfn(UNUSED (Param pm))910 patcharsgetfn(UNUSED(Param pm))
911 {
912 return getpatchars(0);
913 }
914
915 static char **
dispatcharsgetfn(UNUSED (Param pm))916 dispatcharsgetfn(UNUSED(Param pm))
917 {
918 return getpatchars(1);
919 }
920
921 /* Functions for the options special parameter. */
922
923 /**/
924 static void
setpmoption(Param pm,char * value)925 setpmoption(Param pm, char *value)
926 {
927 int n;
928
929 if (!value || (strcmp(value, "on") && strcmp(value, "off")))
930 zwarn("invalid value: %s", value);
931 else if (!(n = optlookup(pm->node.nam)))
932 zwarn("no such option: %s", pm->node.nam);
933 else if (dosetopt(n, (value && strcmp(value, "off")), 0, opts))
934 zwarn("can't change option: %s", pm->node.nam);
935 zsfree(value);
936 }
937
938 /**/
939 static void
unsetpmoption(Param pm,UNUSED (int exp))940 unsetpmoption(Param pm, UNUSED(int exp))
941 {
942 int n;
943
944 if (!(n = optlookup(pm->node.nam)))
945 zwarn("no such option: %s", pm->node.nam);
946 else if (dosetopt(n, 0, 0, opts))
947 zwarn("can't change option: %s", pm->node.nam);
948 }
949
950 /**/
951 static void
setpmoptions(Param pm,HashTable ht)952 setpmoptions(Param pm, HashTable ht)
953 {
954 int i;
955 HashNode hn;
956
957 if (!ht)
958 return;
959
960 for (i = 0; i < ht->hsize; i++)
961 for (hn = ht->nodes[i]; hn; hn = hn->next) {
962 struct value v;
963 char *val;
964
965 v.isarr = v.flags = v.start = 0;
966 v.end = -1;
967 v.arr = NULL;
968 v.pm = (Param) hn;
969
970 val = getstrvalue(&v);
971 if (!val || (strcmp(val, "on") && strcmp(val, "off")))
972 zwarn("invalid value: %s", val);
973 else if (dosetopt(optlookup(hn->nam),
974 (val && strcmp(val, "off")), 0, opts))
975 zwarn("can't change option: %s", hn->nam);
976 }
977 /* See setpmcommands() above */
978 if (ht != pm->u.hash)
979 deleteparamtable(ht);
980 }
981
982 static const struct gsu_scalar pmoption_gsu =
983 { strgetfn, setpmoption, unsetpmoption };
984
985 /**/
986 static HashNode
getpmoption(UNUSED (HashTable ht),const char * name)987 getpmoption(UNUSED(HashTable ht), const char *name)
988 {
989 Param pm = NULL;
990 int n;
991
992 pm = (Param) hcalloc(sizeof(struct param));
993 pm->node.nam = dupstring(name);
994 pm->node.flags = PM_SCALAR;
995 pm->gsu.s = &pmoption_gsu;
996
997 if ((n = optlookup(name)))
998 {
999 int ison;
1000 if (n > 0)
1001 ison = opts[n];
1002 else
1003 ison = !opts[-n];
1004 pm->u.str = dupstring(ison ? "on" : "off");
1005 }
1006 else {
1007 pm->u.str = dupstring("");
1008 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1009 }
1010 return &pm->node;
1011 }
1012
1013 /**/
1014 static void
scanpmoptions(UNUSED (HashTable ht),ScanFunc func,int flags)1015 scanpmoptions(UNUSED(HashTable ht), ScanFunc func, int flags)
1016 {
1017 struct param pm;
1018 int i;
1019 HashNode hn;
1020
1021 memset((void *)&pm, 0, sizeof(struct param));
1022 pm.node.flags = PM_SCALAR;
1023 pm.gsu.s = &pmoption_gsu;
1024
1025 for (i = 0; i < optiontab->hsize; i++)
1026 for (hn = optiontab->nodes[i]; hn; hn = hn->next) {
1027 int optno = ((Optname) hn)->optno, ison;
1028 pm.node.nam = hn->nam;
1029 ison = optno < 0 ? !opts[-optno] : opts[optno];
1030 pm.u.str = dupstring(ison ? "on" : "off");
1031 func(&pm.node, flags);
1032 }
1033 }
1034
1035 /* Functions for the modules special parameter. */
1036
1037 /**/
1038 static HashNode
getpmmodule(UNUSED (HashTable ht),const char * name)1039 getpmmodule(UNUSED(HashTable ht), const char *name)
1040 {
1041 Param pm = NULL;
1042 char *type = NULL;
1043 Module m;
1044
1045 pm = (Param) hcalloc(sizeof(struct param));
1046 pm->node.nam = dupstring(name);
1047 pm->node.flags = PM_SCALAR | PM_READONLY;
1048 pm->gsu.s = &nullsetscalar_gsu;
1049
1050 m = (Module)modulestab->getnode2(modulestab, name);
1051
1052 if (!m)
1053 return NULL;
1054 if (m->u.handle && !(m->node.flags & MOD_UNLOAD)) {
1055 type = ((m->node.flags & MOD_ALIAS) ?
1056 dyncat("alias:", m->u.alias) : "loaded");
1057 }
1058 if (!type) {
1059 if (m->autoloads && firstnode(m->autoloads))
1060 type = "autoloaded";
1061 }
1062 if (type)
1063 pm->u.str = dupstring(type);
1064 else {
1065 pm->u.str = dupstring("");
1066 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1067 }
1068 return &pm->node;
1069 }
1070
1071 /**/
1072 static void
scanpmmodules(UNUSED (HashTable ht),ScanFunc func,int flags)1073 scanpmmodules(UNUSED(HashTable ht), ScanFunc func, int flags)
1074 {
1075 struct param pm;
1076 int i;
1077 HashNode hn;
1078 LinkList done = newlinklist();
1079 Module m;
1080 Conddef p;
1081 char *loaded = dupstring("loaded");
1082
1083 memset((void *)&pm, 0, sizeof(struct param));
1084 pm.node.flags = PM_SCALAR | PM_READONLY;
1085 pm.gsu.s = &nullsetscalar_gsu;
1086
1087 for (i = 0; i < modulestab->hsize; i++) {
1088 for (hn = modulestab->nodes[i]; hn; hn = hn->next) {
1089 m = (Module) hn;
1090 if (m->u.handle && !(m->node.flags & MOD_UNLOAD)) {
1091 pm.node.nam = m->node.nam;
1092 pm.u.str = ((m->node.flags & MOD_ALIAS) ?
1093 dyncat("alias:", m->u.alias) : loaded);
1094 addlinknode(done, pm.node.nam);
1095 func(&pm.node, flags);
1096 }
1097 }
1098 }
1099 pm.u.str = dupstring("autoloaded");
1100 for (i = 0; i < builtintab->hsize; i++)
1101 for (hn = builtintab->nodes[i]; hn; hn = hn->next) {
1102 if (!(((Builtin) hn)->node.flags & BINF_ADDED) &&
1103 !linknodebystring(done, ((Builtin) hn)->optstr)) {
1104 pm.node.nam = ((Builtin) hn)->optstr;
1105 addlinknode(done, pm.node.nam);
1106 func(&pm.node, flags);
1107 }
1108 }
1109 for (p = condtab; p; p = p->next)
1110 if (p->module && !linknodebystring(done, p->module)) {
1111 pm.node.nam = p->module;
1112 addlinknode(done, pm.node.nam);
1113 func(&pm.node, flags);
1114 }
1115 for (i = 0; i < realparamtab->hsize; i++)
1116 for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
1117 if ((((Param) hn)->node.flags & PM_AUTOLOAD) &&
1118 !linknodebystring(done, ((Param) hn)->u.str)) {
1119 pm.node.nam = ((Param) hn)->u.str;
1120 addlinknode(done, pm.node.nam);
1121 func(&pm.node, flags);
1122 }
1123 }
1124 }
1125
1126 /* Functions for the dirstack special parameter. */
1127
1128 /**/
1129 static void
dirssetfn(UNUSED (Param pm),char ** x)1130 dirssetfn(UNUSED(Param pm), char **x)
1131 {
1132 char **ox = x;
1133
1134 if (!incleanup) {
1135 freelinklist(dirstack, freestr);
1136 dirstack = znewlinklist();
1137 while (x && *x)
1138 zaddlinknode(dirstack, ztrdup(*x++));
1139 }
1140 if (ox)
1141 freearray(ox);
1142 }
1143
1144 /**/
1145 static char **
dirsgetfn(UNUSED (Param pm))1146 dirsgetfn(UNUSED(Param pm))
1147 {
1148 return hlinklist2array(dirstack, 1);
1149 }
1150
1151 /* Functions for the history special parameter. */
1152
1153 /**/
1154 static HashNode
getpmhistory(UNUSED (HashTable ht),const char * name)1155 getpmhistory(UNUSED(HashTable ht), const char *name)
1156 {
1157 Param pm = NULL;
1158 Histent he;
1159 const char *p;
1160 int ok = 1;
1161
1162 pm = (Param) hcalloc(sizeof(struct param));
1163 pm->node.nam = dupstring(name);
1164 pm->node.flags = PM_SCALAR | PM_READONLY;
1165 pm->gsu.s = &nullsetscalar_gsu;
1166
1167 if (*name != '0' || name[1]) {
1168 if (*name == '0')
1169 ok = 0;
1170 else {
1171 for (p = name; *p && idigit(*p); p++);
1172 if (*p)
1173 ok = 0;
1174 }
1175 }
1176 if (ok && (he = quietgethist(atoi(name))))
1177 pm->u.str = dupstring(he->node.nam);
1178 else {
1179 pm->u.str = dupstring("");
1180 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1181 }
1182 return &pm->node;
1183 }
1184
1185 /**/
1186 static void
scanpmhistory(UNUSED (HashTable ht),ScanFunc func,int flags)1187 scanpmhistory(UNUSED(HashTable ht), ScanFunc func, int flags)
1188 {
1189 struct param pm;
1190 int i = addhistnum(curhist, -1, HIST_FOREIGN);
1191 Histent he = gethistent(i, GETHIST_UPWARD);
1192 char buf[40];
1193
1194 memset((void *)&pm, 0, sizeof(struct param));
1195 pm.node.flags = PM_SCALAR | PM_READONLY;
1196 pm.gsu.s = &nullsetscalar_gsu;
1197
1198 while (he) {
1199 if (func != scancountparams) {
1200 convbase(buf, he->histnum, 10);
1201 pm.node.nam = dupstring(buf);
1202 if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
1203 !(flags & SCANPM_WANTKEYS))
1204 pm.u.str = dupstring(he->node.nam);
1205 }
1206 func(&pm.node, flags);
1207
1208 he = up_histent(he);
1209 }
1210 }
1211
1212 /* Function for the historywords special parameter. */
1213
1214 /**/
1215 static char **
histwgetfn(UNUSED (Param pm))1216 histwgetfn(UNUSED(Param pm))
1217 {
1218 char *h, *e, sav;
1219 LinkList l = newlinklist(), ll;
1220 LinkNode n;
1221 int i = addhistnum(curhist, -1, HIST_FOREIGN), iw;
1222 Histent he = gethistent(i, GETHIST_UPWARD);
1223
1224 if ((ll = bufferwords(NULL, NULL, NULL, 0)))
1225 for (n = firstnode(ll); n; incnode(n))
1226 pushnode(l, getdata(n));
1227
1228 while (he) {
1229 for (iw = he->nwords - 1; iw >= 0; iw--) {
1230 h = he->node.nam + he->words[iw * 2];
1231 e = he->node.nam + he->words[iw * 2 + 1];
1232 sav = *e;
1233 *e = '\0';
1234 addlinknode(l, dupstring(h));
1235 *e = sav;
1236 }
1237 he = up_histent(he);
1238 }
1239
1240 return hlinklist2array(l, 0);
1241 }
1242
1243 /* Functions for the jobtexts special parameter. */
1244
1245 /**/
1246 static char *
pmjobtext(int job)1247 pmjobtext(int job)
1248 {
1249 Process pn;
1250 int len = 1;
1251 char *ret;
1252
1253 for (pn = jobtab[job].procs; pn; pn = pn->next)
1254 len += strlen(pn->text) + 3;
1255
1256 ret = (char *) zhalloc(len);
1257 ret[0] = '\0';
1258
1259 for (pn = jobtab[job].procs; pn; pn = pn->next) {
1260 strcat(ret, pn->text);
1261 if (pn->next)
1262 strcat(ret, " | ");
1263 }
1264 return ret;
1265 }
1266
1267 /**/
1268 static HashNode
getpmjobtext(UNUSED (HashTable ht),const char * name)1269 getpmjobtext(UNUSED(HashTable ht), const char *name)
1270 {
1271 Param pm = NULL;
1272 int job;
1273 char *pend;
1274
1275 pm = (Param) hcalloc(sizeof(struct param));
1276 pm->node.nam = dupstring(name);
1277 pm->node.flags = PM_SCALAR | PM_READONLY;
1278 pm->gsu.s = &nullsetscalar_gsu;
1279
1280 job = strtod(name, &pend);
1281 /* Non-numeric keys are looked up by job name */
1282 if (*pend)
1283 job = getjob(name, NULL);
1284 if (job >= 1 && job <= maxjob &&
1285 jobtab[job].stat && jobtab[job].procs &&
1286 !(jobtab[job].stat & STAT_NOPRINT))
1287 pm->u.str = pmjobtext(job);
1288 else {
1289 pm->u.str = dupstring("");
1290 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1291 }
1292 return &pm->node;
1293 }
1294
1295 /**/
1296 static void
scanpmjobtexts(UNUSED (HashTable ht),ScanFunc func,int flags)1297 scanpmjobtexts(UNUSED(HashTable ht), ScanFunc func, int flags)
1298 {
1299 struct param pm;
1300 int job;
1301 char buf[40];
1302
1303 memset((void *)&pm, 0, sizeof(struct param));
1304 pm.node.flags = PM_SCALAR | PM_READONLY;
1305 pm.gsu.s = &nullsetscalar_gsu;
1306
1307 for (job = 1; job <= maxjob; job++) {
1308 if (jobtab[job].stat && jobtab[job].procs &&
1309 !(jobtab[job].stat & STAT_NOPRINT)) {
1310 if (func != scancountparams) {
1311 sprintf(buf, "%d", job);
1312 pm.node.nam = dupstring(buf);
1313 if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
1314 !(flags & SCANPM_WANTKEYS))
1315 pm.u.str = pmjobtext(job);
1316 }
1317 func(&pm.node, flags);
1318 }
1319 }
1320 }
1321
1322 /* Functions for the jobstates special parameter. */
1323
1324 /**/
1325 static char *
pmjobstate(int job)1326 pmjobstate(int job)
1327 {
1328 Process pn;
1329 char buf[256], buf2[128], *ret, *state, *cp;
1330
1331 if (job == curjob)
1332 cp = ":+";
1333 else if (job == prevjob)
1334 cp = ":-";
1335 else
1336 cp = ":";
1337
1338 if (jobtab[job].stat & STAT_DONE)
1339 ret = dyncat("done", cp);
1340 else if (jobtab[job].stat & STAT_STOPPED)
1341 ret = dyncat("suspended", cp);
1342 else
1343 ret = dyncat("running", cp);
1344
1345 for (pn = jobtab[job].procs; pn; pn = pn->next) {
1346
1347 if (pn->status == SP_RUNNING)
1348 state = "running";
1349 else if (WIFEXITED(pn->status)) {
1350 if (WEXITSTATUS(pn->status))
1351 sprintf((state = buf2), "exit %d", (pn->status));
1352 else
1353 state = "done";
1354 } else if (WIFSTOPPED(pn->status))
1355 state = sigmsg(WSTOPSIG(pn->status));
1356 else if (WCOREDUMP(pn->status))
1357 sprintf((state = buf2), "%s (core dumped)",
1358 sigmsg(WTERMSIG(pn->status)));
1359 else
1360 state = sigmsg(WTERMSIG(pn->status));
1361
1362 sprintf(buf, ":%d=%s", (int)pn->pid, state);
1363
1364 ret = dyncat(ret, buf);
1365 }
1366 return ret;
1367 }
1368
1369 /**/
1370 static HashNode
getpmjobstate(UNUSED (HashTable ht),const char * name)1371 getpmjobstate(UNUSED(HashTable ht), const char *name)
1372 {
1373 Param pm = NULL;
1374 int job;
1375 char *pend;
1376
1377 pm = (Param) hcalloc(sizeof(struct param));
1378 pm->node.nam = dupstring(name);
1379 pm->node.flags = PM_SCALAR | PM_READONLY;
1380 pm->gsu.s = &nullsetscalar_gsu;
1381
1382 job = strtod(name, &pend);
1383 if (*pend)
1384 job = getjob(name, NULL);
1385 if (job >= 1 && job <= maxjob &&
1386 jobtab[job].stat && jobtab[job].procs &&
1387 !(jobtab[job].stat & STAT_NOPRINT))
1388 pm->u.str = pmjobstate(job);
1389 else {
1390 pm->u.str = dupstring("");
1391 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1392 }
1393 return &pm->node;
1394 }
1395
1396 /**/
1397 static void
scanpmjobstates(UNUSED (HashTable ht),ScanFunc func,int flags)1398 scanpmjobstates(UNUSED(HashTable ht), ScanFunc func, int flags)
1399 {
1400 struct param pm;
1401 int job;
1402 char buf[40];
1403
1404 memset((void *)&pm, 0, sizeof(struct param));
1405 pm.node.flags = PM_SCALAR | PM_READONLY;
1406 pm.gsu.s = &nullsetscalar_gsu;
1407
1408 for (job = 1; job <= maxjob; job++) {
1409 if (jobtab[job].stat && jobtab[job].procs &&
1410 !(jobtab[job].stat & STAT_NOPRINT)) {
1411 if (func != scancountparams) {
1412 sprintf(buf, "%d", job);
1413 pm.node.nam = dupstring(buf);
1414 if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
1415 !(flags & SCANPM_WANTKEYS))
1416 pm.u.str = pmjobstate(job);
1417 }
1418 func(&pm.node, flags);
1419 }
1420 }
1421 }
1422
1423 /* Functions for the jobdirs special parameter. */
1424
1425 /**/
1426 static char *
pmjobdir(int job)1427 pmjobdir(int job)
1428 {
1429 char *ret;
1430
1431 ret = dupstring(jobtab[job].pwd ? jobtab[job].pwd : pwd);
1432 return ret;
1433 }
1434
1435 /**/
1436 static HashNode
getpmjobdir(UNUSED (HashTable ht),const char * name)1437 getpmjobdir(UNUSED(HashTable ht), const char *name)
1438 {
1439 Param pm = NULL;
1440 int job;
1441 char *pend;
1442
1443 pm = (Param) hcalloc(sizeof(struct param));
1444 pm->node.nam = dupstring(name);
1445 pm->node.flags = PM_SCALAR | PM_READONLY;
1446 pm->gsu.s = &nullsetscalar_gsu;
1447
1448 job = strtod(name, &pend);
1449 if (*pend)
1450 job = getjob(name, NULL);
1451 if (job >= 1 && job <= maxjob &&
1452 jobtab[job].stat && jobtab[job].procs &&
1453 !(jobtab[job].stat & STAT_NOPRINT))
1454 pm->u.str = pmjobdir(job);
1455 else {
1456 pm->u.str = dupstring("");
1457 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1458 }
1459 return &pm->node;
1460 }
1461
1462 /**/
1463 static void
scanpmjobdirs(UNUSED (HashTable ht),ScanFunc func,int flags)1464 scanpmjobdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
1465 {
1466 struct param pm;
1467 int job;
1468 char buf[40];
1469
1470 memset((void *)&pm, 0, sizeof(struct param));
1471 pm.node.flags = PM_SCALAR | PM_READONLY;
1472 pm.gsu.s = &nullsetscalar_gsu;
1473
1474 for (job = 1; job <= maxjob; job++) {
1475 if (jobtab[job].stat && jobtab[job].procs &&
1476 !(jobtab[job].stat & STAT_NOPRINT)) {
1477 if (func != scancountparams) {
1478 sprintf(buf, "%d", job);
1479 pm.node.nam = dupstring(buf);
1480 if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
1481 !(flags & SCANPM_WANTKEYS))
1482 pm.u.str = pmjobdir(job);
1483 }
1484 func(&pm.node, flags);
1485 }
1486 }
1487 }
1488
1489 /* Functions for the nameddirs special parameter. */
1490
1491 /**/
1492 static void
setpmnameddir(Param pm,char * value)1493 setpmnameddir(Param pm, char *value)
1494 {
1495 if (!value)
1496 zwarn("invalid value: ''");
1497 else {
1498 Nameddir nd = (Nameddir) zshcalloc(sizeof(*nd));
1499
1500 nd->node.flags = 0;
1501 nd->dir = value;
1502 nameddirtab->addnode(nameddirtab, ztrdup(pm->node.nam), nd);
1503 }
1504 }
1505
1506 /**/
1507 static void
unsetpmnameddir(Param pm,UNUSED (int exp))1508 unsetpmnameddir(Param pm, UNUSED(int exp))
1509 {
1510 HashNode hd = nameddirtab->removenode(nameddirtab, pm->node.nam);
1511
1512 if (hd)
1513 nameddirtab->freenode(hd);
1514 }
1515
1516 /**/
1517 static void
setpmnameddirs(Param pm,HashTable ht)1518 setpmnameddirs(Param pm, HashTable ht)
1519 {
1520 int i;
1521 HashNode hn, next, hd;
1522
1523 if (!ht)
1524 return;
1525
1526 for (i = 0; i < nameddirtab->hsize; i++)
1527 for (hn = nameddirtab->nodes[i]; hn; hn = next) {
1528 next = hn->next;
1529 if (!(((Nameddir) hn)->node.flags & ND_USERNAME) &&
1530 (hd = nameddirtab->removenode(nameddirtab, hn->nam)))
1531 nameddirtab->freenode(hd);
1532 }
1533
1534 for (i = 0; i < ht->hsize; i++)
1535 for (hn = ht->nodes[i]; hn; hn = hn->next) {
1536 struct value v;
1537 char *val;
1538
1539 v.isarr = v.flags = v.start = 0;
1540 v.end = -1;
1541 v.arr = NULL;
1542 v.pm = (Param) hn;
1543
1544 if (!(val = getstrvalue(&v)))
1545 zwarn("invalid value: ''");
1546 else {
1547 Nameddir nd = (Nameddir) zshcalloc(sizeof(*nd));
1548
1549 nd->node.flags = 0;
1550 nd->dir = ztrdup(val);
1551 nameddirtab->addnode(nameddirtab, ztrdup(hn->nam), nd);
1552 }
1553 }
1554
1555 /* The INTERACTIVE stuff ensures that the dirs are not immediately removed
1556 * when the sub-pms are deleted. */
1557
1558 i = opts[INTERACTIVE];
1559 opts[INTERACTIVE] = 0;
1560 /* See setpmcommands() above */
1561 if (ht != pm->u.hash)
1562 deleteparamtable(ht);
1563 opts[INTERACTIVE] = i;
1564 }
1565
1566 static const struct gsu_scalar pmnamedir_gsu =
1567 { strgetfn, setpmnameddir, unsetpmnameddir };
1568
1569 /**/
1570 static HashNode
getpmnameddir(UNUSED (HashTable ht),const char * name)1571 getpmnameddir(UNUSED(HashTable ht), const char *name)
1572 {
1573 Param pm = NULL;
1574 Nameddir nd;
1575
1576 pm = (Param) hcalloc(sizeof(struct param));
1577 pm->node.nam = dupstring(name);
1578 pm->node.flags = PM_SCALAR;
1579 pm->gsu.s = &pmnamedir_gsu;
1580 if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
1581 !(nd->node.flags & ND_USERNAME))
1582 pm->u.str = dupstring(nd->dir);
1583 else {
1584 pm->u.str = dupstring("");
1585 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1586 }
1587 return &pm->node;
1588 }
1589
1590 /**/
1591 static void
scanpmnameddirs(UNUSED (HashTable ht),ScanFunc func,int flags)1592 scanpmnameddirs(UNUSED(HashTable ht), ScanFunc func, int flags)
1593 {
1594 struct param pm;
1595 int i;
1596 HashNode hn;
1597 Nameddir nd;
1598
1599 memset((void *)&pm, 0, sizeof(struct param));
1600 pm.node.flags = PM_SCALAR;
1601 pm.gsu.s = &pmnamedir_gsu;
1602
1603 for (i = 0; i < nameddirtab->hsize; i++)
1604 for (hn = nameddirtab->nodes[i]; hn; hn = hn->next) {
1605 if (!((nd = (Nameddir) hn)->node.flags & ND_USERNAME)) {
1606 pm.node.nam = hn->nam;
1607 if (func != scancountparams &&
1608 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
1609 !(flags & SCANPM_WANTKEYS)))
1610 pm.u.str = dupstring(nd->dir);
1611 func(&pm.node, flags);
1612 }
1613 }
1614 }
1615
1616 /* Functions for the userdirs special parameter. */
1617
1618 /**/
1619 static HashNode
getpmuserdir(UNUSED (HashTable ht),const char * name)1620 getpmuserdir(UNUSED(HashTable ht), const char *name)
1621 {
1622 Param pm = NULL;
1623 Nameddir nd;
1624
1625 nameddirtab->filltable(nameddirtab);
1626
1627 pm = (Param) hcalloc(sizeof(struct param));
1628 pm->node.nam = dupstring(name);
1629 pm->node.flags = PM_SCALAR | PM_READONLY;
1630 pm->gsu.s = &nullsetscalar_gsu;
1631 if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
1632 (nd->node.flags & ND_USERNAME))
1633 pm->u.str = dupstring(nd->dir);
1634 else {
1635 pm->u.str = dupstring("");
1636 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1637 }
1638 return &pm->node;
1639 }
1640
1641 /**/
1642 static void
scanpmuserdirs(UNUSED (HashTable ht),ScanFunc func,int flags)1643 scanpmuserdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
1644 {
1645 struct param pm;
1646 int i;
1647 HashNode hn;
1648 Nameddir nd;
1649
1650 nameddirtab->filltable(nameddirtab);
1651
1652 memset((void *)&pm, 0, sizeof(struct param));
1653 pm.node.flags = PM_SCALAR | PM_READONLY;
1654 pm.gsu.s = &nullsetscalar_gsu;
1655
1656 for (i = 0; i < nameddirtab->hsize; i++)
1657 for (hn = nameddirtab->nodes[i]; hn; hn = hn->next) {
1658 if ((nd = (Nameddir) hn)->node.flags & ND_USERNAME) {
1659 pm.node.nam = hn->nam;
1660 if (func != scancountparams &&
1661 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
1662 !(flags & SCANPM_WANTKEYS)))
1663 pm.u.str = dupstring(nd->dir);
1664 func(&pm.node, flags);
1665 }
1666 }
1667 }
1668
1669 /* Functions for the raliases, galiases and saliases special parameters. */
1670
1671 /**/
1672 static void
setalias(HashTable ht,Param pm,char * value,int flags)1673 setalias(HashTable ht, Param pm, char *value, int flags)
1674 {
1675 ht->addnode(ht, ztrdup(pm->node.nam),
1676 createaliasnode(value, flags));
1677 }
1678
1679 /**/
1680 static void
setpmralias(Param pm,char * value)1681 setpmralias(Param pm, char *value)
1682 {
1683 setalias(aliastab, pm, value, 0);
1684 }
1685
1686 /**/
1687 static void
setpmdisralias(Param pm,char * value)1688 setpmdisralias(Param pm, char *value)
1689 {
1690 setalias(aliastab, pm, value, DISABLED);
1691 }
1692
1693 /**/
1694 static void
setpmgalias(Param pm,char * value)1695 setpmgalias(Param pm, char *value)
1696 {
1697 setalias(aliastab, pm, value, ALIAS_GLOBAL);
1698 }
1699
1700 /**/
1701 static void
setpmdisgalias(Param pm,char * value)1702 setpmdisgalias(Param pm, char *value)
1703 {
1704 setalias(aliastab, pm, value, ALIAS_GLOBAL|DISABLED);
1705 }
1706
1707 /**/
1708 static void
setpmsalias(Param pm,char * value)1709 setpmsalias(Param pm, char *value)
1710 {
1711 setalias(sufaliastab, pm, value, ALIAS_SUFFIX);
1712 }
1713
1714 /**/
1715 static void
setpmdissalias(Param pm,char * value)1716 setpmdissalias(Param pm, char *value)
1717 {
1718 setalias(sufaliastab, pm, value, ALIAS_SUFFIX|DISABLED);
1719 }
1720
1721 /**/
1722 static void
unsetpmalias(Param pm,UNUSED (int exp))1723 unsetpmalias(Param pm, UNUSED(int exp))
1724 {
1725 HashNode hd = aliastab->removenode(aliastab, pm->node.nam);
1726
1727 if (hd)
1728 aliastab->freenode(hd);
1729 }
1730
1731 /**/
1732 static void
unsetpmsalias(Param pm,UNUSED (int exp))1733 unsetpmsalias(Param pm, UNUSED(int exp))
1734 {
1735 HashNode hd = sufaliastab->removenode(sufaliastab, pm->node.nam);
1736
1737 if (hd)
1738 sufaliastab->freenode(hd);
1739 }
1740
1741 /**/
1742 static void
setaliases(HashTable alht,Param pm,HashTable ht,int flags)1743 setaliases(HashTable alht, Param pm, HashTable ht, int flags)
1744 {
1745 int i;
1746 HashNode hn, next, hd;
1747
1748 if (!ht)
1749 return;
1750
1751 for (i = 0; i < alht->hsize; i++)
1752 for (hn = alht->nodes[i]; hn; hn = next) {
1753 next = hn->next;
1754 /*
1755 * The following respects the DISABLED flag, e.g.
1756 * we get a different behaviour for raliases and dis_raliases.
1757 * The predecessor to this code didn't do that; presumably
1758 * that was a bug.
1759 */
1760 if (flags == ((Alias)hn)->node.flags &&
1761 (hd = alht->removenode(alht, hn->nam)))
1762 alht->freenode(hd);
1763 }
1764
1765 for (i = 0; i < ht->hsize; i++)
1766 for (hn = ht->nodes[i]; hn; hn = hn->next) {
1767 struct value v;
1768 char *val;
1769
1770 v.isarr = v.flags = v.start = 0;
1771 v.end = -1;
1772 v.arr = NULL;
1773 v.pm = (Param) hn;
1774
1775 if ((val = getstrvalue(&v)))
1776 alht->addnode(alht, ztrdup(hn->nam),
1777 createaliasnode(ztrdup(val), flags));
1778 }
1779 /* See setpmcommands() above */
1780 if (ht != pm->u.hash)
1781 deleteparamtable(ht);
1782 }
1783
1784 /**/
1785 static void
setpmraliases(Param pm,HashTable ht)1786 setpmraliases(Param pm, HashTable ht)
1787 {
1788 setaliases(aliastab, pm, ht, 0);
1789 }
1790
1791 /**/
1792 static void
setpmdisraliases(Param pm,HashTable ht)1793 setpmdisraliases(Param pm, HashTable ht)
1794 {
1795 setaliases(aliastab, pm, ht, DISABLED);
1796 }
1797
1798 /**/
1799 static void
setpmgaliases(Param pm,HashTable ht)1800 setpmgaliases(Param pm, HashTable ht)
1801 {
1802 setaliases(aliastab, pm, ht, ALIAS_GLOBAL);
1803 }
1804
1805 /**/
1806 static void
setpmdisgaliases(Param pm,HashTable ht)1807 setpmdisgaliases(Param pm, HashTable ht)
1808 {
1809 setaliases(aliastab, pm, ht, ALIAS_GLOBAL|DISABLED);
1810 }
1811
1812 /**/
1813 static void
setpmsaliases(Param pm,HashTable ht)1814 setpmsaliases(Param pm, HashTable ht)
1815 {
1816 setaliases(sufaliastab, pm, ht, ALIAS_SUFFIX);
1817 }
1818
1819 /**/
1820 static void
setpmdissaliases(Param pm,HashTable ht)1821 setpmdissaliases(Param pm, HashTable ht)
1822 {
1823 setaliases(sufaliastab, pm, ht, ALIAS_SUFFIX|DISABLED);
1824 }
1825
1826 static const struct gsu_scalar pmralias_gsu =
1827 { strgetfn, setpmralias, unsetpmalias };
1828 static const struct gsu_scalar pmgalias_gsu =
1829 { strgetfn, setpmgalias, unsetpmalias };
1830 static const struct gsu_scalar pmsalias_gsu =
1831 { strgetfn, setpmsalias, unsetpmsalias };
1832 static const struct gsu_scalar pmdisralias_gsu =
1833 { strgetfn, setpmdisralias, unsetpmalias };
1834 static const struct gsu_scalar pmdisgalias_gsu =
1835 { strgetfn, setpmdisgalias, unsetpmalias };
1836 static const struct gsu_scalar pmdissalias_gsu =
1837 { strgetfn, setpmdissalias, unsetpmsalias };
1838
1839 /**/
1840 static void
assignaliasdefs(Param pm,int flags)1841 assignaliasdefs(Param pm, int flags)
1842 {
1843 pm->node.flags = PM_SCALAR;
1844
1845 /* we really need to squirrel the flags away somewhere... */
1846 switch (flags) {
1847 case 0:
1848 pm->gsu.s = &pmralias_gsu;
1849 break;
1850
1851 case ALIAS_GLOBAL:
1852 pm->gsu.s = &pmgalias_gsu;
1853 break;
1854
1855 case ALIAS_SUFFIX:
1856 pm->gsu.s = &pmsalias_gsu;
1857 break;
1858
1859 case DISABLED:
1860 pm->gsu.s = &pmdisralias_gsu;
1861 break;
1862
1863 case ALIAS_GLOBAL|DISABLED:
1864 pm->gsu.s = &pmdisgalias_gsu;
1865 break;
1866
1867 case ALIAS_SUFFIX|DISABLED:
1868 pm->gsu.s = &pmdissalias_gsu;
1869 break;
1870 }
1871 }
1872
1873 /**/
1874 static HashNode
getalias(HashTable alht,UNUSED (HashTable ht),const char * name,int flags)1875 getalias(HashTable alht, UNUSED(HashTable ht), const char *name, int flags)
1876 {
1877 Param pm = NULL;
1878 Alias al;
1879
1880 pm = (Param) hcalloc(sizeof(struct param));
1881 pm->node.nam = dupstring(name);
1882
1883 assignaliasdefs(pm, flags);
1884
1885 if ((al = (Alias) alht->getnode2(alht, name)) &&
1886 flags == al->node.flags)
1887 pm->u.str = dupstring(al->text);
1888 else {
1889 pm->u.str = dupstring("");
1890 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
1891 }
1892 return &pm->node;
1893 }
1894
1895 /**/
1896 static HashNode
getpmralias(HashTable ht,const char * name)1897 getpmralias(HashTable ht, const char *name)
1898 {
1899 return getalias(aliastab, ht, name, 0);
1900 }
1901
1902 /**/
1903 static HashNode
getpmdisralias(HashTable ht,const char * name)1904 getpmdisralias(HashTable ht, const char *name)
1905 {
1906 return getalias(aliastab, ht, name, DISABLED);
1907 }
1908
1909 /**/
1910 static HashNode
getpmgalias(HashTable ht,const char * name)1911 getpmgalias(HashTable ht, const char *name)
1912 {
1913 return getalias(aliastab, ht, name, ALIAS_GLOBAL);
1914 }
1915
1916 /**/
1917 static HashNode
getpmdisgalias(HashTable ht,const char * name)1918 getpmdisgalias(HashTable ht, const char *name)
1919 {
1920 return getalias(aliastab, ht, name, ALIAS_GLOBAL|DISABLED);
1921 }
1922
1923 /**/
1924 static HashNode
getpmsalias(HashTable ht,const char * name)1925 getpmsalias(HashTable ht, const char *name)
1926 {
1927 return getalias(sufaliastab, ht, name, ALIAS_SUFFIX);
1928 }
1929
1930 /**/
1931 static HashNode
getpmdissalias(HashTable ht,const char * name)1932 getpmdissalias(HashTable ht, const char *name)
1933 {
1934 return getalias(sufaliastab, ht, name, ALIAS_SUFFIX|DISABLED);
1935 }
1936
1937 /**/
1938 static void
scanaliases(HashTable alht,UNUSED (HashTable ht),ScanFunc func,int pmflags,int alflags)1939 scanaliases(HashTable alht, UNUSED(HashTable ht), ScanFunc func,
1940 int pmflags, int alflags)
1941 {
1942 struct param pm;
1943 int i;
1944 Alias al;
1945
1946 memset((void *)&pm, 0, sizeof(struct param));
1947 assignaliasdefs(&pm, alflags);
1948
1949 for (i = 0; i < alht->hsize; i++)
1950 for (al = (Alias) alht->nodes[i]; al; al = (Alias) al->node.next) {
1951 if (alflags == al->node.flags) {
1952 pm.node.nam = al->node.nam;
1953 if (func != scancountparams &&
1954 ((pmflags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
1955 !(pmflags & SCANPM_WANTKEYS)))
1956 pm.u.str = dupstring(al->text);
1957 func(&pm.node, pmflags);
1958 }
1959 }
1960 }
1961
1962 /**/
1963 static void
scanpmraliases(HashTable ht,ScanFunc func,int flags)1964 scanpmraliases(HashTable ht, ScanFunc func, int flags)
1965 {
1966 scanaliases(aliastab, ht, func, flags, 0);
1967 }
1968
1969 /**/
1970 static void
scanpmdisraliases(HashTable ht,ScanFunc func,int flags)1971 scanpmdisraliases(HashTable ht, ScanFunc func, int flags)
1972 {
1973 scanaliases(aliastab, ht, func, flags, DISABLED);
1974 }
1975
1976 /**/
1977 static void
scanpmgaliases(HashTable ht,ScanFunc func,int flags)1978 scanpmgaliases(HashTable ht, ScanFunc func, int flags)
1979 {
1980 scanaliases(aliastab, ht, func, flags, ALIAS_GLOBAL);
1981 }
1982
1983 /**/
1984 static void
scanpmdisgaliases(HashTable ht,ScanFunc func,int flags)1985 scanpmdisgaliases(HashTable ht, ScanFunc func, int flags)
1986 {
1987 scanaliases(aliastab, ht, func, flags, ALIAS_GLOBAL|DISABLED);
1988 }
1989
1990 /**/
1991 static void
scanpmsaliases(HashTable ht,ScanFunc func,int flags)1992 scanpmsaliases(HashTable ht, ScanFunc func, int flags)
1993 {
1994 scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX);
1995 }
1996
1997 /**/
1998 static void
scanpmdissaliases(HashTable ht,ScanFunc func,int flags)1999 scanpmdissaliases(HashTable ht, ScanFunc func, int flags)
2000 {
2001 scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX|DISABLED);
2002 }
2003
2004
2005 /* Functions for the usergroups special parameter */
2006
2007 /*
2008 * Get GID and names for groups of which the current user is a member.
2009 */
2010
2011 /**/
get_all_groups(void)2012 static Groupset get_all_groups(void)
2013 {
2014 Groupset gs = zhalloc(sizeof(*gs));
2015 Groupmap gaptr;
2016 gid_t *list, *lptr, egid;
2017 int add_egid;
2018 struct group *grptr;
2019
2020 egid = getegid();
2021 add_egid = 1;
2022 gs->num = getgroups(0, NULL);
2023 if (gs->num > 0) {
2024 list = zhalloc(gs->num * sizeof(*list));
2025 if (getgroups(gs->num, list) < 0) {
2026 return NULL;
2027 }
2028
2029 /*
2030 * It's unspecified whether $EGID is included in the
2031 * group set, so check.
2032 */
2033 for (lptr = list; lptr < list + gs->num; lptr++) {
2034 if (*lptr == egid) {
2035 add_egid = 0;
2036 break;
2037 }
2038 }
2039 gs->array = zhalloc((gs->num + add_egid) * sizeof(*gs->array));
2040 /* Put EGID if needed first */
2041 gaptr = gs->array + add_egid;
2042 for (lptr = list; lptr < list + gs->num; lptr++) {
2043 gaptr->gid = *lptr;
2044 gaptr++;
2045 }
2046 gs->num += add_egid;
2047 } else {
2048 /* Just use effective GID */
2049 gs->num = 1;
2050 gs->array = zhalloc(sizeof(*gs->array));
2051 }
2052 if (add_egid) {
2053 gs->array->gid = egid;
2054 }
2055
2056 /* Get group names */
2057 for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) {
2058 grptr = getgrgid(gaptr->gid);
2059 if (!grptr) {
2060 return NULL;
2061 }
2062 gaptr->name = dupstring(grptr->gr_name);
2063 }
2064
2065 return gs;
2066 }
2067
2068 /* Standard hash element lookup. */
2069
2070 /**/
2071 static HashNode
getpmusergroups(UNUSED (HashTable ht),const char * name)2072 getpmusergroups(UNUSED(HashTable ht), const char *name)
2073 {
2074 Param pm = NULL;
2075 Groupset gs = get_all_groups();
2076 Groupmap gaptr;
2077
2078 pm = (Param)hcalloc(sizeof(struct param));
2079 pm->node.nam = dupstring(name);
2080 pm->node.flags = PM_SCALAR | PM_READONLY;
2081 pm->gsu.s = &nullsetscalar_gsu;
2082
2083 if (!gs) {
2084 zerr("failed to retrieve groups for user: %e", errno);
2085 pm->u.str = dupstring("");
2086 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
2087 return &pm->node;
2088 }
2089
2090 for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) {
2091 if (!strcmp(name, gaptr->name)) {
2092 char buf[DIGBUFSIZE];
2093
2094 sprintf(buf, "%d", (int)gaptr->gid);
2095 pm->u.str = dupstring(buf);
2096 return &pm->node;
2097 }
2098 }
2099
2100 pm->u.str = dupstring("");
2101 pm->node.flags |= (PM_UNSET|PM_SPECIAL);
2102 return &pm->node;
2103 }
2104
2105 /* Standard hash scan. */
2106
2107 /**/
2108 static void
scanpmusergroups(UNUSED (HashTable ht),ScanFunc func,int flags)2109 scanpmusergroups(UNUSED(HashTable ht), ScanFunc func, int flags)
2110 {
2111 struct param pm;
2112 Groupset gs = get_all_groups();
2113 Groupmap gaptr;
2114
2115 if (!gs) {
2116 zerr("failed to retrieve groups for user: %e", errno);
2117 return;
2118 }
2119
2120 memset((void *)&pm, 0, sizeof(pm));
2121 pm.node.flags = PM_SCALAR | PM_READONLY;
2122 pm.gsu.s = &nullsetscalar_gsu;
2123
2124 for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) {
2125 pm.node.nam = gaptr->name;
2126 if (func != scancountparams &&
2127 ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
2128 !(flags & SCANPM_WANTKEYS))) {
2129 char buf[DIGBUFSIZE];
2130
2131 sprintf(buf, "%d", (int)gaptr->gid);
2132 pm.u.str = dupstring(buf);
2133 }
2134 func(&pm.node, flags);
2135 }
2136 }
2137
2138
2139 /* Table for defined parameters. */
2140
2141 struct pardef {
2142 char *name;
2143 int flags;
2144 GetNodeFunc getnfn;
2145 ScanTabFunc scantfn;
2146 GsuHash hash_gsu;
2147 GsuArray array_gsu;
2148 Param pm;
2149 };
2150
2151 static const struct gsu_hash pmcommands_gsu =
2152 { hashgetfn, setpmcommands, stdunsetfn };
2153 static const struct gsu_hash pmfunctions_gsu =
2154 { hashgetfn, setpmfunctions, stdunsetfn };
2155 static const struct gsu_hash pmdisfunctions_gsu =
2156 { hashgetfn, setpmdisfunctions, stdunsetfn };
2157 static const struct gsu_hash pmoptions_gsu =
2158 { hashgetfn, setpmoptions, stdunsetfn };
2159 static const struct gsu_hash pmnameddirs_gsu =
2160 { hashgetfn, setpmnameddirs, stdunsetfn };
2161 static const struct gsu_hash pmraliases_gsu =
2162 { hashgetfn, setpmraliases, stdunsetfn };
2163 static const struct gsu_hash pmgaliases_gsu =
2164 { hashgetfn, setpmgaliases, stdunsetfn };
2165 static const struct gsu_hash pmsaliases_gsu =
2166 { hashgetfn, setpmsaliases, stdunsetfn };
2167 static const struct gsu_hash pmdisraliases_gsu =
2168 { hashgetfn, setpmdisraliases, stdunsetfn };
2169 static const struct gsu_hash pmdisgaliases_gsu =
2170 { hashgetfn, setpmdisgaliases, stdunsetfn };
2171 static const struct gsu_hash pmdissaliases_gsu =
2172 { hashgetfn, setpmdissaliases, stdunsetfn };
2173
2174 static const struct gsu_array funcstack_gsu =
2175 { funcstackgetfn, arrsetfn, stdunsetfn };
2176 static const struct gsu_array functrace_gsu =
2177 { functracegetfn, arrsetfn, stdunsetfn };
2178 static const struct gsu_array funcsourcetrace_gsu =
2179 { funcsourcetracegetfn, arrsetfn, stdunsetfn };
2180 static const struct gsu_array funcfiletrace_gsu =
2181 { funcfiletracegetfn, arrsetfn, stdunsetfn };
2182 static const struct gsu_array reswords_gsu =
2183 { reswordsgetfn, arrsetfn, stdunsetfn };
2184 static const struct gsu_array disreswords_gsu =
2185 { disreswordsgetfn, arrsetfn, stdunsetfn };
2186 static const struct gsu_array patchars_gsu =
2187 { patcharsgetfn, arrsetfn, stdunsetfn };
2188 static const struct gsu_array dispatchars_gsu =
2189 { dispatcharsgetfn, arrsetfn, stdunsetfn };
2190 static const struct gsu_array dirs_gsu =
2191 { dirsgetfn, dirssetfn, stdunsetfn };
2192 static const struct gsu_array historywords_gsu =
2193 { histwgetfn, arrsetfn, stdunsetfn };
2194
2195 /* Make sure to update autofeatures in parameter.mdd if necessary */
2196 static struct paramdef partab[] = {
2197 SPECIALPMDEF("aliases", 0,
2198 &pmraliases_gsu, getpmralias, scanpmraliases),
2199 SPECIALPMDEF("builtins", PM_READONLY_SPECIAL, NULL, getpmbuiltin, scanpmbuiltins),
2200 SPECIALPMDEF("commands", 0, &pmcommands_gsu, getpmcommand, scanpmcommands),
2201 SPECIALPMDEF("dirstack", PM_ARRAY,
2202 &dirs_gsu, NULL, NULL),
2203 SPECIALPMDEF("dis_aliases", 0,
2204 &pmdisraliases_gsu, getpmdisralias, scanpmdisraliases),
2205 SPECIALPMDEF("dis_builtins", PM_READONLY_SPECIAL,
2206 NULL, getpmdisbuiltin, scanpmdisbuiltins),
2207 SPECIALPMDEF("dis_functions", 0,
2208 &pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions),
2209 SPECIALPMDEF("dis_functions_source", PM_READONLY_SPECIAL, NULL,
2210 getpmdisfunction_source, scanpmdisfunction_source),
2211 SPECIALPMDEF("dis_galiases", 0,
2212 &pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
2213 SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY_SPECIAL,
2214 &dispatchars_gsu, NULL, NULL),
2215 SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY_SPECIAL,
2216 &disreswords_gsu, NULL, NULL),
2217 SPECIALPMDEF("dis_saliases", 0,
2218 &pmdissaliases_gsu, getpmdissalias, scanpmdissaliases),
2219 SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY_SPECIAL,
2220 &funcfiletrace_gsu, NULL, NULL),
2221 SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY_SPECIAL,
2222 &funcsourcetrace_gsu, NULL, NULL),
2223 SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY_SPECIAL,
2224 &funcstack_gsu, NULL, NULL),
2225 SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,
2226 scanpmfunctions),
2227 SPECIALPMDEF("functions_source", PM_READONLY_SPECIAL, NULL,
2228 getpmfunction_source, scanpmfunction_source),
2229 SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY_SPECIAL,
2230 &functrace_gsu, NULL, NULL),
2231 SPECIALPMDEF("galiases", 0,
2232 &pmgaliases_gsu, getpmgalias, scanpmgaliases),
2233 SPECIALPMDEF("history", PM_READONLY_SPECIAL,
2234 NULL, getpmhistory, scanpmhistory),
2235 SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY_SPECIAL,
2236 &historywords_gsu, NULL, NULL),
2237 SPECIALPMDEF("jobdirs", PM_READONLY_SPECIAL,
2238 NULL, getpmjobdir, scanpmjobdirs),
2239 SPECIALPMDEF("jobstates", PM_READONLY_SPECIAL,
2240 NULL, getpmjobstate, scanpmjobstates),
2241 SPECIALPMDEF("jobtexts", PM_READONLY_SPECIAL,
2242 NULL, getpmjobtext, scanpmjobtexts),
2243 SPECIALPMDEF("modules", PM_READONLY_SPECIAL,
2244 NULL, getpmmodule, scanpmmodules),
2245 SPECIALPMDEF("nameddirs", 0,
2246 &pmnameddirs_gsu, getpmnameddir, scanpmnameddirs),
2247 SPECIALPMDEF("options", 0,
2248 &pmoptions_gsu, getpmoption, scanpmoptions),
2249 SPECIALPMDEF("parameters", PM_READONLY_SPECIAL,
2250 NULL, getpmparameter, scanpmparameters),
2251 SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY_SPECIAL,
2252 &patchars_gsu, NULL, NULL),
2253 SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY_SPECIAL,
2254 &reswords_gsu, NULL, NULL),
2255 SPECIALPMDEF("saliases", 0,
2256 &pmsaliases_gsu, getpmsalias, scanpmsaliases),
2257 SPECIALPMDEF("userdirs", PM_READONLY_SPECIAL,
2258 NULL, getpmuserdir, scanpmuserdirs),
2259 SPECIALPMDEF("usergroups", PM_READONLY_SPECIAL,
2260 NULL, getpmusergroups, scanpmusergroups)
2261 };
2262
2263 static struct features module_features = {
2264 NULL, 0,
2265 NULL, 0,
2266 NULL, 0,
2267 partab, sizeof(partab)/sizeof(*partab),
2268 0
2269 };
2270
2271 /**/
2272 int
setup_(UNUSED (Module m))2273 setup_(UNUSED(Module m))
2274 {
2275 return 0;
2276 }
2277
2278 /**/
2279 int
features_(Module m,char *** features)2280 features_(Module m, char ***features)
2281 {
2282 *features = featuresarray(m, &module_features);
2283 return 0;
2284 }
2285
2286 /**/
2287 int
enables_(Module m,int ** enables)2288 enables_(Module m, int **enables)
2289 {
2290 int ret;
2291 /*
2292 * If we remove features, we shouldn't have an effect
2293 * on the main shell, so set the flag to indicate.
2294 */
2295 incleanup = 1;
2296 ret = handlefeatures(m, &module_features, enables);
2297 incleanup = 0;
2298 return ret;
2299 }
2300
2301 /**/
2302 int
boot_(UNUSED (Module m))2303 boot_(UNUSED(Module m))
2304 {
2305 return 0;
2306 }
2307
2308 /**/
2309 int
cleanup_(Module m)2310 cleanup_(Module m)
2311 {
2312 int ret;
2313 incleanup = 1;
2314 ret = setfeatureenables(m, &module_features, NULL);
2315 incleanup = 0;
2316 return ret;
2317 }
2318
2319 /**/
2320 int
finish_(UNUSED (Module m))2321 finish_(UNUSED(Module m))
2322 {
2323 return 0;
2324 }
2325