run.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
run.c (42786B) | |
--- | |
1 /**************************************************************** | |
2 Copyright (C) Lucent Technologies 1997 | |
3 All Rights Reserved | |
4 | |
5 Permission to use, copy, modify, and distribute this software and | |
6 its documentation for any purpose and without fee is hereby | |
7 granted, provided that the above copyright notice appear in all | |
8 copies and that both that the copyright notice and this | |
9 permission notice and warranty disclaimer appear in supporting | |
10 documentation, and that the name Lucent Technologies or any of | |
11 its entities not be used in advertising or publicity pertaining | |
12 to distribution of the software without specific, written prior | |
13 permission. | |
14 | |
15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. | |
17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY | |
18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |
20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
22 THIS SOFTWARE. | |
23 ****************************************************************/ | |
24 | |
25 #define DEBUG | |
26 #include <stdio.h> | |
27 #include <ctype.h> | |
28 #include <setjmp.h> | |
29 #include <math.h> | |
30 #include <string.h> | |
31 #include <stdlib.h> | |
32 #include <time.h> | |
33 #include "awk.h" | |
34 #include "y.tab.h" | |
35 | |
36 #define tempfree(x) if (istemp(x)) tfree(x); else | |
37 | |
38 /* | |
39 #undef tempfree | |
40 | |
41 void tempfree(Cell *p) { | |
42 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) { | |
43 WARNING("bad csub %d in Cell %d %s", | |
44 p->csub, p->ctype, p->sval); | |
45 } | |
46 if (istemp(p)) | |
47 tfree(p); | |
48 } | |
49 */ | |
50 | |
51 #ifdef _NFILE | |
52 #ifndef FOPEN_MAX | |
53 #define FOPEN_MAX _NFILE | |
54 #endif | |
55 #endif | |
56 | |
57 #ifndef FOPEN_MAX | |
58 #define FOPEN_MAX 40 /* max number of open files */ | |
59 #endif | |
60 | |
61 #ifndef RAND_MAX | |
62 #define RAND_MAX 32767 /* all that ansi guarantees */ | |
63 #endif | |
64 | |
65 jmp_buf env; | |
66 extern int pairstack[]; | |
67 | |
68 Node *winner = NULL; /* root of parse tree */ | |
69 Cell *tmps; /* free temporary cells for execution … | |
70 | |
71 static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM }; | |
72 Cell *True = &truecell; | |
73 static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM }; | |
74 Cell *False = &falsecell; | |
75 static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM }; | |
76 Cell *jbreak = &breakcell; | |
77 static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM }; | |
78 Cell *jcont = &contcell; | |
79 static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM }; | |
80 Cell *jnext = &nextcell; | |
81 static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, N… | |
82 Cell *jnextfile = &nextfilecell; | |
83 static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM }; | |
84 Cell *jexit = &exitcell; | |
85 static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM… | |
86 Cell *jret = &retcell; | |
87 static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|… | |
88 | |
89 Node *curnode = NULL; /* the node being executed, for debu… | |
90 | |
91 /* buffer memory management */ | |
92 int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, | |
93 char *whatrtn) | |
94 /* pbuf: address of pointer to buffer being managed | |
95 * psiz: address of buffer size variable | |
96 * minlen: minimum length of buffer needed | |
97 * quantum: buffer size quantum | |
98 * pbptr: address of movable pointer into buffer, or 0 if none | |
99 * whatrtn: name of the calling routine if failure should cause fatal er… | |
100 * | |
101 * return 0 for realloc failure, !=0 for success | |
102 */ | |
103 { | |
104 if (minlen > *psiz) { | |
105 char *tbuf; | |
106 int rminlen = quantum ? minlen % quantum : 0; | |
107 int boff = pbptr ? *pbptr - *pbuf : 0; | |
108 /* round up to next multiple of quantum */ | |
109 if (rminlen) | |
110 minlen += quantum - rminlen; | |
111 tbuf = (char *) realloc(*pbuf, minlen); | |
112 if (tbuf == NULL) { | |
113 if (whatrtn) | |
114 FATAL("out of memory in %s", whatrtn); | |
115 return 0; | |
116 } | |
117 *pbuf = tbuf; | |
118 *psiz = minlen; | |
119 if (pbptr) | |
120 *pbptr = tbuf + boff; | |
121 } | |
122 return 1; | |
123 } | |
124 | |
125 void run(Node *a) /* execution of parse tree starts here */ | |
126 { | |
127 extern void stdinit(void); | |
128 | |
129 stdinit(); | |
130 execute(a); | |
131 closeall(); | |
132 } | |
133 | |
134 Cell *execute(Node *u) /* execute a node of the parse tree */ | |
135 { | |
136 int nobj; | |
137 Cell *(*proc)(Node **, int); | |
138 Cell *x; | |
139 Node *a; | |
140 | |
141 if (u == NULL) | |
142 return(True); | |
143 for (a = u; ; a = a->nnext) { | |
144 curnode = a; | |
145 if (isvalue(a)) { | |
146 x = (Cell *) (a->narg[0]); | |
147 if (isfld(x) && !donefld) | |
148 fldbld(); | |
149 else if (isrec(x) && !donerec) | |
150 recbld(); | |
151 return(x); | |
152 } | |
153 nobj = a->nobj; | |
154 if (notlegal(nobj)) /* probably a Cell* but too r… | |
155 FATAL("illegal statement"); | |
156 proc = proctab[nobj-FIRSTTOKEN]; | |
157 x = (*proc)(a->narg, nobj); | |
158 if (isfld(x) && !donefld) | |
159 fldbld(); | |
160 else if (isrec(x) && !donerec) | |
161 recbld(); | |
162 if (isexpr(a)) | |
163 return(x); | |
164 if (isjump(x)) | |
165 return(x); | |
166 if (a->nnext == NULL) | |
167 return(x); | |
168 tempfree(x); | |
169 } | |
170 } | |
171 | |
172 | |
173 Cell *program(Node **a, int n) /* execute an awk program */ | |
174 { /* a[0] = BEGIN, a[1] = body, a[2] = EN… | |
175 Cell *x; | |
176 | |
177 if (setjmp(env) != 0) | |
178 goto ex; | |
179 if (a[0]) { /* BEGIN */ | |
180 x = execute(a[0]); | |
181 if (isexit(x)) | |
182 return(True); | |
183 if (isjump(x)) | |
184 FATAL("illegal break, continue, next or nextfile… | |
185 tempfree(x); | |
186 } | |
187 if (a[1] || a[2]) | |
188 while (getrec(&record, &recsize, 1) > 0) { | |
189 x = execute(a[1]); | |
190 if (isexit(x)) | |
191 break; | |
192 tempfree(x); | |
193 } | |
194 ex: | |
195 if (setjmp(env) != 0) /* handles exit within END */ | |
196 goto ex1; | |
197 if (a[2]) { /* END */ | |
198 x = execute(a[2]); | |
199 if (isbreak(x) || isnext(x) || iscont(x)) | |
200 FATAL("illegal break, continue, next or nextfile… | |
201 tempfree(x); | |
202 } | |
203 ex1: | |
204 return(True); | |
205 } | |
206 | |
207 struct Frame { /* stack frame for awk function calls */ | |
208 int nargs; /* number of arguments in this call */ | |
209 Cell *fcncell; /* pointer to Cell for function */ | |
210 Cell **args; /* pointer to array of arguments after execu… | |
211 Cell *retval; /* return value */ | |
212 }; | |
213 | |
214 #define NARGS 50 /* max args in a call */ | |
215 | |
216 struct Frame *frame = NULL; /* base of stack frames; dynamically … | |
217 int nframe = 0; /* number of frames allocated */ | |
218 struct Frame *fp = NULL; /* frame pointer. bottom level unused */ | |
219 | |
220 Cell *call(Node **a, int n) /* function call. very kludgy and fr… | |
221 { | |
222 static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DO… | |
223 int i, ncall, ndef; | |
224 Node *x; | |
225 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arra… | |
226 Cell *y, *z, *fcn; | |
227 char *s; | |
228 | |
229 fcn = execute(a[0]); /* the function itself */ | |
230 s = fcn->nval; | |
231 if (!isfcn(fcn)) | |
232 FATAL("calling undefined function %s", s); | |
233 if (frame == NULL) { | |
234 fp = frame = (struct Frame *) calloc(nframe += 100, size… | |
235 if (frame == NULL) | |
236 FATAL("out of space for stack frames calling %s"… | |
237 } | |
238 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* arg… | |
239 ncall++; | |
240 ndef = (int) fcn->fval; /* args in defn */ | |
241 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, nca… | |
242 if (ncall > ndef) | |
243 WARNING("function %s called with %d args, uses only %d", | |
244 s, ncall, ndef); | |
245 if (ncall + ndef > NARGS) | |
246 FATAL("function %s has %d arguments, limit %d", s, ncall… | |
247 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* … | |
248 dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp… | |
249 y = execute(x); | |
250 oargs[i] = y; | |
251 dprintf( ("args[%d]: %s %f <%s>, t=%o\n", | |
252 i, y->nval, y->fval, isarr(y) ? "(array)" : y… | |
253 if (isfcn(y)) | |
254 FATAL("can't use function %s as argument in %s",… | |
255 if (isarr(y)) | |
256 args[i] = y; /* arrays by ref */ | |
257 else | |
258 args[i] = copycell(y); | |
259 tempfree(y); | |
260 } | |
261 for ( ; i < ndef; i++) { /* add null args for ones not pr… | |
262 args[i] = gettemp(); | |
263 *args[i] = newcopycell; | |
264 } | |
265 fp++; /* now ok to up frame */ | |
266 if (fp >= frame + nframe) { | |
267 int dfp = fp - frame; /* old index */ | |
268 frame = (struct Frame *) | |
269 realloc((char *) frame, (nframe += 100) * sizeof… | |
270 if (frame == NULL) | |
271 FATAL("out of space for stack frames in %s", s); | |
272 fp = frame + dfp; | |
273 } | |
274 fp->fcncell = fcn; | |
275 fp->args = args; | |
276 fp->nargs = ndef; /* number defined with (excess are loca… | |
277 fp->retval = gettemp(); | |
278 | |
279 dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) ); | |
280 y = execute((Node *)(fcn->sval)); /* execute body */ | |
281 dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)… | |
282 | |
283 for (i = 0; i < ndef; i++) { | |
284 Cell *t = fp->args[i]; | |
285 if (isarr(t)) { | |
286 if (t->csub == CCOPY) { | |
287 if (i >= ncall) { | |
288 freesymtab(t); | |
289 t->csub = CTEMP; | |
290 tempfree(t); | |
291 } else { | |
292 oargs[i]->tval = t->tval; | |
293 oargs[i]->tval &= ~(STR|NUM|DONT… | |
294 oargs[i]->sval = t->sval; | |
295 tempfree(t); | |
296 } | |
297 } | |
298 } else if (t != y) { /* kludge to prevent freeing… | |
299 t->csub = CTEMP; | |
300 tempfree(t); | |
301 } | |
302 } | |
303 tempfree(fcn); | |
304 if (isexit(y) || isnext(y) || isnextfile(y)) | |
305 return y; | |
306 tempfree(y); /* this can free twice! */ | |
307 z = fp->retval; /* return value */ | |
308 dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z… | |
309 fp--; | |
310 return(z); | |
311 } | |
312 | |
313 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */ | |
314 { | |
315 Cell *y; | |
316 | |
317 y = gettemp(); | |
318 y->csub = CCOPY; /* prevents freeing until call is over */ | |
319 y->nval = x->nval; /* BUG? */ | |
320 y->sval = x->sval ? tostring(x->sval) : NULL; | |
321 y->fval = x->fval; | |
322 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is n… | |
323 /* is DONTFREE r… | |
324 return y; | |
325 } | |
326 | |
327 Cell *arg(Node **a, int n) /* nth argument of a function */ | |
328 { | |
329 | |
330 n = ptoi(a[0]); /* argument number, counting from 0 */ | |
331 dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); | |
332 if (n+1 > fp->nargs) | |
333 FATAL("argument #%d of function %s was not supplied", | |
334 n+1, fp->fcncell->nval); | |
335 return fp->args[n]; | |
336 } | |
337 | |
338 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, r… | |
339 { | |
340 Cell *y; | |
341 | |
342 switch (n) { | |
343 case EXIT: | |
344 if (a[0] != NULL) { | |
345 y = execute(a[0]); | |
346 errorflag = (int) getfval(y); | |
347 tempfree(y); | |
348 } | |
349 longjmp(env, 1); | |
350 case RETURN: | |
351 if (a[0] != NULL) { | |
352 y = execute(a[0]); | |
353 if ((y->tval & (STR|NUM)) == (STR|NUM)) { | |
354 setsval(fp->retval, getsval(y)); | |
355 fp->retval->fval = getfval(y); | |
356 fp->retval->tval |= NUM; | |
357 } | |
358 else if (y->tval & STR) | |
359 setsval(fp->retval, getsval(y)); | |
360 else if (y->tval & NUM) | |
361 setfval(fp->retval, getfval(y)); | |
362 else /* can't happen */ | |
363 FATAL("bad type variable %d", y->tval); | |
364 tempfree(y); | |
365 } | |
366 return(jret); | |
367 case NEXT: | |
368 return(jnext); | |
369 case NEXTFILE: | |
370 nextfile(); | |
371 return(jnextfile); | |
372 case BREAK: | |
373 return(jbreak); | |
374 case CONTINUE: | |
375 return(jcont); | |
376 default: /* can't happen */ | |
377 FATAL("illegal jump type %d", n); | |
378 } | |
379 return 0; /* not reached */ | |
380 } | |
381 | |
382 Cell *getline(Node **a, int n) /* get next line from specific inp… | |
383 { /* a[0] is variable, a[1] is operator, a[2] is filename… | |
384 Cell *r, *x; | |
385 extern Cell **fldtab; | |
386 FILE *fp; | |
387 char *buf; | |
388 int bufsize = recsize; | |
389 int mode; | |
390 | |
391 if ((buf = (char *) malloc(bufsize)) == NULL) | |
392 FATAL("out of memory in getline"); | |
393 | |
394 fflush(stdout); /* in case someone is waiting for a promp… | |
395 r = gettemp(); | |
396 if (a[1] != NULL) { /* getline < file */ | |
397 x = execute(a[2]); /* filename */ | |
398 mode = ptoi(a[1]); | |
399 if (mode == '|') /* input pipe */ | |
400 mode = LE; /* arbitrary flag */ | |
401 fp = openfile(mode, getsval(x)); | |
402 tempfree(x); | |
403 if (fp == NULL) | |
404 n = -1; | |
405 else | |
406 n = readrec(&buf, &bufsize, fp); | |
407 if (n <= 0) { | |
408 ; | |
409 } else if (a[0] != NULL) { /* getline var <file */ | |
410 x = execute(a[0]); | |
411 setsval(x, buf); | |
412 tempfree(x); | |
413 } else { /* getline <file */ | |
414 setsval(fldtab[0], buf); | |
415 if (is_number(fldtab[0]->sval)) { | |
416 fldtab[0]->fval = atof(fldtab[0]->sval); | |
417 fldtab[0]->tval |= NUM; | |
418 } | |
419 } | |
420 } else { /* bare getline; use current inp… | |
421 if (a[0] == NULL) /* getline */ | |
422 n = getrec(&record, &recsize, 1); | |
423 else { /* getline var */ | |
424 n = getrec(&buf, &bufsize, 0); | |
425 x = execute(a[0]); | |
426 setsval(x, buf); | |
427 tempfree(x); | |
428 } | |
429 } | |
430 setfval(r, (Awkfloat) n); | |
431 free(buf); | |
432 return r; | |
433 } | |
434 | |
435 Cell *getnf(Node **a, int n) /* get NF */ | |
436 { | |
437 if (donefld == 0) | |
438 fldbld(); | |
439 return (Cell *) a[0]; | |
440 } | |
441 | |
442 Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of s… | |
443 { | |
444 Cell *x, *y, *z; | |
445 char *s; | |
446 Node *np; | |
447 char *buf; | |
448 int bufsz = recsize; | |
449 int nsub = strlen(*SUBSEP); | |
450 | |
451 if ((buf = (char *) malloc(bufsz)) == NULL) | |
452 FATAL("out of memory in array"); | |
453 | |
454 x = execute(a[0]); /* Cell* for symbol table */ | |
455 buf[0] = 0; | |
456 for (np = a[1]; np; np = np->nnext) { | |
457 y = execute(np); /* subscript */ | |
458 s = getsval(y); | |
459 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, … | |
460 FATAL("out of memory for %s[%s...]", x->nval, bu… | |
461 strcat(buf, s); | |
462 if (np->nnext) | |
463 strcat(buf, *SUBSEP); | |
464 tempfree(y); | |
465 } | |
466 if (!isarr(x)) { | |
467 dprintf( ("making %s into an array\n", x->nval) ); | |
468 if (freeable(x)) | |
469 xfree(x->sval); | |
470 x->tval &= ~(STR|NUM|DONTFREE); | |
471 x->tval |= ARR; | |
472 x->sval = (char *) makesymtab(NSYMTAB); | |
473 } | |
474 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); | |
475 z->ctype = OCELL; | |
476 z->csub = CVAR; | |
477 tempfree(x); | |
478 free(buf); | |
479 return(z); | |
480 } | |
481 | |
482 Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list … | |
483 { | |
484 Cell *x, *y; | |
485 Node *np; | |
486 char *s; | |
487 int nsub = strlen(*SUBSEP); | |
488 | |
489 x = execute(a[0]); /* Cell* for symbol table */ | |
490 if (!isarr(x)) | |
491 return True; | |
492 if (a[1] == 0) { /* delete the elements, not the table */ | |
493 freesymtab(x); | |
494 x->tval &= ~STR; | |
495 x->tval |= ARR; | |
496 x->sval = (char *) makesymtab(NSYMTAB); | |
497 } else { | |
498 int bufsz = recsize; | |
499 char *buf; | |
500 if ((buf = (char *) malloc(bufsz)) == NULL) | |
501 FATAL("out of memory in adelete"); | |
502 buf[0] = 0; | |
503 for (np = a[1]; np; np = np->nnext) { | |
504 y = execute(np); /* subscript */ | |
505 s = getsval(y); | |
506 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+… | |
507 FATAL("out of memory deleting %s[%s...]"… | |
508 strcat(buf, s); | |
509 if (np->nnext) | |
510 strcat(buf, *SUBSEP); | |
511 tempfree(y); | |
512 } | |
513 freeelem(x, buf); | |
514 free(buf); | |
515 } | |
516 tempfree(x); | |
517 return True; | |
518 } | |
519 | |
520 Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is sy… | |
521 { | |
522 Cell *x, *ap, *k; | |
523 Node *p; | |
524 char *buf; | |
525 char *s; | |
526 int bufsz = recsize; | |
527 int nsub = strlen(*SUBSEP); | |
528 | |
529 ap = execute(a[1]); /* array name */ | |
530 if (!isarr(ap)) { | |
531 dprintf( ("making %s into an array\n", ap->nval) ); | |
532 if (freeable(ap)) | |
533 xfree(ap->sval); | |
534 ap->tval &= ~(STR|NUM|DONTFREE); | |
535 ap->tval |= ARR; | |
536 ap->sval = (char *) makesymtab(NSYMTAB); | |
537 } | |
538 if ((buf = (char *) malloc(bufsz)) == NULL) { | |
539 FATAL("out of memory in intest"); | |
540 } | |
541 buf[0] = 0; | |
542 for (p = a[0]; p; p = p->nnext) { | |
543 x = execute(p); /* expr */ | |
544 s = getsval(x); | |
545 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, … | |
546 FATAL("out of memory deleting %s[%s...]", x->nva… | |
547 strcat(buf, s); | |
548 tempfree(x); | |
549 if (p->nnext) | |
550 strcat(buf, *SUBSEP); | |
551 } | |
552 k = lookup(buf, (Array *) ap->sval); | |
553 tempfree(ap); | |
554 free(buf); | |
555 if (k == NULL) | |
556 return(False); | |
557 else | |
558 return(True); | |
559 } | |
560 | |
561 | |
562 Cell *matchop(Node **a, int n) /* ~ and match() */ | |
563 { | |
564 Cell *x, *y; | |
565 char *s, *t; | |
566 int i; | |
567 void *p; | |
568 | |
569 x = execute(a[1]); /* a[1] = target text */ | |
570 s = getsval(x); | |
571 if (a[0] == 0) /* a[1] == 0: already-compiled reg… | |
572 p = (void *) a[2]; | |
573 else { | |
574 y = execute(a[2]); /* a[2] = regular expr */ | |
575 t = getsval(y); | |
576 p = compre(t); | |
577 tempfree(y); | |
578 } | |
579 if (n == MATCHFCN) | |
580 i = pmatch(p, s, s); | |
581 else | |
582 i = match(p, s, s); | |
583 tempfree(x); | |
584 if (n == MATCHFCN) { | |
585 int start = countposn(s, patbeg-s)+1; | |
586 if (patlen < 0) | |
587 start = 0; | |
588 setfval(rstartloc, (Awkfloat) start); | |
589 setfval(rlengthloc, (Awkfloat) countposn(patbeg, patlen)… | |
590 x = gettemp(); | |
591 x->tval = NUM; | |
592 x->fval = start; | |
593 return x; | |
594 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0)) | |
595 return(True); | |
596 else | |
597 return(False); | |
598 } | |
599 | |
600 | |
601 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0… | |
602 { | |
603 Cell *x, *y; | |
604 int i; | |
605 | |
606 x = execute(a[0]); | |
607 i = istrue(x); | |
608 tempfree(x); | |
609 switch (n) { | |
610 case BOR: | |
611 if (i) return(True); | |
612 y = execute(a[1]); | |
613 i = istrue(y); | |
614 tempfree(y); | |
615 if (i) return(True); | |
616 else return(False); | |
617 case AND: | |
618 if ( !i ) return(False); | |
619 y = execute(a[1]); | |
620 i = istrue(y); | |
621 tempfree(y); | |
622 if (i) return(True); | |
623 else return(False); | |
624 case NOT: | |
625 if (i) return(False); | |
626 else return(True); | |
627 default: /* can't happen */ | |
628 FATAL("unknown boolean operator %d", n); | |
629 } | |
630 return 0; /*NOTREACHED*/ | |
631 } | |
632 | |
633 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */ | |
634 { | |
635 int i; | |
636 Cell *x, *y; | |
637 Awkfloat j; | |
638 | |
639 x = execute(a[0]); | |
640 y = execute(a[1]); | |
641 if (x->tval&NUM && y->tval&NUM) { | |
642 j = x->fval - y->fval; | |
643 i = j<0? -1: (j>0? 1: 0); | |
644 } else { | |
645 i = strcmp(getsval(x), getsval(y)); | |
646 } | |
647 tempfree(x); | |
648 tempfree(y); | |
649 switch (n) { | |
650 case LT: if (i<0) return(True); | |
651 else return(False); | |
652 case LE: if (i<=0) return(True); | |
653 else return(False); | |
654 case NE: if (i!=0) return(True); | |
655 else return(False); | |
656 case EQ: if (i == 0) return(True); | |
657 else return(False); | |
658 case GE: if (i>=0) return(True); | |
659 else return(False); | |
660 case GT: if (i>0) return(True); | |
661 else return(False); | |
662 default: /* can't happen */ | |
663 FATAL("unknown relational operator %d", n); | |
664 } | |
665 return 0; /*NOTREACHED*/ | |
666 } | |
667 | |
668 void tfree(Cell *a) /* free a tempcell */ | |
669 { | |
670 if (freeable(a)) { | |
671 dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->… | |
672 xfree(a->sval); | |
673 } | |
674 if (a == tmps) | |
675 FATAL("tempcell list is curdled"); | |
676 a->cnext = tmps; | |
677 tmps = a; | |
678 } | |
679 | |
680 Cell *gettemp(void) /* get a tempcell */ | |
681 { int i; | |
682 Cell *x; | |
683 | |
684 if (!tmps) { | |
685 tmps = (Cell *) calloc(100, sizeof(Cell)); | |
686 if (!tmps) | |
687 FATAL("out of space for temporaries"); | |
688 for(i = 1; i < 100; i++) | |
689 tmps[i-1].cnext = &tmps[i]; | |
690 tmps[i-1].cnext = 0; | |
691 } | |
692 x = tmps; | |
693 tmps = x->cnext; | |
694 *x = tempcell; | |
695 return(x); | |
696 } | |
697 | |
698 Cell *indirect(Node **a, int n) /* $( a[0] ) */ | |
699 { | |
700 Cell *x; | |
701 int m; | |
702 char *s; | |
703 | |
704 x = execute(a[0]); | |
705 m = (int) getfval(x); | |
706 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */ | |
707 FATAL("illegal field $(%s), name \"%s\"", s, x->nval); | |
708 /* BUG: can x->nval ever be null??? */ | |
709 tempfree(x); | |
710 x = fieldadr(m); | |
711 x->ctype = OCELL; /* BUG? why are these needed? */ | |
712 x->csub = CFLD; | |
713 return(x); | |
714 } | |
715 | |
716 Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2… | |
717 { | |
718 int k, m, n; | |
719 char *s, *p; | |
720 int temp; | |
721 Cell *x, *y, *z = 0; | |
722 | |
723 x = execute(a[0]); | |
724 y = execute(a[1]); | |
725 if (a[2] != 0) | |
726 z = execute(a[2]); | |
727 s = getsval(x); | |
728 k = countposn(s, strlen(s)) + 1; | |
729 if (k <= 1) { | |
730 tempfree(x); | |
731 tempfree(y); | |
732 if (a[2] != 0) | |
733 tempfree(z); | |
734 x = gettemp(); | |
735 setsval(x, ""); | |
736 return(x); | |
737 } | |
738 m = (int) getfval(y); | |
739 if (m <= 0) | |
740 m = 1; | |
741 else if (m > k) | |
742 m = k; | |
743 tempfree(y); | |
744 if (a[2] != 0) { | |
745 n = (int) getfval(z); | |
746 tempfree(z); | |
747 } else | |
748 n = k - 1; | |
749 if (n < 0) | |
750 n = 0; | |
751 else if (n > k - m) | |
752 n = k - m; | |
753 dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); | |
754 y = gettemp(); | |
755 while (*s && --m) | |
756 s += mblen(s, k); | |
757 for (p = s; *p && n--; p += mblen(p, k)) | |
758 ; | |
759 temp = *p; /* with thanks to John Linderman */ | |
760 *p = '\0'; | |
761 setsval(y, s); | |
762 *p = temp; | |
763 tempfree(x); | |
764 return(y); | |
765 } | |
766 | |
767 Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ | |
768 { | |
769 Cell *x, *y, *z; | |
770 char *s1, *s2, *p1, *p2, *q; | |
771 Awkfloat v = 0.0; | |
772 | |
773 x = execute(a[0]); | |
774 s1 = getsval(x); | |
775 y = execute(a[1]); | |
776 s2 = getsval(y); | |
777 | |
778 z = gettemp(); | |
779 for (p1 = s1; *p1 != '\0'; p1++) { | |
780 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) | |
781 ; | |
782 if (*p2 == '\0') { | |
783 v = (Awkfloat) countposn(s1, p1-s1) + 1; … | |
784 break; | |
785 } | |
786 } | |
787 tempfree(x); | |
788 tempfree(y); | |
789 setfval(z, v); | |
790 return(z); | |
791 } | |
792 | |
793 #define MAXNUMSIZE 50 | |
794 | |
795 int format(char **pbuf, int *pbufsize, char *s, Node *a) /* print… | |
796 { | |
797 char *fmt; | |
798 char *p, *t, *os; | |
799 Cell *x; | |
800 int flag = 0, n; | |
801 int fmtwd; /* format width */ | |
802 int fmtsz = recsize; | |
803 char *buf = *pbuf; | |
804 int bufsize = *pbufsize; | |
805 | |
806 os = s; | |
807 p = buf; | |
808 if ((fmt = (char *) malloc(fmtsz)) == NULL) | |
809 FATAL("out of memory in format()"); | |
810 while (*s) { | |
811 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, … | |
812 if (*s != '%') { | |
813 *p++ = *s++; | |
814 continue; | |
815 } | |
816 if (*(s+1) == '%') { | |
817 *p++ = '%'; | |
818 s += 2; | |
819 continue; | |
820 } | |
821 /* have to be real careful in case this is a huge number… | |
822 fmtwd = atoi(s+1); | |
823 if (fmtwd < 0) | |
824 fmtwd = -fmtwd; | |
825 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "form… | |
826 for (t = fmt; (*t++ = *s) != '\0'; s++) { | |
827 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, re… | |
828 FATAL("format item %.30s... ran format()… | |
829 if (isalpha(*s) && *s != 'l' && *s != 'h' && *s … | |
830 break; /* the ansi panoply */ | |
831 if (*s == '*') { | |
832 x = execute(a); | |
833 a = a->nnext; | |
834 sprintf(t-1, "%d", fmtwd=(int) getfval(x… | |
835 if (fmtwd < 0) | |
836 fmtwd = -fmtwd; | |
837 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, re… | |
838 t = fmt + strlen(fmt); | |
839 tempfree(x); | |
840 } | |
841 } | |
842 *t = '\0'; | |
843 if (fmtwd < 0) | |
844 fmtwd = -fmtwd; | |
845 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "form… | |
846 | |
847 switch (*s) { | |
848 case 'f': case 'e': case 'g': case 'E': case 'G': | |
849 flag = 1; | |
850 break; | |
851 case 'd': case 'i': | |
852 flag = 2; | |
853 if(*(s-1) == 'l') break; | |
854 *(t-1) = 'l'; | |
855 *t = 'd'; | |
856 *++t = '\0'; | |
857 break; | |
858 case 'o': case 'x': case 'X': case 'u': | |
859 flag = *(s-1) == 'l' ? 2 : 3; | |
860 break; | |
861 case 's': | |
862 flag = 4; | |
863 break; | |
864 case 'c': | |
865 flag = 5; | |
866 break; | |
867 default: | |
868 WARNING("weird printf conversion %s", fmt); | |
869 flag = 0; | |
870 break; | |
871 } | |
872 if (a == NULL) | |
873 FATAL("not enough args in printf(%s)", os); | |
874 x = execute(a); | |
875 a = a->nnext; | |
876 n = MAXNUMSIZE; | |
877 if (fmtwd > n) | |
878 n = fmtwd; | |
879 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format"); | |
880 switch (flag) { | |
881 case 0: sprintf(p, "%s", fmt); /* unknown,… | |
882 t = getsval(x); | |
883 n = strlen(t); | |
884 if (fmtwd > n) | |
885 n = fmtwd; | |
886 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recs… | |
887 p += strlen(p); | |
888 sprintf(p, "%s", t); | |
889 break; | |
890 case 1: sprintf(p, fmt, getfval(x)); break; | |
891 case 2: sprintf(p, fmt, (long) getfval(x)); break; | |
892 case 3: sprintf(p, fmt, (int) getfval(x)); break; | |
893 case 4: | |
894 t = getsval(x); | |
895 n = strlen(t); | |
896 if (fmtwd > n) | |
897 n = fmtwd; | |
898 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, … | |
899 FATAL("huge string/format (%d chars) in … | |
900 sprintf(p, fmt, t); | |
901 break; | |
902 case 5: | |
903 if (isnum(x)) { | |
904 if (getfval(x)) | |
905 sprintf(p, fmt, (int) getfval(x)… | |
906 else{ | |
907 *p++ = '\0'; | |
908 *p = '\0'; | |
909 } | |
910 } else | |
911 sprintf(p, fmt, getsval(x)[0]); | |
912 break; | |
913 } | |
914 tempfree(x); | |
915 p += strlen(p); | |
916 s++; | |
917 } | |
918 *p = '\0'; | |
919 free(fmt); | |
920 for ( ; a; a = a->nnext) /* evaluate any remainin… | |
921 execute(a); | |
922 *pbuf = buf; | |
923 *pbufsize = bufsize; | |
924 return p - buf; | |
925 } | |
926 | |
927 Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ | |
928 { | |
929 Cell *x; | |
930 Node *y; | |
931 char *buf; | |
932 int bufsz=3*recsize; | |
933 | |
934 if ((buf = (char *) malloc(bufsz)) == NULL) | |
935 FATAL("out of memory in awksprintf"); | |
936 y = a[0]->nnext; | |
937 x = execute(a[0]); | |
938 if (format(&buf, &bufsz, getsval(x), y) == -1) | |
939 FATAL("sprintf string %.30s... too long. can't happen."… | |
940 tempfree(x); | |
941 x = gettemp(); | |
942 x->sval = buf; | |
943 x->tval = STR; | |
944 return(x); | |
945 } | |
946 | |
947 Cell *awkprintf(Node **a, int n) /* printf */ | |
948 { /* a[0] is list of args, starting with format string */ | |
949 /* a[1] is redirection operator, a[2] is redirection file */ | |
950 FILE *fp; | |
951 Cell *x; | |
952 Node *y; | |
953 char *buf; | |
954 int len; | |
955 int bufsz=3*recsize; | |
956 | |
957 if ((buf = (char *) malloc(bufsz)) == NULL) | |
958 FATAL("out of memory in awkprintf"); | |
959 y = a[0]->nnext; | |
960 x = execute(a[0]); | |
961 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) | |
962 FATAL("printf string %.30s... too long. can't happen.",… | |
963 tempfree(x); | |
964 if (a[1] == NULL) { | |
965 /* fputs(buf, stdout); */ | |
966 fwrite(buf, len, 1, stdout); | |
967 if (ferror(stdout)) | |
968 FATAL("write error on stdout"); | |
969 } else { | |
970 fp = redirect(ptoi(a[1]), a[2]); | |
971 /* fputs(buf, fp); */ | |
972 fwrite(buf, len, 1, fp); | |
973 fflush(fp); | |
974 if (ferror(fp)) | |
975 FATAL("write error on %s", filename(fp)); | |
976 } | |
977 free(buf); | |
978 return(True); | |
979 } | |
980 | |
981 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ | |
982 { | |
983 Awkfloat i, j = 0; | |
984 double v; | |
985 Cell *x, *y, *z; | |
986 | |
987 x = execute(a[0]); | |
988 i = getfval(x); | |
989 tempfree(x); | |
990 if (n != UMINUS) { | |
991 y = execute(a[1]); | |
992 j = getfval(y); | |
993 tempfree(y); | |
994 } | |
995 z = gettemp(); | |
996 switch (n) { | |
997 case ADD: | |
998 i += j; | |
999 break; | |
1000 case MINUS: | |
1001 i -= j; | |
1002 break; | |
1003 case MULT: | |
1004 i *= j; | |
1005 break; | |
1006 case DIVIDE: | |
1007 if (j == 0) | |
1008 FATAL("division by zero"); | |
1009 i /= j; | |
1010 break; | |
1011 case MOD: | |
1012 if (j == 0) | |
1013 FATAL("division by zero in mod"); | |
1014 modf(i/j, &v); | |
1015 i = i - j * v; | |
1016 break; | |
1017 case UMINUS: | |
1018 i = -i; | |
1019 break; | |
1020 case POWER: | |
1021 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer … | |
1022 i = ipow(i, (int) j); | |
1023 else | |
1024 i = errcheck(pow(i, j), "pow"); | |
1025 break; | |
1026 default: /* can't happen */ | |
1027 FATAL("illegal arithmetic operator %d", n); | |
1028 } | |
1029 setfval(z, i); | |
1030 return(z); | |
1031 } | |
1032 | |
1033 double ipow(double x, int n) /* x**n. ought to be done by pow, b… | |
1034 { | |
1035 double v; | |
1036 | |
1037 if (n <= 0) | |
1038 return 1; | |
1039 v = ipow(x, n/2); | |
1040 if (n % 2 == 0) | |
1041 return v * v; | |
1042 else | |
1043 return x * v * v; | |
1044 } | |
1045 | |
1046 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */ | |
1047 { | |
1048 Cell *x, *z; | |
1049 int k; | |
1050 Awkfloat xf; | |
1051 | |
1052 x = execute(a[0]); | |
1053 xf = getfval(x); | |
1054 k = (n == PREINCR || n == POSTINCR) ? 1 : -1; | |
1055 if (n == PREINCR || n == PREDECR) { | |
1056 setfval(x, xf + k); | |
1057 return(x); | |
1058 } | |
1059 z = gettemp(); | |
1060 setfval(z, xf); | |
1061 setfval(x, xf + k); | |
1062 tempfree(x); | |
1063 return(z); | |
1064 } | |
1065 | |
1066 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. … | |
1067 { /* this is subtle; don't muck with it. */ | |
1068 Cell *x, *y; | |
1069 Awkfloat xf, yf; | |
1070 double v; | |
1071 | |
1072 y = execute(a[1]); | |
1073 x = execute(a[0]); | |
1074 if (n == ASSIGN) { /* ordinary assignment */ | |
1075 if (x == y && !(x->tval & (FLD|REC))) /* self-ass… | |
1076 ; /* leave alone unless it's a fi… | |
1077 else if ((y->tval & (STR|NUM)) == (STR|NUM)) { | |
1078 setsval(x, getsval(y)); | |
1079 x->fval = getfval(y); | |
1080 x->tval |= NUM; | |
1081 } | |
1082 else if (isstr(y)) | |
1083 setsval(x, getsval(y)); | |
1084 else if (isnum(y)) | |
1085 setfval(x, getfval(y)); | |
1086 else | |
1087 funnyvar(y, "read value of"); | |
1088 tempfree(y); | |
1089 return(x); | |
1090 } | |
1091 xf = getfval(x); | |
1092 yf = getfval(y); | |
1093 switch (n) { | |
1094 case ADDEQ: | |
1095 xf += yf; | |
1096 break; | |
1097 case SUBEQ: | |
1098 xf -= yf; | |
1099 break; | |
1100 case MULTEQ: | |
1101 xf *= yf; | |
1102 break; | |
1103 case DIVEQ: | |
1104 if (yf == 0) | |
1105 FATAL("division by zero in /="); | |
1106 xf /= yf; | |
1107 break; | |
1108 case MODEQ: | |
1109 if (yf == 0) | |
1110 FATAL("division by zero in %%="); | |
1111 modf(xf/yf, &v); | |
1112 xf = xf - yf * v; | |
1113 break; | |
1114 case POWEQ: | |
1115 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos intege… | |
1116 xf = ipow(xf, (int) yf); | |
1117 else | |
1118 xf = errcheck(pow(xf, yf), "pow"); | |
1119 break; | |
1120 default: | |
1121 FATAL("illegal assignment operator %d", n); | |
1122 break; | |
1123 } | |
1124 tempfree(y); | |
1125 setfval(x, xf); | |
1126 return(x); | |
1127 } | |
1128 | |
1129 Cell *cat(Node **a, int q) /* a[0] cat a[1] */ | |
1130 { | |
1131 Cell *x, *y, *z; | |
1132 int n1, n2; | |
1133 char *s; | |
1134 | |
1135 x = execute(a[0]); | |
1136 y = execute(a[1]); | |
1137 getsval(x); | |
1138 getsval(y); | |
1139 n1 = strlen(x->sval); | |
1140 n2 = strlen(y->sval); | |
1141 s = (char *) malloc(n1 + n2 + 1); | |
1142 if (s == NULL) | |
1143 FATAL("out of space concatenating %.15s... and %.15s...", | |
1144 x->sval, y->sval); | |
1145 strcpy(s, x->sval); | |
1146 strcpy(s+n1, y->sval); | |
1147 tempfree(y); | |
1148 z = gettemp(); | |
1149 z->sval = s; | |
1150 z->tval = STR; | |
1151 tempfree(x); | |
1152 return(z); | |
1153 } | |
1154 | |
1155 Cell *pastat(Node **a, int n) /* a[0] { a[1] } */ | |
1156 { | |
1157 Cell *x; | |
1158 | |
1159 if (a[0] == 0) | |
1160 x = execute(a[1]); | |
1161 else { | |
1162 x = execute(a[0]); | |
1163 if (istrue(x)) { | |
1164 tempfree(x); | |
1165 x = execute(a[1]); | |
1166 } | |
1167 } | |
1168 return x; | |
1169 } | |
1170 | |
1171 Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ | |
1172 { | |
1173 Cell *x; | |
1174 int pair; | |
1175 | |
1176 pair = ptoi(a[3]); | |
1177 if (pairstack[pair] == 0) { | |
1178 x = execute(a[0]); | |
1179 if (istrue(x)) | |
1180 pairstack[pair] = 1; | |
1181 tempfree(x); | |
1182 } | |
1183 if (pairstack[pair] == 1) { | |
1184 x = execute(a[1]); | |
1185 if (istrue(x)) | |
1186 pairstack[pair] = 0; | |
1187 tempfree(x); | |
1188 x = execute(a[2]); | |
1189 return(x); | |
1190 } | |
1191 return(False); | |
1192 } | |
1193 | |
1194 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] i… | |
1195 { | |
1196 Cell *x = 0, *y, *ap; | |
1197 char *s; | |
1198 int sep; | |
1199 char *t, temp, num[50], *fs = 0; | |
1200 int n, arg3type; | |
1201 | |
1202 y = execute(a[0]); /* source string */ | |
1203 s = getsval(y); | |
1204 arg3type = ptoi(a[3]); | |
1205 if (a[2] == 0) /* fs string */ | |
1206 fs = *FS; | |
1207 else if (arg3type == STRING) { /* split(str,arr,"string")… | |
1208 x = execute(a[2]); | |
1209 fs = getsval(x); | |
1210 } else if (arg3type == REGEXPR) | |
1211 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ | |
1212 else | |
1213 FATAL("illegal type of split"); | |
1214 sep = *fs; | |
1215 ap = execute(a[1]); /* array name */ | |
1216 freesymtab(ap); | |
1217 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs)… | |
1218 ap->tval &= ~STR; | |
1219 ap->tval |= ARR; | |
1220 ap->sval = (char *) makesymtab(NSYMTAB); | |
1221 | |
1222 n = 0; | |
1223 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { … | |
1224 void *p; | |
1225 if (arg3type == REGEXPR) { /* it's ready already … | |
1226 p = (void *) a[2]; | |
1227 } else { | |
1228 p = compre(fs); | |
1229 } | |
1230 t = s; | |
1231 if (nematch(p,s,t)) { | |
1232 do { | |
1233 n++; | |
1234 sprintf(num, "%d", n); | |
1235 temp = *patbeg; | |
1236 *patbeg = '\0'; | |
1237 if (is_number(t)) | |
1238 setsymtab(num, t, atof(t), STR|N… | |
1239 else | |
1240 setsymtab(num, t, 0.0, STR, (Arr… | |
1241 *patbeg = temp; | |
1242 t = patbeg + patlen; | |
1243 if (t[-1] == 0 || *t == 0) { | |
1244 n++; | |
1245 sprintf(num, "%d", n); | |
1246 setsymtab(num, "", 0.0, STR, (Ar… | |
1247 goto spdone; | |
1248 } | |
1249 } while (nematch(p,s,t)); | |
1250 } | |
1251 n++; | |
1252 sprintf(num, "%d", n); | |
1253 if (is_number(t)) | |
1254 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap… | |
1255 else | |
1256 setsymtab(num, t, 0.0, STR, (Array *) ap->sval); | |
1257 spdone: | |
1258 p = NULL; | |
1259 } else if (sep == ' ') { | |
1260 for (n = 0; ; ) { | |
1261 while (*s == ' ' || *s == '\t' || *s == '\n') | |
1262 s++; | |
1263 if (*s == 0) | |
1264 break; | |
1265 n++; | |
1266 t = s; | |
1267 do | |
1268 s++; | |
1269 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\… | |
1270 temp = *s; | |
1271 *s = '\0'; | |
1272 sprintf(num, "%d", n); | |
1273 if (is_number(t)) | |
1274 setsymtab(num, t, atof(t), STR|NUM, (Arr… | |
1275 else | |
1276 setsymtab(num, t, 0.0, STR, (Array *) ap… | |
1277 *s = temp; | |
1278 if (*s != 0) | |
1279 s++; | |
1280 } | |
1281 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/… | |
1282 for (n = 0; *s != 0; s++) { | |
1283 char buf[2]; | |
1284 n++; | |
1285 sprintf(num, "%d", n); | |
1286 buf[0] = *s; | |
1287 buf[1] = 0; | |
1288 if (isdigit(buf[0])) | |
1289 setsymtab(num, buf, atof(buf), STR|NUM, … | |
1290 else | |
1291 setsymtab(num, buf, 0.0, STR, (Array *) … | |
1292 } | |
1293 } else if (*s != 0) { | |
1294 for (;;) { | |
1295 n++; | |
1296 t = s; | |
1297 while (*s != sep && *s != '\n' && *s != '\0') | |
1298 s++; | |
1299 temp = *s; | |
1300 *s = '\0'; | |
1301 sprintf(num, "%d", n); | |
1302 if (is_number(t)) | |
1303 setsymtab(num, t, atof(t), STR|NUM, (Arr… | |
1304 else | |
1305 setsymtab(num, t, 0.0, STR, (Array *) ap… | |
1306 *s = temp; | |
1307 if (*s++ == 0) | |
1308 break; | |
1309 } | |
1310 } | |
1311 tempfree(ap); | |
1312 tempfree(y); | |
1313 if (a[2] != 0 && arg3type == STRING) | |
1314 tempfree(x); | |
1315 x = gettemp(); | |
1316 x->tval = NUM; | |
1317 x->fval = n; | |
1318 return(x); | |
1319 } | |
1320 | |
1321 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ | |
1322 { | |
1323 Cell *x; | |
1324 | |
1325 x = execute(a[0]); | |
1326 if (istrue(x)) { | |
1327 tempfree(x); | |
1328 x = execute(a[1]); | |
1329 } else { | |
1330 tempfree(x); | |
1331 x = execute(a[2]); | |
1332 } | |
1333 return(x); | |
1334 } | |
1335 | |
1336 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ | |
1337 { | |
1338 Cell *x; | |
1339 | |
1340 x = execute(a[0]); | |
1341 if (istrue(x)) { | |
1342 tempfree(x); | |
1343 x = execute(a[1]); | |
1344 } else if (a[2] != 0) { | |
1345 tempfree(x); | |
1346 x = execute(a[2]); | |
1347 } | |
1348 return(x); | |
1349 } | |
1350 | |
1351 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */ | |
1352 { | |
1353 Cell *x; | |
1354 | |
1355 for (;;) { | |
1356 x = execute(a[0]); | |
1357 if (!istrue(x)) | |
1358 return(x); | |
1359 tempfree(x); | |
1360 x = execute(a[1]); | |
1361 if (isbreak(x)) { | |
1362 x = True; | |
1363 return(x); | |
1364 } | |
1365 if (isnext(x) || isexit(x) || isret(x)) | |
1366 return(x); | |
1367 tempfree(x); | |
1368 } | |
1369 } | |
1370 | |
1371 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */ | |
1372 { | |
1373 Cell *x; | |
1374 | |
1375 for (;;) { | |
1376 x = execute(a[0]); | |
1377 if (isbreak(x)) | |
1378 return True; | |
1379 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x)) | |
1380 return(x); | |
1381 tempfree(x); | |
1382 x = execute(a[1]); | |
1383 if (!istrue(x)) | |
1384 return(x); | |
1385 tempfree(x); | |
1386 } | |
1387 } | |
1388 | |
1389 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ | |
1390 { | |
1391 Cell *x; | |
1392 | |
1393 x = execute(a[0]); | |
1394 tempfree(x); | |
1395 for (;;) { | |
1396 if (a[1]!=0) { | |
1397 x = execute(a[1]); | |
1398 if (!istrue(x)) return(x); | |
1399 else tempfree(x); | |
1400 } | |
1401 x = execute(a[3]); | |
1402 if (isbreak(x)) /* turn off break */ | |
1403 return True; | |
1404 if (isnext(x) || isexit(x) || isret(x)) | |
1405 return(x); | |
1406 tempfree(x); | |
1407 x = execute(a[2]); | |
1408 tempfree(x); | |
1409 } | |
1410 } | |
1411 | |
1412 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ | |
1413 { | |
1414 Cell *x, *vp, *arrayp, *cp, *ncp; | |
1415 Array *tp; | |
1416 int i; | |
1417 | |
1418 vp = execute(a[0]); | |
1419 arrayp = execute(a[1]); | |
1420 if (!isarr(arrayp)) { | |
1421 return True; | |
1422 } | |
1423 tp = (Array *) arrayp->sval; | |
1424 tempfree(arrayp); | |
1425 for (i = 0; i < tp->size; i++) { /* this routine knows to… | |
1426 for (cp = tp->tab[i]; cp != NULL; cp = ncp) { | |
1427 setsval(vp, cp->nval); | |
1428 ncp = cp->cnext; | |
1429 x = execute(a[2]); | |
1430 if (isbreak(x)) { | |
1431 tempfree(vp); | |
1432 return True; | |
1433 } | |
1434 if (isnext(x) || isexit(x) || isret(x)) { | |
1435 tempfree(vp); | |
1436 return(x); | |
1437 } | |
1438 tempfree(x); | |
1439 } | |
1440 } | |
1441 return True; | |
1442 } | |
1443 | |
1444 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, … | |
1445 { | |
1446 Cell *x, *y; | |
1447 Awkfloat u; | |
1448 int t; | |
1449 wchar_t wc; | |
1450 char *p, *buf; | |
1451 char mbc[50]; | |
1452 Node *nextarg; | |
1453 FILE *fp; | |
1454 | |
1455 t = ptoi(a[0]); | |
1456 x = execute(a[1]); | |
1457 nextarg = a[1]->nnext; | |
1458 switch (t) { | |
1459 case FLENGTH: | |
1460 p = getsval(x); | |
1461 u = (Awkfloat) countposn(p, strlen(p)); break; | |
1462 case FLOG: | |
1463 u = errcheck(log(getfval(x)), "log"); break; | |
1464 case FINT: | |
1465 modf(getfval(x), &u); break; | |
1466 case FEXP: | |
1467 u = errcheck(exp(getfval(x)), "exp"); break; | |
1468 case FSQRT: | |
1469 u = errcheck(sqrt(getfval(x)), "sqrt"); break; | |
1470 case FSIN: | |
1471 u = sin(getfval(x)); break; | |
1472 case FCOS: | |
1473 u = cos(getfval(x)); break; | |
1474 case FATAN: | |
1475 if (nextarg == 0) { | |
1476 WARNING("atan2 requires two arguments; returning… | |
1477 u = 1.0; | |
1478 } else { | |
1479 y = execute(a[1]->nnext); | |
1480 u = atan2(getfval(x), getfval(y)); | |
1481 tempfree(y); | |
1482 nextarg = nextarg->nnext; | |
1483 } | |
1484 break; | |
1485 case FSYSTEM: | |
1486 fflush(stdout); /* in case something is b… | |
1487 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is uni… | |
1488 break; | |
1489 case FRAND: | |
1490 /* in principle, rand() returns something in 0..RAND_MAX… | |
1491 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; | |
1492 break; | |
1493 case FSRAND: | |
1494 if (isrec(x)) /* no argument provided */ | |
1495 u = time((time_t *)0); | |
1496 else | |
1497 u = getfval(x); | |
1498 srand((unsigned int) u); | |
1499 break; | |
1500 case FTOUPPER: | |
1501 case FTOLOWER: | |
1502 buf = tostring(getsval(x)); | |
1503 if (t == FTOUPPER) { | |
1504 for (p = buf; *p; p++) | |
1505 if (islower(*p)) | |
1506 *p = toupper(*p); | |
1507 } else { | |
1508 for (p = buf; *p; p++) | |
1509 if (isupper(*p)) | |
1510 *p = tolower(*p); | |
1511 } | |
1512 tempfree(x); | |
1513 x = gettemp(); | |
1514 setsval(x, buf); | |
1515 free(buf); | |
1516 return x; | |
1517 case FFLUSH: | |
1518 if ((fp = openfile(FFLUSH, getsval(x))) == NULL) | |
1519 u = EOF; | |
1520 else | |
1521 u = fflush(fp); | |
1522 break; | |
1523 case FUTF: | |
1524 wc = (int)getfval(x); | |
1525 mbc[wctomb(mbc, wc)] = 0; | |
1526 tempfree(x); | |
1527 x = gettemp(); | |
1528 setsval(x, mbc); | |
1529 return x; | |
1530 default: /* can't happen */ | |
1531 FATAL("illegal function type %d", t); | |
1532 break; | |
1533 } | |
1534 tempfree(x); | |
1535 x = gettemp(); | |
1536 setfval(x, u); | |
1537 if (nextarg != 0) { | |
1538 WARNING("warning: function has too many arguments"); | |
1539 for ( ; nextarg; nextarg = nextarg->nnext) | |
1540 execute(nextarg); | |
1541 } | |
1542 return(x); | |
1543 } | |
1544 | |
1545 Cell *printstat(Node **a, int n) /* print a[0] */ | |
1546 { | |
1547 int r; | |
1548 Node *x; | |
1549 Cell *y; | |
1550 FILE *fp; | |
1551 | |
1552 if (a[1] == 0) /* a[1] is redirection operator, a[2] is f… | |
1553 fp = stdout; | |
1554 else | |
1555 fp = redirect(ptoi(a[1]), a[2]); | |
1556 for (x = a[0]; x != NULL; x = x->nnext) { | |
1557 y = execute(x); | |
1558 fputs(getsval(y), fp); | |
1559 tempfree(y); | |
1560 if (x->nnext == NULL) | |
1561 r = fputs(*ORS, fp); | |
1562 else | |
1563 r = fputs(*OFS, fp); | |
1564 if (r == EOF) | |
1565 FATAL("write error on %s", filename(fp)); | |
1566 } | |
1567 if (a[1] != 0) | |
1568 if (fflush(fp) == EOF) | |
1569 FATAL("write error on %s", filename(fp)); | |
1570 return(True); | |
1571 } | |
1572 | |
1573 Cell *nullproc(Node **a, int n) | |
1574 { | |
1575 n = n; | |
1576 a = a; | |
1577 return 0; | |
1578 } | |
1579 | |
1580 | |
1581 FILE *redirect(int a, Node *b) /* set up all i/o redirections */ | |
1582 { | |
1583 FILE *fp; | |
1584 Cell *x; | |
1585 char *fname; | |
1586 | |
1587 x = execute(b); | |
1588 fname = getsval(x); | |
1589 fp = openfile(a, fname); | |
1590 if (fp == NULL) | |
1591 FATAL("can't open file %s", fname); | |
1592 tempfree(x); | |
1593 return fp; | |
1594 } | |
1595 | |
1596 struct files { | |
1597 FILE *fp; | |
1598 char *fname; | |
1599 int mode; /* '|', 'a', 'w' => LE/LT, GT */ | |
1600 } files[FOPEN_MAX] ={ | |
1601 { NULL, "/dev/stdin", LT }, /* watch out: don't free th… | |
1602 { NULL, "/dev/stdout", GT }, | |
1603 { NULL, "/dev/stderr", GT } | |
1604 }; | |
1605 | |
1606 void stdinit(void) /* in case stdin, etc., are not constants */ | |
1607 { | |
1608 files[0].fp = stdin; | |
1609 files[1].fp = stdout; | |
1610 files[2].fp = stderr; | |
1611 } | |
1612 | |
1613 FILE *openfile(int a, char *us) | |
1614 { | |
1615 char *s = us; | |
1616 int i, m; | |
1617 FILE *fp = 0; | |
1618 | |
1619 if (*s == '\0') | |
1620 FATAL("null file name in print or getline"); | |
1621 for (i=0; i < FOPEN_MAX; i++) | |
1622 if (files[i].fname && strcmp(s, files[i].fname) == 0) { | |
1623 if (a == files[i].mode || (a==APPEND && files[i]… | |
1624 return files[i].fp; | |
1625 if (a == FFLUSH) | |
1626 return files[i].fp; | |
1627 } | |
1628 if (a == FFLUSH) /* didn't find it, so don't create it! */ | |
1629 return NULL; | |
1630 | |
1631 for (i=0; i < FOPEN_MAX; i++) | |
1632 if (files[i].fp == 0) | |
1633 break; | |
1634 if (i >= FOPEN_MAX) | |
1635 FATAL("%s makes too many open files", s); | |
1636 fflush(stdout); /* force a semblance of order */ | |
1637 m = a; | |
1638 if (a == GT) { | |
1639 fp = fopen(s, "w"); | |
1640 } else if (a == APPEND) { | |
1641 fp = fopen(s, "a"); | |
1642 m = GT; /* so can mix > and >> */ | |
1643 } else if (a == '|') { /* output pipe */ | |
1644 fp = popen(s, "w"); | |
1645 } else if (a == LE) { /* input pipe */ | |
1646 fp = popen(s, "r"); | |
1647 } else if (a == LT) { /* getline <file */ | |
1648 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); … | |
1649 } else /* can't happen */ | |
1650 FATAL("illegal redirection %d", a); | |
1651 if (fp != NULL) { | |
1652 files[i].fname = tostring(s); | |
1653 files[i].fp = fp; | |
1654 files[i].mode = m; | |
1655 } | |
1656 return fp; | |
1657 } | |
1658 | |
1659 char *filename(FILE *fp) | |
1660 { | |
1661 int i; | |
1662 | |
1663 for (i = 0; i < FOPEN_MAX; i++) | |
1664 if (fp == files[i].fp) | |
1665 return files[i].fname; | |
1666 return "???"; | |
1667 } | |
1668 | |
1669 Cell *closefile(Node **a, int n) | |
1670 { | |
1671 Cell *x; | |
1672 int i, stat; | |
1673 | |
1674 n = n; | |
1675 x = execute(a[0]); | |
1676 getsval(x); | |
1677 for (i = 0; i < FOPEN_MAX; i++) | |
1678 if (files[i].fname && strcmp(x->sval, files[i].fname) ==… | |
1679 if (ferror(files[i].fp)) | |
1680 WARNING( "i/o error occurred on %s", fil… | |
1681 if (files[i].mode == '|' || files[i].mode == LE) | |
1682 stat = pclose(files[i].fp); | |
1683 else | |
1684 stat = fclose(files[i].fp); | |
1685 if (stat == EOF) | |
1686 WARNING( "i/o error occurred closing %s"… | |
1687 if (i > 2) /* don't do /dev/std... */ | |
1688 xfree(files[i].fname); | |
1689 files[i].fname = NULL; /* watch out for r… | |
1690 files[i].fp = NULL; | |
1691 } | |
1692 tempfree(x); | |
1693 return(True); | |
1694 } | |
1695 | |
1696 void closeall(void) | |
1697 { | |
1698 int i, stat; | |
1699 | |
1700 for (i = 0; i < FOPEN_MAX; i++) | |
1701 if (files[i].fp) { | |
1702 if (ferror(files[i].fp)) | |
1703 WARNING( "i/o error occurred on %s", fil… | |
1704 if (files[i].mode == '|' || files[i].mode == LE) | |
1705 stat = pclose(files[i].fp); | |
1706 else | |
1707 stat = fclose(files[i].fp); | |
1708 if (stat == EOF) | |
1709 WARNING( "i/o error occurred while closi… | |
1710 } | |
1711 } | |
1712 | |
1713 void backsub(char **pb_ptr, char **sptr_ptr); | |
1714 | |
1715 Cell *sub(Node **a, int nnn) /* substitute command */ | |
1716 { | |
1717 char *sptr, *pb, *q; | |
1718 Cell *x, *y, *result; | |
1719 char *t, *buf; | |
1720 void *p; | |
1721 int bufsz = recsize; | |
1722 | |
1723 if ((buf = (char *) malloc(bufsz)) == NULL) | |
1724 FATAL("out of memory in sub"); | |
1725 x = execute(a[3]); /* target string */ | |
1726 t = getsval(x); | |
1727 if (a[0] == 0) /* 0 => a[1] is already-compiled r… | |
1728 p = (void *) a[1]; /* regular expression */ | |
1729 else { | |
1730 y = execute(a[1]); | |
1731 p = compre(getsval(y)); | |
1732 tempfree(y); | |
1733 } | |
1734 y = execute(a[2]); /* replacement string */ | |
1735 result = False; | |
1736 if (pmatch(p, t, t)) { | |
1737 sptr = t; | |
1738 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); | |
1739 pb = buf; | |
1740 while (sptr < patbeg) | |
1741 *pb++ = *sptr++; | |
1742 sptr = getsval(y); | |
1743 while (*sptr != 0) { | |
1744 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "su… | |
1745 if (*sptr == '\\') { | |
1746 backsub(&pb, &sptr); | |
1747 } else if (*sptr == '&') { | |
1748 sptr++; | |
1749 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, re… | |
1750 for (q = patbeg; q < patbeg+patlen; ) | |
1751 *pb++ = *q++; | |
1752 } else | |
1753 *pb++ = *sptr++; | |
1754 } | |
1755 *pb = '\0'; | |
1756 if (pb > buf + bufsz) | |
1757 FATAL("sub result1 %.30s too big; can't happen",… | |
1758 sptr = patbeg + patlen; | |
1759 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { | |
1760 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &… | |
1761 while ((*pb++ = *sptr++) != 0) | |
1762 ; | |
1763 } | |
1764 if (pb > buf + bufsz) | |
1765 FATAL("sub result2 %.30s too big; can't happen",… | |
1766 setsval(x, buf); /* BUG: should be able to avoid … | |
1767 result = True;; | |
1768 } | |
1769 tempfree(x); | |
1770 tempfree(y); | |
1771 free(buf); | |
1772 return result; | |
1773 } | |
1774 | |
1775 Cell *gsub(Node **a, int nnn) /* global substitute */ | |
1776 { | |
1777 Cell *x, *y; | |
1778 char *rptr, *sptr, *t, *pb, *c; | |
1779 char *buf; | |
1780 void *p; | |
1781 int mflag, num; | |
1782 int bufsz = recsize; | |
1783 | |
1784 if ((buf = (char *)malloc(bufsz)) == NULL) | |
1785 FATAL("out of memory in gsub"); | |
1786 mflag = 0; /* if mflag == 0, can replace empty string */ | |
1787 num = 0; | |
1788 x = execute(a[3]); /* target string */ | |
1789 c = t = getsval(x); | |
1790 if (a[0] == 0) /* 0 => a[1] is already-compiled r… | |
1791 p = (void *) a[1]; /* regular expression */ | |
1792 else { | |
1793 y = execute(a[1]); | |
1794 p = compre(getsval(y)); | |
1795 tempfree(y); | |
1796 } | |
1797 y = execute(a[2]); /* replacement string */ | |
1798 if (pmatch(p, t, c)) { | |
1799 pb = buf; | |
1800 rptr = getsval(y); | |
1801 do { | |
1802 if (patlen == 0 && *patbeg != 0) { /* mat… | |
1803 if (mflag == 0) { /* can replace … | |
1804 num++; | |
1805 sptr = rptr; | |
1806 while (*sptr != 0) { | |
1807 adjbuf(&buf, &bufsz, 5+p… | |
1808 if (*sptr == '\\') { | |
1809 backsub(&pb, &sp… | |
1810 } else if (*sptr == '&')… | |
1811 char *q; | |
1812 sptr++; | |
1813 adjbuf(&buf, &bu… | |
1814 for (q = patbeg;… | |
1815 *pb++ = … | |
1816 } else | |
1817 *pb++ = *sptr++; | |
1818 } | |
1819 } | |
1820 if (*c == 0) /* at end */ | |
1821 goto done; | |
1822 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, … | |
1823 *pb++ = *c++; | |
1824 if (pb > buf + bufsz) /* BUG: not… | |
1825 FATAL("gsub result0 %.30s too bi… | |
1826 mflag = 0; | |
1827 } | |
1828 else { /* matched nonempty string */ | |
1829 num++; | |
1830 sptr = c; | |
1831 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-… | |
1832 while (sptr < patbeg) | |
1833 *pb++ = *sptr++; | |
1834 sptr = rptr; | |
1835 while (*sptr != 0) { | |
1836 adjbuf(&buf, &bufsz, 5+pb-buf, r… | |
1837 if (*sptr == '\\') { | |
1838 backsub(&pb, &sptr); | |
1839 } else if (*sptr == '&') { | |
1840 char *q; | |
1841 sptr++; | |
1842 adjbuf(&buf, &bufsz, 1+p… | |
1843 for (q = patbeg; q < pat… | |
1844 *pb++ = *q++; | |
1845 } else | |
1846 *pb++ = *sptr++; | |
1847 } | |
1848 c = patbeg + patlen; | |
1849 if ((c[-1] == 0) || (*c == 0)) | |
1850 goto done; | |
1851 if (pb > buf + bufsz) | |
1852 FATAL("gsub result1 %.30s too bi… | |
1853 mflag = 1; | |
1854 } | |
1855 } while (pmatch(p, t, c)); | |
1856 sptr = c; | |
1857 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsu… | |
1858 while ((*pb++ = *sptr++) != 0) | |
1859 ; | |
1860 done: if (pb > buf + bufsz) | |
1861 FATAL("gsub result2 %.30s too big; can't happen"… | |
1862 *pb = '\0'; | |
1863 setsval(x, buf); /* BUG: should be able to avoid … | |
1864 } | |
1865 tempfree(x); | |
1866 tempfree(y); | |
1867 x = gettemp(); | |
1868 x->tval = NUM; | |
1869 x->fval = num; | |
1870 free(buf); | |
1871 return(x); | |
1872 } | |
1873 | |
1874 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variat… | |
1875 { /* sptr[0] == '\\' */ | |
1876 char *pb = *pb_ptr, *sptr = *sptr_ptr; | |
1877 | |
1878 if (sptr[1] == '\\') { | |
1879 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ | |
1880 *pb++ = '\\'; | |
1881 *pb++ = '&'; | |
1882 sptr += 4; | |
1883 } else if (sptr[2] == '&') { /* \\& -> \ + matche… | |
1884 *pb++ = '\\'; | |
1885 sptr += 2; | |
1886 } else { /* \\x -> \\x */ | |
1887 *pb++ = *sptr++; | |
1888 *pb++ = *sptr++; | |
1889 } | |
1890 } else if (sptr[1] == '&') { /* literal & */ | |
1891 sptr++; | |
1892 *pb++ = *sptr++; | |
1893 } else /* literal \ */ | |
1894 *pb++ = *sptr++; | |
1895 | |
1896 *pb_ptr = pb; | |
1897 *sptr_ptr = sptr; | |
1898 } | |
1899 |