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