1 1.40 martin /* $NetBSD: set.c,v 1.40 2022/09/15 11:35:06 martin Exp $ */ 2 1.7 cgd 3 1.1 cgd /*- 4 1.5 mycroft * Copyright (c) 1980, 1991, 1993 5 1.5 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.20 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.10 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.7 cgd #if 0 35 1.7 cgd static char sccsid[] = "@(#)set.c 8.1 (Berkeley) 5/31/93"; 36 1.7 cgd #else 37 1.40 martin __RCSID("$NetBSD: set.c,v 1.40 2022/09/15 11:35:06 martin Exp $"); 38 1.7 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #include <sys/types.h> 42 1.16 wiz 43 1.18 wiz #include <stdarg.h> 44 1.1 cgd #include <stdlib.h> 45 1.16 wiz 46 1.5 mycroft #include <string.h> 47 1.1 cgd 48 1.1 cgd #include "csh.h" 49 1.1 cgd #include "extern.h" 50 1.1 cgd 51 1.16 wiz static Char *getinx(Char *, int *); 52 1.16 wiz static void asx(Char *, int, Char *); 53 1.16 wiz static struct varent *getvx(Char *, int); 54 1.16 wiz static Char *xset(Char *, Char ***); 55 1.16 wiz static Char *operate(int, Char *, Char *); 56 1.16 wiz static void putn1(int); 57 1.16 wiz static struct varent *madrof(Char *, struct varent *); 58 1.16 wiz static void unsetv1(struct varent *); 59 1.16 wiz static void exportpath(Char **); 60 1.16 wiz static void balance(struct varent *, int, int); 61 1.1 cgd 62 1.40 martin #ifdef EDIT 63 1.39 christos static int wantediting; 64 1.39 christos 65 1.37 christos static const char * 66 1.37 christos alias_text(void *dummy __unused, const char *name) 67 1.37 christos { 68 1.37 christos static char *buf; 69 1.37 christos struct varent *vp; 70 1.37 christos Char **av; 71 1.37 christos char *p; 72 1.37 christos size_t len; 73 1.37 christos 74 1.37 christos vp = adrof1(str2short(name), &aliases); 75 1.37 christos if (vp == NULL) 76 1.37 christos return NULL; 77 1.37 christos 78 1.37 christos len = 0; 79 1.37 christos for (av = vp->vec; *av; av++) { 80 1.37 christos len += strlen(vis_str(*av)); 81 1.37 christos if (av[1]) 82 1.37 christos len++; 83 1.37 christos } 84 1.37 christos len++; 85 1.37 christos free(buf); 86 1.37 christos p = buf = xmalloc(len); 87 1.37 christos for (av = vp->vec; *av; av++) { 88 1.37 christos const char *s = vis_str(*av); 89 1.37 christos while ((*p++ = *s++) != '\0') 90 1.37 christos continue; 91 1.37 christos if (av[1]) 92 1.37 christos *p++ = ' '; 93 1.37 christos } 94 1.37 christos *p = '\0'; 95 1.37 christos return buf; 96 1.37 christos } 97 1.37 christos #endif 98 1.37 christos 99 1.1 cgd /* 100 1.1 cgd * C Shell 101 1.1 cgd */ 102 1.1 cgd 103 1.32 christos static void 104 1.32 christos update_vars(Char *vp) 105 1.32 christos { 106 1.32 christos if (eq(vp, STRpath)) { 107 1.32 christos struct varent *pt = adrof(STRpath); 108 1.32 christos if (pt == NULL) 109 1.32 christos stderror(ERR_NAME | ERR_UNDVAR); 110 1.32 christos else { 111 1.32 christos exportpath(pt->vec); 112 1.32 christos dohash(NULL, NULL); 113 1.32 christos } 114 1.32 christos } 115 1.32 christos else if (eq(vp, STRhistchars)) { 116 1.32 christos Char *pn = value(STRhistchars); 117 1.32 christos 118 1.32 christos HIST = *pn++; 119 1.32 christos HISTSUB = *pn; 120 1.32 christos } 121 1.32 christos else if (eq(vp, STRuser)) { 122 1.32 christos Setenv(STRUSER, value(vp)); 123 1.32 christos Setenv(STRLOGNAME, value(vp)); 124 1.32 christos } 125 1.32 christos else if (eq(vp, STRwordchars)) { 126 1.32 christos word_chars = value(vp); 127 1.32 christos } 128 1.32 christos else if (eq(vp, STRterm)) 129 1.32 christos Setenv(STRTERM, value(vp)); 130 1.32 christos else if (eq(vp, STRhome)) { 131 1.32 christos Char *cp; 132 1.32 christos 133 1.32 christos cp = Strsave(value(vp)); /* get the old value back */ 134 1.32 christos 135 1.32 christos /* 136 1.32 christos * convert to canonical pathname (possibly resolving symlinks) 137 1.32 christos */ 138 1.32 christos cp = dcanon(cp, cp); 139 1.32 christos 140 1.32 christos set(vp, Strsave(cp)); /* have to save the new val */ 141 1.32 christos 142 1.32 christos /* and now mirror home with HOME */ 143 1.32 christos Setenv(STRHOME, cp); 144 1.32 christos /* fix directory stack for new tilde home */ 145 1.32 christos dtilde(); 146 1.35 christos free(cp); 147 1.32 christos } 148 1.32 christos #ifdef FILEC 149 1.32 christos else if (eq(vp, STRfilec)) 150 1.32 christos filec = 1; 151 1.32 christos #endif 152 1.32 christos #ifdef EDIT 153 1.39 christos else if (eq(vp, STRedit)) 154 1.39 christos wantediting = 1; 155 1.32 christos #endif 156 1.32 christos } 157 1.32 christos 158 1.1 cgd void 159 1.5 mycroft /*ARGSUSED*/ 160 1.16 wiz doset(Char **v, struct command *t) 161 1.16 wiz { 162 1.16 wiz Char op, *p, **vecp, *vp; 163 1.25 christos int subscr = 0; /* XXX: GCC */ 164 1.29 christos int hadsub; 165 1.1 cgd 166 1.1 cgd v++; 167 1.1 cgd p = *v++; 168 1.1 cgd if (p == 0) { 169 1.1 cgd prvars(); 170 1.1 cgd return; 171 1.1 cgd } 172 1.1 cgd do { 173 1.1 cgd hadsub = 0; 174 1.1 cgd vp = p; 175 1.1 cgd if (letter(*p)) 176 1.1 cgd for (; alnum(*p); p++) 177 1.1 cgd continue; 178 1.13 mycroft if (vp == p || !letter(*vp)) 179 1.1 cgd stderror(ERR_NAME | ERR_VARBEGIN); 180 1.13 mycroft if ((p - vp) > MAXVARLEN) 181 1.1 cgd stderror(ERR_NAME | ERR_VARTOOLONG); 182 1.1 cgd if (*p == '[') { 183 1.1 cgd hadsub++; 184 1.1 cgd p = getinx(p, &subscr); 185 1.1 cgd } 186 1.5 mycroft if ((op = *p) != '\0') { 187 1.1 cgd *p++ = 0; 188 1.1 cgd if (*p == 0 && *v && **v == '(') 189 1.1 cgd p = *v++; 190 1.1 cgd } 191 1.1 cgd else if (*v && eq(*v, STRequal)) { 192 1.1 cgd op = '=', v++; 193 1.1 cgd if (*v) 194 1.1 cgd p = *v++; 195 1.1 cgd } 196 1.13 mycroft if (op && op != '=') 197 1.1 cgd stderror(ERR_NAME | ERR_SYNTAX); 198 1.1 cgd if (eq(p, STRLparen)) { 199 1.9 tls Char **e = v; 200 1.1 cgd 201 1.13 mycroft if (hadsub) 202 1.1 cgd stderror(ERR_NAME | ERR_SYNTAX); 203 1.1 cgd for (;;) { 204 1.13 mycroft if (!*e) 205 1.1 cgd stderror(ERR_NAME | ERR_MISSING, ')'); 206 1.1 cgd if (**e == ')') 207 1.1 cgd break; 208 1.1 cgd e++; 209 1.1 cgd } 210 1.1 cgd p = *e; 211 1.1 cgd *e = 0; 212 1.1 cgd vecp = saveblk(v); 213 1.1 cgd set1(vp, vecp, &shvhed); 214 1.1 cgd *e = p; 215 1.1 cgd v = e + 1; 216 1.1 cgd } 217 1.1 cgd else if (hadsub) 218 1.1 cgd asx(vp, subscr, Strsave(p)); 219 1.1 cgd else 220 1.1 cgd set(vp, Strsave(p)); 221 1.32 christos update_vars(vp); 222 1.5 mycroft } while ((p = *v++) != NULL); 223 1.1 cgd } 224 1.1 cgd 225 1.1 cgd static Char * 226 1.16 wiz getinx(Char *cp, int *ip) 227 1.1 cgd { 228 1.1 cgd *ip = 0; 229 1.1 cgd *cp++ = 0; 230 1.1 cgd while (*cp && Isdigit(*cp)) 231 1.1 cgd *ip = *ip * 10 + *cp++ - '0'; 232 1.13 mycroft if (*cp++ != ']') 233 1.1 cgd stderror(ERR_NAME | ERR_SUBSCRIPT); 234 1.1 cgd return (cp); 235 1.1 cgd } 236 1.1 cgd 237 1.1 cgd static void 238 1.16 wiz asx(Char *vp, int subscr, Char *p) 239 1.1 cgd { 240 1.16 wiz struct varent *v; 241 1.1 cgd 242 1.16 wiz v = getvx(vp, subscr); 243 1.35 christos free(v->vec[subscr - 1]); 244 1.1 cgd v->vec[subscr - 1] = globone(p, G_APPEND); 245 1.1 cgd } 246 1.1 cgd 247 1.1 cgd static struct varent * 248 1.16 wiz getvx(Char *vp, int subscr) 249 1.1 cgd { 250 1.16 wiz struct varent *v; 251 1.1 cgd 252 1.16 wiz v = adrof(vp); 253 1.1 cgd if (v == 0) 254 1.1 cgd udvar(vp); 255 1.13 mycroft if (subscr < 1 || subscr > blklen(v->vec)) 256 1.1 cgd stderror(ERR_NAME | ERR_RANGE); 257 1.1 cgd return (v); 258 1.1 cgd } 259 1.1 cgd 260 1.1 cgd void 261 1.5 mycroft /*ARGSUSED*/ 262 1.16 wiz dolet(Char **v, struct command *t) 263 1.16 wiz { 264 1.16 wiz Char c, op, *p, *vp; 265 1.25 christos int subscr = 0; /* XXX: GCC */ 266 1.29 christos int hadsub; 267 1.1 cgd 268 1.1 cgd v++; 269 1.1 cgd p = *v++; 270 1.1 cgd if (p == 0) { 271 1.1 cgd prvars(); 272 1.1 cgd return; 273 1.1 cgd } 274 1.1 cgd do { 275 1.1 cgd hadsub = 0; 276 1.1 cgd vp = p; 277 1.1 cgd if (letter(*p)) 278 1.1 cgd for (; alnum(*p); p++) 279 1.1 cgd continue; 280 1.13 mycroft if (vp == p || !letter(*vp)) 281 1.1 cgd stderror(ERR_NAME | ERR_VARBEGIN); 282 1.13 mycroft if ((p - vp) > MAXVARLEN) 283 1.1 cgd stderror(ERR_NAME | ERR_VARTOOLONG); 284 1.1 cgd if (*p == '[') { 285 1.1 cgd hadsub++; 286 1.1 cgd p = getinx(p, &subscr); 287 1.1 cgd } 288 1.1 cgd if (*p == 0 && *v) 289 1.1 cgd p = *v++; 290 1.5 mycroft if ((op = *p) != '\0') 291 1.1 cgd *p++ = 0; 292 1.13 mycroft else 293 1.1 cgd stderror(ERR_NAME | ERR_ASSIGN); 294 1.1 cgd 295 1.13 mycroft if (*p == '\0' && *v == NULL) 296 1.1 cgd stderror(ERR_NAME | ERR_ASSIGN); 297 1.1 cgd 298 1.1 cgd vp = Strsave(vp); 299 1.1 cgd if (op == '=') { 300 1.1 cgd c = '='; 301 1.1 cgd p = xset(p, &v); 302 1.1 cgd } 303 1.1 cgd else { 304 1.1 cgd c = *p++; 305 1.1 cgd if (any("+-", c)) { 306 1.13 mycroft if (c != op || *p) 307 1.1 cgd stderror(ERR_NAME | ERR_UNKNOWNOP); 308 1.1 cgd p = Strsave(STR1); 309 1.1 cgd } 310 1.1 cgd else { 311 1.1 cgd if (any("<>", op)) { 312 1.13 mycroft if (c != op) 313 1.1 cgd stderror(ERR_NAME | ERR_UNKNOWNOP); 314 1.1 cgd c = *p++; 315 1.1 cgd stderror(ERR_NAME | ERR_SYNTAX); 316 1.1 cgd } 317 1.1 cgd if (c != '=') 318 1.1 cgd stderror(ERR_NAME | ERR_UNKNOWNOP); 319 1.1 cgd p = xset(p, &v); 320 1.1 cgd } 321 1.1 cgd } 322 1.14 christos if (op == '=') { 323 1.1 cgd if (hadsub) 324 1.1 cgd asx(vp, subscr, p); 325 1.1 cgd else 326 1.1 cgd set(vp, p); 327 1.14 christos } else if (hadsub) { 328 1.1 cgd struct varent *gv = getvx(vp, subscr); 329 1.1 cgd 330 1.1 cgd asx(vp, subscr, operate(op, gv->vec[subscr - 1], p)); 331 1.1 cgd } 332 1.1 cgd else 333 1.1 cgd set(vp, operate(op, value(vp), p)); 334 1.1 cgd if (eq(vp, STRpath)) { 335 1.22 christos struct varent *pt = adrof(STRpath); 336 1.22 christos if (pt == NULL) 337 1.22 christos stderror(ERR_NAME | ERR_UNDVAR); 338 1.22 christos else { 339 1.22 christos exportpath(pt->vec); 340 1.22 christos dohash(NULL, NULL); 341 1.22 christos } 342 1.1 cgd } 343 1.35 christos free(vp); 344 1.1 cgd if (c != '=') 345 1.35 christos free(p); 346 1.5 mycroft } while ((p = *v++) != NULL); 347 1.1 cgd } 348 1.1 cgd 349 1.1 cgd static Char * 350 1.16 wiz xset(Char *cp, Char ***vp) 351 1.1 cgd { 352 1.9 tls Char *dp; 353 1.1 cgd 354 1.1 cgd if (*cp) { 355 1.1 cgd dp = Strsave(cp); 356 1.1 cgd --(*vp); 357 1.35 christos free(** vp); 358 1.1 cgd **vp = dp; 359 1.1 cgd } 360 1.5 mycroft return (putn(expr(vp))); 361 1.1 cgd } 362 1.1 cgd 363 1.1 cgd static Char * 364 1.16 wiz operate(int op, Char *vp, Char *p) 365 1.16 wiz { 366 1.16 wiz Char opr[2], **v, *vec[5], **vecp; 367 1.9 tls int i; 368 1.1 cgd 369 1.16 wiz v = vec; 370 1.16 wiz vecp = v; 371 1.1 cgd if (op != '=') { 372 1.1 cgd if (*vp) 373 1.1 cgd *v++ = vp; 374 1.33 christos opr[0] = (Char)op; 375 1.1 cgd opr[1] = 0; 376 1.1 cgd *v++ = opr; 377 1.1 cgd if (op == '<' || op == '>') 378 1.1 cgd *v++ = opr; 379 1.1 cgd } 380 1.1 cgd *v++ = p; 381 1.1 cgd *v++ = 0; 382 1.5 mycroft i = expr(&vecp); 383 1.13 mycroft if (*vecp) 384 1.1 cgd stderror(ERR_NAME | ERR_EXPRESSION); 385 1.1 cgd return (putn(i)); 386 1.1 cgd } 387 1.1 cgd 388 1.1 cgd static Char *putp; 389 1.1 cgd 390 1.16 wiz Char * 391 1.16 wiz putn(int n) 392 1.1 cgd { 393 1.17 lukem static Char numbers[15]; 394 1.1 cgd 395 1.17 lukem putp = numbers; 396 1.1 cgd if (n < 0) { 397 1.1 cgd n = -n; 398 1.1 cgd *putp++ = '-'; 399 1.1 cgd } 400 1.23 christos if ((unsigned int)n == 0x80000000U) { 401 1.21 christos *putp++ = '2'; 402 1.21 christos n = 147483648; 403 1.1 cgd } 404 1.1 cgd putn1(n); 405 1.1 cgd *putp = 0; 406 1.17 lukem return (Strsave(numbers)); 407 1.1 cgd } 408 1.1 cgd 409 1.1 cgd static void 410 1.16 wiz putn1(int n) 411 1.1 cgd { 412 1.1 cgd if (n > 9) 413 1.1 cgd putn1(n / 10); 414 1.33 christos *putp++ = (Char)(n % 10 + '0'); 415 1.1 cgd } 416 1.1 cgd 417 1.1 cgd int 418 1.16 wiz getn(Char *cp) 419 1.1 cgd { 420 1.16 wiz int n, sign; 421 1.1 cgd 422 1.1 cgd sign = 0; 423 1.1 cgd if (cp[0] == '+' && cp[1]) 424 1.1 cgd cp++; 425 1.1 cgd if (*cp == '-') { 426 1.1 cgd sign++; 427 1.1 cgd cp++; 428 1.13 mycroft if (!Isdigit(*cp)) 429 1.1 cgd stderror(ERR_NAME | ERR_BADNUM); 430 1.1 cgd } 431 1.1 cgd n = 0; 432 1.1 cgd while (Isdigit(*cp)) 433 1.1 cgd n = n * 10 + *cp++ - '0'; 434 1.13 mycroft if (*cp) 435 1.1 cgd stderror(ERR_NAME | ERR_BADNUM); 436 1.1 cgd return (sign ? -n : n); 437 1.1 cgd } 438 1.1 cgd 439 1.16 wiz Char * 440 1.16 wiz value1(Char *var, struct varent *head) 441 1.1 cgd { 442 1.9 tls struct varent *vp; 443 1.1 cgd 444 1.1 cgd vp = adrof1(var, head); 445 1.1 cgd return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]); 446 1.1 cgd } 447 1.1 cgd 448 1.1 cgd static struct varent * 449 1.16 wiz madrof(Char *pat, struct varent *vp) 450 1.1 cgd { 451 1.9 tls struct varent *vp1; 452 1.1 cgd 453 1.1 cgd for (; vp; vp = vp->v_right) { 454 1.1 cgd if (vp->v_left && (vp1 = madrof(pat, vp->v_left))) 455 1.1 cgd return vp1; 456 1.1 cgd if (Gmatch(vp->v_name, pat)) 457 1.1 cgd return vp; 458 1.1 cgd } 459 1.1 cgd return vp; 460 1.1 cgd } 461 1.1 cgd 462 1.1 cgd struct varent * 463 1.16 wiz adrof1(Char *name, struct varent *v) 464 1.1 cgd { 465 1.9 tls int cmp; 466 1.1 cgd 467 1.1 cgd v = v->v_left; 468 1.1 cgd while (v && ((cmp = *name - *v->v_name) || 469 1.1 cgd (cmp = Strcmp(name, v->v_name)))) 470 1.1 cgd if (cmp < 0) 471 1.1 cgd v = v->v_left; 472 1.1 cgd else 473 1.1 cgd v = v->v_right; 474 1.1 cgd return v; 475 1.1 cgd } 476 1.1 cgd 477 1.1 cgd /* 478 1.1 cgd * The caller is responsible for putting value in a safe place 479 1.1 cgd */ 480 1.1 cgd void 481 1.16 wiz set(Char *var, Char *val) 482 1.1 cgd { 483 1.16 wiz Char **vec; 484 1.1 cgd 485 1.33 christos vec = xmalloc(2 * sizeof(*vec)); 486 1.1 cgd vec[0] = val; 487 1.1 cgd vec[1] = 0; 488 1.1 cgd set1(var, vec, &shvhed); 489 1.1 cgd } 490 1.1 cgd 491 1.1 cgd void 492 1.16 wiz set1(Char *var, Char **vec, struct varent *head) 493 1.1 cgd { 494 1.16 wiz Char **oldv; 495 1.1 cgd 496 1.16 wiz oldv = vec; 497 1.1 cgd gflag = 0; 498 1.1 cgd tglob(oldv); 499 1.1 cgd if (gflag) { 500 1.1 cgd vec = globall(oldv); 501 1.1 cgd if (vec == 0) { 502 1.1 cgd blkfree(oldv); 503 1.1 cgd stderror(ERR_NAME | ERR_NOMATCH); 504 1.1 cgd } 505 1.1 cgd blkfree(oldv); 506 1.1 cgd gargv = 0; 507 1.1 cgd } 508 1.1 cgd setq(var, vec, head); 509 1.1 cgd } 510 1.1 cgd 511 1.1 cgd void 512 1.16 wiz setq(Char *name, Char **vec, struct varent *p) 513 1.1 cgd { 514 1.9 tls struct varent *c; 515 1.9 tls int f; 516 1.1 cgd 517 1.1 cgd f = 0; /* tree hangs off the header's left link */ 518 1.5 mycroft while ((c = p->v_link[f]) != NULL) { 519 1.1 cgd if ((f = *name - *c->v_name) == 0 && 520 1.1 cgd (f = Strcmp(name, c->v_name)) == 0) { 521 1.1 cgd blkfree(c->vec); 522 1.1 cgd goto found; 523 1.1 cgd } 524 1.1 cgd p = c; 525 1.1 cgd f = f > 0; 526 1.1 cgd } 527 1.33 christos p->v_link[f] = c = xmalloc(sizeof(*c)); 528 1.1 cgd c->v_name = Strsave(name); 529 1.1 cgd c->v_bal = 0; 530 1.1 cgd c->v_left = c->v_right = 0; 531 1.1 cgd c->v_parent = p; 532 1.1 cgd balance(p, f, 0); 533 1.1 cgd found: 534 1.1 cgd trim(c->vec = vec); 535 1.1 cgd } 536 1.1 cgd 537 1.1 cgd void 538 1.5 mycroft /*ARGSUSED*/ 539 1.16 wiz unset(Char **v, struct command *t) 540 1.1 cgd { 541 1.1 cgd unset1(v, &shvhed); 542 1.1 cgd if (adrof(STRhistchars) == 0) { 543 1.1 cgd HIST = '!'; 544 1.1 cgd HISTSUB = '^'; 545 1.1 cgd } 546 1.36 christos if (adrof(STRwordchars) == 0) 547 1.1 cgd word_chars = STR_WORD_CHARS; 548 1.30 christos #ifdef FILEC 549 1.36 christos if (adrof(STRfilec) == 0) 550 1.30 christos filec = 0; 551 1.30 christos #endif 552 1.30 christos #ifdef EDIT 553 1.39 christos if (adrof(STRedit) == 0) 554 1.39 christos wantediting = 0; 555 1.39 christos #endif 556 1.39 christos } 557 1.39 christos 558 1.40 martin #ifdef EDIT 559 1.39 christos extern int insource; 560 1.39 christos void 561 1.39 christos updateediting(void) 562 1.39 christos { 563 1.39 christos if (insource || wantediting == editing) 564 1.39 christos return; 565 1.39 christos 566 1.39 christos if (wantediting) { 567 1.39 christos HistEvent ev; 568 1.39 christos Char *vn = value(STRhistchars); 569 1.39 christos 570 1.39 christos el = el_init_fd(getprogname(), cshin, cshout, csherr, 571 1.39 christos SHIN, SHOUT, SHERR); 572 1.39 christos el_set(el, EL_EDITOR, *vn ? short2str(vn) : "emacs"); 573 1.39 christos el_set(el, EL_PROMPT, printpromptstr); 574 1.39 christos el_set(el, EL_ALIAS_TEXT, alias_text, NULL); 575 1.39 christos el_set(el, EL_SAFEREAD, 1); 576 1.39 christos el_set(el, EL_ADDFN, "rl-complete", 577 1.39 christos "ReadLine compatible completion function", _el_fn_complete); 578 1.39 christos el_set(el, EL_BIND, "^I", adrof(STRfilec) ? "rl-complete" : "ed-insert", 579 1.39 christos NULL); 580 1.39 christos hi = history_init(); 581 1.39 christos history(hi, &ev, H_SETSIZE, getn(value(STRhistory))); 582 1.39 christos loadhist(Histlist.Hnext); 583 1.39 christos el_set(el, EL_HIST, history, hi); 584 1.39 christos } else { 585 1.36 christos if (el) 586 1.36 christos el_end(el); 587 1.36 christos if (hi) 588 1.36 christos history_end(hi); 589 1.30 christos el = NULL; 590 1.31 christos hi = NULL; 591 1.30 christos } 592 1.39 christos editing = wantediting; 593 1.1 cgd } 594 1.40 martin #endif 595 1.1 cgd 596 1.1 cgd void 597 1.16 wiz unset1(Char *v[], struct varent *head) 598 1.1 cgd { 599 1.9 tls struct varent *vp; 600 1.9 tls int cnt; 601 1.1 cgd 602 1.1 cgd while (*++v) { 603 1.1 cgd cnt = 0; 604 1.5 mycroft while ((vp = madrof(*v, head->v_left)) != NULL) 605 1.1 cgd unsetv1(vp), cnt++; 606 1.1 cgd if (cnt == 0) 607 1.5 mycroft setname(vis_str(*v)); 608 1.1 cgd } 609 1.1 cgd } 610 1.1 cgd 611 1.1 cgd void 612 1.16 wiz unsetv(Char *var) 613 1.1 cgd { 614 1.9 tls struct varent *vp; 615 1.1 cgd 616 1.1 cgd if ((vp = adrof1(var, &shvhed)) == 0) 617 1.1 cgd udvar(var); 618 1.1 cgd unsetv1(vp); 619 1.1 cgd } 620 1.1 cgd 621 1.1 cgd static void 622 1.16 wiz unsetv1(struct varent *p) 623 1.1 cgd { 624 1.9 tls struct varent *c, *pp; 625 1.9 tls int f; 626 1.1 cgd 627 1.1 cgd /* 628 1.1 cgd * Free associated memory first to avoid complications. 629 1.1 cgd */ 630 1.1 cgd blkfree(p->vec); 631 1.35 christos free(p->v_name); 632 1.1 cgd /* 633 1.1 cgd * If p is missing one child, then we can move the other into where p is. 634 1.1 cgd * Otherwise, we find the predecessor of p, which is guaranteed to have no 635 1.24 snj * right child, copy it into p, and move its left child into it. 636 1.1 cgd */ 637 1.1 cgd if (p->v_right == 0) 638 1.1 cgd c = p->v_left; 639 1.1 cgd else if (p->v_left == 0) 640 1.1 cgd c = p->v_right; 641 1.1 cgd else { 642 1.5 mycroft for (c = p->v_left; c->v_right; c = c->v_right) 643 1.5 mycroft continue; 644 1.1 cgd p->v_name = c->v_name; 645 1.1 cgd p->vec = c->vec; 646 1.1 cgd p = c; 647 1.1 cgd c = p->v_left; 648 1.1 cgd } 649 1.1 cgd /* 650 1.1 cgd * Move c into where p is. 651 1.1 cgd */ 652 1.1 cgd pp = p->v_parent; 653 1.1 cgd f = pp->v_right == p; 654 1.5 mycroft if ((pp->v_link[f] = c) != NULL) 655 1.1 cgd c->v_parent = pp; 656 1.1 cgd /* 657 1.1 cgd * Free the deleted node, and rebalance. 658 1.1 cgd */ 659 1.35 christos free(p); 660 1.1 cgd balance(pp, f, 1); 661 1.1 cgd } 662 1.1 cgd 663 1.1 cgd void 664 1.16 wiz setNS(Char *cp) 665 1.1 cgd { 666 1.1 cgd set(cp, Strsave(STRNULL)); 667 1.1 cgd } 668 1.1 cgd 669 1.1 cgd void 670 1.5 mycroft /*ARGSUSED*/ 671 1.16 wiz shift(Char **v, struct command *t) 672 1.1 cgd { 673 1.9 tls struct varent *argv; 674 1.9 tls Char *name; 675 1.1 cgd 676 1.1 cgd v++; 677 1.1 cgd name = *v; 678 1.1 cgd if (name == 0) 679 1.1 cgd name = STRargv; 680 1.1 cgd else 681 1.1 cgd (void) strip(name); 682 1.1 cgd argv = adrof(name); 683 1.1 cgd if (argv == 0) 684 1.1 cgd udvar(name); 685 1.13 mycroft if (argv->vec[0] == 0) 686 1.1 cgd stderror(ERR_NAME | ERR_NOMORE); 687 1.1 cgd lshift(argv->vec, 1); 688 1.32 christos update_vars(name); 689 1.1 cgd } 690 1.1 cgd 691 1.1 cgd static void 692 1.16 wiz exportpath(Char **val) 693 1.1 cgd { 694 1.16 wiz Char exppath[BUFSIZE]; 695 1.1 cgd 696 1.1 cgd exppath[0] = 0; 697 1.1 cgd if (val) 698 1.1 cgd while (*val) { 699 1.15 christos if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZE) { 700 1.16 wiz (void)fprintf(csherr, 701 1.5 mycroft "Warning: ridiculously long PATH truncated\n"); 702 1.1 cgd break; 703 1.1 cgd } 704 1.16 wiz (void)Strcat(exppath, *val++); 705 1.1 cgd if (*val == 0 || eq(*val, STRRparen)) 706 1.1 cgd break; 707 1.16 wiz (void)Strcat(exppath, STRcolon); 708 1.1 cgd } 709 1.1 cgd Setenv(STRPATH, exppath); 710 1.1 cgd } 711 1.1 cgd 712 1.1 cgd #ifndef lint 713 1.1 cgd /* 714 1.1 cgd * Lint thinks these have null effect 715 1.1 cgd */ 716 1.1 cgd /* macros to do single rotations on node p */ 717 1.1 cgd #define rright(p) (\ 718 1.1 cgd t = (p)->v_left,\ 719 1.1 cgd (t)->v_parent = (p)->v_parent,\ 720 1.1 cgd ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\ 721 1.1 cgd (t->v_right = (p))->v_parent = t,\ 722 1.1 cgd (p) = t) 723 1.1 cgd #define rleft(p) (\ 724 1.1 cgd t = (p)->v_right,\ 725 1.1 cgd (t)->v_parent = (p)->v_parent,\ 726 1.1 cgd ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\ 727 1.1 cgd (t->v_left = (p))->v_parent = t,\ 728 1.1 cgd (p) = t) 729 1.1 cgd #else 730 1.1 cgd struct varent * 731 1.16 wiz rleft(struct varent *p) 732 1.1 cgd { 733 1.1 cgd return (p); 734 1.1 cgd } 735 1.1 cgd struct varent * 736 1.16 wiz rright(struct varent *p) 737 1.1 cgd { 738 1.1 cgd return (p); 739 1.1 cgd } 740 1.1 cgd #endif /* ! lint */ 741 1.1 cgd 742 1.1 cgd 743 1.1 cgd /* 744 1.1 cgd * Rebalance a tree, starting at p and up. 745 1.1 cgd * F == 0 means we've come from p's left child. 746 1.1 cgd * D == 1 means we've just done a delete, otherwise an insert. 747 1.1 cgd */ 748 1.1 cgd static void 749 1.16 wiz balance(struct varent *p, int f, int d) 750 1.1 cgd { 751 1.9 tls struct varent *pp; 752 1.1 cgd 753 1.1 cgd #ifndef lint 754 1.9 tls struct varent *t; /* used by the rotate macros */ 755 1.1 cgd 756 1.1 cgd #endif 757 1.9 tls int ff; 758 1.1 cgd 759 1.1 cgd /* 760 1.24 snj * Ok, from here on, p is the node we're operating on; pp is its parent; f 761 1.1 cgd * is the branch of p from which we have come; ff is the branch of pp which 762 1.1 cgd * is p. 763 1.1 cgd */ 764 1.5 mycroft for (; (pp = p->v_parent) != NULL; p = pp, f = ff) { 765 1.1 cgd ff = pp->v_right == p; 766 1.1 cgd if (f ^ d) { /* right heavy */ 767 1.1 cgd switch (p->v_bal) { 768 1.1 cgd case -1: /* was left heavy */ 769 1.1 cgd p->v_bal = 0; 770 1.1 cgd break; 771 1.1 cgd case 0: /* was balanced */ 772 1.1 cgd p->v_bal = 1; 773 1.1 cgd break; 774 1.1 cgd case 1: /* was already right heavy */ 775 1.1 cgd switch (p->v_right->v_bal) { 776 1.26 msaitoh case 1: /* single rotate */ 777 1.1 cgd pp->v_link[ff] = rleft(p); 778 1.1 cgd p->v_left->v_bal = 0; 779 1.1 cgd p->v_bal = 0; 780 1.1 cgd break; 781 1.1 cgd case 0: /* single rotate */ 782 1.1 cgd pp->v_link[ff] = rleft(p); 783 1.1 cgd p->v_left->v_bal = 1; 784 1.1 cgd p->v_bal = -1; 785 1.1 cgd break; 786 1.1 cgd case -1: /* double rotate */ 787 1.1 cgd (void) rright(p->v_right); 788 1.1 cgd pp->v_link[ff] = rleft(p); 789 1.1 cgd p->v_left->v_bal = 790 1.1 cgd p->v_bal < 1 ? 0 : -1; 791 1.1 cgd p->v_right->v_bal = 792 1.1 cgd p->v_bal > -1 ? 0 : 1; 793 1.1 cgd p->v_bal = 0; 794 1.1 cgd break; 795 1.1 cgd } 796 1.1 cgd break; 797 1.1 cgd } 798 1.1 cgd } 799 1.1 cgd else { /* left heavy */ 800 1.1 cgd switch (p->v_bal) { 801 1.1 cgd case 1: /* was right heavy */ 802 1.1 cgd p->v_bal = 0; 803 1.1 cgd break; 804 1.1 cgd case 0: /* was balanced */ 805 1.1 cgd p->v_bal = -1; 806 1.1 cgd break; 807 1.1 cgd case -1: /* was already left heavy */ 808 1.1 cgd switch (p->v_left->v_bal) { 809 1.1 cgd case -1: /* single rotate */ 810 1.1 cgd pp->v_link[ff] = rright(p); 811 1.1 cgd p->v_right->v_bal = 0; 812 1.1 cgd p->v_bal = 0; 813 1.1 cgd break; 814 1.26 msaitoh case 0: /* single rotate */ 815 1.1 cgd pp->v_link[ff] = rright(p); 816 1.1 cgd p->v_right->v_bal = -1; 817 1.1 cgd p->v_bal = 1; 818 1.1 cgd break; 819 1.1 cgd case 1: /* double rotate */ 820 1.1 cgd (void) rleft(p->v_left); 821 1.1 cgd pp->v_link[ff] = rright(p); 822 1.1 cgd p->v_left->v_bal = 823 1.1 cgd p->v_bal < 1 ? 0 : -1; 824 1.1 cgd p->v_right->v_bal = 825 1.1 cgd p->v_bal > -1 ? 0 : 1; 826 1.1 cgd p->v_bal = 0; 827 1.1 cgd break; 828 1.1 cgd } 829 1.1 cgd break; 830 1.1 cgd } 831 1.1 cgd } 832 1.1 cgd /* 833 1.1 cgd * If from insert, then we terminate when p is balanced. If from 834 1.1 cgd * delete, then we terminate when p is unbalanced. 835 1.1 cgd */ 836 1.1 cgd if ((p->v_bal == 0) ^ d) 837 1.1 cgd break; 838 1.1 cgd } 839 1.1 cgd } 840 1.1 cgd 841 1.1 cgd void 842 1.16 wiz plist(struct varent *p) 843 1.1 cgd { 844 1.9 tls struct varent *c; 845 1.19 kleink sigset_t nsigset; 846 1.9 tls int len; 847 1.1 cgd 848 1.8 mycroft if (setintr) { 849 1.19 kleink sigemptyset(&nsigset); 850 1.19 kleink (void)sigaddset(&nsigset, SIGINT); 851 1.19 kleink (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); 852 1.8 mycroft } 853 1.1 cgd 854 1.1 cgd for (;;) { 855 1.1 cgd while (p->v_left) 856 1.1 cgd p = p->v_left; 857 1.1 cgd x: 858 1.1 cgd if (p->v_parent == 0) /* is it the header? */ 859 1.1 cgd return; 860 1.1 cgd len = blklen(p->vec); 861 1.16 wiz (void)fprintf(cshout, "%s\t", short2str(p->v_name)); 862 1.1 cgd if (len != 1) 863 1.16 wiz (void)fputc('(', cshout); 864 1.5 mycroft blkpr(cshout, p->vec); 865 1.1 cgd if (len != 1) 866 1.16 wiz (void)fputc(')', cshout); 867 1.16 wiz (void)fputc('\n', cshout); 868 1.1 cgd if (p->v_right) { 869 1.1 cgd p = p->v_right; 870 1.1 cgd continue; 871 1.1 cgd } 872 1.1 cgd do { 873 1.1 cgd c = p; 874 1.1 cgd p = p->v_parent; 875 1.1 cgd } while (p->v_right == c); 876 1.1 cgd goto x; 877 1.1 cgd } 878 1.1 cgd } 879