|
|
1.1 ! root 1: static char *RCSid = "$Header: var.c,v 3.1 88/11/03 09:18:22 egisin Exp $"; ! 2: ! 3: #include <stddef.h> ! 4: #include <stdlib.h> ! 5: #include <string.h> ! 6: #include <errno.h> ! 7: #include <setjmp.h> ! 8: #include <time.h> ! 9: #include <sys/types.h> ! 10: #include "sh.h" ! 11: #include "table.h" ! 12: #include "expand.h" ! 13: ! 14: /* ! 15: * Variables ! 16: * ! 17: * WARNING: unreadable code, needs a rewrite ! 18: * ! 19: * if (flag&INTEGER), val.i contains integer value, and type contains base. ! 20: * otherwise, (val.s + type) contains string value. ! 21: * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting. ! 22: */ ! 23: char null [] = ""; ! 24: static struct tbl vtemp; ! 25: static void getspec(), setspec(); ! 26: static void export ARGS((struct tbl *, char *val)); ! 27: static int special ARGS ((char *name)); ! 28: ! 29: /* ! 30: * create a new block for function calls and simple commands ! 31: * assume caller has allocated and set up e.loc ! 32: */ ! 33: void ! 34: newblock() ! 35: { ! 36: register struct block *l = e.loc; ! 37: static char *empty[] = {""}; ! 38: ! 39: ainit(&l->area); ! 40: l->argc = 0; ! 41: l->argv = empty; ! 42: l->exit = l->error = NULL; ! 43: tinit(&l->vars, &l->area); ! 44: tinit(&l->funs, &l->area); ! 45: } ! 46: ! 47: /* ! 48: * pop a block handling special variables ! 49: */ ! 50: void ! 51: popblock() ! 52: { ! 53: register struct block *l = e.loc; ! 54: register struct tbl *vp, **vpp = l->vars.tbls; ! 55: register int i; ! 56: ! 57: e.loc = l->next; /* pop block */ ! 58: for (i = l->vars.size; --i >= 0; ) ! 59: if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) ! 60: setspec(global(vp->name)); ! 61: afreeall(&l->area); ! 62: } ! 63: ! 64: /* ! 65: * Search for variable, if not found create globally. ! 66: */ ! 67: struct tbl * ! 68: global(n) ! 69: register char *n; ! 70: { ! 71: register struct block *l = e.loc; ! 72: register struct tbl *vp; ! 73: register int c; ! 74: unsigned h = hash(n); ! 75: ! 76: c = n[0]; ! 77: if (digit(c)) { ! 78: vp = &vtemp; ! 79: lastarea = ATEMP; ! 80: vp->flag = (DEFINED|RDONLY); ! 81: vp->type = 0; ! 82: *vp->name = c; /* should strncpy */ ! 83: for (c = 0; digit(*n) && c < 1000; n++) ! 84: c = c*10 + *n-'0'; ! 85: if (c <= l->argc) ! 86: setstr(vp, l->argv[c]); ! 87: return vp; ! 88: } else ! 89: if (!letter(c)) { ! 90: vp = &vtemp; ! 91: lastarea = ATEMP; ! 92: vp->flag = (DEFINED|RDONLY); ! 93: vp->type = 0; ! 94: *vp->name = c; ! 95: if (n[1] != '\0') ! 96: return vp; ! 97: vp->flag |= ISSET|INTEGER; ! 98: switch (c) { ! 99: case '$': ! 100: vp->val.i = getpid(); ! 101: break; ! 102: case '!': ! 103: vp->val.i = async; ! 104: break; ! 105: case '?': ! 106: vp->val.i = exstat; ! 107: break; ! 108: case '#': ! 109: vp->val.i = l->argc; ! 110: break; ! 111: case '-': ! 112: vp->flag &= ~ INTEGER; ! 113: vp->val.s = getoptions(); ! 114: break; ! 115: default: ! 116: vp->flag &= ~(ISSET|INTEGER); ! 117: } ! 118: return vp; ! 119: } ! 120: for (l = e.loc; l != NULL; l = l->next) { ! 121: vp = tsearch(&l->vars, n, h); ! 122: lastarea = &l->area; ! 123: if (vp != NULL) ! 124: return vp; ! 125: if (l->next == NULL) ! 126: break; ! 127: } ! 128: vp = tenter(&l->vars, n, h); ! 129: vp->flag |= DEFINED; ! 130: if (special(n)) ! 131: vp->flag |= SPECIAL; ! 132: return vp; ! 133: } ! 134: ! 135: /* ! 136: * Search for local variable, if not found create locally. ! 137: */ ! 138: struct tbl * ! 139: local(n) ! 140: register char *n; ! 141: { ! 142: register struct block *l = e.loc; ! 143: register struct tbl *vp; ! 144: unsigned h = hash(n); ! 145: ! 146: if (!letter(*n)) { ! 147: vp = &vtemp; ! 148: lastarea = ATEMP; ! 149: vp->flag = (DEFINED|RDONLY); ! 150: vp->type = 0; ! 151: return vp; ! 152: } ! 153: vp = tenter(&l->vars, n, h); ! 154: lastarea = &l->area; ! 155: vp->flag |= DEFINED; ! 156: if (special(n)) ! 157: vp->flag |= SPECIAL; ! 158: return vp; ! 159: } ! 160: ! 161: /* get variable string value */ ! 162: char * ! 163: strval(vp) ! 164: register struct tbl *vp; ! 165: { ! 166: register char *s; ! 167: static char strbuf[40]; ! 168: ! 169: if ((vp->flag&SPECIAL)) ! 170: getspec(vp); ! 171: if (!(vp->flag&ISSET)) ! 172: return null; /* special to dollar() */ ! 173: if (!(vp->flag&INTEGER)) /* string source */ ! 174: s = vp->val.s + vp->type; ! 175: else { /* integer source */ ! 176: register unsigned long n; ! 177: register int base; ! 178: ! 179: s = strbuf + sizeof(strbuf); ! 180: n = (vp->val.i < 0) ? -vp->val.i : vp->val.i; ! 181: base = (vp->type == 0) ? 10 : vp->type; ! 182: ! 183: *--s = '\0'; ! 184: do { ! 185: *--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base]; ! 186: n /= base; ! 187: } while (n != 0); ! 188: /* todo: should we output base# ? */ ! 189: if (vp->val.i < 0) ! 190: *--s = '-'; ! 191: } ! 192: return s; ! 193: } ! 194: ! 195: /* get variable integer value */ ! 196: long ! 197: intval(vp) ! 198: register struct tbl *vp; ! 199: { ! 200: register struct tbl *vq; ! 201: ! 202: if ((vp->flag&SPECIAL)) ! 203: getspec(vp); ! 204: if ((vp->flag&INTEGER)) ! 205: return vp->val.i; ! 206: vq = &vtemp; ! 207: vq->flag = (INTEGER); ! 208: vq->type = 0; ! 209: strint(vq, vp); ! 210: return vq->val.i; ! 211: } ! 212: ! 213: /* set variable to string value */ ! 214: void ! 215: setstr(vq, s) ! 216: register struct tbl *vq; ! 217: char *s; ! 218: { ! 219: if (!(vq->flag&INTEGER)) { /* string dest */ ! 220: if ((vq->flag&ALLOC)) ! 221: afree((Void*)vq->val.s, lastarea); ! 222: vq->flag &= ~ (ISSET|ALLOC); ! 223: vq->type = 0; ! 224: if ((vq->flag&EXPORT)) ! 225: export(vq, s); ! 226: else ! 227: vq->val.s = strsave(s, lastarea); ! 228: vq->flag |= ALLOC; ! 229: } else { /* integer dest */ ! 230: register struct tbl *vp = &vtemp; ! 231: vp->flag = (DEFINED|ISSET); ! 232: vp->type = 0; ! 233: vp->val.s = s; ! 234: strint(vq, vp); ! 235: } ! 236: vq->flag |= ISSET; ! 237: if ((vq->flag&SPECIAL)) ! 238: setspec(vq); ! 239: } ! 240: ! 241: /* convert variable to integer variable */ ! 242: struct tbl * ! 243: strint(vq, vp) ! 244: register struct tbl *vq, *vp; ! 245: { ! 246: register char *s = vp->val.s + vp->type; ! 247: register int c; ! 248: int base, neg = 0; ! 249: ! 250: vq->flag |= INTEGER; ! 251: if ((vp->flag&INTEGER)) { ! 252: vq->val.i = vp->val.i; ! 253: return vq; ! 254: } ! 255: vq->val.i = 0; ! 256: base = 10; ! 257: for (c = *s++; c ; c = *s++) ! 258: if (c == '-') { ! 259: neg++; ! 260: } else if (c == '#') { ! 261: base = vq->type = vq->val.i; ! 262: vq->val.i = 0; ! 263: } else if (letnum(c)) { ! 264: if ('0' <= c && c <= '9') ! 265: c -= '0'; ! 266: else if ('a' <= c && c <= 'z') /* fuck EBCDIC */ ! 267: c -= 'a'-10; ! 268: else if ('A' <= c && c <= 'Z') ! 269: c -= 'A'-10; ! 270: vq->val.i = (vq->val.i*base) + c; ! 271: } else ! 272: break; ! 273: if (neg) ! 274: vq->val.i = -vq->val.i; ! 275: if (vq->type < 2 || vq->type > 36) ! 276: vq->type = 0; /* default base (10) */ ! 277: return vq; ! 278: } ! 279: ! 280: /* set variable to integer */ ! 281: void ! 282: setint(vq, n) ! 283: register struct tbl *vq; ! 284: long n; ! 285: { ! 286: if (!(vq->flag&INTEGER)) { ! 287: register struct tbl *vp = &vtemp; ! 288: vp->flag = (ISSET|INTEGER); ! 289: vp->type = 0; ! 290: vp->val.i = n; ! 291: setstr(vq, strval(vp)); /* ? */ ! 292: } else ! 293: vq->val.i = n; ! 294: vq->flag |= ISSET; ! 295: if ((vq->flag&SPECIAL)) ! 296: setspec(vq); ! 297: } ! 298: ! 299: /* set variable from enviroment */ ! 300: import(thing) ! 301: char *thing; ! 302: { ! 303: register struct tbl *vp; ! 304: register char *val; ! 305: ! 306: val = strchr(thing, '='); ! 307: if (val == NULL) ! 308: return 0; ! 309: *val = '\0'; ! 310: vp = local(thing); ! 311: *val++ = '='; ! 312: vp->flag |= DEFINED|ISSET|EXPORT; ! 313: vp->val.s = thing; ! 314: vp->type = val - thing; ! 315: if ((vp->flag&SPECIAL)) ! 316: setspec(vp); ! 317: return 1; ! 318: } ! 319: ! 320: /* ! 321: * make vp->val.s be "name=value" for quick exporting. ! 322: */ ! 323: static void ! 324: export(vp, val) ! 325: register struct tbl *vp; ! 326: char *val; ! 327: { ! 328: register char *cp, *xp; ! 329: char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; ! 330: ! 331: xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea); ! 332: vp->flag |= ALLOC; ! 333: vp->val.s = xp; ! 334: for (cp = vp->name; (*xp = *cp++) != '\0'; xp++) ! 335: ; ! 336: *xp++ = '='; ! 337: vp->type = xp - vp->val.s; /* offset to value */ ! 338: for (cp = val; (*xp++ = *cp++) != '\0'; ) ! 339: ; ! 340: if (op != NULL) ! 341: afree((Void*)op, lastarea); ! 342: } ! 343: ! 344: /* ! 345: * lookup variable (according to (set&LOCAL)), ! 346: * set its attributes (INTEGER, RDONLY, EXPORT, TRACE), ! 347: * and optionally set its value if an assignment. ! 348: */ ! 349: struct tbl * ! 350: typeset(var, set, clr) ! 351: register char *var; ! 352: int clr, set; ! 353: { ! 354: register struct tbl *vp; ! 355: register char *val; ! 356: ! 357: /* check for valid variable name, search for value */ ! 358: val = var; ! 359: if (!letter(*val)) ! 360: return NULL; ! 361: for (val++; *val != '\0'; val++) ! 362: if (*val == '=') ! 363: break; ! 364: else if (letnum(*val)) ! 365: ; ! 366: else ! 367: return NULL; ! 368: if (*val == '=') ! 369: *val = '\0'; ! 370: else ! 371: val = NULL; ! 372: vp = (set&LOCAL) ? local(var) : global(var); ! 373: set &= ~ LOCAL; ! 374: if (val != NULL) ! 375: *val++ = '='; ! 376: ! 377: if (!(vp->flag&ISSET)) ! 378: vp->flag = vp->flag & ~clr | set; ! 379: else ! 380: if (!(vp->flag&INTEGER) && (set&INTEGER)) { ! 381: /* string to integer */ ! 382: vtemp.flag = (ISSET); ! 383: vtemp.type = 0; ! 384: vtemp.val.s = vp->val.s + vp->type; ! 385: if ((vp->flag&ALLOC)) ! 386: afree((Void*)vp->val.s, lastarea); /* dangerous, used later */ ! 387: vp->flag &= ~ ALLOC; ! 388: vp->flag |= INTEGER; ! 389: vp->type = 0; ! 390: strint(vp, &vtemp); ! 391: } else ! 392: if ((clr&INTEGER) && (vp->flag&INTEGER)) { ! 393: /* integer to string */ ! 394: vtemp.val.s = strval(vp); ! 395: vp->flag &= ~ INTEGER; ! 396: setstr(vp, vtemp.val.s); ! 397: } ! 398: ! 399: vp->flag = vp->flag & ~clr | set; ! 400: ! 401: if (val != NULL) { ! 402: if ((vp->flag&RDONLY)) ! 403: errorf("cannot set readonly %s\n", var); ! 404: if ((vp->flag&INTEGER)) ! 405: /* setstr should be able to handle this */ ! 406: (void)evaluate(var); ! 407: else ! 408: setstr(vp, val); ! 409: } ! 410: ! 411: if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0) ! 412: export(vp, (vp->flag&ISSET) ? vp->val.s : null); ! 413: ! 414: return vp; ! 415: } ! 416: ! 417: void ! 418: unset(vp) ! 419: register struct tbl *vp; ! 420: { ! 421: if ((vp->flag&ALLOC)) ! 422: afree((Void*)vp->val.s, lastarea); ! 423: vp->flag &= ~ (ALLOC|ISSET); ! 424: } ! 425: ! 426: int ! 427: isassign(s) ! 428: register char *s; ! 429: { ! 430: if (!letter(*s)) ! 431: return (0); ! 432: for (s++; *s != '='; s++) ! 433: if (*s == 0 || !letnum(*s)) ! 434: return (0); ! 435: return (1); ! 436: } ! 437: ! 438: /* ! 439: * Make the exported environment from the exported names in the dictionary. ! 440: */ ! 441: char ** ! 442: makenv() ! 443: { ! 444: struct block *l = e.loc; ! 445: XPtrV env; ! 446: register struct tbl *vp, **vpp; ! 447: register int i; ! 448: ! 449: XPinit(env, 64); ! 450: for (l = e.loc; l != NULL; l = l->next) ! 451: for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; ) ! 452: if ((vp = *vpp++) != NULL ! 453: && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) { ! 454: register struct block *l2; ! 455: register struct tbl *vp2; ! 456: unsigned h = hash(vp->name); ! 457: ! 458: lastarea = &l->area; ! 459: ! 460: /* unexport any redefined instances */ ! 461: for (l2 = l->next; l2 != NULL; l2 = l2->next) { ! 462: vp2 = tsearch(&l2->vars, vp->name, h); ! 463: if (vp2 != NULL) ! 464: vp2->flag &= ~ EXPORT; ! 465: } ! 466: if ((vp->flag&INTEGER)) { ! 467: /* integer to string */ ! 468: char *val; ! 469: val = strval(vp); ! 470: vp->flag &= ~ INTEGER; ! 471: setstr(vp, val); ! 472: } ! 473: XPput(env, vp->val.s); ! 474: } ! 475: XPput(env, NULL); ! 476: return (char **) XPclose(env); ! 477: } ! 478: ! 479: /* ! 480: * handle special variables with side effects - PATH, SECONDS. ! 481: */ ! 482: ! 483: static int ! 484: special(name) ! 485: register char * name; ! 486: { ! 487: if (strcmp("PATH", name) == 0) ! 488: return V_PATH; ! 489: if (strcmp("IFS", name) == 0) ! 490: return V_IFS; ! 491: if (strcmp("SECONDS", name) == 0) ! 492: return V_SECONDS; ! 493: if (strcmp("OPTIND", name) == 0) ! 494: return V_OPTIND; ! 495: return V_NONE; ! 496: } ! 497: ! 498: extern time_t time(); ! 499: static time_t seconds; /* time SECONDS last set */ ! 500: ! 501: static void ! 502: getspec(vp) ! 503: register struct tbl *vp; ! 504: { ! 505: switch (special(vp->name)) { ! 506: case V_SECONDS: ! 507: vp->flag &= ~ SPECIAL; ! 508: setint(vp, time((time_t *)0) - seconds); ! 509: vp->flag |= SPECIAL; ! 510: break; ! 511: } ! 512: } ! 513: ! 514: static void ! 515: setspec(vp) ! 516: register struct tbl *vp; ! 517: { ! 518: switch (special(vp->name)) { ! 519: case V_PATH: ! 520: path = strval(vp); ! 521: flushcom(1); /* clear tracked aliases */ ! 522: break; ! 523: case V_IFS: ! 524: setctypes(strval(vp), C_IFS); ! 525: break; ! 526: case V_SECONDS: ! 527: seconds = time((time_t *)0); ! 528: break; ! 529: case V_OPTIND: ! 530: if (intval(vp) == 1) ! 531: resetopts(); ! 532: break; ! 533: } ! 534: } ! 535:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.