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