|
|
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.