|
|
1.1 ! root 1: /* ! 2: * Awk - internal execution functions. ! 3: */ ! 4: ! 5: #include "awk.h" ! 6: #include "y.tab.h" ! 7: ! 8: FILE *xoutput(); ! 9: ! 10: /* ! 11: * `print' directive. ! 12: * First argument is the NODE (or list) to print ! 13: * and the second is the output. ! 14: * Have to close pipes specially. ! 15: * The ALIST stuff should be generalised ! 16: * so that functions can get their arguments ! 17: * a little more easily. ! 18: */ ! 19: xprint(np, xp) ! 20: register NODE *np; ! 21: register NODE *xp; ! 22: { ! 23: register FILE *ofp; ! 24: ! 25: ofp = xoutput(xp); ! 26: while (np != NULL) { ! 27: if (np->n_op == ALIST) { ! 28: xp = np->n_O1; ! 29: np = np->n_O2; ! 30: } else { ! 31: xp = np; ! 32: np = NULL; ! 33: } ! 34: xp = evalexpr(xp); ! 35: if (xp->t_flag & T_NUM) { ! 36: if (xp->t_flag & T_INT) ! 37: fprintf(ofp, OFMT, xp->t_INT); else ! 38: fprintf(ofp, "%.6g", xp->t_FLOAT); ! 39: } else ! 40: fprintf(ofp, "%s", xp->t_STRING); ! 41: if (np != NULL) ! 42: fprintf(ofp, "%s", OFS); ! 43: } ! 44: fprintf(ofp, "%s", ORS); ! 45: fflush(ofp); ! 46: } ! 47: ! 48: /* ! 49: * `printf' directive. ! 50: * First argument is list, second ! 51: * is output. ! 52: * If third argument is non-NULL, ! 53: * it is used for sprintf rather than ! 54: * printf. ! 55: */ ! 56: xprintf(np, xp, sp) ! 57: NODE *np; ! 58: NODE *xp; ! 59: STRING sp; ! 60: { ! 61: NODE *nextarg(); ! 62: int *pflist; ! 63: register CHAR *cp; ! 64: register int *pflp; ! 65: register int c; ! 66: register int i; ! 67: register FILE *ofp; ! 68: ! 69: pflp = pflist = (int *)xalloc(fnargs(np) * sizeof(double)); ! 70: if (sp == NULL) ! 71: ofp = xoutput(xp); else ! 72: *sp = '\0'; ! 73: i = 1; ! 74: *((CHAR **)pflp) = cp = evalstring(nextarg(np, i++)); ! 75: bump(pflp, CHAR*); ! 76: for (;;) { ! 77: while ((c = *cp++)!='%' && c!='\0') ! 78: ; ! 79: if (c == '\0') ! 80: break; ! 81: if (*cp == '-') ! 82: cp++; ! 83: if (*cp == '*') { ! 84: *pflp++ = evalint(nextarg(np, i++)); ! 85: cp++; ! 86: } else ! 87: while (isdigit(*cp)) ! 88: cp++; ! 89: if (*cp == '.') { ! 90: cp++; ! 91: if (*cp == '*') { ! 92: *pflp++ = evalint(nextarg(np, i++)); ! 93: cp++; ! 94: } else ! 95: while (isdigit(*cp)) ! 96: cp++; ! 97: } ! 98: if ((c = *cp++) == 'l') ! 99: c = toupper(*cp++); ! 100: switch (c) { ! 101: case 'd': ! 102: case 'u': ! 103: case 'x': ! 104: case 'o': ! 105: *pflp++ = evalint(nextarg(np, i++)); ! 106: break; ! 107: ! 108: case 'D': ! 109: case 'U': ! 110: case 'X': ! 111: case 'O': ! 112: *((long *)pflp) = (long)evalint(nextarg(np, i++)); ! 113: bump(pflp, long); ! 114: break; ! 115: ! 116: case 'e': ! 117: case 'f': ! 118: case 'g': ! 119: *((double *)pflp) = (double)evalfloat(nextarg(np, i++)); ! 120: bump(pflp, double); ! 121: break; ! 122: ! 123: case 'c': ! 124: xp = evalexpr(nextarg(np, i++)); ! 125: if (xp->n_flag & T_NUM) ! 126: *pflp++ = evalint(xp); else ! 127: *pflp++ = *evalstring(xp); ! 128: break; ! 129: ! 130: case 's': ! 131: *((CHAR **)pflp) = evalstring(nextarg(np, i++)); ! 132: bump(pflp, CHAR*); ! 133: break; ! 134: ! 135: case 'r': ! 136: awkwarn("%%r not available in sprintf/printf"); ! 137: break; ! 138: } ! 139: } ! 140: if (sp == NULL) { ! 141: fprintf(ofp, "%r", pflist); ! 142: fflush(ofp); ! 143: } else ! 144: sprintf(sp, "%r", pflist); ! 145: free(pflist); ! 146: } ! 147: ! 148: /* ! 149: * Return the next argument for printf. ! 150: */ ! 151: static NODE * ! 152: nextarg(anp, n) ! 153: register NODE *anp; ! 154: register int n; ! 155: { ! 156: if ((anp = fargn(anp, n)) == NULL) ! 157: awkerr("Missing argument to printf/sprintf"); ! 158: return (anp); ! 159: } ! 160: ! 161: /* ! 162: * Calculate the output ! 163: * stream for print or printf. ! 164: * This saves up names so that they ! 165: * don't get re-opened every time. ! 166: */ ! 167: FILE * ! 168: xoutput(np) ! 169: register NODE *np; ! 170: { ! 171: register CHAR *s; ! 172: register OFILE *ofp; ! 173: register OFILE *ofslot; ! 174: ! 175: if (np == NULL) ! 176: return (stdout); ! 177: s = evalstring(np->n_O1); ! 178: ofslot = NULL; ! 179: for (ofp = files; ofp < endof(files); ofp++) ! 180: if (ofp->of_fp != NULL) { ! 181: if (strcmp(ofp->of_name, s) == 0) ! 182: return (ofp->of_fp); ! 183: } else ! 184: ofslot = ofp; ! 185: if ((ofp = ofslot) == NULL) ! 186: awkerr("Too many output files or pipes"); ! 187: ofp->of_flag = 0; ! 188: switch (np->n_op) { ! 189: case AFOUT: ! 190: if ((ofp->of_fp = fopen(s, "w")) == NULL) ! 191: awkerr("Cannot open output `%s'", s); ! 192: break; ! 193: ! 194: case AFAPP: ! 195: if ((ofp->of_fp = fopen(s, "a")) == NULL) ! 196: awkerr("Cannot open `%s' for append", s); ! 197: break; ! 198: ! 199: case AFPIPE: ! 200: #ifndef GEMDOS ! 201: if ((ofp->of_fp = popen(s, "w")) == NULL) ! 202: #endif ! 203: awkerr("Cannot create pipe to `%s'", s); ! 204: ofp->of_flag = OFPIPE; ! 205: break; ! 206: ! 207: default: ! 208: awkerr("Bad output tree op %d", np->n_op); ! 209: } ! 210: ofp->of_name = xalloc(strlen(s) + sizeof(CHAR)); ! 211: strcpy(ofp->of_name, s); ! 212: setbuf(ofp->of_fp, outbuf); ! 213: return (ofp->of_fp); ! 214: } ! 215: ! 216: /* ! 217: * Do the form: for (i in array) stat ! 218: * `var' is the index and `stat' the statement. ! 219: */ ! 220: xforin(var, array, stat) ! 221: NODE *var; ! 222: register NODE *array; ! 223: NODE *stat; ! 224: { ! 225: register CHAR *cp; ! 226: register TERM *tp; ! 227: register int i; ! 228: register int j; ! 229: ! 230: for (i=0; i<NHASH; i++) ! 231: for (tp = symtab[i]; tp != NULL; tp = tp->t_next) ! 232: if (tp->t_ahval==array->t_hval && tp->t_flag&T_ARRAY ! 233: && streq(tp->t_name, array->t_name)) { ! 234: if ((j = setjmp(fwenv[fwlevel])) == ABREAK) ! 235: break; ! 236: else if (j == ACONTIN) ! 237: continue; ! 238: cp = tp->t_name; ! 239: while (*cp++ != '\0') ! 240: ; ! 241: xassign(var, snode(cp, 0)); ! 242: evalact(stat); ! 243: } ! 244: } ! 245: ! 246: /* ! 247: * Return a node associated with ! 248: * an array element. ! 249: * `array' is the array identifier, ! 250: * and `index' is the index expression ! 251: * represented as a STRING. ! 252: */ ! 253: NODE * ! 254: xarray(array, index) ! 255: NODE *array; ! 256: NODE *index; ! 257: { ! 258: return (alookup(array->t_name, evalstring(index))); ! 259: } ! 260: ! 261: /* ! 262: * Extract the field given by the expression. ! 263: * A negative field number is ! 264: * considered to be from the end. ! 265: * The `asval' is non-NULL when ! 266: * the string is to be assigned to a field. ! 267: */ ! 268: NODE * ! 269: xfield(i, asval) ! 270: int i; ! 271: STRING asval; ! 272: { ! 273: CHAR *xfield1(); ! 274: register CHAR *as, *s1, *s2; ! 275: register int c, i1; ! 276: register unsigned nb; ! 277: ! 278: if ((s1 = inline) == NULL) { ! 279: awkwarn("field, $%d, illegal in BEGIN or END", i); ! 280: return (snode(SNULL, 0)); ! 281: } ! 282: if (i == 0) { ! 283: if (asval != NULL) { ! 284: inline = xalloc(strlen(asval)+sizeof(CHAR)); ! 285: strcpy(inline, asval); ! 286: } ! 287: return (snode(inline, 0)); ! 288: } ! 289: if (i < 0) ! 290: if ((i += (int)NF + 1) == 0) ! 291: i = -1; ! 292: ! 293: i1 = i; ! 294: if (whitesw) { ! 295: do { ! 296: while ((c = *s1) && FSMAP[c]) ! 297: s1++; ! 298: if (!c || --i==0) ! 299: break; ! 300: while ((c = *s1) && !FSMAP[c]) ! 301: s1++; ! 302: } while (c); ! 303: } else { ! 304: do { ! 305: if (!*s1 || --i==0) ! 306: break; ! 307: while ((c = *s1) && !FSMAP[c]) ! 308: s1++; ! 309: if (FSMAP[*s1]) ! 310: s1++; ! 311: } while (c); ! 312: } ! 313: s2 = s1; ! 314: nb = sizeof(CHAR); ! 315: while ((c = *s2++)!='\0' && !FSMAP[c]) ! 316: nb++; ! 317: s2--; ! 318: if (asval != NULL) { ! 319: /* ! 320: * An attempt to set an arg past the end. ! 321: */ ! 322: if(0 < (i1 -= evalint(NFp))) { ! 323: if (whitesw && (i1 > 1)) ! 324: awkwarn("Assignment to unbuildable field"); ! 325: /* remove trailing delimeters */ ! 326: while ((--s1 > inline) && FSMAP[*s1]) ! 327: ; ! 328: s2 = ++s1; ! 329: as = xalloc(strlen(asval) + i1 + 1); ! 330: strcpy(as + i1, asval); ! 331: memset(as, FS[0], i1); ! 332: ! 333: inline = xfield1(inline, s1, as, s2, s2); ! 334: free(as); ! 335: return (snode(inline, 0)); ! 336: } ! 337: inline = as = xfield1(inline, s1, asval, s2, s2+strlen(s2)); ! 338: return (snode(inline, 0)); ! 339: } else { ! 340: as = xalloc(nb); ! 341: while (s1 < s2) ! 342: *as++ = *s1++; ! 343: *as++ = '\0'; ! 344: as -= nb; ! 345: } ! 346: return (snode(as, T_ALLOC)); ! 347: } ! 348: ! 349: /* ! 350: * Assignment of fields support. ! 351: * The arguments are: ! 352: * `f1', `f2', `middle', `e1', `e2' ! 353: * for the front start and stop, the middle ! 354: * and the end start and stop, respectively. ! 355: */ ! 356: CHAR * ! 357: xfield1(f1, f2, middle, e1, e2) ! 358: CHAR *f1, *f2; ! 359: CHAR *middle; ! 360: CHAR *e1, *e2; ! 361: { ! 362: register CHAR *p1, *p2; ! 363: register CHAR *as; ! 364: ! 365: as = xalloc(f2-f1 + e2-e1 + strlen(middle) + sizeof(CHAR)); ! 366: p1 = as; ! 367: p2 = f1; ! 368: while (p2 < f2) ! 369: *p1++ = *p2++; ! 370: p2 = middle; ! 371: while (*p2 != '\0') ! 372: *p1++ = *p2++; ! 373: p2 = e1; ! 374: while (p2 < e2) ! 375: *p1++ = *p2++; ! 376: *p1 = '\0'; ! 377: return (as); ! 378: } ! 379: ! 380: /* ! 381: * String catenation in two nodes. ! 382: */ ! 383: NODE * ! 384: xconc(n1, n2) ! 385: register NODE *n1, *n2; ! 386: { ! 387: register CHAR *ap; ! 388: register CHAR *cp1, *cp2; ! 389: register int n; ! 390: ! 391: n = strlen(ap = evalstring(n1)) + sizeof(CHAR); ! 392: if ((n1->t_un.t_flag & T_NUM) == 0) { ! 393: cp1 = xalloc(n); ! 394: strcpy(cp1, ap); ! 395: } else ! 396: cp1 = ap; ! 397: n += strlen(cp2 = evalstring(n2)); ! 398: ap = xalloc(n); ! 399: strcpy(ap, cp1); ! 400: strcat(ap, cp2); ! 401: if ((n1->t_un.t_flag & T_NUM) == 0) ! 402: free(cp1); ! 403: return (snode(ap, T_ALLOC)); ! 404: } ! 405: ! 406: /* ! 407: * Arithmetic operations -- ! 408: * ! 409: * Numeric addition ! 410: */ ! 411: NODE * ! 412: xadd(n1, n2) ! 413: register NODE *n1, *n2; ! 414: { ! 415: if (isfloat(n1) || isfloat(n2)) ! 416: return (fnode(evalfloat(n1) + evalfloat(n2))); ! 417: return (inode(evalint(n1) + evalint(n2))); ! 418: } ! 419: ! 420: /* ! 421: * Subtraction -- actually a numeric operation. ! 422: */ ! 423: NODE * ! 424: xsub(n1, n2) ! 425: register NODE *n1, *n2; ! 426: { ! 427: if (isfloat(n1) || isfloat(n2)) ! 428: return (fnode(evalfloat(n1) - evalfloat(n2))); ! 429: return (inode(evalint(n1) - evalint(n2))); ! 430: } ! 431: ! 432: /* ! 433: * Multiplication ! 434: */ ! 435: NODE * ! 436: xmul(n1, n2) ! 437: register NODE *n1, *n2; ! 438: { ! 439: if (isfloat(n1) || isfloat(n2)) ! 440: return (fnode(evalfloat(n1) * evalfloat(n2))); ! 441: return (inode(evalint(n1) * evalint(n2))); ! 442: } ! 443: ! 444: /* ! 445: * Negation ! 446: */ ! 447: NODE * ! 448: xneg(n1) ! 449: register NODE *n1; ! 450: { ! 451: if (isfloat(n1)) ! 452: return (fnode(-evalfloat(n1))); ! 453: return (inode(-evalint(n1))); ! 454: } ! 455: ! 456: /* ! 457: * Division ! 458: * If either numeric is of internal FLOAT type, ! 459: * the division will be a float one, otherwise use ! 460: * INT division. ! 461: */ ! 462: NODE * ! 463: xdiv(n1, n2) ! 464: register NODE *n1, *n2; ! 465: { ! 466: if (isfloat(n1) || isfloat(n2)) ! 467: return (fnode(evalfloat(n1) / evalfloat(n2))); ! 468: return (inode(evalint(n1) / evalint(n2))); ! 469: } ! 470: ! 471: /* ! 472: * Modulus ! 473: * Same type conversion rule as for division. ! 474: */ ! 475: NODE * ! 476: xmod(n1, n2) ! 477: register NODE *n1, *n2; ! 478: { ! 479: if (isfloat(n1) || isfloat(n2)) ! 480: awkwarn("Modulus operator not allowed on floating point"); ! 481: return (inode(evalint(n1) % evalint(n2))); ! 482: } ! 483: ! 484: /* ! 485: * Comparison operators -- ! 486: * string or numeric comparison ! 487: * for equality or non-equality. ! 488: * The tricks come in conversions ! 489: * between FLOAT and INT. ! 490: * The nodes passed should not be evaluated ! 491: * beforehand so that checks for fields can ! 492: * be made as here fields are always considered ! 493: * as strings. ! 494: */ ! 495: NODE * ! 496: xcmp(n1, n2, op) ! 497: register NODE *n1, *n2; ! 498: int op; ! 499: { ! 500: register int result; ! 501: register int isnum = 0; ! 502: ! 503: if (n1->n_op != AFIELD) ! 504: isnum = isnumeric(n1 = evalexpr(n1)); ! 505: else ! 506: n1 = evalexpr(n1); ! 507: if (n2->n_op != AFIELD) ! 508: isnum |= isnumeric(n2 = evalexpr(n2)); ! 509: else ! 510: n2 = evalexpr(n2); ! 511: if (isnum) { ! 512: result = 0; ! 513: if (isfloat(n1) || isfloat(n2)) { ! 514: register FLOAT f1, f2; ! 515: ! 516: if ((f1 = evalfloat(n1)) > (f2 = evalfloat(n2))) ! 517: result++; ! 518: else if (f1 < f2) ! 519: result--; ! 520: } else { ! 521: register INT i1, i2; ! 522: ! 523: if ((i1 = evalint(n1)) > (i2 = evalint(n2))) ! 524: result++; ! 525: else if (i1 < i2) ! 526: result--; ! 527: } ! 528: } else if ((n1->t_flag & T_NUM)==0 && (n2->t_flag & T_NUM)==0) ! 529: result = strcmp(n1->t_STRING, n2->t_STRING); ! 530: else ! 531: result = strcmp(evalstring(n1), evalstring(n2)); ! 532: switch (op) { ! 533: case AEQ: ! 534: result = result==0; ! 535: break; ! 536: ! 537: case ANE: ! 538: result = result!=0; ! 539: break; ! 540: ! 541: case AGT: ! 542: result = result>0; ! 543: break; ! 544: ! 545: case AGE: ! 546: result = result>=0; ! 547: break; ! 548: ! 549: case ALT: ! 550: result = result<0; ! 551: break; ! 552: ! 553: case ALE: ! 554: result = result<=0; ! 555: break; ! 556: } ! 557: return (inode((INT)result)); ! 558: } ! 559: ! 560: /* ! 561: * Assignment ! 562: * The two nodes `l' and `r' are the left ! 563: * and right sides of the assignment, ! 564: * respectively. ! 565: */ ! 566: NODE * ! 567: xassign(l, r) ! 568: register NODE *l, *r; ! 569: { ! 570: if (l->t_op == AFIELD) ! 571: return (xfield((int)evalint(l->n_O1), evalstring(r))); ! 572: else if (l->t_op == AARRAY) ! 573: l = xarray(l->n_O1, l->n_O2); ! 574: if ((l->t_flag & (T_ALLOC|T_NUM)) == T_ALLOC) ! 575: free(l->t_STRING); ! 576: l->t_flag &= ~(T_INT|T_NUM); ! 577: l->t_flag |= T_ALLOC|(r->t_flag & (T_INT|T_NUM)); ! 578: if (r->t_flag & T_NUM) ! 579: if (r->t_flag & T_INT) ! 580: l->t_INT = r->t_INT; else ! 581: l->t_FLOAT = r->t_FLOAT; ! 582: else { ! 583: l->t_STRING = xalloc(strlen(r->t_STRING)+sizeof(CHAR)); ! 584: strcpy(l->t_STRING, r->t_STRING); ! 585: } ! 586: if (l == FSp) ! 587: fsmapinit(evalstring(l)); ! 588: return (l); ! 589: } ! 590: ! 591: /* ! 592: * Post increment -- return the old ! 593: * value before the increment of the ! 594: * node. ! 595: */ ! 596: NODE * ! 597: xinca(np) ! 598: register NODE *np; ! 599: { ! 600: register NODE *rnp; ! 601: register NODE *enp; ! 602: ! 603: enp = evalexpr(np); ! 604: rnp = inode((INT)0); ! 605: xassign(rnp, enp); ! 606: xassign(np, xadd(enp, &xone)); ! 607: return (rnp); ! 608: } ! 609: ! 610: /* ! 611: * Post decrement -- return the old value ! 612: * but increment the variable. ! 613: */ ! 614: NODE * ! 615: xdeca(np) ! 616: register NODE *np; ! 617: { ! 618: register NODE *rnp; ! 619: register NODE *enp; ! 620: ! 621: enp = evalexpr(np); ! 622: rnp = inode((INT)0); ! 623: xassign(rnp, enp); ! 624: xassign(np, xsub(enp, &xone)); ! 625: return (rnp); ! 626: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.