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