1 1.26 rillig /* $NetBSD: var.c,v 1.26 2024/09/08 17:28:36 rillig Exp $ */ 2 1.8 agc 3 1.8 agc #include <sys/cdefs.h> 4 1.8 agc 5 1.8 agc #ifndef lint 6 1.26 rillig __RCSID("$NetBSD: var.c,v 1.26 2024/09/08 17:28:36 rillig Exp $"); 7 1.8 agc #endif 8 1.8 agc 9 1.19 kamil #include <sys/stat.h> 10 1.18 kamil #include <sys/time.h> 11 1.18 kamil #include <time.h> 12 1.18 kamil #include <ctype.h> 13 1.20 kamil #include <stdbool.h> 14 1.2 tls 15 1.1 jtc #include "sh.h" 16 1.1 jtc #include "ksh_limval.h" 17 1.1 jtc 18 1.1 jtc /* 19 1.1 jtc * Variables 20 1.1 jtc * 21 1.1 jtc * WARNING: unreadable code, needs a rewrite 22 1.1 jtc * 23 1.1 jtc * if (flag&INTEGER), val.i contains integer value, and type contains base. 24 1.1 jtc * otherwise, (val.s + type) contains string value. 25 1.1 jtc * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. 26 1.1 jtc */ 27 1.1 jtc static struct tbl vtemp; 28 1.1 jtc static struct table specials; 29 1.1 jtc static char *formatstr ARGS((struct tbl *vp, const char *s)); 30 1.1 jtc static void export ARGS((struct tbl *vp, const char *val)); 31 1.1 jtc static int special ARGS((const char *name)); 32 1.6 hubertf static void unspecial ARGS((const char *name)); 33 1.1 jtc static void getspec ARGS((struct tbl *vp)); 34 1.1 jtc static void setspec ARGS((struct tbl *vp)); 35 1.1 jtc static void unsetspec ARGS((struct tbl *vp)); 36 1.1 jtc static struct tbl *arraysearch ARGS((struct tbl *, int)); 37 1.1 jtc 38 1.1 jtc /* 39 1.1 jtc * create a new block for function calls and simple commands 40 1.1 jtc * assume caller has allocated and set up e->loc 41 1.1 jtc */ 42 1.1 jtc void 43 1.1 jtc newblock() 44 1.1 jtc { 45 1.24 kamil struct block *l; 46 1.1 jtc static char *const empty[] = {null}; 47 1.1 jtc 48 1.1 jtc l = (struct block *) alloc(sizeof(struct block), ATEMP); 49 1.6 hubertf l->flags = 0; 50 1.6 hubertf ainit(&l->area); /* todo: could use e->area (l->area => l->areap) */ 51 1.1 jtc if (!e->loc) { 52 1.1 jtc l->argc = 0; 53 1.12 christos l->argv = (char **) __UNCONST(empty); 54 1.1 jtc } else { 55 1.1 jtc l->argc = e->loc->argc; 56 1.1 jtc l->argv = e->loc->argv; 57 1.1 jtc } 58 1.1 jtc l->exit = l->error = NULL; 59 1.1 jtc tinit(&l->vars, &l->area, 0); 60 1.1 jtc tinit(&l->funs, &l->area, 0); 61 1.1 jtc l->next = e->loc; 62 1.1 jtc e->loc = l; 63 1.1 jtc } 64 1.1 jtc 65 1.1 jtc /* 66 1.1 jtc * pop a block handling special variables 67 1.1 jtc */ 68 1.1 jtc void 69 1.1 jtc popblock() 70 1.1 jtc { 71 1.24 kamil struct block *l = e->loc; 72 1.24 kamil struct tbl *vp, **vpp = l->vars.tbls, *vq; 73 1.24 kamil int i; 74 1.1 jtc 75 1.1 jtc e->loc = l->next; /* pop block */ 76 1.4 thorpej for (i = l->vars.size; --i >= 0; ) { 77 1.4 thorpej if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) { 78 1.1 jtc if ((vq = global(vp->name))->flag & ISSET) 79 1.1 jtc setspec(vq); 80 1.1 jtc else 81 1.1 jtc unsetspec(vq); 82 1.4 thorpej } 83 1.4 thorpej } 84 1.6 hubertf if (l->flags & BF_DOGETOPTS) 85 1.6 hubertf user_opt = l->getopts_state; 86 1.1 jtc afreeall(&l->area); 87 1.1 jtc afree(l, ATEMP); 88 1.1 jtc } 89 1.1 jtc 90 1.1 jtc /* called by main() to initialize variable data structures */ 91 1.1 jtc void 92 1.1 jtc initvar() 93 1.1 jtc { 94 1.1 jtc static const struct { 95 1.1 jtc const char *name; 96 1.1 jtc int v; 97 1.1 jtc } names[] = { 98 1.1 jtc { "COLUMNS", V_COLUMNS }, 99 1.1 jtc { "IFS", V_IFS }, 100 1.1 jtc { "OPTIND", V_OPTIND }, 101 1.1 jtc { "PATH", V_PATH }, 102 1.1 jtc { "POSIXLY_CORRECT", V_POSIXLY_CORRECT }, 103 1.1 jtc { "TMPDIR", V_TMPDIR }, 104 1.1 jtc #ifdef HISTORY 105 1.1 jtc { "HISTFILE", V_HISTFILE }, 106 1.1 jtc { "HISTSIZE", V_HISTSIZE }, 107 1.1 jtc #endif /* HISTORY */ 108 1.1 jtc #ifdef EDIT 109 1.1 jtc { "EDITOR", V_EDITOR }, 110 1.1 jtc { "VISUAL", V_VISUAL }, 111 1.1 jtc #endif /* EDIT */ 112 1.1 jtc #ifdef KSH 113 1.1 jtc { "MAIL", V_MAIL }, 114 1.1 jtc { "MAILCHECK", V_MAILCHECK }, 115 1.1 jtc { "MAILPATH", V_MAILPATH }, 116 1.1 jtc { "RANDOM", V_RANDOM }, 117 1.1 jtc { "SECONDS", V_SECONDS }, 118 1.1 jtc { "TMOUT", V_TMOUT }, 119 1.1 jtc #endif /* KSH */ 120 1.6 hubertf { "LINENO", V_LINENO }, 121 1.1 jtc { (char *) 0, 0 } 122 1.1 jtc }; 123 1.1 jtc int i; 124 1.1 jtc struct tbl *tp; 125 1.1 jtc 126 1.6 hubertf tinit(&specials, APERM, 32); /* must be 2^n (currently 17 specials) */ 127 1.1 jtc for (i = 0; names[i].name; i++) { 128 1.1 jtc tp = tenter(&specials, names[i].name, hash(names[i].name)); 129 1.1 jtc tp->flag = DEFINED|ISSET; 130 1.1 jtc tp->type = names[i].v; 131 1.1 jtc } 132 1.1 jtc } 133 1.1 jtc 134 1.1 jtc /* Used to calculate an array index for global()/local(). Sets *arrayp to 135 1.1 jtc * non-zero if this is an array, sets *valp to the array index, returns 136 1.1 jtc * the basename of the array. 137 1.1 jtc */ 138 1.20 kamil const char *array_index_calc(const char *n, bool *arrayp, int *valp); 139 1.9 mycroft 140 1.9 mycroft const char * 141 1.1 jtc array_index_calc(n, arrayp, valp) 142 1.1 jtc const char *n; 143 1.20 kamil bool *arrayp; 144 1.1 jtc int *valp; 145 1.1 jtc { 146 1.1 jtc const char *p; 147 1.1 jtc int len; 148 1.1 jtc 149 1.20 kamil *arrayp = false; 150 1.20 kamil p = skip_varname(n, false); 151 1.1 jtc if (p != n && *p == '[' && (len = array_ref_len(p))) { 152 1.1 jtc char *sub, *tmp; 153 1.1 jtc long rval; 154 1.1 jtc 155 1.1 jtc /* Calculate the value of the subscript */ 156 1.20 kamil *arrayp = true; 157 1.1 jtc tmp = str_nsave(p+1, len-2, ATEMP); 158 1.1 jtc sub = substitute(tmp, 0); 159 1.1 jtc afree(tmp, ATEMP); 160 1.1 jtc n = str_nsave(n, p - n, ATEMP); 161 1.6 hubertf evaluate(sub, &rval, KSH_UNWIND_ERROR); 162 1.1 jtc if (rval < 0 || rval > ARRAYMAX) 163 1.1 jtc errorf("%s: subscript out of range", n); 164 1.1 jtc *valp = rval; 165 1.1 jtc afree(sub, ATEMP); 166 1.1 jtc } 167 1.1 jtc return n; 168 1.1 jtc } 169 1.1 jtc 170 1.1 jtc /* 171 1.1 jtc * Search for variable, if not found create globally. 172 1.1 jtc */ 173 1.1 jtc struct tbl * 174 1.1 jtc global(n) 175 1.24 kamil const char *n; 176 1.1 jtc { 177 1.24 kamil struct block *l = e->loc; 178 1.24 kamil struct tbl *vp; 179 1.24 kamil int c; 180 1.9 mycroft unsigned h; 181 1.20 kamil bool array; 182 1.1 jtc int val; 183 1.1 jtc 184 1.1 jtc /* Check to see if this is an array */ 185 1.1 jtc n = array_index_calc(n, &array, &val); 186 1.1 jtc h = hash(n); 187 1.1 jtc c = n[0]; 188 1.1 jtc if (!letter(c)) { 189 1.1 jtc if (array) 190 1.1 jtc errorf("bad substitution"); 191 1.1 jtc vp = &vtemp; 192 1.6 hubertf vp->flag = DEFINED; 193 1.1 jtc vp->type = 0; 194 1.1 jtc vp->areap = ATEMP; 195 1.1 jtc *vp->name = c; 196 1.1 jtc if (digit(c)) { 197 1.1 jtc for (c = 0; digit(*n); n++) 198 1.1 jtc c = c*10 + *n-'0'; 199 1.1 jtc if (c <= l->argc) 200 1.6 hubertf /* setstr can't fail here */ 201 1.6 hubertf setstr(vp, l->argv[c], KSH_RETURN_ERROR); 202 1.6 hubertf vp->flag |= RDONLY; 203 1.1 jtc return vp; 204 1.1 jtc } 205 1.6 hubertf vp->flag |= RDONLY; 206 1.1 jtc if (n[1] != '\0') 207 1.1 jtc return vp; 208 1.1 jtc vp->flag |= ISSET|INTEGER; 209 1.1 jtc switch (c) { 210 1.1 jtc case '$': 211 1.1 jtc vp->val.i = kshpid; 212 1.1 jtc break; 213 1.1 jtc case '!': 214 1.1 jtc /* If no job, expand to nothing */ 215 1.1 jtc if ((vp->val.i = j_async()) == 0) 216 1.1 jtc vp->flag &= ~(ISSET|INTEGER); 217 1.1 jtc break; 218 1.1 jtc case '?': 219 1.1 jtc vp->val.i = exstat; 220 1.1 jtc break; 221 1.1 jtc case '#': 222 1.1 jtc vp->val.i = l->argc; 223 1.1 jtc break; 224 1.1 jtc case '-': 225 1.1 jtc vp->flag &= ~INTEGER; 226 1.1 jtc vp->val.s = getoptions(); 227 1.1 jtc break; 228 1.1 jtc default: 229 1.1 jtc vp->flag &= ~(ISSET|INTEGER); 230 1.1 jtc } 231 1.1 jtc return vp; 232 1.1 jtc } 233 1.1 jtc for (l = e->loc; ; l = l->next) { 234 1.23 kamil vp = mytsearch(&l->vars, n, h); 235 1.4 thorpej if (vp != NULL) { 236 1.1 jtc if (array) 237 1.1 jtc return arraysearch(vp, val); 238 1.1 jtc else 239 1.1 jtc return vp; 240 1.4 thorpej } 241 1.1 jtc if (l->next == NULL) 242 1.1 jtc break; 243 1.1 jtc } 244 1.1 jtc vp = tenter(&l->vars, n, h); 245 1.1 jtc if (array) 246 1.1 jtc vp = arraysearch(vp, val); 247 1.1 jtc vp->flag |= DEFINED; 248 1.1 jtc if (special(n)) 249 1.1 jtc vp->flag |= SPECIAL; 250 1.1 jtc return vp; 251 1.1 jtc } 252 1.1 jtc 253 1.1 jtc /* 254 1.1 jtc * Search for local variable, if not found create locally. 255 1.1 jtc */ 256 1.1 jtc struct tbl * 257 1.21 joerg local(const char *n, bool copy) 258 1.1 jtc { 259 1.24 kamil struct block *l = e->loc; 260 1.24 kamil struct tbl *vp; 261 1.1 jtc unsigned h; 262 1.20 kamil bool array; 263 1.1 jtc int val; 264 1.1 jtc 265 1.1 jtc /* Check to see if this is an array */ 266 1.1 jtc n = array_index_calc(n, &array, &val); 267 1.1 jtc h = hash(n); 268 1.1 jtc if (!letter(*n)) { 269 1.1 jtc vp = &vtemp; 270 1.1 jtc vp->flag = DEFINED|RDONLY; 271 1.1 jtc vp->type = 0; 272 1.1 jtc vp->areap = ATEMP; 273 1.1 jtc return vp; 274 1.1 jtc } 275 1.1 jtc vp = tenter(&l->vars, n, h); 276 1.1 jtc if (copy && !(vp->flag & DEFINED)) { 277 1.1 jtc struct block *ll = l; 278 1.1 jtc struct tbl *vq = (struct tbl *) 0; 279 1.1 jtc 280 1.23 kamil while ((ll = ll->next) && !(vq = mytsearch(&ll->vars, n, h))) 281 1.1 jtc ; 282 1.1 jtc if (vq) { 283 1.1 jtc vp->flag |= vq->flag & (EXPORT|INTEGER|RDONLY 284 1.1 jtc |LJUST|RJUST|ZEROFIL 285 1.1 jtc |LCASEV|UCASEV_AL|INT_U|INT_L); 286 1.1 jtc if (vq->flag & INTEGER) 287 1.1 jtc vp->type = vq->type; 288 1.1 jtc vp->u2.field = vq->u2.field; 289 1.1 jtc } 290 1.1 jtc } 291 1.1 jtc if (array) 292 1.1 jtc vp = arraysearch(vp, val); 293 1.1 jtc vp->flag |= DEFINED; 294 1.1 jtc if (special(n)) 295 1.1 jtc vp->flag |= SPECIAL; 296 1.1 jtc return vp; 297 1.1 jtc } 298 1.1 jtc 299 1.1 jtc /* get variable string value */ 300 1.1 jtc char * 301 1.1 jtc str_val(vp) 302 1.24 kamil struct tbl *vp; 303 1.1 jtc { 304 1.1 jtc char *s; 305 1.1 jtc 306 1.1 jtc if ((vp->flag&SPECIAL)) 307 1.1 jtc getspec(vp); 308 1.1 jtc if (!(vp->flag&ISSET)) 309 1.1 jtc s = null; /* special to dollar() */ 310 1.1 jtc else if (!(vp->flag&INTEGER)) /* string source */ 311 1.1 jtc s = vp->val.s + vp->type; 312 1.1 jtc else { /* integer source */ 313 1.1 jtc /* worst case number length is when base=2, so use BITS(long) */ 314 1.1 jtc /* minus base # number null */ 315 1.1 jtc static char strbuf[1 + 2 + 1 + BITS(long) + 1]; 316 1.1 jtc const char *digits = (vp->flag & UCASEV_AL) ? 317 1.1 jtc "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 318 1.1 jtc : "0123456789abcdefghijklmnopqrstuvwxyz"; 319 1.24 kamil unsigned long n; 320 1.24 kamil int base; 321 1.1 jtc 322 1.1 jtc s = strbuf + sizeof(strbuf); 323 1.1 jtc if (vp->flag & INT_U) 324 1.1 jtc n = (unsigned long) vp->val.i; 325 1.1 jtc else 326 1.1 jtc n = (vp->val.i < 0) ? -vp->val.i : vp->val.i; 327 1.1 jtc base = (vp->type == 0) ? 10 : vp->type; 328 1.1 jtc 329 1.1 jtc *--s = '\0'; 330 1.1 jtc do { 331 1.1 jtc *--s = digits[n % base]; 332 1.1 jtc n /= base; 333 1.1 jtc } while (n != 0); 334 1.1 jtc if (base != 10) { 335 1.1 jtc *--s = '#'; 336 1.1 jtc *--s = digits[base % 10]; 337 1.1 jtc if (base >= 10) 338 1.1 jtc *--s = digits[base / 10]; 339 1.1 jtc } 340 1.1 jtc if (!(vp->flag & INT_U) && vp->val.i < 0) 341 1.1 jtc *--s = '-'; 342 1.14 christos if (vp->flag & (RJUST|LJUST)) { /* case already dealt with */ 343 1.1 jtc s = formatstr(vp, s); 344 1.14 christos (void)strlcpy(strbuf, s, sizeof(strbuf)); 345 1.14 christos afree(s, ATEMP); 346 1.14 christos s = strbuf; 347 1.14 christos } 348 1.1 jtc } 349 1.1 jtc return s; 350 1.1 jtc } 351 1.1 jtc 352 1.1 jtc /* get variable integer value, with error checking */ 353 1.1 jtc long 354 1.1 jtc intval(vp) 355 1.24 kamil struct tbl *vp; 356 1.1 jtc { 357 1.1 jtc long num; 358 1.1 jtc int base; 359 1.1 jtc 360 1.1 jtc base = getint(vp, &num); 361 1.1 jtc if (base == -1) 362 1.1 jtc /* XXX check calls - is error here ok by POSIX? */ 363 1.1 jtc errorf("%s: bad number", str_val(vp)); 364 1.1 jtc return num; 365 1.1 jtc } 366 1.1 jtc 367 1.1 jtc /* set variable to string value */ 368 1.6 hubertf int 369 1.6 hubertf setstr(vq, s, error_ok) 370 1.24 kamil struct tbl *vq; 371 1.1 jtc const char *s; 372 1.6 hubertf int error_ok; 373 1.1 jtc { 374 1.13 christos char *fs = NULL; 375 1.7 christos int no_ro_check = error_ok & 0x4; 376 1.7 christos error_ok &= ~0x4; 377 1.7 christos if ((vq->flag & RDONLY) && !no_ro_check) { 378 1.20 kamil warningf(true, "%s: is read only", vq->name); 379 1.6 hubertf if (!error_ok) 380 1.17 joerg errorf("%s", null); 381 1.6 hubertf return 0; 382 1.6 hubertf } 383 1.1 jtc if (!(vq->flag&INTEGER)) { /* string dest */ 384 1.1 jtc if ((vq->flag&ALLOC)) { 385 1.1 jtc /* debugging */ 386 1.1 jtc if (s >= vq->val.s 387 1.1 jtc && s <= vq->val.s + strlen(vq->val.s)) 388 1.20 kamil internal_errorf(true, 389 1.1 jtc "setstr: %s=%s: assigning to self", 390 1.1 jtc vq->name, s); 391 1.1 jtc afree((void*)vq->val.s, vq->areap); 392 1.1 jtc } 393 1.1 jtc vq->flag &= ~(ISSET|ALLOC); 394 1.1 jtc vq->type = 0; 395 1.1 jtc if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) 396 1.13 christos s = fs = formatstr(vq, s); 397 1.1 jtc if ((vq->flag&EXPORT)) 398 1.1 jtc export(vq, s); 399 1.1 jtc else { 400 1.1 jtc vq->val.s = str_save(s, vq->areap); 401 1.9 mycroft vq->flag |= ALLOC; 402 1.1 jtc } 403 1.1 jtc } else /* integer dest */ 404 1.6 hubertf if (!v_evaluate(vq, s, error_ok)) 405 1.6 hubertf return 0; 406 1.1 jtc vq->flag |= ISSET; 407 1.1 jtc if ((vq->flag&SPECIAL)) 408 1.1 jtc setspec(vq); 409 1.13 christos if (fs) 410 1.13 christos afree(fs, ATEMP); 411 1.6 hubertf return 1; 412 1.1 jtc } 413 1.1 jtc 414 1.1 jtc /* set variable to integer */ 415 1.1 jtc void 416 1.1 jtc setint(vq, n) 417 1.24 kamil struct tbl *vq; 418 1.1 jtc long n; 419 1.1 jtc { 420 1.1 jtc if (!(vq->flag&INTEGER)) { 421 1.24 kamil struct tbl *vp = &vtemp; 422 1.1 jtc vp->flag = (ISSET|INTEGER); 423 1.1 jtc vp->type = 0; 424 1.1 jtc vp->areap = ATEMP; 425 1.1 jtc vp->val.i = n; 426 1.6 hubertf /* setstr can't fail here */ 427 1.6 hubertf setstr(vq, str_val(vp), KSH_RETURN_ERROR); 428 1.1 jtc } else 429 1.1 jtc vq->val.i = n; 430 1.1 jtc vq->flag |= ISSET; 431 1.1 jtc if ((vq->flag&SPECIAL)) 432 1.1 jtc setspec(vq); 433 1.1 jtc } 434 1.1 jtc 435 1.1 jtc int 436 1.1 jtc getint(vp, nump) 437 1.1 jtc struct tbl *vp; 438 1.1 jtc long *nump; 439 1.1 jtc { 440 1.24 kamil char *s; 441 1.24 kamil int c; 442 1.1 jtc int base, neg; 443 1.1 jtc int have_base = 0; 444 1.1 jtc long num; 445 1.9 mycroft 446 1.1 jtc if (vp->flag&SPECIAL) 447 1.1 jtc getspec(vp); 448 1.1 jtc /* XXX is it possible for ISSET to be set and val.s to be 0? */ 449 1.1 jtc if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL)) 450 1.1 jtc return -1; 451 1.1 jtc if (vp->flag&INTEGER) { 452 1.1 jtc *nump = vp->val.i; 453 1.1 jtc return vp->type; 454 1.1 jtc } 455 1.1 jtc s = vp->val.s + vp->type; 456 1.9 mycroft if (s == NULL) /* redundant given initial test */ 457 1.1 jtc s = null; 458 1.1 jtc base = 10; 459 1.1 jtc num = 0; 460 1.1 jtc neg = 0; 461 1.15 dsl if (*s == '-') { 462 1.15 dsl neg = 1; 463 1.15 dsl s++; 464 1.15 dsl } 465 1.15 dsl if (s[0] == '0' && s[1] == 'x') { 466 1.15 dsl base = 16; 467 1.15 dsl have_base = 1; 468 1.15 dsl s += 2; 469 1.15 dsl } 470 1.11 rillig for (c = (unsigned char)*s++; c ; c = (unsigned char)*s++) { 471 1.15 dsl if (c == '#') { 472 1.1 jtc base = (int) num; 473 1.1 jtc if (have_base || base < 2 || base > 36) 474 1.1 jtc return -1; 475 1.1 jtc num = 0; 476 1.1 jtc have_base = 1; 477 1.1 jtc } else if (letnum(c)) { 478 1.1 jtc if (isdigit(c)) 479 1.1 jtc c -= '0'; 480 1.1 jtc else if (islower(c)) 481 1.1 jtc c -= 'a' - 10; /* todo: assumes ascii */ 482 1.1 jtc else if (isupper(c)) 483 1.1 jtc c -= 'A' - 10; /* todo: assumes ascii */ 484 1.1 jtc else 485 1.1 jtc c = -1; /* _: force error */ 486 1.1 jtc if (c < 0 || c >= base) 487 1.1 jtc return -1; 488 1.1 jtc num = num * base + c; 489 1.1 jtc } else 490 1.1 jtc return -1; 491 1.1 jtc } 492 1.1 jtc if (neg) 493 1.1 jtc num = -num; 494 1.1 jtc *nump = num; 495 1.1 jtc return base; 496 1.1 jtc } 497 1.1 jtc 498 1.1 jtc /* convert variable vq to integer variable, setting its value from vp 499 1.1 jtc * (vq and vp may be the same) 500 1.1 jtc */ 501 1.1 jtc struct tbl * 502 1.1 jtc setint_v(vq, vp) 503 1.24 kamil struct tbl *vq, *vp; 504 1.1 jtc { 505 1.1 jtc int base; 506 1.1 jtc long num; 507 1.9 mycroft 508 1.1 jtc if ((base = getint(vp, &num)) == -1) 509 1.1 jtc return NULL; 510 1.1 jtc if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) { 511 1.1 jtc vq->flag &= ~ALLOC; 512 1.1 jtc afree(vq->val.s, vq->areap); 513 1.1 jtc } 514 1.1 jtc vq->val.i = num; 515 1.1 jtc if (vq->type == 0) /* default base */ 516 1.1 jtc vq->type = base; 517 1.1 jtc vq->flag |= ISSET|INTEGER; 518 1.1 jtc if (vq->flag&SPECIAL) 519 1.1 jtc setspec(vq); 520 1.1 jtc return vq; 521 1.1 jtc } 522 1.1 jtc 523 1.1 jtc static char * 524 1.1 jtc formatstr(vp, s) 525 1.1 jtc struct tbl *vp; 526 1.1 jtc const char *s; 527 1.1 jtc { 528 1.1 jtc int olen, nlen; 529 1.1 jtc char *p, *q; 530 1.1 jtc 531 1.1 jtc olen = strlen(s); 532 1.1 jtc 533 1.1 jtc if (vp->flag & (RJUST|LJUST)) { 534 1.1 jtc if (!vp->u2.field) /* default field width */ 535 1.1 jtc vp->u2.field = olen; 536 1.1 jtc nlen = vp->u2.field; 537 1.1 jtc } else 538 1.1 jtc nlen = olen; 539 1.1 jtc 540 1.1 jtc p = (char *) alloc(nlen + 1, ATEMP); 541 1.1 jtc if (vp->flag & (RJUST|LJUST)) { 542 1.1 jtc int slen; 543 1.1 jtc 544 1.1 jtc if (vp->flag & RJUST) { 545 1.12 christos const char *r = s + olen; 546 1.1 jtc /* strip trailing spaces (at&t ksh uses q[-1] == ' ') */ 547 1.12 christos while (r > s && isspace((unsigned char)r[-1])) 548 1.12 christos --r; 549 1.12 christos slen = r - s; 550 1.1 jtc if (slen > vp->u2.field) { 551 1.1 jtc s += slen - vp->u2.field; 552 1.1 jtc slen = vp->u2.field; 553 1.1 jtc } 554 1.1 jtc shf_snprintf(p, nlen + 1, 555 1.1 jtc ((vp->flag & ZEROFIL) && digit(*s)) ? 556 1.1 jtc "%0*s%.*s" : "%*s%.*s", 557 1.1 jtc vp->u2.field - slen, null, slen, s); 558 1.1 jtc } else { 559 1.1 jtc /* strip leading spaces/zeros */ 560 1.5 christos while (isspace((unsigned char)*s)) 561 1.1 jtc s++; 562 1.1 jtc if (vp->flag & ZEROFIL) 563 1.1 jtc while (*s == '0') 564 1.1 jtc s++; 565 1.1 jtc shf_snprintf(p, nlen + 1, "%-*.*s", 566 1.1 jtc vp->u2.field, vp->u2.field, s); 567 1.1 jtc } 568 1.1 jtc } else 569 1.1 jtc memcpy(p, s, olen + 1); 570 1.1 jtc 571 1.1 jtc if (vp->flag & UCASEV_AL) { 572 1.1 jtc for (q = p; *q; q++) 573 1.5 christos if (islower((unsigned char)*q)) 574 1.10 dsl *q = toupper((unsigned char)*q); 575 1.1 jtc } else if (vp->flag & LCASEV) { 576 1.1 jtc for (q = p; *q; q++) 577 1.5 christos if (isupper((unsigned char)*q)) 578 1.10 dsl *q = tolower((unsigned char)*q); 579 1.1 jtc } 580 1.1 jtc 581 1.1 jtc return p; 582 1.1 jtc } 583 1.1 jtc 584 1.1 jtc /* 585 1.1 jtc * make vp->val.s be "name=value" for quick exporting. 586 1.1 jtc */ 587 1.1 jtc static void 588 1.1 jtc export(vp, val) 589 1.24 kamil struct tbl *vp; 590 1.1 jtc const char *val; 591 1.1 jtc { 592 1.24 kamil char *xp; 593 1.1 jtc char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; 594 1.1 jtc int namelen = strlen(vp->name); 595 1.1 jtc int vallen = strlen(val) + 1; 596 1.1 jtc 597 1.1 jtc vp->flag |= ALLOC; 598 1.1 jtc xp = (char*)alloc(namelen + 1 + vallen, vp->areap); 599 1.1 jtc memcpy(vp->val.s = xp, vp->name, namelen); 600 1.1 jtc xp += namelen; 601 1.1 jtc *xp++ = '='; 602 1.1 jtc vp->type = xp - vp->val.s; /* offset to value */ 603 1.1 jtc memcpy(xp, val, vallen); 604 1.1 jtc if (op != NULL) 605 1.1 jtc afree((void*)op, vp->areap); 606 1.1 jtc } 607 1.1 jtc 608 1.1 jtc /* 609 1.1 jtc * lookup variable (according to (set&LOCAL)), 610 1.1 jtc * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, 611 1.1 jtc * LCASEV, UCASEV_AL), and optionally set its value if an assignment. 612 1.1 jtc */ 613 1.1 jtc struct tbl * 614 1.1 jtc typeset(var, set, clr, field, base) 615 1.24 kamil const char *var; 616 1.1 jtc Tflag clr, set; 617 1.1 jtc int field, base; 618 1.1 jtc { 619 1.24 kamil struct tbl *vp; 620 1.1 jtc struct tbl *vpbase, *t; 621 1.1 jtc char *tvar; 622 1.1 jtc const char *val; 623 1.1 jtc 624 1.1 jtc /* check for valid variable name, search for value */ 625 1.20 kamil val = skip_varname(var, false); 626 1.1 jtc if (val == var) 627 1.1 jtc return NULL; 628 1.1 jtc if (*val == '[') { 629 1.1 jtc int len; 630 1.9 mycroft 631 1.1 jtc len = array_ref_len(val); 632 1.1 jtc if (len == 0) 633 1.1 jtc return NULL; 634 1.1 jtc /* IMPORT is only used when the shell starts up and is 635 1.1 jtc * setting up its environment. Allow only simple array 636 1.1 jtc * references at this time since parameter/command substitution 637 1.16 reed * is performed on the [expression], which would be a major 638 1.1 jtc * security hole. 639 1.1 jtc */ 640 1.1 jtc if (set & IMPORT) { 641 1.1 jtc int i; 642 1.1 jtc for (i = 1; i < len - 1; i++) 643 1.1 jtc if (!digit(val[i])) 644 1.1 jtc return NULL; 645 1.1 jtc } 646 1.1 jtc val += len; 647 1.1 jtc } 648 1.1 jtc if (*val == '=') 649 1.1 jtc tvar = str_nsave(var, val++ - var, ATEMP); 650 1.1 jtc else { 651 1.9 mycroft /* Importing from original environment: must have an = */ 652 1.1 jtc if (set & IMPORT) 653 1.1 jtc return NULL; 654 1.12 christos tvar = (char *) __UNCONST(var); 655 1.1 jtc val = NULL; 656 1.1 jtc } 657 1.1 jtc 658 1.1 jtc /* Prevent typeset from creating a local PATH/ENV/SHELL */ 659 1.1 jtc if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 660 1.1 jtc || strcmp(tvar, "ENV") == 0 661 1.1 jtc || strcmp(tvar, "SHELL") == 0)) 662 1.1 jtc errorf("%s: restricted", tvar); 663 1.1 jtc 664 1.20 kamil vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? true : false) 665 1.1 jtc : global(tvar); 666 1.1 jtc set &= ~(LOCAL|LOCAL_COPY); 667 1.1 jtc 668 1.1 jtc vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp; 669 1.1 jtc 670 1.1 jtc /* only allow export flag to be set. at&t ksh allows any attribute to 671 1.1 jtc * be changed, which means it can be truncated or modified 672 1.1 jtc * (-L/-R/-Z/-i). 673 1.1 jtc */ 674 1.1 jtc if ((vpbase->flag&RDONLY) 675 1.1 jtc && (val || clr || (set & ~EXPORT))) 676 1.1 jtc /* XXX check calls - is error here ok by POSIX? */ 677 1.1 jtc errorf("%s: is read only", tvar); 678 1.1 jtc if (val) 679 1.1 jtc afree(tvar, ATEMP); 680 1.1 jtc 681 1.1 jtc /* most calls are with set/clr == 0 */ 682 1.1 jtc if (set | clr) { 683 1.6 hubertf int ok = 1; 684 1.1 jtc /* XXX if x[0] isn't set, there will be problems: need to have 685 1.1 jtc * one copy of attributes for arrays... 686 1.1 jtc */ 687 1.1 jtc for (t = vpbase; t; t = t->u.array) { 688 1.1 jtc int fake_assign; 689 1.1 jtc char UNINITIALIZED(*s); 690 1.1 jtc char UNINITIALIZED(*free_me); 691 1.1 jtc 692 1.1 jtc fake_assign = (t->flag & ISSET) && (!val || t != vp) 693 1.1 jtc && ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) 694 1.1 jtc || ((t->flag & INTEGER) && (clr & INTEGER)) 695 1.1 jtc || (!(t->flag & INTEGER) && (set & INTEGER))); 696 1.1 jtc if (fake_assign) { 697 1.1 jtc if (t->flag & INTEGER) { 698 1.1 jtc s = str_val(t); 699 1.1 jtc free_me = (char *) 0; 700 1.1 jtc } else { 701 1.1 jtc s = t->val.s + t->type; 702 1.1 jtc free_me = (t->flag & ALLOC) ? t->val.s 703 1.1 jtc : (char *) 0; 704 1.1 jtc } 705 1.1 jtc t->flag &= ~ALLOC; 706 1.1 jtc } 707 1.1 jtc if (!(t->flag & INTEGER) && (set & INTEGER)) { 708 1.1 jtc t->type = 0; 709 1.1 jtc t->flag &= ~ALLOC; 710 1.1 jtc } 711 1.1 jtc t->flag = (t->flag | set) & ~clr; 712 1.1 jtc /* Don't change base if assignment is to be done, 713 1.1 jtc * in case assignment fails. 714 1.1 jtc */ 715 1.1 jtc if ((set & INTEGER) && base > 0 && (!val || t != vp)) 716 1.1 jtc t->type = base; 717 1.1 jtc if (set & (LJUST|RJUST|ZEROFIL)) 718 1.1 jtc t->u2.field = field; 719 1.1 jtc if (fake_assign) { 720 1.6 hubertf if (!setstr(t, s, KSH_RETURN_ERROR)) { 721 1.6 hubertf /* Somewhat arbitrary action here: 722 1.9 mycroft * zap contents of variable, but keep 723 1.6 hubertf * the flag settings. 724 1.6 hubertf */ 725 1.6 hubertf ok = 0; 726 1.6 hubertf if (t->flag & INTEGER) 727 1.6 hubertf t->flag &= ~ISSET; 728 1.6 hubertf else { 729 1.6 hubertf if (t->flag & ALLOC) 730 1.6 hubertf afree((void*) t->val.s, 731 1.6 hubertf t->areap); 732 1.6 hubertf t->flag &= ~(ISSET|ALLOC); 733 1.6 hubertf t->type = 0; 734 1.6 hubertf } 735 1.6 hubertf } 736 1.1 jtc if (free_me) 737 1.1 jtc afree((void *) free_me, t->areap); 738 1.1 jtc } 739 1.1 jtc } 740 1.6 hubertf if (!ok) 741 1.17 joerg errorf("%s", null); 742 1.1 jtc } 743 1.1 jtc 744 1.1 jtc if (val != NULL) { 745 1.1 jtc if (vp->flag&INTEGER) { 746 1.1 jtc /* do not zero base before assignment */ 747 1.7 christos setstr(vp, val, KSH_UNWIND_ERROR | 0x4); 748 1.1 jtc /* Done after assignment to override default */ 749 1.1 jtc if (base > 0) 750 1.1 jtc vp->type = base; 751 1.1 jtc } else 752 1.6 hubertf /* setstr can't fail (readonly check already done) */ 753 1.7 christos setstr(vp, val, KSH_RETURN_ERROR | 0x4); 754 1.1 jtc } 755 1.1 jtc 756 1.1 jtc /* only x[0] is ever exported, so use vpbase */ 757 1.1 jtc if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) 758 1.1 jtc && vpbase->type == 0) 759 1.1 jtc export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null); 760 1.1 jtc 761 1.1 jtc return vp; 762 1.1 jtc } 763 1.1 jtc 764 1.1 jtc /* Unset a variable. array_ref is set if there was an array reference in 765 1.1 jtc * the name lookup (eg, x[2]). 766 1.1 jtc */ 767 1.1 jtc void 768 1.1 jtc unset(vp, array_ref) 769 1.24 kamil struct tbl *vp; 770 1.1 jtc int array_ref; 771 1.1 jtc { 772 1.1 jtc if (vp->flag & ALLOC) 773 1.1 jtc afree((void*)vp->val.s, vp->areap); 774 1.1 jtc if ((vp->flag & ARRAY) && !array_ref) { 775 1.1 jtc struct tbl *a, *tmp; 776 1.1 jtc 777 1.1 jtc /* Free up entire array */ 778 1.1 jtc for (a = vp->u.array; a; ) { 779 1.1 jtc tmp = a; 780 1.1 jtc a = a->u.array; 781 1.1 jtc if (tmp->flag & ALLOC) 782 1.1 jtc afree((void *) tmp->val.s, tmp->areap); 783 1.1 jtc afree(tmp, tmp->areap); 784 1.1 jtc } 785 1.1 jtc vp->u.array = (struct tbl *) 0; 786 1.1 jtc } 787 1.1 jtc /* If foo[0] is being unset, the remainder of the array is kept... */ 788 1.1 jtc vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0); 789 1.1 jtc if (vp->flag & SPECIAL) 790 1.1 jtc unsetspec(vp); /* responsible for `unspecial'ing var */ 791 1.1 jtc } 792 1.1 jtc 793 1.1 jtc /* return a pointer to the first char past a legal variable name (returns the 794 1.1 jtc * argument if there is no legal name, returns * a pointer to the terminating 795 1.1 jtc * null if whole string is legal). 796 1.1 jtc */ 797 1.1 jtc char * 798 1.1 jtc skip_varname(s, aok) 799 1.1 jtc const char *s; 800 1.1 jtc int aok; 801 1.1 jtc { 802 1.1 jtc int alen; 803 1.1 jtc 804 1.1 jtc if (s && letter(*s)) { 805 1.1 jtc while (*++s && letnum(*s)) 806 1.1 jtc ; 807 1.1 jtc if (aok && *s == '[' && (alen = array_ref_len(s))) 808 1.1 jtc s += alen; 809 1.1 jtc } 810 1.12 christos return (char *) __UNCONST(s); 811 1.1 jtc } 812 1.1 jtc 813 1.1 jtc /* Return a pointer to the first character past any legal variable name. */ 814 1.1 jtc char * 815 1.1 jtc skip_wdvarname(s, aok) 816 1.1 jtc const char *s; 817 1.1 jtc int aok; /* skip array de-reference? */ 818 1.1 jtc { 819 1.1 jtc if (s[0] == CHAR && letter(s[1])) { 820 1.1 jtc do 821 1.1 jtc s += 2; 822 1.1 jtc while (s[0] == CHAR && letnum(s[1])); 823 1.2 tls if (aok && s[0] == CHAR && s[1] == '[') { 824 1.1 jtc /* skip possible array de-reference */ 825 1.1 jtc const char *p = s; 826 1.1 jtc char c; 827 1.1 jtc int depth = 0; 828 1.1 jtc 829 1.1 jtc while (1) { 830 1.1 jtc if (p[0] != CHAR) 831 1.1 jtc break; 832 1.1 jtc c = p[1]; 833 1.1 jtc p += 2; 834 1.1 jtc if (c == '[') 835 1.1 jtc depth++; 836 1.1 jtc else if (c == ']' && --depth == 0) { 837 1.1 jtc s = p; 838 1.1 jtc break; 839 1.1 jtc } 840 1.1 jtc } 841 1.1 jtc } 842 1.1 jtc } 843 1.12 christos return (char *) __UNCONST(s); 844 1.1 jtc } 845 1.1 jtc 846 1.1 jtc /* Check if coded string s is a variable name */ 847 1.1 jtc int 848 1.1 jtc is_wdvarname(s, aok) 849 1.1 jtc const char *s; 850 1.1 jtc int aok; 851 1.1 jtc { 852 1.1 jtc char *p = skip_wdvarname(s, aok); 853 1.1 jtc 854 1.1 jtc return p != s && p[0] == EOS; 855 1.1 jtc } 856 1.1 jtc 857 1.1 jtc /* Check if coded string s is a variable assignment */ 858 1.1 jtc int 859 1.1 jtc is_wdvarassign(s) 860 1.1 jtc const char *s; 861 1.1 jtc { 862 1.20 kamil char *p = skip_wdvarname(s, true); 863 1.1 jtc 864 1.1 jtc return p != s && p[0] == CHAR && p[1] == '='; 865 1.1 jtc } 866 1.1 jtc 867 1.1 jtc /* 868 1.1 jtc * Make the exported environment from the exported names in the dictionary. 869 1.1 jtc */ 870 1.1 jtc char ** 871 1.1 jtc makenv() 872 1.1 jtc { 873 1.1 jtc struct block *l = e->loc; 874 1.1 jtc XPtrV env; 875 1.24 kamil struct tbl *vp, **vpp; 876 1.24 kamil int i; 877 1.1 jtc 878 1.1 jtc XPinit(env, 64); 879 1.1 jtc for (l = e->loc; l != NULL; l = l->next) 880 1.1 jtc for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; ) 881 1.1 jtc if ((vp = *vpp++) != NULL 882 1.1 jtc && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { 883 1.24 kamil struct block *l2; 884 1.24 kamil struct tbl *vp2; 885 1.1 jtc unsigned h = hash(vp->name); 886 1.1 jtc 887 1.1 jtc /* unexport any redefined instances */ 888 1.1 jtc for (l2 = l->next; l2 != NULL; l2 = l2->next) { 889 1.23 kamil vp2 = mytsearch(&l2->vars, vp->name, h); 890 1.1 jtc if (vp2 != NULL) 891 1.1 jtc vp2->flag &= ~EXPORT; 892 1.1 jtc } 893 1.1 jtc if ((vp->flag&INTEGER)) { 894 1.1 jtc /* integer to string */ 895 1.1 jtc char *val; 896 1.1 jtc val = str_val(vp); 897 1.6 hubertf vp->flag &= ~(INTEGER|RDONLY); 898 1.6 hubertf /* setstr can't fail here */ 899 1.6 hubertf setstr(vp, val, KSH_RETURN_ERROR); 900 1.1 jtc } 901 1.1 jtc XPput(env, vp->val.s); 902 1.1 jtc } 903 1.1 jtc XPput(env, NULL); 904 1.1 jtc return (char **) XPclose(env); 905 1.1 jtc } 906 1.1 jtc 907 1.1 jtc /* 908 1.6 hubertf * Called after a fork in parent to bump the random number generator. 909 1.6 hubertf * Done to ensure children will not get the same random number sequence 910 1.6 hubertf * if the parent doesn't use $RANDOM. 911 1.6 hubertf */ 912 1.6 hubertf void 913 1.6 hubertf change_random() 914 1.6 hubertf { 915 1.6 hubertf rand(); 916 1.6 hubertf } 917 1.6 hubertf 918 1.6 hubertf /* 919 1.1 jtc * handle special variables with side effects - PATH, SECONDS. 920 1.1 jtc */ 921 1.1 jtc 922 1.1 jtc /* Test if name is a special parameter */ 923 1.1 jtc static int 924 1.1 jtc special(name) 925 1.24 kamil const char * name; 926 1.1 jtc { 927 1.24 kamil struct tbl *tp; 928 1.1 jtc 929 1.23 kamil tp = mytsearch(&specials, name, hash(name)); 930 1.6 hubertf return tp && (tp->flag & ISSET) ? tp->type : V_NONE; 931 1.6 hubertf } 932 1.6 hubertf 933 1.6 hubertf /* Make a variable non-special */ 934 1.6 hubertf static void 935 1.6 hubertf unspecial(name) 936 1.24 kamil const char * name; 937 1.6 hubertf { 938 1.24 kamil struct tbl *tp; 939 1.6 hubertf 940 1.23 kamil tp = mytsearch(&specials, name, hash(name)); 941 1.6 hubertf if (tp) 942 1.22 kamil mytdelete(tp); 943 1.1 jtc } 944 1.1 jtc 945 1.1 jtc #ifdef KSH 946 1.1 jtc static time_t seconds; /* time SECONDS last set */ 947 1.1 jtc #endif /* KSH */ 948 1.6 hubertf static int user_lineno; /* what user set $LINENO to */ 949 1.1 jtc 950 1.1 jtc static void 951 1.1 jtc getspec(vp) 952 1.24 kamil struct tbl *vp; 953 1.1 jtc { 954 1.1 jtc switch (special(vp->name)) { 955 1.1 jtc #ifdef KSH 956 1.1 jtc case V_SECONDS: 957 1.1 jtc vp->flag &= ~SPECIAL; 958 1.6 hubertf /* On start up the value of SECONDS is used before seconds 959 1.6 hubertf * has been set - don't do anything in this case 960 1.6 hubertf * (see initcoms[] in main.c). 961 1.6 hubertf */ 962 1.6 hubertf if (vp->flag & ISSET) 963 1.6 hubertf setint(vp, (long) (time((time_t *)0) - seconds)); 964 1.1 jtc vp->flag |= SPECIAL; 965 1.1 jtc break; 966 1.1 jtc case V_RANDOM: 967 1.1 jtc vp->flag &= ~SPECIAL; 968 1.1 jtc setint(vp, (long) (rand() & 0x7fff)); 969 1.1 jtc vp->flag |= SPECIAL; 970 1.1 jtc break; 971 1.1 jtc #endif /* KSH */ 972 1.1 jtc #ifdef HISTORY 973 1.1 jtc case V_HISTSIZE: 974 1.1 jtc vp->flag &= ~SPECIAL; 975 1.1 jtc setint(vp, (long) histsize); 976 1.1 jtc vp->flag |= SPECIAL; 977 1.1 jtc break; 978 1.1 jtc #endif /* HISTORY */ 979 1.6 hubertf case V_OPTIND: 980 1.6 hubertf vp->flag &= ~SPECIAL; 981 1.6 hubertf setint(vp, (long) user_opt.uoptind); 982 1.6 hubertf vp->flag |= SPECIAL; 983 1.6 hubertf break; 984 1.6 hubertf case V_LINENO: 985 1.6 hubertf vp->flag &= ~SPECIAL; 986 1.6 hubertf setint(vp, (long) current_lineno + user_lineno); 987 1.6 hubertf vp->flag |= SPECIAL; 988 1.6 hubertf break; 989 1.1 jtc } 990 1.1 jtc } 991 1.1 jtc 992 1.1 jtc static void 993 1.1 jtc setspec(vp) 994 1.24 kamil struct tbl *vp; 995 1.1 jtc { 996 1.1 jtc char *s; 997 1.1 jtc 998 1.1 jtc switch (special(vp->name)) { 999 1.1 jtc case V_PATH: 1000 1.6 hubertf if (path) 1001 1.6 hubertf afree(path, APERM); 1002 1.6 hubertf path = str_save(str_val(vp), APERM); 1003 1.1 jtc flushcom(1); /* clear tracked aliases */ 1004 1.1 jtc break; 1005 1.1 jtc case V_IFS: 1006 1.1 jtc setctypes(s = str_val(vp), C_IFS); 1007 1.1 jtc ifs0 = *s; 1008 1.1 jtc break; 1009 1.1 jtc case V_OPTIND: 1010 1.6 hubertf vp->flag &= ~SPECIAL; 1011 1.1 jtc getopts_reset((int) intval(vp)); 1012 1.6 hubertf vp->flag |= SPECIAL; 1013 1.1 jtc break; 1014 1.1 jtc case V_POSIXLY_CORRECT: 1015 1.1 jtc change_flag(FPOSIX, OF_SPECIAL, 1); 1016 1.1 jtc break; 1017 1.1 jtc case V_TMPDIR: 1018 1.1 jtc if (tmpdir) { 1019 1.1 jtc afree(tmpdir, APERM); 1020 1.1 jtc tmpdir = (char *) 0; 1021 1.1 jtc } 1022 1.1 jtc /* Use tmpdir iff it is an absolute path, is writable and 1023 1.1 jtc * searchable and is a directory... 1024 1.1 jtc */ 1025 1.1 jtc { 1026 1.1 jtc struct stat statb; 1027 1.1 jtc s = str_val(vp); 1028 1.1 jtc if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0 1029 1.1 jtc && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode)) 1030 1.1 jtc tmpdir = str_save(s, APERM); 1031 1.1 jtc } 1032 1.1 jtc break; 1033 1.1 jtc #ifdef HISTORY 1034 1.1 jtc case V_HISTSIZE: 1035 1.1 jtc vp->flag &= ~SPECIAL; 1036 1.1 jtc sethistsize((int) intval(vp)); 1037 1.1 jtc vp->flag |= SPECIAL; 1038 1.1 jtc break; 1039 1.1 jtc case V_HISTFILE: 1040 1.1 jtc sethistfile(str_val(vp)); 1041 1.1 jtc break; 1042 1.1 jtc #endif /* HISTORY */ 1043 1.1 jtc #ifdef EDIT 1044 1.1 jtc case V_VISUAL: 1045 1.1 jtc set_editmode(str_val(vp)); 1046 1.1 jtc break; 1047 1.1 jtc case V_EDITOR: 1048 1.1 jtc if (!(global("VISUAL")->flag & ISSET)) 1049 1.1 jtc set_editmode(str_val(vp)); 1050 1.1 jtc break; 1051 1.1 jtc case V_COLUMNS: 1052 1.1 jtc if ((x_cols = intval(vp)) <= MIN_COLS) 1053 1.1 jtc x_cols = MIN_COLS; 1054 1.1 jtc break; 1055 1.1 jtc #endif /* EDIT */ 1056 1.1 jtc #ifdef KSH 1057 1.1 jtc case V_MAIL: 1058 1.1 jtc mbset(str_val(vp)); 1059 1.1 jtc break; 1060 1.1 jtc case V_MAILPATH: 1061 1.1 jtc mpset(str_val(vp)); 1062 1.1 jtc break; 1063 1.1 jtc case V_MAILCHECK: 1064 1.6 hubertf vp->flag &= ~SPECIAL; 1065 1.6 hubertf mcset(intval(vp)); 1066 1.6 hubertf vp->flag |= SPECIAL; 1067 1.1 jtc break; 1068 1.1 jtc case V_RANDOM: 1069 1.1 jtc vp->flag &= ~SPECIAL; 1070 1.1 jtc srand((unsigned int)intval(vp)); 1071 1.1 jtc vp->flag |= SPECIAL; 1072 1.1 jtc break; 1073 1.1 jtc case V_SECONDS: 1074 1.1 jtc vp->flag &= ~SPECIAL; 1075 1.1 jtc seconds = time((time_t*) 0) - intval(vp); 1076 1.1 jtc vp->flag |= SPECIAL; 1077 1.1 jtc break; 1078 1.1 jtc case V_TMOUT: 1079 1.1 jtc /* at&t ksh seems to do this (only listen if integer) */ 1080 1.1 jtc if (vp->flag & INTEGER) 1081 1.1 jtc ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0; 1082 1.1 jtc break; 1083 1.1 jtc #endif /* KSH */ 1084 1.6 hubertf case V_LINENO: 1085 1.6 hubertf vp->flag &= ~SPECIAL; 1086 1.6 hubertf /* The -1 is because line numbering starts at 1. */ 1087 1.6 hubertf user_lineno = (unsigned int) intval(vp) - current_lineno - 1; 1088 1.6 hubertf vp->flag |= SPECIAL; 1089 1.6 hubertf break; 1090 1.1 jtc } 1091 1.1 jtc } 1092 1.1 jtc 1093 1.1 jtc static void 1094 1.1 jtc unsetspec(vp) 1095 1.24 kamil struct tbl *vp; 1096 1.1 jtc { 1097 1.1 jtc switch (special(vp->name)) { 1098 1.1 jtc case V_PATH: 1099 1.6 hubertf if (path) 1100 1.6 hubertf afree(path, APERM); 1101 1.6 hubertf path = str_save(def_path, APERM); 1102 1.1 jtc flushcom(1); /* clear tracked aliases */ 1103 1.1 jtc break; 1104 1.1 jtc case V_IFS: 1105 1.1 jtc setctypes(" \t\n", C_IFS); 1106 1.1 jtc ifs0 = ' '; 1107 1.1 jtc break; 1108 1.1 jtc case V_TMPDIR: 1109 1.1 jtc /* should not become unspecial */ 1110 1.1 jtc if (tmpdir) { 1111 1.1 jtc afree(tmpdir, APERM); 1112 1.1 jtc tmpdir = (char *) 0; 1113 1.1 jtc } 1114 1.1 jtc break; 1115 1.1 jtc #ifdef KSH 1116 1.1 jtc case V_MAIL: 1117 1.1 jtc mbset((char *) 0); 1118 1.1 jtc break; 1119 1.1 jtc case V_MAILPATH: 1120 1.1 jtc mpset((char *) 0); 1121 1.1 jtc break; 1122 1.6 hubertf #endif /* KSH */ 1123 1.6 hubertf 1124 1.6 hubertf case V_LINENO: 1125 1.6 hubertf #ifdef KSH 1126 1.6 hubertf case V_MAILCHECK: /* at&t ksh leaves previous value in place */ 1127 1.6 hubertf case V_RANDOM: 1128 1.6 hubertf case V_SECONDS: 1129 1.6 hubertf case V_TMOUT: /* at&t ksh leaves previous value in place */ 1130 1.6 hubertf #endif /* KSH */ 1131 1.6 hubertf unspecial(vp->name); 1132 1.1 jtc break; 1133 1.6 hubertf 1134 1.6 hubertf /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning, 1135 1.6 hubertf * but OPTARG does not (still set by getopts) and _ is also still 1136 1.6 hubertf * set in various places. 1137 1.6 hubertf * Don't know what at&t does for: 1138 1.6 hubertf * MAIL, MAILPATH, HISTSIZE, HISTFILE, 1139 1.25 andvar * Unsetting these in at&t ksh does not lose the `specialness': 1140 1.1 jtc * no effect: IFS, COLUMNS, PATH, TMPDIR, 1141 1.1 jtc * VISUAL, EDITOR, 1142 1.6 hubertf * pdkshisms: no effect: 1143 1.1 jtc * POSIXLY_CORRECT (use set +o posix instead) 1144 1.1 jtc */ 1145 1.1 jtc } 1146 1.1 jtc } 1147 1.1 jtc 1148 1.1 jtc /* 1149 1.1 jtc * Search for (and possibly create) a table entry starting with 1150 1.1 jtc * vp, indexed by val. 1151 1.1 jtc */ 1152 1.1 jtc static struct tbl * 1153 1.1 jtc arraysearch(vp, val) 1154 1.1 jtc struct tbl *vp; 1155 1.1 jtc int val; 1156 1.1 jtc { 1157 1.1 jtc struct tbl *prev, *curr, *new; 1158 1.9 mycroft size_t namelen = strlen(vp->name) + 1; 1159 1.1 jtc 1160 1.1 jtc vp->flag |= ARRAY|DEFINED; 1161 1.1 jtc 1162 1.1 jtc /* The table entry is always [0] */ 1163 1.1 jtc if (val == 0) { 1164 1.1 jtc vp->index = 0; 1165 1.1 jtc return vp; 1166 1.1 jtc } 1167 1.1 jtc prev = vp; 1168 1.1 jtc curr = vp->u.array; 1169 1.1 jtc while (curr && curr->index < val) { 1170 1.1 jtc prev = curr; 1171 1.1 jtc curr = curr->u.array; 1172 1.1 jtc } 1173 1.1 jtc if (curr && curr->index == val) { 1174 1.1 jtc if (curr->flag&ISSET) 1175 1.1 jtc return curr; 1176 1.1 jtc else 1177 1.1 jtc new = curr; 1178 1.1 jtc } else 1179 1.9 mycroft new = (struct tbl *)alloc(sizeof(struct tbl) + namelen, 1180 1.9 mycroft vp->areap); 1181 1.9 mycroft strlcpy(new->name, vp->name, namelen); 1182 1.1 jtc new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL); 1183 1.1 jtc new->type = vp->type; 1184 1.1 jtc new->areap = vp->areap; 1185 1.1 jtc new->u2.field = vp->u2.field; 1186 1.1 jtc new->index = val; 1187 1.1 jtc if (curr != new) { /* not reusing old array entry */ 1188 1.1 jtc prev->u.array = new; 1189 1.1 jtc new->u.array = curr; 1190 1.1 jtc } 1191 1.1 jtc return new; 1192 1.1 jtc } 1193 1.1 jtc 1194 1.1 jtc /* Return the length of an array reference (eg, [1+2]) - cp is assumed 1195 1.1 jtc * to point to the open bracket. Returns 0 if there is no matching closing 1196 1.1 jtc * bracket. 1197 1.1 jtc */ 1198 1.1 jtc int 1199 1.1 jtc array_ref_len(cp) 1200 1.1 jtc const char *cp; 1201 1.1 jtc { 1202 1.1 jtc const char *s = cp; 1203 1.1 jtc int c; 1204 1.1 jtc int depth = 0; 1205 1.1 jtc 1206 1.1 jtc while ((c = *s++) && (c != ']' || --depth)) 1207 1.1 jtc if (c == '[') 1208 1.1 jtc depth++; 1209 1.1 jtc if (!c) 1210 1.1 jtc return 0; 1211 1.1 jtc return s - cp; 1212 1.1 jtc } 1213 1.1 jtc 1214 1.1 jtc /* 1215 1.1 jtc * Make a copy of the base of an array name 1216 1.1 jtc */ 1217 1.1 jtc char * 1218 1.1 jtc arrayname(str) 1219 1.1 jtc const char *str; 1220 1.1 jtc { 1221 1.1 jtc const char *p; 1222 1.1 jtc 1223 1.1 jtc if ((p = strchr(str, '[')) == 0) 1224 1.1 jtc /* Shouldn't happen, but why worry? */ 1225 1.12 christos return (char *) __UNCONST(str); 1226 1.1 jtc 1227 1.1 jtc return str_nsave(str, p - str, ATEMP); 1228 1.1 jtc } 1229 1.1 jtc 1230 1.1 jtc /* Set (or overwrite, if !reset) the array variable var to the values in vals. 1231 1.1 jtc */ 1232 1.1 jtc void 1233 1.1 jtc set_array(var, reset, vals) 1234 1.1 jtc const char *var; 1235 1.1 jtc int reset; 1236 1.1 jtc char **vals; 1237 1.1 jtc { 1238 1.1 jtc struct tbl *vp, *vq; 1239 1.1 jtc int i; 1240 1.1 jtc 1241 1.1 jtc /* to get local array, use "typeset foo; set -A foo" */ 1242 1.1 jtc vp = global(var); 1243 1.1 jtc 1244 1.1 jtc /* Note: at&t ksh allows set -A but not set +A of a read-only var */ 1245 1.1 jtc if ((vp->flag&RDONLY)) 1246 1.1 jtc errorf("%s: is read only", var); 1247 1.1 jtc /* This code is quite non-optimal */ 1248 1.1 jtc if (reset > 0) 1249 1.1 jtc /* trash existing values and attributes */ 1250 1.1 jtc unset(vp, 0); 1251 1.1 jtc /* todo: would be nice for assignment to completely succeed or 1252 1.26 rillig * completely fail. Only really affects integer arrays: 1253 1.1 jtc * evaluation of some of vals[] may fail... 1254 1.1 jtc */ 1255 1.1 jtc for (i = 0; vals[i]; i++) { 1256 1.1 jtc vq = arraysearch(vp, i); 1257 1.6 hubertf /* would be nice to deal with errors here... (see above) */ 1258 1.6 hubertf setstr(vq, vals[i], KSH_RETURN_ERROR); 1259 1.1 jtc } 1260 1.1 jtc } 1261