00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef lint
00038 static char sccsid[] = "@(#)var.c 5.3 (Berkeley) 4/12/91";
00039 #endif
00040
00041
00042
00043
00044
00045 #include "shell.h"
00046 #include "output.h"
00047 #include "expand.h"
00048 #include "nodes.h"
00049 #include "eval.h"
00050 #include "exec.h"
00051 #include "syntax.h"
00052 #include "options.h"
00053 #include "mail.h"
00054 #include "var.h"
00055 #include "memalloc.h"
00056 #include "error.h"
00057 #include "mystring.h"
00058
00059
00060 #define VTABSIZE 39
00061
00062
00063 struct varinit {
00064 struct var *var;
00065 int flags;
00066 char *text;
00067 };
00068
00069
00070 #if ATTY
00071 struct var vatty;
00072 #endif
00073 struct var vifs;
00074 struct var vmail;
00075 struct var vmpath;
00076 struct var vpath;
00077 struct var vps1;
00078 struct var vps2;
00079 struct var vpse;
00080 struct var vvers;
00081 #if ATTY
00082 struct var vterm;
00083 #endif
00084
00085 const struct varinit varinit[] = {
00086 #if ATTY
00087 {&vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY="},
00088 #endif
00089 {&vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n"},
00090 {&vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL="},
00091 {&vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH="},
00092 {&vpath, VSTRFIXED|VTEXTFIXED, "PATH=:/bin:/usr/bin"},
00093
00094
00095
00096 {&vps2, VSTRFIXED|VTEXTFIXED, "PS2=> "},
00097 {&vpse, VSTRFIXED|VTEXTFIXED, "PSE=* "},
00098 #if ATTY
00099 {&vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM="},
00100 #endif
00101 {NULL, 0, NULL}
00102 };
00103
00104 struct var *vartab[VTABSIZE];
00105
00106 STATIC void unsetvar __P((char *));
00107 STATIC struct var **hashvar __P((char *));
00108 STATIC int varequal __P((char *, char *));
00109
00110
00111
00112
00113
00114 #ifdef mkinit
00115 INCLUDE "var.h"
00116 INIT {
00117 char **envp;
00118 extern char **environ;
00119
00120 initvar();
00121 for (envp = environ ; *envp ; envp++) {
00122 if (strchr(*envp, '=')) {
00123 setvareq(*envp, VEXPORT|VTEXTFIXED);
00124 }
00125 }
00126 }
00127 #endif
00128
00129
00130
00131
00132
00133
00134
00135 void
00136 initvar() {
00137 const struct varinit *ip;
00138 struct var *vp;
00139 struct var **vpp;
00140
00141 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
00142 if ((vp->flags & VEXPORT) == 0) {
00143 vpp = hashvar(ip->text);
00144 vp->next = *vpp;
00145 *vpp = vp;
00146 vp->text = ip->text;
00147 vp->flags = ip->flags;
00148 }
00149 }
00150
00151
00152
00153 if ((vps1.flags & VEXPORT) == 0) {
00154 vpp = hashvar("PS1=");
00155 vps1.next = *vpp;
00156 *vpp = &vps1;
00157 vps1.text = getuid() ? "PS1=$ " : "PS1=# ";
00158 vps1.flags = VSTRFIXED|VTEXTFIXED;
00159 }
00160 }
00161
00162
00163
00164
00165
00166
00167 void
00168 setvar(name, val, flags)
00169 char *name, *val;
00170 {
00171 char *p, *q;
00172 int len;
00173 int namelen;
00174 char *nameeq;
00175 int isbad;
00176
00177 isbad = 0;
00178 p = name;
00179 if (! is_name(*p++))
00180 isbad = 1;
00181 for (;;) {
00182 if (! is_in_name(*p)) {
00183 if (*p == '\0' || *p == '=')
00184 break;
00185 isbad = 1;
00186 }
00187 p++;
00188 }
00189 namelen = p - name;
00190 if (isbad)
00191 error("%.*s: is read only", namelen, name);
00192 len = namelen + 2;
00193 if (val == NULL) {
00194 flags |= VUNSET;
00195 } else {
00196 len += strlen(val);
00197 }
00198 p = nameeq = ckmalloc(len);
00199 q = name;
00200 while (--namelen >= 0)
00201 *p++ = *q++;
00202 *p++ = '=';
00203 *p = '\0';
00204 if (val)
00205 scopy(val, p);
00206 setvareq(nameeq, flags);
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 void
00219 setvareq(s, flags)
00220 char *s;
00221 {
00222 struct var *vp, **vpp;
00223
00224 vpp = hashvar(s);
00225 for (vp = *vpp ; vp ; vp = vp->next) {
00226 if (varequal(s, vp->text)) {
00227 if (vp->flags & VREADONLY) {
00228 int len = strchr(s, '=') - s;
00229 error("%.*s: is read only", len, s);
00230 }
00231 INTOFF;
00232 if (vp == &vpath)
00233 changepath(s + 5);
00234 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
00235 ckfree(vp->text);
00236 vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
00237 vp->flags |= flags;
00238 vp->text = s;
00239 if (vp == &vmpath || (vp == &vmail && ! mpathset()))
00240 chkmail(1);
00241 INTON;
00242 return;
00243 }
00244 }
00245
00246 vp = ckmalloc(sizeof (*vp));
00247 vp->flags = flags;
00248 vp->text = s;
00249 vp->next = *vpp;
00250 *vpp = vp;
00251 }
00252
00253
00254
00255
00256
00257
00258
00259 void
00260 listsetvar(list)
00261 struct strlist *list;
00262 {
00263 struct strlist *lp;
00264
00265 INTOFF;
00266 for (lp = list ; lp ; lp = lp->next) {
00267 setvareq(savestr(lp->text), 0);
00268 }
00269 INTON;
00270 }
00271
00272
00273
00274
00275
00276
00277
00278 char *
00279 lookupvar(name)
00280 char *name;
00281 {
00282 struct var *v;
00283
00284 for (v = *hashvar(name) ; v ; v = v->next) {
00285 if (varequal(v->text, name)) {
00286 if (v->flags & VUNSET)
00287 return NULL;
00288 return strchr(v->text, '=') + 1;
00289 }
00290 }
00291 return NULL;
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 char *
00303 bltinlookup(name, doall)
00304 char *name;
00305 {
00306 struct strlist *sp;
00307 struct var *v;
00308
00309 for (sp = cmdenviron ; sp ; sp = sp->next) {
00310 if (varequal(sp->text, name))
00311 return strchr(sp->text, '=') + 1;
00312 }
00313 for (v = *hashvar(name) ; v ; v = v->next) {
00314 if (varequal(v->text, name)) {
00315 if (v->flags & VUNSET
00316 || ! doall && (v->flags & VEXPORT) == 0)
00317 return NULL;
00318 return strchr(v->text, '=') + 1;
00319 }
00320 }
00321 return NULL;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331 char **
00332 environment() {
00333 int nenv;
00334 struct var **vpp;
00335 struct var *vp;
00336 char **env, **ep;
00337
00338 nenv = 0;
00339 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00340 for (vp = *vpp ; vp ; vp = vp->next)
00341 if (vp->flags & VEXPORT)
00342 nenv++;
00343 }
00344 ep = env = stalloc((nenv + 1) * sizeof *env);
00345 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00346 for (vp = *vpp ; vp ; vp = vp->next)
00347 if (vp->flags & VEXPORT)
00348 *ep++ = vp->text;
00349 }
00350 *ep = NULL;
00351 return env;
00352 }
00353
00354
00355
00356
00357
00358
00359
00360
00361 #ifdef mkinit
00362 MKINIT void shprocvar();
00363
00364 SHELLPROC {
00365 shprocvar();
00366 }
00367 #endif
00368
00369 void
00370 shprocvar() {
00371 struct var **vpp;
00372 struct var *vp, **prev;
00373
00374 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00375 for (prev = vpp ; (vp = *prev) != NULL ; ) {
00376 if ((vp->flags & VEXPORT) == 0) {
00377 *prev = vp->next;
00378 if ((vp->flags & VTEXTFIXED) == 0)
00379 ckfree(vp->text);
00380 if ((vp->flags & VSTRFIXED) == 0)
00381 ckfree(vp);
00382 } else {
00383 if (vp->flags & VSTACK) {
00384 vp->text = savestr(vp->text);
00385 vp->flags &=~ VSTACK;
00386 }
00387 prev = &vp->next;
00388 }
00389 }
00390 }
00391 initvar();
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 int
00403 showvarscmd(argc, argv) char **argv; {
00404 struct var **vpp;
00405 struct var *vp;
00406
00407 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00408 for (vp = *vpp ; vp ; vp = vp->next) {
00409 if ((vp->flags & VUNSET) == 0)
00410 out1fmt("%s\n", vp->text);
00411 }
00412 }
00413 return 0;
00414 }
00415
00416
00417
00418
00419
00420
00421
00422 int
00423 exportcmd(argc, argv) char **argv; {
00424 struct var **vpp;
00425 struct var *vp;
00426 char *name;
00427 char *p;
00428 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
00429
00430 listsetvar(cmdenviron);
00431 if (argc > 1) {
00432 while ((name = *argptr++) != NULL) {
00433 if ((p = strchr(name, '=')) != NULL) {
00434 p++;
00435 } else {
00436 vpp = hashvar(name);
00437 for (vp = *vpp ; vp ; vp = vp->next) {
00438 if (varequal(vp->text, name)) {
00439 vp->flags |= flag;
00440 goto found;
00441 }
00442 }
00443 }
00444 setvar(name, p, flag);
00445 found:;
00446 }
00447 } else {
00448 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
00449 for (vp = *vpp ; vp ; vp = vp->next) {
00450 if (vp->flags & flag) {
00451 for (p = vp->text ; *p != '=' ; p++)
00452 out1c(*p);
00453 out1c('\n');
00454 }
00455 }
00456 }
00457 }
00458 return 0;
00459 }
00460
00461
00462
00463
00464
00465
00466 localcmd(argc, argv) char **argv; {
00467 char *name;
00468
00469 if (! in_function())
00470 error("Not in a function");
00471 while ((name = *argptr++) != NULL) {
00472 mklocal(name);
00473 }
00474 return 0;
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 void
00486 mklocal(name)
00487 char *name;
00488 {
00489 struct localvar *lvp;
00490 struct var **vpp;
00491 struct var *vp;
00492
00493 INTOFF;
00494 lvp = ckmalloc(sizeof (struct localvar));
00495 if (name[0] == '-' && name[1] == '\0') {
00496 lvp->text = ckmalloc(sizeof optval);
00497 bcopy(optval, lvp->text, sizeof optval);
00498 vp = NULL;
00499 } else {
00500 vpp = hashvar(name);
00501 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
00502 if (vp == NULL) {
00503 if (strchr(name, '='))
00504 setvareq(savestr(name), VSTRFIXED);
00505 else
00506 setvar(name, NULL, VSTRFIXED);
00507 vp = *vpp;
00508 lvp->text = NULL;
00509 lvp->flags = VUNSET;
00510 } else {
00511 lvp->text = vp->text;
00512 lvp->flags = vp->flags;
00513 vp->flags |= VSTRFIXED|VTEXTFIXED;
00514 if (strchr(name, '='))
00515 setvareq(savestr(name), 0);
00516 }
00517 }
00518 lvp->vp = vp;
00519 lvp->next = localvars;
00520 localvars = lvp;
00521 INTON;
00522 }
00523
00524
00525
00526
00527
00528
00529 void
00530 poplocalvars() {
00531 struct localvar *lvp;
00532 struct var *vp;
00533
00534 while ((lvp = localvars) != NULL) {
00535 localvars = lvp->next;
00536 vp = lvp->vp;
00537 if (vp == NULL) {
00538 bcopy(lvp->text, optval, sizeof optval);
00539 ckfree(lvp->text);
00540 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
00541 unsetvar(vp->text);
00542 } else {
00543 if ((vp->flags & VTEXTFIXED) == 0)
00544 ckfree(vp->text);
00545 vp->flags = lvp->flags;
00546 vp->text = lvp->text;
00547 }
00548 ckfree(lvp);
00549 }
00550 }
00551
00552
00553 setvarcmd(argc, argv) char **argv; {
00554 if (argc <= 2)
00555 return unsetcmd(argc, argv);
00556 else if (argc == 3)
00557 setvar(argv[1], argv[2], 0);
00558 else
00559 error("List assignment not implemented");
00560 return 0;
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570 unsetcmd(argc, argv) char **argv; {
00571 char **ap;
00572
00573 for (ap = argv + 1 ; *ap ; ap++) {
00574 unsetfunc(*ap);
00575 unsetvar(*ap);
00576 }
00577 return 0;
00578 }
00579
00580
00581
00582
00583
00584
00585 STATIC void
00586 unsetvar(s)
00587 char *s;
00588 {
00589 struct var **vpp;
00590 struct var *vp;
00591
00592 vpp = hashvar(s);
00593 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
00594 if (varequal(vp->text, s)) {
00595 INTOFF;
00596 if (*(strchr(vp->text, '=') + 1) != '\0'
00597 || vp->flags & VREADONLY) {
00598 setvar(s, nullstr, 0);
00599 }
00600 vp->flags &=~ VEXPORT;
00601 vp->flags |= VUNSET;
00602 if ((vp->flags & VSTRFIXED) == 0) {
00603 if ((vp->flags & VTEXTFIXED) == 0)
00604 ckfree(vp->text);
00605 *vpp = vp->next;
00606 ckfree(vp);
00607 }
00608 INTON;
00609 return;
00610 }
00611 }
00612 }
00613
00614
00615
00616
00617
00618
00619
00620 STATIC struct var **
00621 hashvar(p)
00622 register char *p;
00623 {
00624 unsigned int hashval;
00625
00626 hashval = *p << 4;
00627 while (*p && *p != '=')
00628 hashval += *p++;
00629 return &vartab[hashval % VTABSIZE];
00630 }
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640 STATIC int
00641 varequal(p, q)
00642 register char *p, *q;
00643 {
00644 while (*p == *q++) {
00645 if (*p++ == '=')
00646 return 1;
00647 }
00648 if (*p == '=' && *(q - 1) == '\0')
00649 return 1;
00650 return 0;
00651 }