sh: Change the CTL* bytes to ones invalid in UTF-8.
[dragonfly.git] / bin / sh / var.c
CommitLineData
984263bc
MD
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.
1de703da
MD
35 *
36 * @(#)var.c 8.3 (Berkeley) 5/4/95
99512ac4 37 * $FreeBSD: src/bin/sh/var.c,v 1.56 2011/02/04 22:47:55 jilles Exp $
984263bc
MD
38 */
39
984263bc
MD
40#include <unistd.h>
41#include <stdlib.h>
42
43/*
44 * Shell variables.
45 */
46
47#include <locale.h>
6a25bb17 48#include <paths.h>
984263bc
MD
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
72struct varinit {
73 struct var *var;
74 int flags;
934863d7 75 const char *text;
984263bc
MD
76 void (*func)(const char *);
77};
78
79
984263bc
MD
80#ifndef NO_HISTORY
81struct var vhistsize;
99512ac4 82struct var vterm;
984263bc
MD
83#endif
84struct var vifs;
85struct var vmail;
86struct var vmpath;
87struct var vpath;
88struct var vppid;
89struct var vps1;
90struct var vps2;
0d5aaed6 91struct var vps4;
984263bc 92struct var vvers;
99512ac4 93static struct var voptind;
984263bc 94
99512ac4 95static const struct varinit varinit[] = {
984263bc 96#ifndef NO_HISTORY
99512ac4 97 { &vhistsize, VUNSET, "HISTSIZE=",
984263bc
MD
98 sethistsize },
99#endif
99512ac4 100 { &vifs, 0, "IFS= \t\n",
984263bc 101 NULL },
99512ac4 102 { &vmail, VUNSET, "MAIL=",
984263bc 103 NULL },
99512ac4 104 { &vmpath, VUNSET, "MAILPATH=",
984263bc 105 NULL },
99512ac4 106 { &vpath, 0, "PATH=" _PATH_DEFPATH,
984263bc 107 changepath },
99512ac4 108 { &vppid, VUNSET, "PPID=",
984263bc
MD
109 NULL },
110 /*
111 * vps1 depends on uid
112 */
99512ac4 113 { &vps2, 0, "PS2=> ",
984263bc 114 NULL },
99512ac4 115 { &vps4, 0, "PS4=+ ",
0d5aaed6 116 NULL },
99512ac4
PA
117#ifndef NO_HISTORY
118 { &vterm, VUNSET, "TERM=",
119 setterm },
120#endif
121 { &voptind, 0, "OPTIND=1",
984263bc
MD
122 getoptsreset },
123 { NULL, 0, NULL,
124 NULL }
125};
126
99512ac4 127static struct var *vartab[VTABSIZE];
984263bc 128
99512ac4
PA
129static const char *const locale_names[7] = {
130 "LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
131 "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
132};
133static const int locale_categories[7] = {
134 LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
135};
136
137static struct var **hashvar(const char *);
138static int varequal(const char *, const char *);
139static int localevar(const char *);
984263bc
MD
140
141/*
492efe05 142 * Initialize the variable symbol tables and import the environment.
984263bc
MD
143 */
144
145#ifdef mkinit
146INCLUDE "var.h"
934863d7 147MKINIT char **environ;
984263bc
MD
148INIT {
149 char **envp;
984263bc
MD
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
99512ac4 163 * shell is initialized.
984263bc
MD
164 */
165
166void
167initvar(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;
99512ac4
PA
179 vp->text = __DECONST(char *, ip->text);
180 vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
984263bc
MD
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;
99512ac4 191 vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
984263bc
MD
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
204int
492efe05 205setvarsafe(const char *name, const char *val, int flags)
984263bc
MD
206{
207 struct jmploc jmploc;
99512ac4 208 struct jmploc *const savehandler = handler;
984263bc 209 int err = 0;
99512ac4 210 int inton;
984263bc 211
99512ac4 212 inton = is_int_on();
984263bc
MD
213 if (setjmp(jmploc.loc))
214 err = 1;
215 else {
216 handler = &jmploc;
217 setvar(name, val, flags);
218 }
219 handler = savehandler;
99512ac4 220 SETINTON(inton);
984263bc
MD
221 return err;
222}
223
224/*
fab926b5 225 * Set the value of a variable. The flags argument is stored with the
984263bc
MD
226 * flags of the variable. If val is NULL, the variable is unset.
227 */
228
229void
492efe05 230setvar(const char *name, const char *val, int flags)
984263bc 231{
99512ac4 232 const char *p;
984263bc
MD
233 int len;
234 int namelen;
235 char *nameeq;
236 int isbad;
237
238 isbad = 0;
99512ac4
PA
239 p = name;
240 if (!is_name(*p))
984263bc 241 isbad = 1;
99512ac4 242 p++;
984263bc 243 for (;;) {
99512ac4
PA
244 if (!is_in_name(*p)) {
245 if (*p == '\0' || *p == '=')
984263bc
MD
246 break;
247 isbad = 1;
248 }
99512ac4 249 p++;
984263bc 250 }
99512ac4 251 namelen = p - name;
984263bc
MD
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 }
99512ac4
PA
260 nameeq = ckmalloc(len);
261 memcpy(nameeq, name, namelen);
262 nameeq[namelen] = '=';
984263bc 263 if (val)
99512ac4
PA
264 scopy(val, nameeq + namelen + 1);
265 else
266 nameeq[namelen + 1] = '\0';
984263bc
MD
267 setvareq(nameeq, flags);
268}
269
99512ac4 270static int
492efe05 271localevar(const char *s)
984263bc 272{
99512ac4 273 const char *const *ss;
984263bc
MD
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;
99512ac4
PA
281 if (varequal(s + 3, "ALL"))
282 return 1;
283 for (ss = locale_names; *ss ; ss++)
284 if (varequal(s + 3, *ss + 3))
984263bc
MD
285 return 1;
286 return 0;
287}
288
5d0641a4
PA
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 */
293static void
99512ac4 294change_env(const char *s, int set)
5d0641a4
PA
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
984263bc
MD
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
318void
319setvareq(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 }
99512ac4
PA
333 if (flags & VNOSET)
334 return;
984263bc
MD
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?
99512ac4
PA
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.
984263bc 354 */
99512ac4
PA
355 if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
356 iflag == 1)
984263bc
MD
357 chkmail(1);
358 if ((vp->flags & VEXPORT) && localevar(s)) {
5d0641a4 359 change_env(s, 1);
57fed2af 360 setlocale(LC_ALL, "");
984263bc
MD
361 }
362 INTON;
363 return;
364 }
365 }
366 /* not found */
99512ac4
PA
367 if (flags & VNOSET)
368 return;
984263bc
MD
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)) {
5d0641a4 377 change_env(s, 1);
57fed2af 378 setlocale(LC_ALL, "");
984263bc
MD
379 }
380 INTON;
381}
382
383
384
385/*
386 * Process a linked list of variable assignments.
387 */
388
389void
99512ac4 390listsetvar(struct strlist *list, int flags)
984263bc
MD
391{
392 struct strlist *lp;
393
394 INTOFF;
395 for (lp = list ; lp ; lp = lp->next) {
99512ac4 396 setvareq(savestr(lp->text), flags);
984263bc
MD
397 }
398 INTON;
399}
400
401
402
403/*
404 * Find the value of a variable. Returns NULL if not set.
405 */
406
407char *
492efe05 408lookupvar(const char *name)
984263bc
MD
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
430char *
492efe05 431bltinlookup(const char *name, int doall)
984263bc
MD
432{
433 struct strlist *sp;
434 struct var *v;
99512ac4 435 char *result;
984263bc 436
99512ac4 437 result = NULL;
984263bc
MD
438 for (sp = cmdenviron ; sp ; sp = sp->next) {
439 if (varequal(sp->text, name))
99512ac4 440 result = strchr(sp->text, '=') + 1;
984263bc 441 }
99512ac4
PA
442 if (result != NULL)
443 return result;
984263bc
MD
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
99512ac4
PA
456/*
457 * Set up locale for a builtin (LANG/LC_* assignments).
458 */
459void
460bltinsetlocale(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 */
496void
497bltinunsetlocale(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
984263bc
MD
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
517char **
518environment(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
fab926b5
PA
542static int
543var_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
984263bc
MD
557
558/*
99512ac4
PA
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.
984263bc
MD
561 */
562
563int
564showvarscmd(int argc __unused, char **argv __unused)
565{
566 struct var **vpp;
567 struct var *vp;
568 const char *s;
fab926b5
PA
569 const char **vars;
570 int i, n;
984263bc 571
fab926b5
PA
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++;
984263bc
MD
580 }
581 }
fab926b5
PA
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++) {
99512ac4
PA
595 s = strchr(vars[i], '=');
596 s++;
597 outbin(vars[i], s - vars[i], out1);
598 out1qstr(s);
fab926b5
PA
599 out1c('\n');
600 }
601 ckfree(vars);
602 INTOFF;
603
984263bc
MD
604 return 0;
605}
606
607
608
609/*
610 * The export and readonly commands.
611 */
612
613int
614exportcmd(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
fab926b5
PA
641 if (values && argc != 0)
642 error("-p requires no arguments");
984263bc 643 if (argc != 0) {
fab926b5 644 while ((name = *argv++) != NULL) {
984263bc
MD
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)) {
5d0641a4 654 change_env(vp->text, 1);
57fed2af 655 setlocale(LC_ALL, "");
984263bc
MD
656 }
657 goto found;
658 }
659 }
660 }
661 setvar(name, p, flag);
662found:;
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 }
99512ac4 672 p = strchr(vp->text, '=');
984263bc 673 if (values && !(vp->flags & VUNSET)) {
99512ac4
PA
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);
984263bc
MD
681 out1c('\n');
682 }
683 }
684 }
685 }
686 return 0;
687}
688
689
690/*
691 * The "local" command.
692 */
693
694int
695localcmd(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
715void
716mklocal(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
758void
759poplocalvars(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);
99512ac4 770 optschanged();
984263bc 771 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
57fed2af 772 unsetvar(vp->text);
984263bc
MD
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
784int
785setvarcmd(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
99512ac4 792 error("too many arguments");
984263bc
MD
793 return 0;
794}
795
796
797/*
99512ac4 798 * The unset builtin command.
984263bc
MD
799 */
800
801int
802unsetcmd(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
833int
492efe05 834unsetvar(const char *s)
984263bc
MD
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)) {
99130033 848 change_env(__DECONST(char *, s), 0);
984263bc
MD
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 }
31b6347c 863 return (0);
984263bc
MD
864}
865
866
867
868/*
869 * Find the appropriate entry in the hash table from the name.
870 */
871
99512ac4 872static struct var **
492efe05 873hashvar(const char *p)
984263bc
MD
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
99512ac4 891static int
492efe05 892varequal(const char *p, const char *q)
984263bc
MD
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}