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