var.c revision 17562
1273796Sbrooks/*- 2244541Sbrooks * Copyright (c) 1991, 1993 3244541Sbrooks * The Regents of the University of California. All rights reserved. 4244541Sbrooks * 5244541Sbrooks * This code is derived from software contributed to Berkeley by 6244541Sbrooks * Kenneth Almquist. 7244541Sbrooks * 8244541Sbrooks * Redistribution and use in source and binary forms, with or without 9244541Sbrooks * modification, are permitted provided that the following conditions 10244541Sbrooks * are met: 11244541Sbrooks * 1. Redistributions of source code must retain the above copyright 12244541Sbrooks * notice, this list of conditions and the following disclaimer. 13244541Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 14244541Sbrooks * notice, this list of conditions and the following disclaimer in the 15244541Sbrooks * documentation and/or other materials provided with the distribution. 16244541Sbrooks * 3. All advertising materials mentioning features or use of this software 17244541Sbrooks * must display the following acknowledgement: 18244541Sbrooks * This product includes software developed by the University of 19244541Sbrooks * California, Berkeley and its contributors. 20244541Sbrooks * 4. Neither the name of the University nor the names of its contributors 21244541Sbrooks * may be used to endorse or promote products derived from this software 22244541Sbrooks * without specific prior written permission. 23244541Sbrooks * 24244541Sbrooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25244541Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26244541Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27244541Sbrooks * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28244541Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29244541Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30244541Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31244541Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32244541Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33244541Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34244541Sbrooks * SUCH DAMAGE. 35244541Sbrooks * 36244541Sbrooks * $Id: var.c,v 1.4 1996/08/11 22:51:00 ache Exp $ 37244541Sbrooks */ 38244541Sbrooks 39244541Sbrooks#ifndef lint 40244541Sbrooksstatic char sccsid[] = "@(#)var.c 8.1 (Berkeley) 5/31/93"; 41244541Sbrooks#endif /* not lint */ 42244541Sbrooks 43244541Sbrooks/* 44244541Sbrooks * Shell variables. 45244541Sbrooks */ 46273796Sbrooks 47244541Sbrooks#include <locale.h> 48244541Sbrooks 49244541Sbrooks#include "shell.h" 50244541Sbrooks#include "output.h" 51244541Sbrooks#include "expand.h" 52244541Sbrooks#include "nodes.h" /* for other headers */ 53244541Sbrooks#include "eval.h" /* defines cmdenviron */ 54244541Sbrooks#include "exec.h" 55244541Sbrooks#include "syntax.h" 56244541Sbrooks#include "options.h" 57244541Sbrooks#include "mail.h" 58244541Sbrooks#include "parser.h" 59244541Sbrooks#include "var.h" 60244541Sbrooks#include "memalloc.h" 61244541Sbrooks#include "error.h" 62249293Sed#include "mystring.h" 63249293Sed 64244541Sbrooks 65244541Sbrooks#define VTABSIZE 39 66244541Sbrooks 67244541Sbrooks 68244541Sbrooksstruct varinit { 69244541Sbrooks struct var *var; 70244541Sbrooks int flags; 71244541Sbrooks char *text; 72244541Sbrooks}; 73244541Sbrooks 74244541Sbrooks 75244541Sbrooks#if ATTY 76244541Sbrooksstruct var vatty; 77244541Sbrooks#endif 78244541Sbrooksstruct var vhistsize; 79244541Sbrooksstruct var vifs; 80244541Sbrooksstruct var vmail; 81244541Sbrooksstruct var vmpath; 82249293Sedstruct var vpath; 83244541Sbrooksstruct var vps1; 84244541Sbrooksstruct var vps2; 85244541Sbrooksstruct var vvers; 86244541Sbrooks#if ATTY 87244541Sbrooksstruct var vterm; 88249293Sed#endif 89244541Sbrooks 90244541Sbrooksconst struct varinit varinit[] = { 91244541Sbrooks#if ATTY 92244541Sbrooks {&vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY="}, 93244541Sbrooks#endif 94244541Sbrooks {&vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE="}, 95249293Sed {&vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n"}, 96244541Sbrooks {&vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL="}, 97244541Sbrooks {&vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH="}, 98244541Sbrooks {&vpath, VSTRFIXED|VTEXTFIXED, "PATH=:/bin:/usr/bin"}, 99244541Sbrooks /* 100244541Sbrooks * vps1 depends on uid 101244541Sbrooks */ 102244541Sbrooks {&vps2, VSTRFIXED|VTEXTFIXED, "PS2=> "}, 103244541Sbrooks#if ATTY 104244541Sbrooks {&vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM="}, 105244541Sbrooks#endif 106244541Sbrooks {NULL, 0, NULL} 107244541Sbrooks}; 108244541Sbrooks 109244541Sbrooksstruct var *vartab[VTABSIZE]; 110244541Sbrooks 111244541SbrooksSTATIC int unsetvar __P((char *)); 112244541SbrooksSTATIC struct var **hashvar __P((char *)); 113244541SbrooksSTATIC int varequal __P((char *, char *)); 114244541SbrooksSTATIC int localevar __P((char *)); 115244541Sbrooks 116244541Sbrooks/* 117244541Sbrooks * Initialize the varable symbol tables and import the environment 118244541Sbrooks */ 119244541Sbrooks 120244541Sbrooks#ifdef mkinit 121244541SbrooksINCLUDE "var.h" 122244541SbrooksINIT { 123244541Sbrooks char **envp; 124244541Sbrooks extern char **environ; 125244541Sbrooks 126244541Sbrooks initvar(); 127244541Sbrooks for (envp = environ ; *envp ; envp++) { 128244541Sbrooks if (strchr(*envp, '=')) { 129244541Sbrooks setvareq(*envp, VEXPORT|VTEXTFIXED); 130244541Sbrooks } 131244541Sbrooks } 132244541Sbrooks} 133244541Sbrooks#endif 134244541Sbrooks 135244541Sbrooks 136244541Sbrooks/* 137244541Sbrooks * This routine initializes the builtin variables. It is called when the 138244541Sbrooks * shell is initialized and again when a shell procedure is spawned. 139244541Sbrooks */ 140244541Sbrooks 141244541Sbrooksvoid 142244541Sbrooksinitvar() { 143244541Sbrooks const struct varinit *ip; 144244541Sbrooks struct var *vp; 145244541Sbrooks struct var **vpp; 146244541Sbrooks 147244541Sbrooks for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 148244541Sbrooks if ((vp->flags & VEXPORT) == 0) { 149244541Sbrooks vpp = hashvar(ip->text); 150244541Sbrooks vp->next = *vpp; 151244541Sbrooks *vpp = vp; 152244541Sbrooks vp->text = ip->text; 153244541Sbrooks vp->flags = ip->flags; 154244541Sbrooks } 155244541Sbrooks } 156244541Sbrooks /* 157244541Sbrooks * PS1 depends on uid 158244541Sbrooks */ 159244541Sbrooks if ((vps1.flags & VEXPORT) == 0) { 160244541Sbrooks vpp = hashvar("PS1="); 161244541Sbrooks vps1.next = *vpp; 162244541Sbrooks *vpp = &vps1; 163244541Sbrooks vps1.text = geteuid() ? "PS1=$ " : "PS1=# "; 164244541Sbrooks vps1.flags = VSTRFIXED|VTEXTFIXED; 165244541Sbrooks } 166244541Sbrooks} 167244541Sbrooks 168244541Sbrooks/* 169244541Sbrooks * Set the value of a variable. The flags argument is ored with the 170244541Sbrooks * flags of the variable. If val is NULL, the variable is unset. 171244541Sbrooks */ 172244541Sbrooks 173244541Sbrooksvoid 174244541Sbrookssetvar(name, val, flags) 175244541Sbrooks char *name, *val; 176244541Sbrooks { 177244541Sbrooks char *p, *q; 178244541Sbrooks int len; 179244541Sbrooks int namelen; 180244541Sbrooks char *nameeq; 181244541Sbrooks int isbad; 182244541Sbrooks 183244541Sbrooks isbad = 0; 184249293Sed p = name; 185249293Sed if (! is_name(*p)) 186249293Sed isbad = 1; 187244541Sbrooks p++; 188244541Sbrooks for (;;) { 189244541Sbrooks if (! is_in_name(*p)) { 190244541Sbrooks if (*p == '\0' || *p == '=') 191244541Sbrooks break; 192244541Sbrooks isbad = 1; 193244541Sbrooks } 194244541Sbrooks p++; 195244541Sbrooks } 196244541Sbrooks namelen = p - name; 197244541Sbrooks if (isbad) 198244541Sbrooks error("%.*s: bad variable name", namelen, name); 199244541Sbrooks len = namelen + 2; /* 2 is space for '=' and '\0' */ 200244541Sbrooks if (val == NULL) { 201244541Sbrooks flags |= VUNSET; 202244541Sbrooks } else { 203244541Sbrooks len += strlen(val); 204244541Sbrooks } 205244541Sbrooks p = nameeq = ckmalloc(len); 206244541Sbrooks q = name; 207244541Sbrooks while (--namelen >= 0) 208244541Sbrooks *p++ = *q++; 209244541Sbrooks *p++ = '='; 210244541Sbrooks *p = '\0'; 211244541Sbrooks if (val) 212244541Sbrooks scopy(val, p); 213244541Sbrooks setvareq(nameeq, flags); 214244541Sbrooks} 215244541Sbrooks 216244541SbrooksSTATIC int 217244541Sbrookslocalevar(s) 218244541Sbrooks char *s; 219244541Sbrooks { 220244541Sbrooks static char *lnames[7] = { 221244541Sbrooks "ALL", "COLLATE", "CTYPE", "MONETARY", 222244541Sbrooks "NUMERIC", "TIME", NULL 223244541Sbrooks }; 224244541Sbrooks char **ss; 225244541Sbrooks 226244541Sbrooks if (*s != 'L') 227244541Sbrooks return 0; 228244541Sbrooks if (varequal(s + 1, "ANG")) 229244541Sbrooks return 1; 230244541Sbrooks if (strncmp(s + 1, "C_", 2) != 0) 231244541Sbrooks return 0; 232244541Sbrooks for (ss = lnames; *ss ; ss++) 233244541Sbrooks if (varequal(s + 3, *ss)) 234244541Sbrooks return 1; 235244541Sbrooks return 0; 236244541Sbrooks} 237244541Sbrooks 238244541Sbrooks/* 239244541Sbrooks * Same as setvar except that the variable and value are passed in 240244541Sbrooks * the first argument as name=value. Since the first argument will 241244541Sbrooks * be actually stored in the table, it should not be a string that 242244541Sbrooks * will go away. 243244541Sbrooks */ 244244541Sbrooks 245244541Sbrooksvoid 246244541Sbrookssetvareq(s, flags) 247244541Sbrooks char *s; 248244541Sbrooks { 249244541Sbrooks struct var *vp, **vpp; 250244541Sbrooks 251244541Sbrooks vpp = hashvar(s); 252244541Sbrooks for (vp = *vpp ; vp ; vp = vp->next) { 253244541Sbrooks if (varequal(s, vp->text)) { 254244541Sbrooks if (vp->flags & VREADONLY) { 255244541Sbrooks int len = strchr(s, '=') - s; 256244541Sbrooks error("%.*s: is read only", len, s); 257244541Sbrooks } 258244541Sbrooks INTOFF; 259244541Sbrooks if (vp == &vpath) 260244541Sbrooks changepath(s + 5); /* 5 = strlen("PATH=") */ 261244541Sbrooks if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 262244541Sbrooks ckfree(vp->text); 263244541Sbrooks vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET); 264244541Sbrooks vp->flags |= flags; 265244541Sbrooks vp->text = s; 266244541Sbrooks if (vp == &vmpath || (vp == &vmail && ! mpathset())) 267244541Sbrooks chkmail(1); 268244541Sbrooks if (vp == &vhistsize) 269244541Sbrooks sethistsize(); 270244541Sbrooks if ((vp->flags & VEXPORT) && localevar(s)) { 271244541Sbrooks putenv(s); 272244541Sbrooks (void) setlocale(LC_ALL, ""); 273244541Sbrooks } 274244541Sbrooks INTON; 275244541Sbrooks return; 276244541Sbrooks } 277244541Sbrooks } 278244541Sbrooks /* not found */ 279244541Sbrooks vp = ckmalloc(sizeof (*vp)); 280244541Sbrooks vp->flags = flags; 281244541Sbrooks vp->text = s; 282244541Sbrooks vp->next = *vpp; 283244541Sbrooks INTOFF; 284244541Sbrooks *vpp = vp; 285244541Sbrooks if ((vp->flags & VEXPORT) && localevar(s)) { 286244541Sbrooks putenv(s); 287244541Sbrooks (void) setlocale(LC_ALL, ""); 288244541Sbrooks } 289244541Sbrooks INTON; 290244541Sbrooks} 291244541Sbrooks 292244541Sbrooks 293244541Sbrooks 294244541Sbrooks/* 295244541Sbrooks * Process a linked list of variable assignments. 296244541Sbrooks */ 297244541Sbrooks 298244541Sbrooksvoid 299273796Sbrookslistsetvar(list) 300244541Sbrooks struct strlist *list; 301244541Sbrooks { 302244541Sbrooks struct strlist *lp; 303273796Sbrooks 304244541Sbrooks INTOFF; 305244541Sbrooks for (lp = list ; lp ; lp = lp->next) { 306244541Sbrooks setvareq(savestr(lp->text), 0); 307244541Sbrooks } 308244541Sbrooks INTON; 309244541Sbrooks} 310244541Sbrooks 311244541Sbrooks 312244541Sbrooks 313244541Sbrooks/* 314244541Sbrooks * Find the value of a variable. Returns NULL if not set. 315244541Sbrooks */ 316244541Sbrooks 317244541Sbrookschar * 318244541Sbrookslookupvar(name) 319244541Sbrooks char *name; 320244541Sbrooks { 321244541Sbrooks struct var *v; 322244541Sbrooks 323244541Sbrooks for (v = *hashvar(name) ; v ; v = v->next) { 324244541Sbrooks if (varequal(v->text, name)) { 325244541Sbrooks if (v->flags & VUNSET) 326244541Sbrooks return NULL; 327244541Sbrooks return strchr(v->text, '=') + 1; 328244541Sbrooks } 329244541Sbrooks } 330244541Sbrooks return NULL; 331244541Sbrooks} 332244541Sbrooks 333 334 335/* 336 * Search the environment of a builtin command. If the second argument 337 * is nonzero, return the value of a variable even if it hasn't been 338 * exported. 339 */ 340 341char * 342bltinlookup(name, doall) 343 char *name; 344 { 345 struct strlist *sp; 346 struct var *v; 347 348 for (sp = cmdenviron ; sp ; sp = sp->next) { 349 if (varequal(sp->text, name)) 350 return strchr(sp->text, '=') + 1; 351 } 352 for (v = *hashvar(name) ; v ; v = v->next) { 353 if (varequal(v->text, name)) { 354 if (v->flags & VUNSET 355 || ! doall && (v->flags & VEXPORT) == 0) 356 return NULL; 357 return strchr(v->text, '=') + 1; 358 } 359 } 360 return NULL; 361} 362 363 364 365/* 366 * Generate a list of exported variables. This routine is used to construct 367 * the third argument to execve when executing a program. 368 */ 369 370char ** 371environment() { 372 int nenv; 373 struct var **vpp; 374 struct var *vp; 375 char **env, **ep; 376 377 nenv = 0; 378 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 379 for (vp = *vpp ; vp ; vp = vp->next) 380 if (vp->flags & VEXPORT) 381 nenv++; 382 } 383 ep = env = stalloc((nenv + 1) * sizeof *env); 384 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 385 for (vp = *vpp ; vp ; vp = vp->next) 386 if (vp->flags & VEXPORT) 387 *ep++ = vp->text; 388 } 389 *ep = NULL; 390 return env; 391} 392 393 394/* 395 * Called when a shell procedure is invoked to clear out nonexported 396 * variables. It is also necessary to reallocate variables of with 397 * VSTACK set since these are currently allocated on the stack. 398 */ 399 400#ifdef mkinit 401MKINIT void shprocvar(); 402 403SHELLPROC { 404 shprocvar(); 405} 406#endif 407 408void 409shprocvar() { 410 struct var **vpp; 411 struct var *vp, **prev; 412 413 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 414 for (prev = vpp ; (vp = *prev) != NULL ; ) { 415 if ((vp->flags & VEXPORT) == 0) { 416 *prev = vp->next; 417 if ((vp->flags & VTEXTFIXED) == 0) 418 ckfree(vp->text); 419 if ((vp->flags & VSTRFIXED) == 0) 420 ckfree(vp); 421 } else { 422 if (vp->flags & VSTACK) { 423 vp->text = savestr(vp->text); 424 vp->flags &=~ VSTACK; 425 } 426 prev = &vp->next; 427 } 428 } 429 } 430 initvar(); 431} 432 433 434 435/* 436 * Command to list all variables which are set. Currently this command 437 * is invoked from the set command when the set command is called without 438 * any variables. 439 */ 440 441int 442showvarscmd(argc, argv) char **argv; { 443 struct var **vpp; 444 struct var *vp; 445 446 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 447 for (vp = *vpp ; vp ; vp = vp->next) { 448 if ((vp->flags & VUNSET) == 0) 449 out1fmt("%s\n", vp->text); 450 } 451 } 452 return 0; 453} 454 455 456 457/* 458 * The export and readonly commands. 459 */ 460 461int 462exportcmd(argc, argv) char **argv; { 463 struct var **vpp; 464 struct var *vp; 465 char *name; 466 char *p; 467 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 468 469 listsetvar(cmdenviron); 470 if (argc > 1) { 471 while ((name = *argptr++) != NULL) { 472 if ((p = strchr(name, '=')) != NULL) { 473 p++; 474 } else { 475 vpp = hashvar(name); 476 for (vp = *vpp ; vp ; vp = vp->next) { 477 if (varequal(vp->text, name)) { 478 vp->flags |= flag; 479 if ((vp->flags & VEXPORT) && localevar(vp->text)) { 480 putenv(vp->text); 481 (void) setlocale(LC_ALL, ""); 482 } 483 goto found; 484 } 485 } 486 } 487 setvar(name, p, flag); 488found:; 489 } 490 } else { 491 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 492 for (vp = *vpp ; vp ; vp = vp->next) { 493 if (vp->flags & flag) { 494 for (p = vp->text ; *p != '=' ; p++) 495 out1c(*p); 496 out1c('\n'); 497 } 498 } 499 } 500 } 501 return 0; 502} 503 504 505/* 506 * The "local" command. 507 */ 508 509localcmd(argc, argv) char **argv; { 510 char *name; 511 512 if (! in_function()) 513 error("Not in a function"); 514 while ((name = *argptr++) != NULL) { 515 mklocal(name); 516 } 517 return 0; 518} 519 520 521/* 522 * Make a variable a local variable. When a variable is made local, it's 523 * value and flags are saved in a localvar structure. The saved values 524 * will be restored when the shell function returns. We handle the name 525 * "-" as a special case. 526 */ 527 528void 529mklocal(name) 530 char *name; 531 { 532 struct localvar *lvp; 533 struct var **vpp; 534 struct var *vp; 535 536 INTOFF; 537 lvp = ckmalloc(sizeof (struct localvar)); 538 if (name[0] == '-' && name[1] == '\0') { 539 lvp->text = ckmalloc(sizeof optlist); 540 bcopy(optlist, lvp->text, sizeof optlist); 541 vp = NULL; 542 } else { 543 vpp = hashvar(name); 544 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); 545 if (vp == NULL) { 546 if (strchr(name, '=')) 547 setvareq(savestr(name), VSTRFIXED); 548 else 549 setvar(name, NULL, VSTRFIXED); 550 vp = *vpp; /* the new variable */ 551 lvp->text = NULL; 552 lvp->flags = VUNSET; 553 } else { 554 lvp->text = vp->text; 555 lvp->flags = vp->flags; 556 vp->flags |= VSTRFIXED|VTEXTFIXED; 557 if (strchr(name, '=')) 558 setvareq(savestr(name), 0); 559 } 560 } 561 lvp->vp = vp; 562 lvp->next = localvars; 563 localvars = lvp; 564 INTON; 565} 566 567 568/* 569 * Called after a function returns. 570 */ 571 572void 573poplocalvars() { 574 struct localvar *lvp; 575 struct var *vp; 576 577 while ((lvp = localvars) != NULL) { 578 localvars = lvp->next; 579 vp = lvp->vp; 580 if (vp == NULL) { /* $- saved */ 581 bcopy(lvp->text, optlist, sizeof optlist); 582 ckfree(lvp->text); 583 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 584 (void)unsetvar(vp->text); 585 } else { 586 if ((vp->flags & VTEXTFIXED) == 0) 587 ckfree(vp->text); 588 vp->flags = lvp->flags; 589 vp->text = lvp->text; 590 } 591 ckfree(lvp); 592 } 593} 594 595 596setvarcmd(argc, argv) char **argv; { 597 if (argc <= 2) 598 return unsetcmd(argc, argv); 599 else if (argc == 3) 600 setvar(argv[1], argv[2], 0); 601 else 602 error("List assignment not implemented"); 603 return 0; 604} 605 606 607/* 608 * The unset builtin command. We unset the function before we unset the 609 * variable to allow a function to be unset when there is a readonly variable 610 * with the same name. 611 */ 612 613unsetcmd(argc, argv) char **argv; { 614 char **ap; 615 int i; 616 int flg_func = 0; 617 int flg_var = 0; 618 int ret = 0; 619 620 while ((i = nextopt("vf")) != '\0') { 621 if (i == 'f') 622 flg_func = 1; 623 else 624 flg_var = 1; 625 } 626 if (flg_func == 0 && flg_var == 0) 627 flg_var = 1; 628 629 for (ap = argptr; *ap ; ap++) { 630 if (flg_func) 631 ret |= unsetfunc(*ap); 632 if (flg_var) 633 ret |= unsetvar(*ap); 634 } 635 return ret; 636} 637 638 639/* 640 * Unset the specified variable. 641 */ 642 643STATIC int 644unsetvar(s) 645 char *s; 646 { 647 struct var **vpp; 648 struct var *vp; 649 650 vpp = hashvar(s); 651 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { 652 if (varequal(vp->text, s)) { 653 if (vp->flags & VREADONLY) 654 return (1); 655 INTOFF; 656 if (*(strchr(vp->text, '=') + 1) != '\0') 657 setvar(s, nullstr, 0); 658 if ((vp->flags & VEXPORT) && localevar(vp->text)) { 659 unsetenv(s); 660 setlocale(LC_ALL, ""); 661 } 662 vp->flags &=~ VEXPORT; 663 vp->flags |= VUNSET; 664 if ((vp->flags & VSTRFIXED) == 0) { 665 if ((vp->flags & VTEXTFIXED) == 0) 666 ckfree(vp->text); 667 *vpp = vp->next; 668 ckfree(vp); 669 } 670 INTON; 671 return (0); 672 } 673 } 674 675 return (1); 676} 677 678 679 680/* 681 * Find the appropriate entry in the hash table from the name. 682 */ 683 684STATIC struct var ** 685hashvar(p) 686 register char *p; 687 { 688 unsigned int hashval; 689 690 hashval = ((unsigned char)*p) << 4; 691 while (*p && *p != '=') 692 hashval += (unsigned char)*p++; 693 return &vartab[hashval % VTABSIZE]; 694} 695 696 697 698/* 699 * Returns true if the two strings specify the same varable. The first 700 * variable name is terminated by '='; the second may be terminated by 701 * either '=' or '\0'. 702 */ 703 704STATIC int 705varequal(p, q) 706 register char *p, *q; 707 { 708 while (*p == *q++) { 709 if (*p++ == '=') 710 return 1; 711 } 712 if (*p == '=' && *(q - 1) == '\0') 713 return 1; 714 return 0; 715} 716