sh.set.c revision 167465
1244197Sgonzo/* $Header: /p/tcsh/cvsroot/tcsh/sh.set.c,v 3.70 2006/08/24 20:56:31 christos Exp $ */ 2244197Sgonzo/* 3244197Sgonzo * sh.set.c: Setting and Clearing of variables 4244197Sgonzo */ 5244197Sgonzo/*- 6244197Sgonzo * Copyright (c) 1980, 1991 The Regents of the University of California. 7244197Sgonzo * All rights reserved. 8244197Sgonzo * 9244197Sgonzo * Redistribution and use in source and binary forms, with or without 10244197Sgonzo * modification, are permitted provided that the following conditions 11244197Sgonzo * are met: 12244197Sgonzo * 1. Redistributions of source code must retain the above copyright 13244197Sgonzo * notice, this list of conditions and the following disclaimer. 14244197Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 15244197Sgonzo * notice, this list of conditions and the following disclaimer in the 16244197Sgonzo * documentation and/or other materials provided with the distribution. 17244197Sgonzo * 3. Neither the name of the University nor the names of its contributors 18244197Sgonzo * may be used to endorse or promote products derived from this software 19244197Sgonzo * without specific prior written permission. 20244197Sgonzo * 21244197Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22244197Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23244197Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24244197Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25244197Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26244197Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27244197Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28244197Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29244197Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30244197Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31244197Sgonzo * SUCH DAMAGE. 32244197Sgonzo */ 33244197Sgonzo#include "sh.h" 34244197Sgonzo 35244197SgonzoRCSID("$tcsh: sh.set.c,v 3.70 2006/08/24 20:56:31 christos Exp $") 36244197Sgonzo 37244197Sgonzo#include "ed.h" 38244197Sgonzo#include "tw.h" 39244197Sgonzo 40244197Sgonzo#ifdef HAVE_NL_LANGINFO 41244197Sgonzo#include <langinfo.h> 42244197Sgonzo#endif 43244197Sgonzo 44244197Sgonzoextern int GotTermCaps; 45244197Sgonzoint numeof = 0; 46244197Sgonzo 47244197Sgonzostatic void update_vars (Char *); 48244197Sgonzostatic Char *getinx (Char *, int *); 49244197Sgonzostatic void asx (Char *, int, Char *); 50244197Sgonzostatic struct varent *getvx (Char *, int); 51244197Sgonzostatic Char *xset (Char *, Char ***); 52244197Sgonzostatic Char *operate (int, Char *, Char *); 53244197Sgonzostatic void putn1 (unsigned); 54244197Sgonzostatic struct varent *madrof (Char *, struct varent *); 55244197Sgonzostatic void unsetv1 (struct varent *); 56244197Sgonzostatic void exportpath (Char **); 57244197Sgonzostatic void balance (struct varent *, int, int); 58244197Sgonzo 59244197Sgonzo/* 60244197Sgonzo * C Shell 61244197Sgonzo */ 62244197Sgonzo 63244197Sgonzostatic void 64244197Sgonzoupdate_vars(Char *vp) 65244197Sgonzo{ 66244197Sgonzo if (eq(vp, STRpath)) { 67244197Sgonzo struct varent *p = adrof(STRpath); 68244197Sgonzo if (p == NULL) 69244197Sgonzo stderror(ERR_NAME | ERR_UNDVAR); 70244197Sgonzo else { 71244197Sgonzo exportpath(p->vec); 72244197Sgonzo dohash(NULL, NULL); 73244197Sgonzo } 74244197Sgonzo } 75244197Sgonzo else if (eq(vp, STRhistchars)) { 76244197Sgonzo Char *pn = varval(vp); 77244197Sgonzo 78244197Sgonzo HIST = *pn++; 79244197Sgonzo HISTSUB = *pn; 80244197Sgonzo } 81244197Sgonzo else if (eq(vp, STRpromptchars)) { 82244197Sgonzo Char *pn = varval(vp); 83244197Sgonzo 84244197Sgonzo PRCH = *pn++; 85244197Sgonzo PRCHROOT = *pn; 86244197Sgonzo } 87244197Sgonzo else if (eq(vp, STRhistlit)) { 88244197Sgonzo HistLit = 1; 89244197Sgonzo } 90244197Sgonzo else if (eq(vp, STRuser)) { 91244197Sgonzo tsetenv(STRKUSER, varval(vp)); 92244197Sgonzo tsetenv(STRLOGNAME, varval(vp)); 93244197Sgonzo } 94244197Sgonzo else if (eq(vp, STRgroup)) { 95244197Sgonzo tsetenv(STRKGROUP, varval(vp)); 96244197Sgonzo } 97244197Sgonzo else if (eq(vp, STRwordchars)) { 98244197Sgonzo word_chars = varval(vp); 99244197Sgonzo } 100244197Sgonzo else if (eq(vp, STRloginsh)) { 101244197Sgonzo loginsh = 1; 102244197Sgonzo } 103244197Sgonzo else if (eq(vp, STRsymlinks)) { 104244197Sgonzo Char *pn = varval(vp); 105244197Sgonzo 106244197Sgonzo if (eq(pn, STRignore)) 107244197Sgonzo symlinks = SYM_IGNORE; 108244197Sgonzo else if (eq(pn, STRexpand)) 109244197Sgonzo symlinks = SYM_EXPAND; 110244197Sgonzo else if (eq(pn, STRchase)) 111244197Sgonzo symlinks = SYM_CHASE; 112244197Sgonzo else 113244197Sgonzo symlinks = 0; 114244197Sgonzo } 115244197Sgonzo else if (eq(vp, STRterm)) { 116244197Sgonzo Char *cp = varval(vp); 117244197Sgonzo tsetenv(STRKTERM, cp); 118244197Sgonzo#ifdef DOESNT_WORK_RIGHT 119244197Sgonzo cp = getenv("TERMCAP"); 120244197Sgonzo if (cp && (*cp != '/')) /* if TERMCAP and not a path */ 121244197Sgonzo Unsetenv(STRTERMCAP); 122244197Sgonzo#endif /* DOESNT_WORK_RIGHT */ 123244197Sgonzo GotTermCaps = 0; 124244197Sgonzo if (noediting && Strcmp(cp, STRnetwork) != 0 && 125244197Sgonzo Strcmp(cp, STRunknown) != 0 && Strcmp(cp, STRdumb) != 0) { 126244197Sgonzo editing = 1; 127244197Sgonzo noediting = 0; 128244197Sgonzo setNS(STRedit); 129244197Sgonzo } 130244197Sgonzo ed_Init(); /* reset the editor */ 131244197Sgonzo } 132244197Sgonzo else if (eq(vp, STRhome)) { 133244197Sgonzo Char *cp, *canon; 134244197Sgonzo 135244197Sgonzo cp = Strsave(varval(vp)); /* get the old value back */ 136244197Sgonzo cleanup_push(cp, xfree); 137244197Sgonzo 138244197Sgonzo /* 139244197Sgonzo * convert to cononical pathname (possibly resolving symlinks) 140244197Sgonzo */ 141244197Sgonzo canon = dcanon(cp, cp); 142244197Sgonzo cleanup_ignore(cp); 143244197Sgonzo cleanup_until(cp); 144244197Sgonzo cleanup_push(canon, xfree); 145266152Sian 146266152Sian setcopy(vp, canon, VAR_READWRITE); /* have to save the new val */ 147266152Sian 148244197Sgonzo /* and now mirror home with HOME */ 149244197Sgonzo tsetenv(STRKHOME, canon); 150244197Sgonzo /* fix directory stack for new tilde home */ 151244197Sgonzo dtilde(); 152244197Sgonzo cleanup_until(canon); 153244197Sgonzo } 154244197Sgonzo else if (eq(vp, STRedit)) { 155244197Sgonzo editing = 1; 156244197Sgonzo noediting = 0; 157244197Sgonzo /* PWP: add more stuff in here later */ 158244197Sgonzo } 159244197Sgonzo else if (eq(vp, STRshlvl)) { 160244197Sgonzo tsetenv(STRKSHLVL, varval(vp)); 161244197Sgonzo } 162244197Sgonzo else if (eq(vp, STRignoreeof)) { 163244197Sgonzo Char *cp; 164244197Sgonzo numeof = 0; 165244197Sgonzo for ((cp = varval(STRignoreeof)); cp && *cp; cp++) { 166244197Sgonzo if (!Isdigit(*cp)) { 167244197Sgonzo numeof = 0; 168244197Sgonzo break; 169244197Sgonzo } 170244197Sgonzo numeof = numeof * 10 + *cp - '0'; 171244197Sgonzo } 172244197Sgonzo if (numeof <= 0) numeof = 26; /* Sanity check */ 173244197Sgonzo } 174244197Sgonzo else if (eq(vp, STRbackslash_quote)) { 175244197Sgonzo bslash_quote = 1; 176252395Sgonzo } 177252395Sgonzo else if (eq(vp, STRdirstack)) { 178252395Sgonzo dsetstack(); 179244197Sgonzo } 180244197Sgonzo else if (eq(vp, STRrecognize_only_executables)) { 181244197Sgonzo tw_cmd_free(); 182252395Sgonzo } 183244197Sgonzo else if (eq(vp, STRkillring)) { 184252395Sgonzo SetKillRing(getn(varval(vp))); 185252395Sgonzo } 186252395Sgonzo#ifndef HAVENOUTMP 187244197Sgonzo else if (eq(vp, STRwatch)) { 188244197Sgonzo resetwatch(); 189244197Sgonzo } 190244197Sgonzo#endif /* HAVENOUTMP */ 191244197Sgonzo else if (eq(vp, STRimplicitcd)) { 192244197Sgonzo implicit_cd = ((eq(varval(vp), STRverbose)) ? 2 : 1); 193244197Sgonzo } 194244197Sgonzo#ifdef COLOR_LS_F 195244197Sgonzo else if (eq(vp, STRcolor)) { 196244197Sgonzo set_color_context(); 197244197Sgonzo } 198244197Sgonzo#endif /* COLOR_LS_F */ 199244197Sgonzo#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 200244197Sgonzo else if(eq(vp, CHECK_MBYTEVAR) || eq(vp, STRnokanji)) { 201244197Sgonzo update_dspmbyte_vars(); 202244197Sgonzo } 203244197Sgonzo#endif 204244197Sgonzo#ifdef NLS_CATALOGS 205244197Sgonzo else if (eq(vp, STRcatalog)) { 206244197Sgonzo nlsclose(); 207244197Sgonzo nlsinit(); 208244197Sgonzo } 209244197Sgonzo#if defined(FILEC) && defined(TIOCSTI) 210244197Sgonzo else if (eq(vp, STRfilec)) 211244197Sgonzo filec = 1; 212244197Sgonzo#endif 213244197Sgonzo#endif /* NLS_CATALOGS */ 214244197Sgonzo} 215244197Sgonzo 216244197Sgonzo 217244197Sgonzo/*ARGSUSED*/ 218244197Sgonzovoid 219244197Sgonzodoset(Char **v, struct command *c) 220244197Sgonzo{ 221244197Sgonzo Char *p; 222244197Sgonzo Char *vp, op; 223244197Sgonzo Char **vecp; 224244197Sgonzo int hadsub; 225244197Sgonzo int subscr; 226244197Sgonzo int flags = VAR_READWRITE; 227244197Sgonzo int first_match = 0; 228244197Sgonzo int last_match = 0; 229244197Sgonzo int changed = 0; 230244197Sgonzo 231244197Sgonzo USE(c); 232244197Sgonzo v++; 233244197Sgonzo do { 234244197Sgonzo changed = 0; 235244197Sgonzo /* 236244197Sgonzo * Readonly addition From: Tim P. Starrin <noid@cyborg.larc.nasa.gov> 237244197Sgonzo */ 238244197Sgonzo if (*v && eq(*v, STRmr)) { 239244197Sgonzo flags = VAR_READONLY; 240244197Sgonzo v++; 241244197Sgonzo changed = 1; 242244197Sgonzo } 243244197Sgonzo if (*v && eq(*v, STRmf) && !last_match) { 244244197Sgonzo first_match = 1; 245244197Sgonzo v++; 246244197Sgonzo changed = 1; 247244197Sgonzo } 248244197Sgonzo if (*v && eq(*v, STRml) && !first_match) { 249244197Sgonzo last_match = 1; 250244197Sgonzo v++; 251244197Sgonzo changed = 1; 252244197Sgonzo } 253244197Sgonzo } while(changed); 254244197Sgonzo p = *v++; 255244197Sgonzo if (p == 0) { 256244197Sgonzo plist(&shvhed, flags); 257244197Sgonzo return; 258244197Sgonzo } 259244197Sgonzo do { 260244197Sgonzo hadsub = 0; 261244197Sgonzo vp = p; 262244197Sgonzo if (letter(*p)) 263244197Sgonzo for (; alnum(*p); p++) 264244197Sgonzo continue; 265244197Sgonzo if (vp == p || !letter(*vp)) 266244197Sgonzo stderror(ERR_NAME | ERR_VARBEGIN); 267244197Sgonzo if (*p == '[') { 268244197Sgonzo hadsub++; 269244197Sgonzo p = getinx(p, &subscr); 270244197Sgonzo } 271244197Sgonzo if ((op = *p) != 0) { 272244197Sgonzo *p++ = 0; 273244197Sgonzo if (*p == 0 && *v && **v == '(') 274244197Sgonzo p = *v++; 275244197Sgonzo } 276244197Sgonzo else if (*v && eq(*v, STRequal)) { 277244197Sgonzo op = '=', v++; 278244197Sgonzo if (*v) 279244197Sgonzo p = *v++; 280244197Sgonzo } 281244197Sgonzo if (op && op != '=') 282244197Sgonzo stderror(ERR_NAME | ERR_SYNTAX); 283244197Sgonzo if (eq(p, STRLparen)) { 284244197Sgonzo Char **e = v; 285244197Sgonzo 286244197Sgonzo if (hadsub) 287244197Sgonzo stderror(ERR_NAME | ERR_SYNTAX); 288244197Sgonzo for (;;) { 289244197Sgonzo if (!*e) 290244197Sgonzo stderror(ERR_NAME | ERR_MISSING, ')'); 291244197Sgonzo if (**e == ')') 292244197Sgonzo break; 293244197Sgonzo e++; 294244197Sgonzo } 295244197Sgonzo p = *e; 296244197Sgonzo *e = 0; 297244197Sgonzo vecp = saveblk(v); 298244197Sgonzo if (first_match) 299244197Sgonzo flags |= VAR_FIRST; 300244197Sgonzo else if (last_match) 301244197Sgonzo flags |= VAR_LAST; 302244197Sgonzo 303244197Sgonzo set1(vp, vecp, &shvhed, flags); 304244197Sgonzo *e = p; 305244197Sgonzo v = e + 1; 306244197Sgonzo } 307244197Sgonzo else if (hadsub) { 308244197Sgonzo Char *copy; 309244197Sgonzo 310244197Sgonzo copy = Strsave(p); 311252395Sgonzo cleanup_push(copy, xfree); 312244197Sgonzo asx(vp, subscr, copy); 313244197Sgonzo cleanup_ignore(copy); 314244197Sgonzo cleanup_until(copy); 315244197Sgonzo } 316244197Sgonzo else 317244197Sgonzo setv(vp, Strsave(p), flags); 318244197Sgonzo update_vars(vp); 319244197Sgonzo } while ((p = *v++) != NULL); 320244197Sgonzo} 321244197Sgonzo 322244197Sgonzostatic Char * 323244197Sgonzogetinx(Char *cp, int *ip) 324244197Sgonzo{ 325244197Sgonzo *ip = 0; 326244197Sgonzo *cp++ = 0; 327244197Sgonzo while (*cp && Isdigit(*cp)) 328244197Sgonzo *ip = *ip * 10 + *cp++ - '0'; 329244197Sgonzo if (*cp++ != ']') 330244197Sgonzo stderror(ERR_NAME | ERR_SUBSCRIPT); 331244197Sgonzo return (cp); 332244197Sgonzo} 333244197Sgonzo 334244197Sgonzostatic void 335244197Sgonzoasx(Char *vp, int subscr, Char *p) 336244197Sgonzo{ 337244197Sgonzo struct varent *v = getvx(vp, subscr); 338244197Sgonzo Char *prev; 339244197Sgonzo 340244197Sgonzo if (v->v_flags & VAR_READONLY) 341244197Sgonzo stderror(ERR_READONLY|ERR_NAME, v->v_name); 342244197Sgonzo prev = v->vec[subscr - 1]; 343244197Sgonzo cleanup_push(prev, xfree); 344244197Sgonzo v->vec[subscr - 1] = globone(p, G_APPEND); 345244197Sgonzo cleanup_until(prev); 346244197Sgonzo} 347244197Sgonzo 348252395Sgonzostatic struct varent * 349244197Sgonzogetvx(Char *vp, int subscr) 350252395Sgonzo{ 351252395Sgonzo struct varent *v = adrof(vp); 352252395Sgonzo 353252395Sgonzo if (v == 0) 354252395Sgonzo udvar(vp); 355252395Sgonzo if (subscr < 1 || subscr > blklen(v->vec)) 356278727Sian stderror(ERR_NAME | ERR_RANGE); 357252395Sgonzo return (v); 358252395Sgonzo} 359252395Sgonzo 360252395Sgonzo/*ARGSUSED*/ 361252395Sgonzovoid 362252395Sgonzodolet(Char **v, struct command *dummy) 363256292Sdim{ 364256292Sdim Char *p; 365256292Sdim Char *vp, c, op; 366244197Sgonzo int hadsub; 367252395Sgonzo int subscr; 368244197Sgonzo 369244197Sgonzo USE(dummy); 370244197Sgonzo v++; 371244197Sgonzo p = *v++; 372244197Sgonzo if (p == 0) { 373244197Sgonzo prvars(); 374244197Sgonzo return; 375244197Sgonzo } 376244197Sgonzo do { 377244197Sgonzo hadsub = 0; 378244197Sgonzo vp = p; 379244197Sgonzo if (letter(*p)) 380244197Sgonzo for (; alnum(*p); p++) 381244197Sgonzo continue; 382244197Sgonzo if (vp == p || !letter(*vp)) 383244197Sgonzo stderror(ERR_NAME | ERR_VARBEGIN); 384244197Sgonzo if (*p == '[') { 385244197Sgonzo hadsub++; 386244197Sgonzo p = getinx(p, &subscr); 387244197Sgonzo } 388244197Sgonzo if (*p == 0 && *v) 389244197Sgonzo p = *v++; 390244197Sgonzo if ((op = *p) != 0) 391244197Sgonzo *p++ = 0; 392244197Sgonzo else 393244197Sgonzo stderror(ERR_NAME | ERR_ASSIGN); 394244197Sgonzo 395244197Sgonzo /* 396244197Sgonzo * if there is no expression after the '=' then print a "Syntax Error" 397244197Sgonzo * message - strike 398244197Sgonzo */ 399244197Sgonzo if (*p == '\0' && *v == NULL) 400244197Sgonzo stderror(ERR_NAME | ERR_ASSIGN); 401244197Sgonzo 402244197Sgonzo vp = Strsave(vp); 403244197Sgonzo cleanup_push(vp, xfree); 404244197Sgonzo if (op == '=') { 405244197Sgonzo c = '='; 406244197Sgonzo p = xset(p, &v); 407244197Sgonzo } 408244197Sgonzo else { 409244197Sgonzo c = *p++; 410244197Sgonzo if (any("+-", c)) { 411244197Sgonzo if (c != op || *p) 412244197Sgonzo stderror(ERR_NAME | ERR_UNKNOWNOP); 413244197Sgonzo p = Strsave(STR1); 414244197Sgonzo } 415244197Sgonzo else { 416244197Sgonzo if (any("<>", op)) { 417244197Sgonzo if (c != op) 418244197Sgonzo stderror(ERR_NAME | ERR_UNKNOWNOP); 419244197Sgonzo stderror(ERR_NAME | ERR_SYNTAX); 420244197Sgonzo } 421244197Sgonzo if (c != '=') 422244197Sgonzo stderror(ERR_NAME | ERR_UNKNOWNOP); 423244197Sgonzo p = xset(p, &v); 424244197Sgonzo } 425244197Sgonzo } 426244197Sgonzo cleanup_push(p, xfree); 427244197Sgonzo if (op == '=') { 428244197Sgonzo if (hadsub) 429244197Sgonzo asx(vp, subscr, p); 430244197Sgonzo else 431244197Sgonzo setv(vp, p, VAR_READWRITE); 432244197Sgonzo cleanup_ignore(p); 433244197Sgonzo } 434244197Sgonzo else if (hadsub) { 435244197Sgonzo struct varent *gv = getvx(vp, subscr); 436244197Sgonzo Char *val; 437244197Sgonzo 438244197Sgonzo val = operate(op, gv->vec[subscr - 1], p); 439244197Sgonzo cleanup_push(val, xfree); 440244197Sgonzo asx(vp, subscr, val); 441244197Sgonzo cleanup_ignore(val); 442244197Sgonzo cleanup_until(val); 443244197Sgonzo } 444244197Sgonzo else { 445244197Sgonzo Char *val; 446244197Sgonzo 447244197Sgonzo val = operate(op, varval(vp), p); 448244197Sgonzo cleanup_push(val, xfree); 449244197Sgonzo setv(vp, val, VAR_READWRITE); 450244197Sgonzo cleanup_ignore(val); 451244197Sgonzo cleanup_until(val); 452244197Sgonzo } 453244197Sgonzo update_vars(vp); 454244197Sgonzo cleanup_until(vp); 455244197Sgonzo } while ((p = *v++) != NULL); 456244197Sgonzo} 457244197Sgonzo 458244197Sgonzostatic Char * 459244197Sgonzoxset(Char *cp, Char ***vp) 460244197Sgonzo{ 461244197Sgonzo Char *dp; 462244197Sgonzo 463244197Sgonzo if (*cp) { 464244197Sgonzo dp = Strsave(cp); 465244197Sgonzo --(*vp); 466244197Sgonzo xfree(** vp); 467244197Sgonzo **vp = dp; 468244197Sgonzo } 469244197Sgonzo return (putn(expr(vp))); 470244197Sgonzo} 471244197Sgonzo 472244197Sgonzostatic Char * 473244197Sgonzooperate(int op, Char *vp, Char *p) 474244197Sgonzo{ 475244197Sgonzo Char opr[2]; 476244197Sgonzo Char *vec[5]; 477244197Sgonzo Char **v = vec; 478244197Sgonzo Char **vecp = v; 479244197Sgonzo int i; 480244197Sgonzo 481244197Sgonzo if (op != '=') { 482244197Sgonzo if (*vp) 483244197Sgonzo *v++ = vp; 484244197Sgonzo opr[0] = op; 485244197Sgonzo opr[1] = 0; 486244197Sgonzo *v++ = opr; 487244197Sgonzo if (op == '<' || op == '>') 488244197Sgonzo *v++ = opr; 489244197Sgonzo } 490244197Sgonzo *v++ = p; 491244197Sgonzo *v++ = 0; 492244197Sgonzo i = expr(&vecp); 493244197Sgonzo if (*vecp) 494244197Sgonzo stderror(ERR_NAME | ERR_EXPRESSION); 495244197Sgonzo return (putn(i)); 496244197Sgonzo} 497244197Sgonzo 498244197Sgonzostatic Char *putp; 499244197Sgonzo 500244197SgonzoChar * 501244197Sgonzoputn(int n) 502244197Sgonzo{ 503244197Sgonzo Char nbuf[(CHAR_BIT * sizeof (n) + 2) / 3 + 2]; /* Enough even for octal */ 504244197Sgonzo 505244197Sgonzo putp = nbuf; 506244197Sgonzo if (n < 0) { 507244197Sgonzo n = -n; 508244197Sgonzo *putp++ = '-'; 509244197Sgonzo } 510244197Sgonzo putn1(n); 511244197Sgonzo *putp = 0; 512244197Sgonzo return (Strsave(nbuf)); 513244197Sgonzo} 514244197Sgonzo 515244197Sgonzostatic void 516244197Sgonzoputn1(unsigned n) 517244197Sgonzo{ 518 if (n > 9) 519 putn1(n / 10); 520 *putp++ = n % 10 + '0'; 521} 522 523int 524getn(Char *cp) 525{ 526 int n; 527 int sign; 528 529 if (!cp) /* PWP: extra error checking */ 530 stderror(ERR_NAME | ERR_BADNUM); 531 532 sign = 0; 533 if (cp[0] == '+' && cp[1]) 534 cp++; 535 if (*cp == '-') { 536 sign++; 537 cp++; 538 if (!Isdigit(*cp)) 539 stderror(ERR_NAME | ERR_BADNUM); 540 } 541 n = 0; 542 while (Isdigit(*cp)) 543 n = n * 10 + *cp++ - '0'; 544 if (*cp) 545 stderror(ERR_NAME | ERR_BADNUM); 546 return (sign ? -n : n); 547} 548 549Char * 550value1(Char *var, struct varent *head) 551{ 552 struct varent *vp; 553 554 if (!var || !head) /* PWP: extra error checking */ 555 return (STRNULL); 556 557 vp = adrof1(var, head); 558 return ((vp == NULL || vp->vec == NULL || vp->vec[0] == NULL) ? 559 STRNULL : vp->vec[0]); 560} 561 562static struct varent * 563madrof(Char *pat, struct varent *vp) 564{ 565 struct varent *vp1; 566 567 for (vp = vp->v_left; vp; vp = vp->v_right) { 568 if (vp->v_left && (vp1 = madrof(pat, vp)) != NULL) 569 return vp1; 570 if (Gmatch(vp->v_name, pat)) 571 return vp; 572 } 573 return vp; 574} 575 576struct varent * 577adrof1(const Char *name, struct varent *v) 578{ 579 int cmp; 580 581 v = v->v_left; 582 while (v && ((cmp = *name - *v->v_name) != 0 || 583 (cmp = Strcmp(name, v->v_name)) != 0)) 584 if (cmp < 0) 585 v = v->v_left; 586 else 587 v = v->v_right; 588 return v; 589} 590 591void 592setcopy(const Char *var, const Char *val, int flags) 593{ 594 Char *copy; 595 596 copy = Strsave(val); 597 cleanup_push(copy, xfree); 598 setv(var, copy, flags); 599 cleanup_ignore(copy); 600 cleanup_until(copy); 601} 602 603/* 604 * The caller is responsible for putting value in a safe place 605 */ 606void 607setv(const Char *var, Char *val, int flags) 608{ 609 Char **vec = xmalloc(2 * sizeof(Char **)); 610 611 vec[0] = val; 612 vec[1] = 0; 613 set1(var, vec, &shvhed, flags); 614} 615 616void 617set1(const Char *var, Char **vec, struct varent *head, int flags) 618{ 619 Char **oldv = vec; 620 621 if ((flags & VAR_NOGLOB) == 0) { 622 int gflag; 623 624 gflag = tglob(oldv); 625 if (gflag) { 626 vec = globall(oldv, gflag); 627 if (vec == 0) { 628 blkfree(oldv); 629 stderror(ERR_NAME | ERR_NOMATCH); 630 } 631 blkfree(oldv); 632 } 633 } 634 /* 635 * Uniqueness addition from: Michael Veksler <mveksler@vnet.ibm.com> 636 */ 637 if ( flags & (VAR_FIRST | VAR_LAST) ) { 638 /* 639 * Code for -f (VAR_FIRST) and -l (VAR_LAST) options. 640 * Method: 641 * Delete all duplicate words leaving "holes" in the word array (vec). 642 * Then remove the "holes", keeping the order of the words unchanged. 643 */ 644 if (vec && vec[0] && vec[1]) { /* more than one word ? */ 645 int i, j; 646 int num_items; 647 648 for (num_items = 0; vec[num_items]; num_items++) 649 continue; 650 if (flags & VAR_FIRST) { 651 /* delete duplications, keeping first occurance */ 652 for (i = 1; i < num_items; i++) 653 for (j = 0; j < i; j++) 654 /* If have earlier identical item, remove i'th item */ 655 if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) { 656 xfree(vec[i]); 657 vec[i] = NULL; 658 break; 659 } 660 } else if (flags & VAR_LAST) { 661 /* delete duplications, keeping last occurance */ 662 for (i = 0; i < num_items - 1; i++) 663 for (j = i + 1; j < num_items; j++) 664 /* If have later identical item, remove i'th item */ 665 if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) { 666 /* remove identical item (the first) */ 667 xfree(vec[i]); 668 vec[i] = NULL; 669 } 670 } 671 /* Compress items - remove empty items */ 672 for (j = i = 0; i < num_items; i++) 673 if (vec[i]) 674 vec[j++] = vec[i]; 675 676 /* NULL-fy remaining items */ 677 for (; j < num_items; j++) 678 vec[j] = NULL; 679 } 680 /* don't let the attribute propagate */ 681 flags &= ~(VAR_FIRST|VAR_LAST); 682 } 683 setq(var, vec, head, flags); 684} 685 686 687void 688setq(const Char *name, Char **vec, struct varent *p, int flags) 689{ 690 struct varent *c; 691 int f; 692 693 f = 0; /* tree hangs off the header's left link */ 694 while ((c = p->v_link[f]) != 0) { 695 if ((f = *name - *c->v_name) == 0 && 696 (f = Strcmp(name, c->v_name)) == 0) { 697 if (c->v_flags & VAR_READONLY) 698 stderror(ERR_READONLY|ERR_NAME, c->v_name); 699 blkfree(c->vec); 700 c->v_flags = flags; 701 trim(c->vec = vec); 702 return; 703 } 704 p = c; 705 f = f > 0; 706 } 707 p->v_link[f] = c = xmalloc(sizeof(struct varent)); 708 c->v_name = Strsave(name); 709 c->v_flags = flags; 710 c->v_bal = 0; 711 c->v_left = c->v_right = 0; 712 c->v_parent = p; 713 balance(p, f, 0); 714 trim(c->vec = vec); 715} 716 717/*ARGSUSED*/ 718void 719unset(Char **v, struct command *c) 720{ 721 int did_roe, did_edit; 722 723 USE(c); 724 did_roe = adrof(STRrecognize_only_executables) != NULL; 725 did_edit = adrof(STRedit) != NULL; 726 unset1(v, &shvhed); 727 728#if defined(FILEC) && defined(TIOCSTI) 729 if (adrof(STRfilec) == 0) 730 filec = 0; 731#endif /* FILEC && TIOCSTI */ 732 733 if (adrof(STRhistchars) == 0) { 734 HIST = '!'; 735 HISTSUB = '^'; 736 } 737 if (adrof(STRignoreeof) == 0) 738 numeof = 0; 739 if (adrof(STRpromptchars) == 0) { 740 PRCH = '>'; 741 PRCHROOT = '#'; 742 } 743 if (adrof(STRhistlit) == 0) 744 HistLit = 0; 745 if (adrof(STRloginsh) == 0) 746 loginsh = 0; 747 if (adrof(STRwordchars) == 0) 748 word_chars = STR_WORD_CHARS; 749 if (adrof(STRedit) == 0) 750 editing = 0; 751 if (adrof(STRbackslash_quote) == 0) 752 bslash_quote = 0; 753 if (adrof(STRsymlinks) == 0) 754 symlinks = 0; 755 if (adrof(STRimplicitcd) == 0) 756 implicit_cd = 0; 757 if (adrof(STRkillring) == 0) 758 SetKillRing(0); 759 if (did_edit && noediting && adrof(STRedit) == 0) 760 noediting = 0; 761 if (did_roe && adrof(STRrecognize_only_executables) == 0) 762 tw_cmd_free(); 763#ifdef COLOR_LS_F 764 if (adrof(STRcolor) == 0) 765 set_color_context(); 766#endif /* COLOR_LS_F */ 767#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 768 update_dspmbyte_vars(); 769#endif 770#ifdef NLS_CATALOGS 771 nlsclose(); 772 nlsinit(); 773#endif /* NLS_CATALOGS */ 774} 775 776void 777unset1(Char *v[], struct varent *head) 778{ 779 struct varent *vp; 780 int cnt; 781 782 while (*++v) { 783 cnt = 0; 784 while ((vp = madrof(*v, head)) != NULL) 785 if (vp->v_flags & VAR_READONLY) 786 stderror(ERR_READONLY|ERR_NAME, vp->v_name); 787 else 788 unsetv1(vp), cnt++; 789 if (cnt == 0) 790 setname(short2str(*v)); 791 } 792} 793 794void 795unsetv(Char *var) 796{ 797 struct varent *vp; 798 799 if ((vp = adrof1(var, &shvhed)) == 0) 800 udvar(var); 801 unsetv1(vp); 802} 803 804static void 805unsetv1(struct varent *p) 806{ 807 struct varent *c, *pp; 808 int f; 809 810 /* 811 * Free associated memory first to avoid complications. 812 */ 813 blkfree(p->vec); 814 xfree(p->v_name); 815 /* 816 * If p is missing one child, then we can move the other into where p is. 817 * Otherwise, we find the predecessor of p, which is guaranteed to have no 818 * right child, copy it into p, and move it's left child into it. 819 */ 820 if (p->v_right == 0) 821 c = p->v_left; 822 else if (p->v_left == 0) 823 c = p->v_right; 824 else { 825 for (c = p->v_left; c->v_right; c = c->v_right) 826 continue; 827 p->v_name = c->v_name; 828 p->v_flags = c->v_flags; 829 p->vec = c->vec; 830 p = c; 831 c = p->v_left; 832 } 833 834 /* 835 * Move c into where p is. 836 */ 837 pp = p->v_parent; 838 f = pp->v_right == p; 839 if ((pp->v_link[f] = c) != 0) 840 c->v_parent = pp; 841 /* 842 * Free the deleted node, and rebalance. 843 */ 844 xfree(p); 845 balance(pp, f, 1); 846} 847 848void 849setNS(Char *cp) 850{ 851 setcopy(cp, STRNULL, VAR_READWRITE); 852} 853 854/*ARGSUSED*/ 855void 856shift(Char **v, struct command *c) 857{ 858 struct varent *argv; 859 Char *name; 860 861 USE(c); 862 v++; 863 name = *v; 864 if (name == 0) 865 name = STRargv; 866 else 867 (void) strip(name); 868 argv = adrof(name); 869 if (argv == NULL || argv->vec == NULL) 870 udvar(name); 871 if (argv->vec[0] == 0) 872 stderror(ERR_NAME | ERR_NOMORE); 873 lshift(argv->vec, 1); 874 update_vars(name); 875} 876 877static void 878exportpath(Char **val) 879{ 880 struct Strbuf buf = Strbuf_INIT; 881 Char *exppath; 882 883 if (val) 884 while (*val) { 885 Strbuf_append(&buf, *val++); 886 if (*val == 0 || eq(*val, STRRparen)) 887 break; 888 Strbuf_append1(&buf, PATHSEP); 889 } 890 exppath = Strbuf_finish(&buf); 891 cleanup_push(exppath, xfree); 892 tsetenv(STRKPATH, exppath); 893 cleanup_until(exppath); 894} 895 896#ifndef lint 897 /* 898 * Lint thinks these have null effect 899 */ 900 /* macros to do single rotations on node p */ 901# define rright(p) (\ 902 t = (p)->v_left,\ 903 (t)->v_parent = (p)->v_parent,\ 904 (((p)->v_left = t->v_right) != NULL) ?\ 905 (t->v_right->v_parent = (p)) : 0,\ 906 (t->v_right = (p))->v_parent = t,\ 907 (p) = t) 908# define rleft(p) (\ 909 t = (p)->v_right,\ 910 ((t)->v_parent = (p)->v_parent,\ 911 ((p)->v_right = t->v_left) != NULL) ? \ 912 (t->v_left->v_parent = (p)) : 0,\ 913 (t->v_left = (p))->v_parent = t,\ 914 (p) = t) 915#else 916static struct varent * 917rleft(struct varent *p) 918{ 919 return (p); 920} 921static struct varent * 922rright(struct varent *p) 923{ 924 return (p); 925} 926 927#endif /* ! lint */ 928 929 930/* 931 * Rebalance a tree, starting at p and up. 932 * F == 0 means we've come from p's left child. 933 * D == 1 means we've just done a delete, otherwise an insert. 934 */ 935static void 936balance(struct varent *p, int f, int d) 937{ 938 struct varent *pp; 939 940#ifndef lint 941 struct varent *t; /* used by the rotate macros */ 942#endif /* !lint */ 943 int ff; 944#ifdef lint 945 ff = 0; /* Sun's lint is dumb! */ 946#endif 947 948 /* 949 * Ok, from here on, p is the node we're operating on; pp is it's parent; f 950 * is the branch of p from which we have come; ff is the branch of pp which 951 * is p. 952 */ 953 for (; (pp = p->v_parent) != 0; p = pp, f = ff) { 954 ff = pp->v_right == p; 955 if (f ^ d) { /* right heavy */ 956 switch (p->v_bal) { 957 case -1: /* was left heavy */ 958 p->v_bal = 0; 959 break; 960 case 0: /* was balanced */ 961 p->v_bal = 1; 962 break; 963 case 1: /* was already right heavy */ 964 switch (p->v_right->v_bal) { 965 case 1: /* single rotate */ 966 pp->v_link[ff] = rleft(p); 967 p->v_left->v_bal = 0; 968 p->v_bal = 0; 969 break; 970 case 0: /* single rotate */ 971 pp->v_link[ff] = rleft(p); 972 p->v_left->v_bal = 1; 973 p->v_bal = -1; 974 break; 975 case -1: /* double rotate */ 976 (void) rright(p->v_right); 977 pp->v_link[ff] = rleft(p); 978 p->v_left->v_bal = 979 p->v_bal < 1 ? 0 : -1; 980 p->v_right->v_bal = 981 p->v_bal > -1 ? 0 : 1; 982 p->v_bal = 0; 983 break; 984 default: 985 break; 986 } 987 break; 988 default: 989 break; 990 } 991 } 992 else { /* left heavy */ 993 switch (p->v_bal) { 994 case 1: /* was right heavy */ 995 p->v_bal = 0; 996 break; 997 case 0: /* was balanced */ 998 p->v_bal = -1; 999 break; 1000 case -1: /* was already left heavy */ 1001 switch (p->v_left->v_bal) { 1002 case -1: /* single rotate */ 1003 pp->v_link[ff] = rright(p); 1004 p->v_right->v_bal = 0; 1005 p->v_bal = 0; 1006 break; 1007 case 0: /* single rotate */ 1008 pp->v_link[ff] = rright(p); 1009 p->v_right->v_bal = -1; 1010 p->v_bal = 1; 1011 break; 1012 case 1: /* double rotate */ 1013 (void) rleft(p->v_left); 1014 pp->v_link[ff] = rright(p); 1015 p->v_left->v_bal = 1016 p->v_bal < 1 ? 0 : -1; 1017 p->v_right->v_bal = 1018 p->v_bal > -1 ? 0 : 1; 1019 p->v_bal = 0; 1020 break; 1021 default: 1022 break; 1023 } 1024 break; 1025 default: 1026 break; 1027 } 1028 } 1029 /* 1030 * If from insert, then we terminate when p is balanced. If from 1031 * delete, then we terminate when p is unbalanced. 1032 */ 1033 if ((p->v_bal == 0) ^ d) 1034 break; 1035 } 1036} 1037 1038void 1039plist(struct varent *p, int what) 1040{ 1041 struct varent *c; 1042 int len; 1043 1044 for (;;) { 1045 while (p->v_left) 1046 p = p->v_left; 1047x: 1048 if (p->v_parent == 0) /* is it the header? */ 1049 break; 1050 if ((p->v_flags & what) != 0) { 1051 if (setintr) { 1052 int old_pintr_disabled; 1053 1054 pintr_push_enable(&old_pintr_disabled); 1055 cleanup_until(&old_pintr_disabled); 1056 } 1057 len = blklen(p->vec); 1058 xprintf("%S\t", p->v_name); 1059 if (len != 1) 1060 xputchar('('); 1061 blkpr(p->vec); 1062 if (len != 1) 1063 xputchar(')'); 1064 xputchar('\n'); 1065 } 1066 if (p->v_right) { 1067 p = p->v_right; 1068 continue; 1069 } 1070 do { 1071 c = p; 1072 p = p->v_parent; 1073 } while (p->v_right == c); 1074 goto x; 1075 } 1076} 1077 1078#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 1079extern int dspmbyte_ls; 1080 1081void 1082update_dspmbyte_vars(void) 1083{ 1084 int lp, iskcode; 1085 Char *dstr1; 1086 struct varent *vp; 1087 1088 /* if variable "nokanji" is set, multi-byte display is disabled */ 1089 if ((vp = adrof(CHECK_MBYTEVAR)) && !adrof(STRnokanji)) { 1090 _enable_mbdisp = 1; 1091 dstr1 = vp->vec[0]; 1092 if(eq (dstr1, STRsjis)) 1093 iskcode = 1; 1094 else if (eq(dstr1, STReuc)) 1095 iskcode = 2; 1096 else if (eq(dstr1, STRbig5)) 1097 iskcode = 3; 1098 else if (eq(dstr1, STRutf8)) 1099 iskcode = 4; 1100 else if ((dstr1[0] - '0') >= 0 && (dstr1[0] - '0') <= 3) { 1101 iskcode = 0; 1102 } 1103 else { 1104 xprintf(CGETS(18, 2, 1105 "Warning: unknown multibyte display; using default(euc(JP))\n")); 1106 iskcode = 2; 1107 } 1108 if (dstr1 && vp->vec[1] && eq(vp->vec[1], STRls)) 1109 dspmbyte_ls = 1; 1110 else 1111 dspmbyte_ls = 0; 1112 for (lp = 0; lp < 256 && iskcode > 0; lp++) { 1113 switch (iskcode) { 1114 case 1: 1115 /* Shift-JIS */ 1116 _cmap[lp] = _cmap_mbyte[lp]; 1117 _mbmap[lp] = _mbmap_sjis[lp]; 1118 break; 1119 case 2: 1120 /* 2 ... euc */ 1121 _cmap[lp] = _cmap_mbyte[lp]; 1122 _mbmap[lp] = _mbmap_euc[lp]; 1123 break; 1124 case 3: 1125 /* 3 ... big5 */ 1126 _cmap[lp] = _cmap_mbyte[lp]; 1127 _mbmap[lp] = _mbmap_big5[lp]; 1128 break; 1129 case 4: 1130 /* 4 ... utf8 */ 1131 _cmap[lp] = _cmap_mbyte[lp]; 1132 _mbmap[lp] = _mbmap_utf8[lp]; 1133 break; 1134 default: 1135 xprintf(CGETS(18, 3, 1136 "Warning: unknown multibyte code %d; multibyte disabled\n"), 1137 iskcode); 1138 _cmap[lp] = _cmap_c[lp]; 1139 _mbmap[lp] = 0; /* Default map all 0 */ 1140 _enable_mbdisp = 0; 1141 break; 1142 } 1143 } 1144 if (iskcode == 0) { 1145 /* check original table */ 1146 if (Strlen(dstr1) != 256) { 1147 xprintf(CGETS(18, 4, 1148 "Warning: Invalid multibyte table length (%d); multibyte disabled\n"), 1149 Strlen(dstr1)); 1150 _enable_mbdisp = 0; 1151 } 1152 for (lp = 0; lp < 256 && _enable_mbdisp == 1; lp++) { 1153 if (!((dstr1[lp] - '0') >= 0 && (dstr1[lp] - '0') <= 3)) { 1154 xprintf(CGETS(18, 4, 1155 "Warning: bad multibyte code at offset +%d; multibyte diabled\n"), 1156 lp); 1157 _enable_mbdisp = 0; 1158 break; 1159 } 1160 } 1161 /* set original table */ 1162 for (lp = 0; lp < 256; lp++) { 1163 if (_enable_mbdisp == 1) { 1164 _cmap[lp] = _cmap_mbyte[lp]; 1165 _mbmap[lp] = (unsigned short) ((dstr1[lp] - '0') & 0x0f); 1166 } 1167 else { 1168 _cmap[lp] = _cmap_c[lp]; 1169 _mbmap[lp] = 0; /* Default map all 0 */ 1170 } 1171 } 1172 } 1173 } 1174 else { 1175 for (lp = 0; lp < 256; lp++) { 1176 _cmap[lp] = _cmap_c[lp]; 1177 _mbmap[lp] = 0; /* Default map all 0 */ 1178 } 1179 _enable_mbdisp = 0; 1180 dspmbyte_ls = 0; 1181 } 1182#ifdef MBYTEDEBUG /* Sorry, use for beta testing */ 1183 { 1184 Char mbmapstr[300]; 1185 for (lp = 0; lp < 256; lp++) 1186 mbmapstr[lp] = _mbmap[lp] + '0'; 1187 mbmapstr[lp] = 0; 1188 setcopy(STRmbytemap, mbmapstr, VAR_READWRITE); 1189 } 1190#endif /* MBYTEMAP */ 1191} 1192 1193/* dspkanji/dspmbyte autosetting */ 1194/* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1195void 1196autoset_dspmbyte(const Char *pcp) 1197{ 1198 int i; 1199 static const struct dspm_autoset_Table { 1200 Char *n; 1201 Char *v; 1202 } dspmt[] = { 1203 { STRLANGEUCJP, STReuc }, 1204 { STRLANGEUCKR, STReuc }, 1205 { STRLANGEUCZH, STReuc }, 1206 { STRLANGEUCJPB, STReuc }, 1207 { STRLANGEUCKRB, STReuc }, 1208 { STRLANGEUCZHB, STReuc }, 1209#ifdef linux 1210 { STRLANGEUCJPC, STReuc }, 1211#endif 1212 { STRLANGSJIS, STRsjis }, 1213 { STRLANGSJISB, STRsjis }, 1214 { STRLANGBIG5, STRbig5 }, 1215 { STRstarutfstar8, STRutf8 }, 1216 { NULL, NULL } 1217 }; 1218#if defined(HAVE_NL_LANGINFO) && defined(CODESET) 1219 static const struct dspm_autoset_Table dspmc[] = { 1220 { STRstarutfstar8, STRutf8 }, 1221 { STReuc, STReuc }, 1222 { STRGB2312, STReuc }, 1223 { STRLANGBIG5, STRbig5 }, 1224 { NULL, NULL } 1225 }; 1226 Char *codeset; 1227 1228 codeset = str2short(nl_langinfo(CODESET)); 1229 if (*codeset != '\0') { 1230 for (i = 0; dspmc[i].n; i++) { 1231 const Char *estr; 1232 if (dspmc[i].n[0] && t_pmatch(pcp, dspmc[i].n, &estr, 0) > 0) { 1233 setcopy(CHECK_MBYTEVAR, dspmc[i].v, VAR_READWRITE); 1234 update_dspmbyte_vars(); 1235 return; 1236 } 1237 } 1238 } 1239#endif 1240 1241 if (*pcp == '\0') 1242 return; 1243 1244 for (i = 0; dspmt[i].n; i++) { 1245 const Char *estr; 1246 if (dspmt[i].n[0] && t_pmatch(pcp, dspmt[i].n, &estr, 0) > 0) { 1247 setcopy(CHECK_MBYTEVAR, dspmt[i].v, VAR_READWRITE); 1248 update_dspmbyte_vars(); 1249 break; 1250 } 1251 } 1252} 1253#endif 1254