avoid null ptr deref, from glenn@sun
[unix-history] / usr / src / bin / csh / set.c
CommitLineData
b79f4fa9
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
094e80ed 3 * All rights reserved. The Berkeley Software License Agreement
b79f4fa9
DF
4 * specifies the terms and conditions for redistribution.
5 */
6
35371dec 7#ifndef lint
094e80ed
EW
8static char *sccsid = "@(#)set.c 5.2 (Berkeley) %G%";
9#endif
b278c146
BJ
10
11#include "sh.h"
12
13/*
14 * C Shell
15 */
16
17doset(v)
18 register char **v;
19{
20 register char *p;
21 char *vp, op;
22 char **vecp;
23 bool hadsub;
24 int subscr;
25
26 v++;
27 p = *v++;
28 if (p == 0) {
29 prvars();
30 return;
31 }
32 do {
33 hadsub = 0;
34 for (vp = p; alnum(*p); p++)
35 continue;
58295a3c 36 if (vp == p || !letter(*vp))
b278c146
BJ
37 goto setsyn;
38 if (*p == '[') {
39 hadsub++;
40 p = getinx(p, &subscr);
41 }
42 if (op = *p) {
43 *p++ = 0;
44 if (*p == 0 && *v && **v == '(')
45 p = *v++;
46 } else if (*v && eq(*v, "=")) {
47 op = '=', v++;
48 if (*v)
49 p = *v++;
50 }
51 if (op && op != '=')
52setsyn:
53 bferr("Syntax error");
54 if (eq(p, "(")) {
55 register char **e = v;
56
57 if (hadsub)
58 goto setsyn;
59 for (;;) {
60 if (!*e)
61 bferr("Missing )");
62 if (**e == ')')
63 break;
64 e++;
65 }
66 p = *e;
67 *e = 0;
68 vecp = saveblk(v);
69 set1(vp, vecp, &shvhed);
70 *e = p;
71 v = e + 1;
72 } else if (hadsub)
73 asx(vp, subscr, savestr(p));
74 else
75 set(vp, savestr(p));
76 if (eq(vp, "path")) {
77 exportpath(adrof("path")->vec);
78 dohash();
79 } else if (eq(vp, "histchars")) {
80 register char *p = value("histchars");
81
82 HIST = *p++;
83 HISTSUB = *p;
84 } else if (eq(vp, "user"))
85 setenv("USER", value(vp));
86 else if (eq(vp, "term"))
87 setenv("TERM", value(vp));
88 else if (eq(vp, "home"))
89 setenv("HOME", value(vp));
35371dec
EW
90#ifdef FILEC
91 else if (eq(vp, "filec"))
92 filec = 1;
93#endif
b278c146
BJ
94 } while (p = *v++);
95}
96
97char *
98getinx(cp, ip)
99 register char *cp;
100 register int *ip;
101{
102
103 *ip = 0;
104 *cp++ = 0;
105 while (*cp && digit(*cp))
106 *ip = *ip * 10 + *cp++ - '0';
107 if (*cp++ != ']')
108 bferr("Subscript error");
109 return (cp);
110}
111
112asx(vp, subscr, p)
113 char *vp;
114 int subscr;
115 char *p;
116{
117 register struct varent *v = getvx(vp, subscr);
118
119 xfree(v->vec[subscr - 1]);
120 v->vec[subscr - 1] = globone(p);
121}
122
123struct varent *
124getvx(vp, subscr)
35371dec 125 char *vp;
b278c146
BJ
126{
127 register struct varent *v = adrof(vp);
128
129 if (v == 0)
130 udvar(vp);
131 if (subscr < 1 || subscr > blklen(v->vec))
132 bferr("Subscript out of range");
133 return (v);
134}
135
136char plusplus[2] = { '1', 0 };
137
b278c146
BJ
138dolet(v)
139 char **v;
140{
141 register char *p;
142 char *vp, c, op;
143 bool hadsub;
144 int subscr;
145
146 v++;
147 p = *v++;
148 if (p == 0) {
149 prvars();
150 return;
151 }
152 do {
153 hadsub = 0;
58295a3c 154 for (vp = p; alnum(*p); p++)
b278c146 155 continue;
58295a3c 156 if (vp == p || !letter(*vp))
b278c146
BJ
157 goto letsyn;
158 if (*p == '[') {
159 hadsub++;
160 p = getinx(p, &subscr);
161 }
162 if (*p == 0 && *v)
163 p = *v++;
164 if (op = *p)
165 *p++ = 0;
166 else
167 goto letsyn;
168 vp = savestr(vp);
169 if (op == '=') {
170 c = '=';
171 p = xset(p, &v);
172 } else {
173 c = *p++;
174 if (any(c, "+-")) {
175 if (c != op || *p)
176 goto letsyn;
177 p = plusplus;
178 } else {
179 if (any(op, "<>")) {
180 if (c != op)
181 goto letsyn;
182 c = *p++;
183letsyn:
184 bferr("Syntax error");
185 }
186 if (c != '=')
187 goto letsyn;
188 p = xset(p, &v);
189 }
190 }
191 if (op == '=')
192 if (hadsub)
193 asx(vp, subscr, p);
194 else
195 set(vp, p);
196 else
197 if (hadsub)
198#ifndef V6
199 /* avoid bug in vax CC */
200 {
201 struct varent *gv = getvx(vp, subscr);
202
203 asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
204 }
205#else
206 asx(vp, subscr, operate(op, getvx(vp, subscr)->vec[subscr - 1], p));
207#endif
208 else
209 set(vp, operate(op, value(vp), p));
35371dec
EW
210 if (eq(vp, "path")) {
211 exportpath(adrof("path")->vec);
b278c146 212 dohash();
35371dec
EW
213 }
214 XFREE(vp)
b278c146 215 if (c != '=')
35371dec 216 XFREE(p)
b278c146
BJ
217 } while (p = *v++);
218}
219
220char *
221xset(cp, vp)
222 char *cp, ***vp;
223{
224 register char *dp;
225
226 if (*cp) {
227 dp = savestr(cp);
228 --(*vp);
229 xfree(**vp);
230 **vp = dp;
231 }
232 return (putn(exp(vp)));
233}
234
235char *
236operate(op, vp, p)
237 char op, *vp, *p;
238{
239 char opr[2];
240 char *vec[5];
241 register char **v = vec;
242 char **vecp = v;
243 register int i;
244
245 if (op != '=') {
246 if (*vp)
247 *v++ = vp;
248 opr[0] = op;
249 opr[1] = 0;
250 *v++ = opr;
251 if (op == '<' || op == '>')
252 *v++ = opr;
253 }
254 *v++ = p;
255 *v++ = 0;
256 i = exp(&vecp);
257 if (*vecp)
258 bferr("Expression syntax");
259 return (putn(i));
260}
261
b278c146
BJ
262static char *putp;
263
264char *
265putn(n)
266 register int n;
267{
268 static char number[15];
269
270 putp = number;
271 if (n < 0) {
272 n = -n;
273 *putp++ = '-';
274 }
275 if (sizeof (int) == 2 && n == -32768) {
276 *putp++ = '3';
277 n = 2768;
278#ifdef pdp11
279 }
280#else
281 } else if (sizeof (int) == 4 && n == -2147483648) {
282 *putp++ = '2';
283 n = 147483648;
284 }
285#endif
286 putn1(n);
287 *putp = 0;
288 return (savestr(number));
289}
290
291putn1(n)
292 register int n;
293{
294 if (n > 9)
295 putn1(n / 10);
296 *putp++ = n % 10 + '0';
297}
298
299getn(cp)
300 register char *cp;
301{
302 register int n;
303 int sign;
304
305 sign = 0;
306 if (cp[0] == '+' && cp[1])
307 cp++;
308 if (*cp == '-') {
309 sign++;
310 cp++;
311 if (!digit(*cp))
312 goto badnum;
313 }
314 n = 0;
315 while (digit(*cp))
316 n = n * 10 + *cp++ - '0';
317 if (*cp)
318 goto badnum;
319 return (sign ? -n : n);
320badnum:
321 bferr("Badly formed number");
322 return (0);
323}
324
b278c146
BJ
325char *
326value1(var, head)
327 char *var;
328 struct varent *head;
329{
330 register struct varent *vp;
331
332 vp = adrof1(var, head);
333 return (vp == 0 || vp->vec[0] == 0 ? "" : vp->vec[0]);
334}
335
b278c146 336struct varent *
35371dec 337madrof(pat, vp)
b278c146 338 char *pat;
b278c146 339 register struct varent *vp;
35371dec
EW
340{
341 register struct varent *vp1;
b278c146 342
35371dec
EW
343 for (; vp; vp = vp->v_right) {
344 if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
345 return vp1;
346 if (Gmatch(vp->v_name, pat))
347 return vp;
b278c146 348 }
35371dec 349 return vp;
b278c146
BJ
350}
351
352struct varent *
35371dec
EW
353adrof1(name, v)
354 register char *name;
355 register struct varent *v;
b278c146 356{
35371dec
EW
357 register cmp;
358
359 v = v->v_left;
360 while (v && ((cmp = *name - *v->v_name) ||
361 (cmp = strcmp(name, v->v_name))))
362 if (cmp < 0)
363 v = v->v_left;
364 else
365 v = v->v_right;
366 return v;
b278c146
BJ
367}
368
369/*
370 * The caller is responsible for putting value in a safe place
371 */
35371dec
EW
372set(var, val)
373 char *var, *val;
b278c146 374{
35371dec 375 register char **vec = (char **) xalloc(2 * sizeof (char **));
b278c146 376
35371dec
EW
377 vec[0] = onlyread(val) ? savestr(val) : val;
378 vec[1] = 0;
b278c146
BJ
379 set1(var, vec, &shvhed);
380}
381
382set1(var, vec, head)
383 char *var, **vec;
384 struct varent *head;
385{
b278c146
BJ
386 register char **oldv = vec;
387
35371dec 388 gflag = 0; tglob(oldv);
b278c146
BJ
389 if (gflag) {
390 vec = glob(oldv);
391 if (vec == 0) {
392 bferr("No match");
393 blkfree(oldv);
394 return;
395 }
396 blkfree(oldv);
397 gargv = 0;
398 }
399 setq(var, vec, head);
400}
401
35371dec
EW
402setq(name, vec, p)
403 char *name, **vec;
404 register struct varent *p;
b278c146 405{
35371dec
EW
406 register struct varent *c;
407 register f;
408
409 f = 0; /* tree hangs off the header's left link */
410 while (c = p->v_link[f]) {
411 if ((f = *name - *c->v_name) == 0 &&
412 (f = strcmp(name, c->v_name)) == 0) {
413 blkfree(c->vec);
414 goto found;
415 }
416 p = c;
417 f = f > 0;
b278c146 418 }
35371dec
EW
419 p->v_link[f] = c = (struct varent *)xalloc(sizeof (struct varent));
420 c->v_name = savestr(name);
421 c->v_bal = 0;
422 c->v_left = c->v_right = 0;
423 c->v_parent = p;
424 balance(p, f, 0);
425found:
426 trim(c->vec = vec);
b278c146
BJ
427}
428
429unset(v)
35371dec 430 char *v[];
b278c146
BJ
431{
432
433 unset1(v, &shvhed);
434 if (adrof("histchars") == 0) {
435 HIST = '!';
436 HISTSUB = '^';
437 }
35371dec
EW
438#ifdef FILEC
439 if (adrof("filec") == 0)
440 filec = 0;
441#endif
b278c146
BJ
442}
443
444unset1(v, head)
445 register char *v[];
446 struct varent *head;
447{
b278c146
BJ
448 register struct varent *vp;
449 register int cnt;
450
35371dec 451 while (*++v) {
b278c146 452 cnt = 0;
35371dec
EW
453 while (vp = madrof(*v, head->v_left))
454 unsetv1(vp), cnt++;
b278c146 455 if (cnt == 0)
35371dec 456 setname(*v);
b278c146
BJ
457 }
458}
459
460unsetv(var)
461 char *var;
462{
35371dec 463 register struct varent *vp;
b278c146 464
35371dec
EW
465 if ((vp = adrof1(var, &shvhed)) == 0)
466 udvar(var);
467 unsetv1(vp);
b278c146
BJ
468}
469
35371dec
EW
470unsetv1(p)
471 register struct varent *p;
b278c146 472{
35371dec
EW
473 register struct varent *c, *pp;
474 register f;
475
476 /*
477 * Free associated memory first to avoid complications.
478 */
479 blkfree(p->vec);
480 XFREE(p->v_name);
481 /*
482 * If p is missing one child, then we can move the other
483 * into where p is. Otherwise, we find the predecessor
484 * of p, which is guaranteed to have no right child, copy
485 * it into p, and move it's left child into it.
486 */
487 if (p->v_right == 0)
488 c = p->v_left;
489 else if (p->v_left == 0)
490 c = p->v_right;
491 else {
492 for (c = p->v_left; c->v_right; c = c->v_right)
493 ;
494 p->v_name = c->v_name;
495 p->vec = c->vec;
496 p = c;
497 c = p->v_left;
498 }
499 /*
500 * Move c into where p is.
501 */
502 pp = p->v_parent;
503 f = pp->v_right == p;
504 if (pp->v_link[f] = c)
505 c->v_parent = pp;
506 /*
507 * Free the deleted node, and rebalance.
508 */
509 XFREE((char *)p);
510 balance(pp, f, 1);
b278c146
BJ
511}
512
513setNS(cp)
514 char *cp;
515{
516
517 set(cp, "");
518}
519
520shift(v)
521 register char **v;
522{
523 register struct varent *argv;
524 register char *name;
525
526 v++;
527 name = *v;
528 if (name == 0)
529 name = "argv";
530 else
35371dec 531 (void) strip(name);
b278c146
BJ
532 argv = adrof(name);
533 if (argv == 0)
534 udvar(name);
535 if (argv->vec[0] == 0)
536 bferr("No more words");
537 lshift(argv->vec, 1);
538}
539
540exportpath(val)
541char **val;
542{
543 char exppath[BUFSIZ];
b278c146
BJ
544
545 exppath[0] = 0;
546 if (val)
547 while (*val) {
548 if (strlen(*val) + strlen(exppath) + 2 > BUFSIZ) {
549 printf("Warning: ridiculously long PATH truncated\n");
550 break;
551 }
35371dec 552 (void) strcat(exppath, *val++);
b278c146
BJ
553 if (*val == 0 || eq(*val, ")"))
554 break;
35371dec 555 (void) strcat(exppath, ":");
b278c146
BJ
556 }
557 setenv("PATH", exppath);
558}
35371dec
EW
559
560 /* macros to do single rotations on node p */
561#define rright(p) (\
562 t = (p)->v_left,\
563 (t)->v_parent = (p)->v_parent,\
564 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
565 (t->v_right = (p))->v_parent = t,\
566 (p) = t)
567#define rleft(p) (\
568 t = (p)->v_right,\
569 (t)->v_parent = (p)->v_parent,\
570 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
571 (t->v_left = (p))->v_parent = t,\
572 (p) = t)
573
574/*
575 * Rebalance a tree, starting at p and up.
576 * F == 0 means we've come from p's left child.
577 * D == 1 means we've just done a delete, otherwise an insert.
578 */
579balance(p, f, d)
580 register struct varent *p;
581 register f;
582{
583 register struct varent *pp;
584 register struct varent *t; /* used by the rotate macros */
585 register ff;
586
587 /*
588 * Ok, from here on, p is the node we're operating on;
589 * pp is it's parent; f is the branch of p from which we have come;
590 * ff is the branch of pp which is p.
591 */
592 for (; pp = p->v_parent; p = pp, f = ff) {
593 ff = pp->v_right == p;
594 if (f ^ d) { /* right heavy */
595 switch (p->v_bal) {
596 case -1: /* was left heavy */
597 p->v_bal = 0;
598 break;
599 case 0: /* was balanced */
600 p->v_bal = 1;
601 break;
602 case 1: /* was already right heavy */
603 switch (p->v_right->v_bal) {
604 case 1: /* sigle rotate */
605 pp->v_link[ff] = rleft(p);
606 p->v_left->v_bal = 0;
607 p->v_bal = 0;
608 break;
609 case 0: /* single rotate */
610 pp->v_link[ff] = rleft(p);
611 p->v_left->v_bal = 1;
612 p->v_bal = -1;
613 break;
614 case -1: /* double rotate */
615 rright(p->v_right);
616 pp->v_link[ff] = rleft(p);
617 p->v_left->v_bal =
618 p->v_bal < 1 ? 0 : -1;
619 p->v_right->v_bal =
620 p->v_bal > -1 ? 0 : 1;
621 p->v_bal = 0;
622 break;
623 }
624 break;
625 }
626 } else { /* left heavy */
627 switch (p->v_bal) {
628 case 1: /* was right heavy */
629 p->v_bal = 0;
630 break;
631 case 0: /* was balanced */
632 p->v_bal = -1;
633 break;
634 case -1: /* was already left heavy */
635 switch (p->v_left->v_bal) {
636 case -1: /* single rotate */
637 pp->v_link[ff] = rright(p);
638 p->v_right->v_bal = 0;
639 p->v_bal = 0;
640 break;
641 case 0: /* signle rotate */
642 pp->v_link[ff] = rright(p);
643 p->v_right->v_bal = -1;
644 p->v_bal = 1;
645 break;
646 case 1: /* double rotate */
647 rleft(p->v_left);
648 pp->v_link[ff] = rright(p);
649 p->v_left->v_bal =
650 p->v_bal < 1 ? 0 : -1;
651 p->v_right->v_bal =
652 p->v_bal > -1 ? 0 : 1;
653 p->v_bal = 0;
654 break;
655 }
656 break;
657 }
658 }
659 /*
660 * If from insert, then we terminate when p is balanced.
661 * If from delete, then we terminate when p is unbalanced.
662 */
663 if ((p->v_bal == 0) ^ d)
664 break;
665 }
666}
667
668plist(p)
669 register struct varent *p;
670{
671 register struct varent *c;
672 register len;
673
674 if (setintr)
675 (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
676 for (;;) {
677 while (p->v_left)
678 p = p->v_left;
679 x:
680 if (p->v_parent == 0) /* is it the header? */
681 return;
682 len = blklen(p->vec);
683 printf(p->v_name);
684 putchar('\t');
685 if (len != 1)
686 putchar('(');
687 blkpr(p->vec);
688 if (len != 1)
689 putchar(')');
690 putchar('\n');
691 if (p->v_right) {
692 p = p->v_right;
693 continue;
694 }
695 do {
696 c = p;
697 p = p->v_parent;
698 } while (p->v_right == c);
699 goto x;
700 }
701}