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