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