Blob


1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
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.
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 ****************************************************************/
25 #define DEBUG
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include "awk.h"
33 #include "y.tab.h"
35 FILE *infile = NULL;
36 char *file = "";
37 char *record;
38 int recsize = RECSIZE;
39 char *fields;
40 int fieldssize = RECSIZE;
42 Cell **fldtab; /* pointers to Cells */
43 char inputFS[100] = " ";
45 #define MAXFLD 200
46 int nfields = MAXFLD; /* last allocated slot for $i */
48 int donefld; /* 1 = implies rec broken into fields */
49 int donerec; /* 1 = record is valid (no flds have changed) */
51 int lastfld = 0; /* last used field */
52 int argno = 1; /* current input argument number */
53 extern Awkfloat *ARGC;
55 static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
56 static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
58 void recinit(unsigned int n)
59 {
60 record = (char *) malloc(n);
61 fields = (char *) malloc(n);
62 fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
63 if (record == NULL || fields == NULL || fldtab == NULL)
64 FATAL("out of space for $0 and fields");
65 fldtab[0] = (Cell *) malloc(sizeof (Cell));
66 *fldtab[0] = dollar0;
67 fldtab[0]->sval = record;
68 fldtab[0]->nval = tostring("0");
69 makefields(1, nfields);
70 }
72 void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
73 {
74 char temp[50];
75 int i;
77 for (i = n1; i <= n2; i++) {
78 fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
79 if (fldtab[i] == NULL)
80 FATAL("out of space in makefields %d", i);
81 *fldtab[i] = dollar1;
82 sprintf(temp, "%d", i);
83 fldtab[i]->nval = tostring(temp);
84 }
85 }
87 void initgetrec(void)
88 {
89 int i;
90 char *p;
92 for (i = 1; i < *ARGC; i++) {
93 if (!isclvar(p = getargv(i))) { /* find 1st real filename */
94 setsval(lookup("FILENAME", symtab), getargv(i));
95 return;
96 }
97 setclvar(p); /* a commandline assignment before filename */
98 argno++;
99 }
100 infile = stdin; /* no filenames, so use stdin */
103 int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
104 { /* note: cares whether buf == record */
105 int c;
106 static int firsttime = 1;
107 char *buf = *pbuf;
108 int bufsize = *pbufsize;
110 if (firsttime) {
111 firsttime = 0;
112 initgetrec();
114 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
115 *RS, *FS, *ARGC, *FILENAME) );
116 if (isrecord) {
117 donefld = 0;
118 donerec = 1;
120 buf[0] = 0;
121 while (argno < *ARGC || infile == stdin) {
122 dprintf( ("argno=%d, file=|%s|\n", argno, file) );
123 if (infile == NULL) { /* have to open a new file */
124 file = getargv(argno);
125 if (*file == '\0') { /* it's been zapped */
126 argno++;
127 continue;
129 if (isclvar(file)) { /* a var=value arg */
130 setclvar(file);
131 argno++;
132 continue;
134 *FILENAME = file;
135 dprintf( ("opening file %s\n", file) );
136 if (*file == '-' && *(file+1) == '\0')
137 infile = stdin;
138 else if ((infile = fopen(file, "r")) == NULL)
139 FATAL("can't open file %s", file);
140 setfval(fnrloc, 0.0);
142 c = readrec(&buf, &bufsize, infile);
143 if (c != 0 || buf[0] != '\0') { /* normal record */
144 if (isrecord) {
145 if (freeable(fldtab[0]))
146 xfree(fldtab[0]->sval);
147 fldtab[0]->sval = buf; /* buf == record */
148 fldtab[0]->tval = REC | STR | DONTFREE;
149 if (is_number(fldtab[0]->sval)) {
150 fldtab[0]->fval = atof(fldtab[0]->sval);
151 fldtab[0]->tval |= NUM;
154 setfval(nrloc, nrloc->fval+1);
155 setfval(fnrloc, fnrloc->fval+1);
156 *pbuf = buf;
157 *pbufsize = bufsize;
158 return 1;
160 /* EOF arrived on this file; set up next */
161 if (infile != stdin)
162 fclose(infile);
163 infile = NULL;
164 argno++;
166 *pbuf = buf;
167 *pbufsize = bufsize;
168 return 0; /* true end of file */
171 void nextfile(void)
173 if (infile != stdin)
174 fclose(infile);
175 infile = NULL;
176 argno++;
179 int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
181 int sep, c;
182 char *rr, *buf = *pbuf;
183 int bufsize = *pbufsize;
185 if (strlen(*FS) >= sizeof(inputFS))
186 FATAL("field separator %.10s... is too long", *FS);
187 strcpy(inputFS, *FS); /* for subsequent field splitting */
188 if ((sep = **RS) == 0) {
189 sep = '\n';
190 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
192 if (c != EOF)
193 ungetc(c, inf);
195 for (rr = buf; ; ) {
196 for (; (c=getc(inf)) != sep && c != EOF; ) {
197 if (rr-buf+1 > bufsize)
198 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
199 FATAL("input record `%.30s...' too long", buf);
200 *rr++ = c;
202 if (**RS == sep || c == EOF)
203 break;
204 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
205 break;
206 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
207 FATAL("input record `%.30s...' too long", buf);
208 *rr++ = '\n';
209 *rr++ = c;
211 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
212 FATAL("input record `%.30s...' too long", buf);
213 *rr = 0;
214 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
215 *pbuf = buf;
216 *pbufsize = bufsize;
217 return c == EOF && rr == buf ? 0 : 1;
220 char *getargv(int n) /* get ARGV[n] */
222 Cell *x;
223 char *s, temp[50];
224 extern Array *ARGVtab;
226 sprintf(temp, "%d", n);
227 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
228 s = getsval(x);
229 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
230 return s;
233 void setclvar(char *s) /* set var=value from s */
235 char *p;
236 Cell *q;
238 for (p=s; *p != '='; p++)
240 *p++ = 0;
241 p = qstring(p, '\0');
242 q = setsymtab(s, p, 0.0, STR, symtab);
243 setsval(q, p);
244 if (is_number(q->sval)) {
245 q->fval = atof(q->sval);
246 q->tval |= NUM;
248 dprintf( ("command line set %s to |%s|\n", s, p) );
252 void fldbld(void) /* create fields from current record */
254 /* this relies on having fields[] the same length as $0 */
255 /* the fields are all stored in this one array with \0's */
256 char *r, *fr, sep;
257 Cell *p;
258 int i, j, n;
260 if (donefld)
261 return;
262 if (!isstr(fldtab[0]))
263 getsval(fldtab[0]);
264 r = fldtab[0]->sval;
265 n = strlen(r);
266 if (n > fieldssize) {
267 xfree(fields);
268 if ((fields = (char *) malloc(n+1)) == NULL)
269 FATAL("out of space for fields in fldbld %d", n);
270 fieldssize = n;
272 fr = fields;
273 i = 0; /* number of fields accumulated here */
274 if (strlen(inputFS) > 1) { /* it's a regular expression */
275 i = refldbld(r, inputFS);
276 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
277 for (i = 0; ; ) {
278 while (*r == ' ' || *r == '\t' || *r == '\n')
279 r++;
280 if (*r == 0)
281 break;
282 i++;
283 if (i > nfields)
284 growfldtab(i);
285 if (freeable(fldtab[i]))
286 xfree(fldtab[i]->sval);
287 fldtab[i]->sval = fr;
288 fldtab[i]->tval = FLD | STR | DONTFREE;
289 do
290 *fr++ = *r++;
291 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
292 *fr++ = 0;
294 *fr = 0;
295 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
296 for (i = 0; *r != 0; r++) {
297 char buf[2];
298 i++;
299 if (i > nfields)
300 growfldtab(i);
301 if (freeable(fldtab[i]))
302 xfree(fldtab[i]->sval);
303 buf[0] = *r;
304 buf[1] = 0;
305 fldtab[i]->sval = tostring(buf);
306 fldtab[i]->tval = FLD | STR;
308 *fr = 0;
309 } else if (*r != 0) { /* if 0, it's a null field */
310 for (;;) {
311 i++;
312 if (i > nfields)
313 growfldtab(i);
314 if (freeable(fldtab[i]))
315 xfree(fldtab[i]->sval);
316 fldtab[i]->sval = fr;
317 fldtab[i]->tval = FLD | STR | DONTFREE;
318 while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */
319 *fr++ = *r++;
320 *fr++ = 0;
321 if (*r++ == 0)
322 break;
324 *fr = 0;
326 if (i > nfields)
327 FATAL("record `%.30s...' has too many fields; can't happen", r);
328 cleanfld(i+1, lastfld); /* clean out junk from previous record */
329 lastfld = i;
330 donefld = 1;
331 for (j = 1; j <= lastfld; j++) {
332 p = fldtab[j];
333 if(is_number(p->sval)) {
334 p->fval = atof(p->sval);
335 p->tval |= NUM;
338 setfval(nfloc, (Awkfloat) lastfld);
339 if (dbg) {
340 for (j = 0; j <= lastfld; j++) {
341 p = fldtab[j];
342 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
347 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
348 { /* nvals remain intact */
349 Cell *p;
350 int i;
352 for (i = n1; i <= n2; i++) {
353 p = fldtab[i];
354 if (freeable(p))
355 xfree(p->sval);
356 p->sval = "";
357 p->tval = FLD | STR | DONTFREE;
361 void newfld(int n) /* add field n after end of existing lastfld */
363 if (n > nfields)
364 growfldtab(n);
365 cleanfld(lastfld+1, n);
366 lastfld = n;
367 setfval(nfloc, (Awkfloat) n);
370 Cell *fieldadr(int n) /* get nth field */
372 if (n < 0)
373 FATAL("trying to access field %d", n);
374 if (n > nfields) /* fields after NF are empty */
375 growfldtab(n); /* but does not increase NF */
376 return(fldtab[n]);
379 void growfldtab(int n) /* make new fields up to at least $n */
381 int nf = 2 * nfields;
383 if (n > nf)
384 nf = n;
385 fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
386 if (fldtab == NULL)
387 FATAL("out of space creating %d fields", nf);
388 makefields(nfields+1, nf);
389 nfields = nf;
392 int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */
394 /* this relies on having fields[] the same length as $0 */
395 /* the fields are all stored in this one array with \0's */
396 char *fr;
397 void *p;
398 int i, n;
400 n = strlen(rec);
401 if (n > fieldssize) {
402 xfree(fields);
403 if ((fields = (char *) malloc(n+1)) == NULL)
404 FATAL("out of space for fields in refldbld %d", n);
405 fieldssize = n;
407 fr = fields;
408 *fr = '\0';
409 if (*rec == '\0')
410 return 0;
411 p = compre(fs);
412 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
413 for (i = 1; ; i++) {
414 if (i > nfields)
415 growfldtab(i);
416 if (freeable(fldtab[i]))
417 xfree(fldtab[i]->sval);
418 fldtab[i]->tval = FLD | STR | DONTFREE;
419 fldtab[i]->sval = fr;
420 dprintf( ("refldbld: i=%d\n", i) );
421 if (nematch(p, rec, rec)) {
422 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
423 strncpy(fr, rec, patbeg-rec);
424 fr += patbeg - rec + 1;
425 *(fr-1) = '\0';
426 rec = patbeg + patlen;
427 } else {
428 dprintf( ("no match %s\n", rec) );
429 strcpy(fr, rec);
430 break;
433 return i;
436 void recbld(void) /* create $0 from $1..$NF if necessary */
438 int i;
439 char *r, *p;
441 if (donerec == 1)
442 return;
443 r = record;
444 for (i = 1; i <= *NF; i++) {
445 p = getsval(fldtab[i]);
446 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
447 FATAL("created $0 `%.30s...' too long", record);
448 while ((*r = *p++) != 0)
449 r++;
450 if (i < *NF) {
451 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
452 FATAL("created $0 `%.30s...' too long", record);
453 for (p = *OFS; (*r = *p++) != 0; )
454 r++;
457 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
458 FATAL("built giant record `%.30s...'", record);
459 *r = '\0';
460 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
462 if (freeable(fldtab[0]))
463 xfree(fldtab[0]->sval);
464 fldtab[0]->tval = REC | STR | DONTFREE;
465 fldtab[0]->sval = record;
467 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
468 dprintf( ("recbld = |%s|\n", record) );
469 donerec = 1;
472 int errorflag = 0;
474 void yyerror(char *s)
476 SYNTAX(s);
479 void SYNTAX(char *fmt, ...)
481 extern char *cmdname, *curfname;
482 static int been_here = 0;
483 va_list varg;
485 if (been_here++ > 2)
486 return;
487 fprintf(stderr, "%s: ", cmdname);
488 va_start(varg, fmt);
489 vfprintf(stderr, fmt, varg);
490 va_end(varg);
491 if(compile_time == 1 && cursource() != NULL)
492 fprintf(stderr, " at %s:%d", cursource(), lineno);
493 else
494 fprintf(stderr, " at line %d", lineno);
495 if (curfname != NULL)
496 fprintf(stderr, " in function %s", curfname);
497 fprintf(stderr, "\n");
498 errorflag = 2;
499 eprint();
502 void fpecatch(int n)
504 FATAL("floating point exception %d", n);
507 extern int bracecnt, brackcnt, parencnt;
509 void bracecheck(void)
511 int c;
512 static int beenhere = 0;
514 if (beenhere++)
515 return;
516 while ((c = input()) != EOF && c != '\0')
517 bclass(c);
518 bcheck2(bracecnt, '{', '}');
519 bcheck2(brackcnt, '[', ']');
520 bcheck2(parencnt, '(', ')');
523 void bcheck2(int n, int c1, int c2)
525 if (n == 1)
526 fprintf(stderr, "\tmissing %c\n", c2);
527 else if (n > 1)
528 fprintf(stderr, "\t%d missing %c's\n", n, c2);
529 else if (n == -1)
530 fprintf(stderr, "\textra %c\n", c2);
531 else if (n < -1)
532 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
535 void FATAL(char *fmt, ...)
537 extern char *cmdname;
538 va_list varg;
540 fflush(stdout);
541 fprintf(stderr, "%s: ", cmdname);
542 va_start(varg, fmt);
543 vfprintf(stderr, fmt, varg);
544 va_end(varg);
545 error();
546 if (dbg > 1) /* core dump if serious debugging on */
547 abort();
548 exit(2);
551 void WARNING(char *fmt, ...)
553 extern char *cmdname;
554 va_list varg;
556 fflush(stdout);
557 fprintf(stderr, "%s: ", cmdname);
558 va_start(varg, fmt);
559 vfprintf(stderr, fmt, varg);
560 va_end(varg);
561 error();
564 void error()
566 extern Node *curnode;
567 int line;
569 fprintf(stderr, "\n");
570 if (compile_time != 2 && NR && *NR > 0) {
571 if (strcmp(*FILENAME, "-") != 0)
572 fprintf(stderr, " input record %s:%d", *FILENAME, (int) (*FNR));
573 else
574 fprintf(stderr, " input record number %d", (int) (*FNR));
575 fprintf(stderr, "\n");
577 if (compile_time != 2 && curnode)
578 line = curnode->lineno;
579 else if (compile_time != 2 && lineno)
580 line = lineno;
581 else
582 line = -1;
583 if (compile_time == 1 && cursource() != NULL){
584 if(line >= 0)
585 fprintf(stderr, " source %s:%d", cursource(), line);
586 else
587 fprintf(stderr, " source file %s", cursource());
588 }else if(line >= 0)
589 fprintf(stderr, " source line %d", line);
590 fprintf(stderr, "\n");
591 eprint();
594 void eprint(void) /* try to print context around error */
596 char *p, *q;
597 int c;
598 static int been_here = 0;
599 extern char ebuf[], *ep;
601 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
602 return;
603 p = ep - 1;
604 if (p > ebuf && *p == '\n')
605 p--;
606 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
608 while (*p == '\n')
609 p++;
610 fprintf(stderr, " context is\n\t");
611 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
613 for ( ; p < q; p++)
614 if (*p)
615 putc(*p, stderr);
616 fprintf(stderr, " >>> ");
617 for ( ; p < ep; p++)
618 if (*p)
619 putc(*p, stderr);
620 fprintf(stderr, " <<< ");
621 if (*ep)
622 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
623 putc(c, stderr);
624 bclass(c);
626 putc('\n', stderr);
627 ep = ebuf;
630 void bclass(int c)
632 switch (c) {
633 case '{': bracecnt++; break;
634 case '}': bracecnt--; break;
635 case '[': brackcnt++; break;
636 case ']': brackcnt--; break;
637 case '(': parencnt++; break;
638 case ')': parencnt--; break;
642 double errcheck(double x, char *s)
645 if (errno == EDOM) {
646 errno = 0;
647 WARNING("%s argument out of domain", s);
648 x = 1;
649 } else if (errno == ERANGE) {
650 errno = 0;
651 WARNING("%s result out of range", s);
652 x = 1;
654 return x;
657 int isclvar(char *s) /* is s of form var=something ? */
659 char *os = s;
661 if (!isalpha(*s) && *s != '_')
662 return 0;
663 for ( ; *s; s++)
664 if (!(isalnum(*s) || *s == '_'))
665 break;
666 return *s == '=' && s > os && *(s+1) != '=';
669 /* strtod is supposed to be a proper test of what's a valid number */
671 #include <math.h>
672 int is_number(char *s)
674 double r;
675 char *ep;
677 /*
678 * fast could-it-be-a-number check before calling strtod,
679 * which takes a surprisingly long time to reject non-numbers.
680 */
681 switch (*s) {
682 case '0': case '1': case '2': case '3': case '4':
683 case '5': case '6': case '7': case '8': case '9':
684 case '\t':
685 case '\n':
686 case '\v':
687 case '\f':
688 case '\r':
689 case ' ':
690 case '-':
691 case '+':
692 case '.':
693 case 'n': /* nans */
694 case 'N':
695 case 'i': /* infs */
696 case 'I':
697 break;
698 default:
699 return 0; /* can't be a number */
702 errno = 0;
703 r = strtod(s, &ep);
704 if (ep == s || r == HUGE_VAL || errno == ERANGE)
705 return 0;
706 while (*ep == ' ' || *ep == '\t' || *ep == '\n')
707 ep++;
708 if (*ep == '\0')
709 return 1;
710 else
711 return 0;