var.c revision 217847
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; 36#endif 37#endif /* not lint */ 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD: head/bin/sh/var.c 217847 2011-01-25 20:56:18Z jilles $"); 40 41#include <unistd.h> 42#include <stdlib.h> 43#include <paths.h> 44 45/* 46 * Shell variables. 47 */ 48 49#include <locale.h> 50 51#include "shell.h" 52#include "output.h" 53#include "expand.h" 54#include "nodes.h" /* for other headers */ 55#include "eval.h" /* defines cmdenviron */ 56#include "exec.h" 57#include "syntax.h" 58#include "options.h" 59#include "mail.h" 60#include "var.h" 61#include "memalloc.h" 62#include "error.h" 63#include "mystring.h" 64#include "parser.h" 65#ifndef NO_HISTORY 66#include "myhistedit.h" 67#endif 68 69 70#define VTABSIZE 39 71 72 73struct varinit { 74 struct var *var; 75 int flags; 76 const char *text; 77 void (*func)(const char *); 78}; 79 80 81#ifndef NO_HISTORY 82struct var vhistsize; 83struct var vterm; 84#endif 85struct var vifs; 86struct var vmail; 87struct var vmpath; 88struct var vpath; 89struct var vppid; 90struct var vps1; 91struct var vps2; 92struct var vps4; 93struct var vvers; 94static struct var voptind; 95 96static const struct varinit varinit[] = { 97#ifndef NO_HISTORY 98 { &vhistsize, VUNSET, "HISTSIZE=", 99 sethistsize }, 100#endif 101 { &vifs, 0, "IFS= \t\n", 102 NULL }, 103 { &vmail, VUNSET, "MAIL=", 104 NULL }, 105 { &vmpath, VUNSET, "MAILPATH=", 106 NULL }, 107 { &vpath, 0, "PATH=" _PATH_DEFPATH, 108 changepath }, 109 { &vppid, VUNSET, "PPID=", 110 NULL }, 111 /* 112 * vps1 depends on uid 113 */ 114 { &vps2, 0, "PS2=> ", 115 NULL }, 116 { &vps4, 0, "PS4=+ ", 117 NULL }, 118#ifndef NO_HISTORY 119 { &vterm, VUNSET, "TERM=", 120 setterm }, 121#endif 122 { &voptind, 0, "OPTIND=1", 123 getoptsreset }, 124 { NULL, 0, NULL, 125 NULL } 126}; 127 128static struct var *vartab[VTABSIZE]; 129 130static const char *const locale_names[7] = { 131 "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", 132 "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL 133}; 134static const int locale_categories[7] = { 135 LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0 136}; 137 138static struct var **hashvar(const char *); 139static int varequal(const char *, const char *); 140static int localevar(const char *); 141 142/* 143 * Initialize the variable symbol tables and import the environment. 144 */ 145 146#ifdef mkinit 147INCLUDE "var.h" 148MKINIT char **environ; 149INIT { 150 char **envp; 151 152 initvar(); 153 for (envp = environ ; *envp ; envp++) { 154 if (strchr(*envp, '=')) { 155 setvareq(*envp, VEXPORT|VTEXTFIXED); 156 } 157 } 158} 159#endif 160 161 162/* 163 * This routine initializes the builtin variables. It is called when the 164 * shell is initialized and again when a shell procedure is spawned. 165 */ 166 167void 168initvar(void) 169{ 170 char ppid[20]; 171 const struct varinit *ip; 172 struct var *vp; 173 struct var **vpp; 174 175 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 176 if ((vp->flags & VEXPORT) == 0) { 177 vpp = hashvar(ip->text); 178 vp->next = *vpp; 179 *vpp = vp; 180 vp->text = __DECONST(char *, ip->text); 181 vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED; 182 vp->func = ip->func; 183 } 184 } 185 /* 186 * PS1 depends on uid 187 */ 188 if ((vps1.flags & VEXPORT) == 0) { 189 vpp = hashvar("PS1="); 190 vps1.next = *vpp; 191 *vpp = &vps1; 192 vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# "); 193 vps1.flags = VSTRFIXED|VTEXTFIXED; 194 } 195 if ((vppid.flags & VEXPORT) == 0) { 196 fmtstr(ppid, sizeof(ppid), "%d", (int)getppid()); 197 setvarsafe("PPID", ppid, 0); 198 } 199} 200 201/* 202 * Safe version of setvar, returns 1 on success 0 on failure. 203 */ 204 205int 206setvarsafe(const char *name, const char *val, int flags) 207{ 208 struct jmploc jmploc; 209 struct jmploc *const savehandler = handler; 210 int err = 0; 211 int inton; 212 213 inton = is_int_on(); 214 if (setjmp(jmploc.loc)) 215 err = 1; 216 else { 217 handler = &jmploc; 218 setvar(name, val, flags); 219 } 220 handler = savehandler; 221 SETINTON(inton); 222 return err; 223} 224 225/* 226 * Set the value of a variable. The flags argument is stored with the 227 * flags of the variable. If val is NULL, the variable is unset. 228 */ 229 230void 231setvar(const char *name, const char *val, int flags) 232{ 233 const char *p; 234 int len; 235 int namelen; 236 char *nameeq; 237 int isbad; 238 239 isbad = 0; 240 p = name; 241 if (! is_name(*p)) 242 isbad = 1; 243 p++; 244 for (;;) { 245 if (! is_in_name(*p)) { 246 if (*p == '\0' || *p == '=') 247 break; 248 isbad = 1; 249 } 250 p++; 251 } 252 namelen = p - name; 253 if (isbad) 254 error("%.*s: bad variable name", namelen, name); 255 len = namelen + 2; /* 2 is space for '=' and '\0' */ 256 if (val == NULL) { 257 flags |= VUNSET; 258 } else { 259 len += strlen(val); 260 } 261 nameeq = ckmalloc(len); 262 memcpy(nameeq, name, namelen); 263 nameeq[namelen] = '='; 264 if (val) 265 scopy(val, nameeq + namelen + 1); 266 else 267 nameeq[namelen + 1] = '\0'; 268 setvareq(nameeq, flags); 269} 270 271static int 272localevar(const char *s) 273{ 274 const char *const *ss; 275 276 if (*s != 'L') 277 return 0; 278 if (varequal(s + 1, "ANG")) 279 return 1; 280 if (strncmp(s + 1, "C_", 2) != 0) 281 return 0; 282 if (varequal(s + 3, "ALL")) 283 return 1; 284 for (ss = locale_names; *ss ; ss++) 285 if (varequal(s + 3, *ss + 3)) 286 return 1; 287 return 0; 288} 289 290 291/* 292 * Sets/unsets an environment variable from a pointer that may actually be a 293 * pointer into environ where the string should not be manipulated. 294 */ 295static void 296change_env(const char *s, int set) 297{ 298 char *eqp; 299 char *ss; 300 301 ss = savestr(s); 302 if ((eqp = strchr(ss, '=')) != NULL) 303 *eqp = '\0'; 304 if (set && eqp != NULL) 305 (void) setenv(ss, eqp + 1, 1); 306 else 307 (void) unsetenv(ss); 308 ckfree(ss); 309 310 return; 311} 312 313 314/* 315 * Same as setvar except that the variable and value are passed in 316 * the first argument as name=value. Since the first argument will 317 * be actually stored in the table, it should not be a string that 318 * will go away. 319 */ 320 321void 322setvareq(char *s, int flags) 323{ 324 struct var *vp, **vpp; 325 int len; 326 327 if (aflag) 328 flags |= VEXPORT; 329 vpp = hashvar(s); 330 for (vp = *vpp ; vp ; vp = vp->next) { 331 if (varequal(s, vp->text)) { 332 if (vp->flags & VREADONLY) { 333 len = strchr(s, '=') - s; 334 error("%.*s: is read only", len, s); 335 } 336 if (flags & VNOSET) 337 return; 338 INTOFF; 339 340 if (vp->func && (flags & VNOFUNC) == 0) 341 (*vp->func)(strchr(s, '=') + 1); 342 343 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 344 ckfree(vp->text); 345 346 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); 347 vp->flags |= flags; 348 vp->text = s; 349 350 /* 351 * We could roll this to a function, to handle it as 352 * a regular variable function callback, but why bother? 353 * 354 * Note: this assumes iflag is not set to 1 initially. 355 * As part of init(), this is called before arguments 356 * are looked at. 357 */ 358 if ((vp == &vmpath || (vp == &vmail && ! mpathset())) && 359 iflag == 1) 360 chkmail(1); 361 if ((vp->flags & VEXPORT) && localevar(s)) { 362 change_env(s, 1); 363 (void) setlocale(LC_ALL, ""); 364 } 365 INTON; 366 return; 367 } 368 } 369 /* not found */ 370 if (flags & VNOSET) 371 return; 372 vp = ckmalloc(sizeof (*vp)); 373 vp->flags = flags; 374 vp->text = s; 375 vp->next = *vpp; 376 vp->func = NULL; 377 INTOFF; 378 *vpp = vp; 379 if ((vp->flags & VEXPORT) && localevar(s)) { 380 change_env(s, 1); 381 (void) setlocale(LC_ALL, ""); 382 } 383 INTON; 384} 385 386 387 388/* 389 * Process a linked list of variable assignments. 390 */ 391 392void 393listsetvar(struct strlist *list, int flags) 394{ 395 struct strlist *lp; 396 397 INTOFF; 398 for (lp = list ; lp ; lp = lp->next) { 399 setvareq(savestr(lp->text), flags); 400 } 401 INTON; 402} 403 404 405 406/* 407 * Find the value of a variable. Returns NULL if not set. 408 */ 409 410char * 411lookupvar(const char *name) 412{ 413 struct var *v; 414 415 for (v = *hashvar(name) ; v ; v = v->next) { 416 if (varequal(v->text, name)) { 417 if (v->flags & VUNSET) 418 return NULL; 419 return strchr(v->text, '=') + 1; 420 } 421 } 422 return NULL; 423} 424 425 426 427/* 428 * Search the environment of a builtin command. If the second argument 429 * is nonzero, return the value of a variable even if it hasn't been 430 * exported. 431 */ 432 433char * 434bltinlookup(const char *name, int doall) 435{ 436 struct strlist *sp; 437 struct var *v; 438 char *result; 439 440 result = NULL; 441 for (sp = cmdenviron ; sp ; sp = sp->next) { 442 if (varequal(sp->text, name)) 443 result = strchr(sp->text, '=') + 1; 444 } 445 if (result != NULL) 446 return result; 447 for (v = *hashvar(name) ; v ; v = v->next) { 448 if (varequal(v->text, name)) { 449 if ((v->flags & VUNSET) 450 || (!doall && (v->flags & VEXPORT) == 0)) 451 return NULL; 452 return strchr(v->text, '=') + 1; 453 } 454 } 455 return NULL; 456} 457 458 459/* 460 * Set up locale for a builtin (LANG/LC_* assignments). 461 */ 462void 463bltinsetlocale(void) 464{ 465 struct strlist *lp; 466 int act = 0; 467 char *loc, *locdef; 468 int i; 469 470 for (lp = cmdenviron ; lp ; lp = lp->next) { 471 if (localevar(lp->text)) { 472 act = 1; 473 break; 474 } 475 } 476 if (!act) 477 return; 478 loc = bltinlookup("LC_ALL", 0); 479 INTOFF; 480 if (loc != NULL) { 481 setlocale(LC_ALL, loc); 482 INTON; 483 return; 484 } 485 locdef = bltinlookup("LANG", 0); 486 for (i = 0; locale_names[i] != NULL; i++) { 487 loc = bltinlookup(locale_names[i], 0); 488 if (loc == NULL) 489 loc = locdef; 490 if (loc != NULL) 491 setlocale(locale_categories[i], loc); 492 } 493 INTON; 494} 495 496/* 497 * Undo the effect of bltinlocaleset(). 498 */ 499void 500bltinunsetlocale(void) 501{ 502 struct strlist *lp; 503 504 INTOFF; 505 for (lp = cmdenviron ; lp ; lp = lp->next) { 506 if (localevar(lp->text)) { 507 setlocale(LC_ALL, ""); 508 return; 509 } 510 } 511 INTON; 512} 513 514 515/* 516 * Generate a list of exported variables. This routine is used to construct 517 * the third argument to execve when executing a program. 518 */ 519 520char ** 521environment(void) 522{ 523 int nenv; 524 struct var **vpp; 525 struct var *vp; 526 char **env, **ep; 527 528 nenv = 0; 529 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 530 for (vp = *vpp ; vp ; vp = vp->next) 531 if (vp->flags & VEXPORT) 532 nenv++; 533 } 534 ep = env = stalloc((nenv + 1) * sizeof *env); 535 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 536 for (vp = *vpp ; vp ; vp = vp->next) 537 if (vp->flags & VEXPORT) 538 *ep++ = vp->text; 539 } 540 *ep = NULL; 541 return env; 542} 543 544 545/* 546 * Called when a shell procedure is invoked to clear out nonexported 547 * variables. It is also necessary to reallocate variables of with 548 * VSTACK set since these are currently allocated on the stack. 549 */ 550 551MKINIT void shprocvar(void); 552 553#ifdef mkinit 554SHELLPROC { 555 shprocvar(); 556} 557#endif 558 559void 560shprocvar(void) 561{ 562 struct var **vpp; 563 struct var *vp, **prev; 564 565 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 566 for (prev = vpp ; (vp = *prev) != NULL ; ) { 567 if ((vp->flags & VEXPORT) == 0) { 568 *prev = vp->next; 569 if ((vp->flags & VTEXTFIXED) == 0) 570 ckfree(vp->text); 571 if ((vp->flags & VSTRFIXED) == 0) 572 ckfree(vp); 573 } else { 574 if (vp->flags & VSTACK) { 575 vp->text = savestr(vp->text); 576 vp->flags &=~ VSTACK; 577 } 578 prev = &vp->next; 579 } 580 } 581 } 582 initvar(); 583} 584 585 586static int 587var_compare(const void *a, const void *b) 588{ 589 const char *const *sa, *const *sb; 590 591 sa = a; 592 sb = b; 593 /* 594 * This compares two var=value strings which creates a different 595 * order from what you would probably expect. POSIX is somewhat 596 * ambiguous on what should be sorted exactly. 597 */ 598 return strcoll(*sa, *sb); 599} 600 601 602/* 603 * Command to list all variables which are set. This is invoked from the 604 * set command when it is called without any options or operands. 605 */ 606 607int 608showvarscmd(int argc __unused, char **argv __unused) 609{ 610 struct var **vpp; 611 struct var *vp; 612 const char *s; 613 const char **vars; 614 int i, n; 615 616 /* 617 * POSIX requires us to sort the variables. 618 */ 619 n = 0; 620 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 621 for (vp = *vpp; vp; vp = vp->next) { 622 if (!(vp->flags & VUNSET)) 623 n++; 624 } 625 } 626 627 INTON; 628 vars = ckmalloc(n * sizeof(*vars)); 629 i = 0; 630 for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 631 for (vp = *vpp; vp; vp = vp->next) { 632 if (!(vp->flags & VUNSET)) 633 vars[i++] = vp->text; 634 } 635 } 636 637 qsort(vars, n, sizeof(*vars), var_compare); 638 for (i = 0; i < n; i++) { 639 s = strchr(vars[i], '='); 640 s++; 641 outbin(vars[i], s - vars[i], out1); 642 out1qstr(s); 643 out1c('\n'); 644 } 645 ckfree(vars); 646 INTOFF; 647 648 return 0; 649} 650 651 652 653/* 654 * The export and readonly commands. 655 */ 656 657int 658exportcmd(int argc, char **argv) 659{ 660 struct var **vpp; 661 struct var *vp; 662 char *name; 663 char *p; 664 char *cmdname; 665 int ch, values; 666 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 667 668 cmdname = argv[0]; 669 optreset = optind = 1; 670 opterr = 0; 671 values = 0; 672 while ((ch = getopt(argc, argv, "p")) != -1) { 673 switch (ch) { 674 case 'p': 675 values = 1; 676 break; 677 case '?': 678 default: 679 error("unknown option: -%c", optopt); 680 } 681 } 682 argc -= optind; 683 argv += optind; 684 685 if (values && argc != 0) 686 error("-p requires no arguments"); 687 if (argc != 0) { 688 while ((name = *argv++) != NULL) { 689 if ((p = strchr(name, '=')) != NULL) { 690 p++; 691 } else { 692 vpp = hashvar(name); 693 for (vp = *vpp ; vp ; vp = vp->next) { 694 if (varequal(vp->text, name)) { 695 696 vp->flags |= flag; 697 if ((vp->flags & VEXPORT) && localevar(vp->text)) { 698 change_env(vp->text, 1); 699 (void) setlocale(LC_ALL, ""); 700 } 701 goto found; 702 } 703 } 704 } 705 setvar(name, p, flag); 706found:; 707 } 708 } else { 709 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 710 for (vp = *vpp ; vp ; vp = vp->next) { 711 if (vp->flags & flag) { 712 if (values) { 713 out1str(cmdname); 714 out1c(' '); 715 } 716 p = strchr(vp->text, '='); 717 if (values && !(vp->flags & VUNSET)) { 718 p++; 719 outbin(vp->text, p - vp->text, 720 out1); 721 out1qstr(p); 722 } else 723 outbin(vp->text, p - vp->text, 724 out1); 725 out1c('\n'); 726 } 727 } 728 } 729 } 730 return 0; 731} 732 733 734/* 735 * The "local" command. 736 */ 737 738int 739localcmd(int argc __unused, char **argv __unused) 740{ 741 char *name; 742 743 if (! in_function()) 744 error("Not in a function"); 745 while ((name = *argptr++) != NULL) { 746 mklocal(name); 747 } 748 return 0; 749} 750 751 752/* 753 * Make a variable a local variable. When a variable is made local, it's 754 * value and flags are saved in a localvar structure. The saved values 755 * will be restored when the shell function returns. We handle the name 756 * "-" as a special case. 757 */ 758 759void 760mklocal(char *name) 761{ 762 struct localvar *lvp; 763 struct var **vpp; 764 struct var *vp; 765 766 INTOFF; 767 lvp = ckmalloc(sizeof (struct localvar)); 768 if (name[0] == '-' && name[1] == '\0') { 769 lvp->text = ckmalloc(sizeof optlist); 770 memcpy(lvp->text, optlist, sizeof optlist); 771 vp = NULL; 772 } else { 773 vpp = hashvar(name); 774 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); 775 if (vp == NULL) { 776 if (strchr(name, '=')) 777 setvareq(savestr(name), VSTRFIXED); 778 else 779 setvar(name, NULL, VSTRFIXED); 780 vp = *vpp; /* the new variable */ 781 lvp->text = NULL; 782 lvp->flags = VUNSET; 783 } else { 784 lvp->text = vp->text; 785 lvp->flags = vp->flags; 786 vp->flags |= VSTRFIXED|VTEXTFIXED; 787 if (strchr(name, '=')) 788 setvareq(savestr(name), 0); 789 } 790 } 791 lvp->vp = vp; 792 lvp->next = localvars; 793 localvars = lvp; 794 INTON; 795} 796 797 798/* 799 * Called after a function returns. 800 */ 801 802void 803poplocalvars(void) 804{ 805 struct localvar *lvp; 806 struct var *vp; 807 808 while ((lvp = localvars) != NULL) { 809 localvars = lvp->next; 810 vp = lvp->vp; 811 if (vp == NULL) { /* $- saved */ 812 memcpy(optlist, lvp->text, sizeof optlist); 813 ckfree(lvp->text); 814 optschanged(); 815 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 816 (void)unsetvar(vp->text); 817 } else { 818 if ((vp->flags & VTEXTFIXED) == 0) 819 ckfree(vp->text); 820 vp->flags = lvp->flags; 821 vp->text = lvp->text; 822 } 823 ckfree(lvp); 824 } 825} 826 827 828int 829setvarcmd(int argc, char **argv) 830{ 831 if (argc <= 2) 832 return unsetcmd(argc, argv); 833 else if (argc == 3) 834 setvar(argv[1], argv[2], 0); 835 else 836 error("too many arguments"); 837 return 0; 838} 839 840 841/* 842 * The unset builtin command. 843 */ 844 845int 846unsetcmd(int argc __unused, char **argv __unused) 847{ 848 char **ap; 849 int i; 850 int flg_func = 0; 851 int flg_var = 0; 852 int ret = 0; 853 854 while ((i = nextopt("vf")) != '\0') { 855 if (i == 'f') 856 flg_func = 1; 857 else 858 flg_var = 1; 859 } 860 if (flg_func == 0 && flg_var == 0) 861 flg_var = 1; 862 863 for (ap = argptr; *ap ; ap++) { 864 if (flg_func) 865 ret |= unsetfunc(*ap); 866 if (flg_var) 867 ret |= unsetvar(*ap); 868 } 869 return ret; 870} 871 872 873/* 874 * Unset the specified variable. 875 */ 876 877int 878unsetvar(const char *s) 879{ 880 struct var **vpp; 881 struct var *vp; 882 883 vpp = hashvar(s); 884 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { 885 if (varequal(vp->text, s)) { 886 if (vp->flags & VREADONLY) 887 return (1); 888 INTOFF; 889 if (*(strchr(vp->text, '=') + 1) != '\0') 890 setvar(s, nullstr, 0); 891 if ((vp->flags & VEXPORT) && localevar(vp->text)) { 892 change_env(s, 0); 893 setlocale(LC_ALL, ""); 894 } 895 vp->flags &= ~VEXPORT; 896 vp->flags |= VUNSET; 897 if ((vp->flags & VSTRFIXED) == 0) { 898 if ((vp->flags & VTEXTFIXED) == 0) 899 ckfree(vp->text); 900 *vpp = vp->next; 901 ckfree(vp); 902 } 903 INTON; 904 return (0); 905 } 906 } 907 908 return (0); 909} 910 911 912 913/* 914 * Find the appropriate entry in the hash table from the name. 915 */ 916 917static struct var ** 918hashvar(const char *p) 919{ 920 unsigned int hashval; 921 922 hashval = ((unsigned char) *p) << 4; 923 while (*p && *p != '=') 924 hashval += (unsigned char) *p++; 925 return &vartab[hashval % VTABSIZE]; 926} 927 928 929 930/* 931 * Returns true if the two strings specify the same varable. The first 932 * variable name is terminated by '='; the second may be terminated by 933 * either '=' or '\0'. 934 */ 935 936static int 937varequal(const char *p, const char *q) 938{ 939 while (*p == *q++) { 940 if (*p++ == '=') 941 return 1; 942 } 943 if (*p == '=' && *(q - 1) == '\0') 944 return 1; 945 return 0; 946} 947