1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
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
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
23 ****************************************************************/
38 int recsize = RECSIZE;
40 int fieldssize = RECSIZE;
42 Cell **fldtab; /* pointers to Cells */
43 char inputFS[100] = " ";
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)
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");
66 fldtab[0] = (Cell *) malloc(sizeof (Cell));
68 fldtab[0]->sval = record;
69 fldtab[0]->nval = tostring("0");
70 makefields(1, nfields);
73 void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
78 for (i = n1; i <= n2; i++) {
79 fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
80 if (fldtab[i] == NULL)
81 FATAL("out of space in makefields %d", i);
83 sprintf(temp, "%d", i);
84 fldtab[i]->nval = tostring(temp);
93 for (i = 1; i < *ARGC; i++) {
94 if (!isclvar(p = getargv(i))) { /* find 1st real filename */
95 setsval(lookup("FILENAME", symtab), getargv(i));
98 setclvar(p); /* a commandline assignment before filename */
101 infile = stdin; /* no filenames, so use stdin */
104 int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
105 { /* note: cares whether buf == record */
107 static int firsttime = 1;
109 int bufsize = *pbufsize;
115 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
116 *RS, *FS, *ARGC, *FILENAME) );
122 while (argno < *ARGC || infile == stdin) {
123 dprintf( ("argno=%d, file=|%s|\n", argno, file) );
124 if (infile == NULL) { /* have to open a new file */
125 file = getargv(argno);
126 if (*file == '\0') { /* it's been zapped */
130 if (isclvar(file)) { /* a var=value arg */
136 dprintf( ("opening file %s\n", file) );
137 if (*file == '-' && *(file+1) == '\0')
139 else if ((infile = fopen(file, "r")) == NULL)
140 FATAL("can't open file %s", file);
141 setfval(fnrloc, 0.0);
143 c = readrec(&buf, &bufsize, infile);
144 if (c != 0 || buf[0] != '\0') { /* normal record */
146 if (freeable(fldtab[0]))
147 xfree(fldtab[0]->sval);
148 fldtab[0]->sval = buf; /* buf == record */
149 fldtab[0]->tval = REC | STR | DONTFREE;
150 if (is_number(fldtab[0]->sval)) {
151 fldtab[0]->fval = atof(fldtab[0]->sval);
152 fldtab[0]->tval |= NUM;
155 setfval(nrloc, nrloc->fval+1);
156 setfval(fnrloc, fnrloc->fval+1);
161 /* EOF arrived on this file; set up next */
169 return 0; /* true end of file */
180 int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
183 char *rr, *buf = *pbuf;
184 int bufsize = *pbufsize;
186 if (strlen(*FS) >= sizeof(inputFS))
187 FATAL("field separator %.10s... is too long", *FS);
188 strcpy(inputFS, *FS); /* for subsequent field splitting */
189 if ((sep = **RS) == 0) {
191 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
197 for (; (c=getc(inf)) != sep && c != EOF; ) {
198 if (rr-buf+1 > bufsize)
199 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
200 FATAL("input record `%.30s...' too long", buf);
203 if (**RS == sep || c == EOF)
205 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
207 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
208 FATAL("input record `%.30s...' too long", buf);
212 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
213 FATAL("input record `%.30s...' too long", buf);
215 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
218 return c == EOF && rr == buf ? 0 : 1;
221 char *getargv(int n) /* get ARGV[n] */
225 extern Array *ARGVtab;
227 sprintf(temp, "%d", n);
228 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
230 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
234 void setclvar(char *s) /* set var=value from s */
239 for (p=s; *p != '='; p++)
242 p = qstring(p, '\0');
243 q = setsymtab(s, p, 0.0, STR, symtab);
245 if (is_number(q->sval)) {
246 q->fval = atof(q->sval);
249 dprintf( ("command line set %s to |%s|\n", s, p) );
253 void fldbld(void) /* create fields from current record */
255 /* this relies on having fields[] the same length as $0 */
256 /* the fields are all stored in this one array with \0's */
263 if (!isstr(fldtab[0]))
267 if (n > fieldssize) {
269 if ((fields = (char *) malloc(n+1)) == NULL)
270 FATAL("out of space for fields in fldbld %d", n);
274 i = 0; /* number of fields accumulated here */
275 if (strlen(inputFS) > 1) { /* it's a regular expression */
276 i = refldbld(r, inputFS);
277 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
279 while (*r == ' ' || *r == '\t' || *r == '\n')
286 if (freeable(fldtab[i]))
287 xfree(fldtab[i]->sval);
288 fldtab[i]->sval = fr;
289 fldtab[i]->tval = FLD | STR | DONTFREE;
292 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
296 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
297 for (i = 0; *r != 0; r++) {
302 if (freeable(fldtab[i]))
303 xfree(fldtab[i]->sval);
306 fldtab[i]->sval = tostring(buf);
307 fldtab[i]->tval = FLD | STR;
310 } else if (*r != 0) { /* if 0, it's a null field */
315 if (freeable(fldtab[i]))
316 xfree(fldtab[i]->sval);
317 fldtab[i]->sval = fr;
318 fldtab[i]->tval = FLD | STR | DONTFREE;
319 while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */
328 FATAL("record `%.30s...' has too many fields; can't happen", r);
329 cleanfld(i+1, lastfld); /* clean out junk from previous record */
332 for (j = 1; j <= lastfld; j++) {
334 if(is_number(p->sval)) {
335 p->fval = atof(p->sval);
339 setfval(nfloc, (Awkfloat) lastfld);
341 for (j = 0; j <= lastfld; j++) {
343 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
348 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
349 { /* nvals remain intact */
353 for (i = n1; i <= n2; i++) {
358 p->tval = FLD | STR | DONTFREE;
362 void newfld(int n) /* add field n after end of existing lastfld */
366 cleanfld(lastfld+1, n);
368 setfval(nfloc, (Awkfloat) n);
371 Cell *fieldadr(int n) /* get nth field */
374 FATAL("trying to access field %d", n);
375 if (n > nfields) /* fields after NF are empty */
376 growfldtab(n); /* but does not increase NF */
380 void growfldtab(int n) /* make new fields up to at least $n */
382 int nf = 2 * nfields;
386 fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
388 FATAL("out of space creating %d fields", nf);
389 makefields(nfields+1, nf);
393 int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */
395 /* this relies on having fields[] the same length as $0 */
396 /* the fields are all stored in this one array with \0's */
402 if (n > fieldssize) {
404 if ((fields = (char *) malloc(n+1)) == NULL)
405 FATAL("out of space for fields in refldbld %d", n);
412 pfa = makedfa(fs, 1);
413 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
414 tempstat = pfa->initstat;
418 if (freeable(fldtab[i]))
419 xfree(fldtab[i]->sval);
420 fldtab[i]->tval = FLD | STR | DONTFREE;
421 fldtab[i]->sval = fr;
422 dprintf( ("refldbld: i=%d\n", i) );
423 if (nematch(pfa, rec)) {
424 pfa->initstat = 2; /* horrible coupling to b.c */
425 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
426 strncpy(fr, rec, patbeg-rec);
427 fr += patbeg - rec + 1;
429 rec = patbeg + patlen;
431 dprintf( ("no match %s\n", rec) );
433 pfa->initstat = tempstat;
440 void recbld(void) /* create $0 from $1..$NF if necessary */
448 for (i = 1; i <= *NF; i++) {
449 p = getsval(fldtab[i]);
450 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
451 FATAL("created $0 `%.30s...' too long", record);
452 while ((*r = *p++) != 0)
455 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
456 FATAL("created $0 `%.30s...' too long", record);
457 for (p = *OFS; (*r = *p++) != 0; )
461 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
462 FATAL("built giant record `%.30s...'", record);
464 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
466 if (freeable(fldtab[0]))
467 xfree(fldtab[0]->sval);
468 fldtab[0]->tval = REC | STR | DONTFREE;
469 fldtab[0]->sval = record;
471 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
472 dprintf( ("recbld = |%s|\n", record) );
478 void yyerror(char *s)
483 void SYNTAX(char *fmt, ...)
485 extern char *cmdname, *curfname;
486 static int been_here = 0;
491 fprintf(stderr, "%s: ", cmdname);
493 vfprintf(stderr, fmt, varg);
495 fprintf(stderr, " at source line %d", lineno);
496 if (curfname != NULL)
497 fprintf(stderr, " in function %s", curfname);
498 if (compile_time == 1 && cursource() != NULL)
499 fprintf(stderr, " source file %s", cursource());
500 fprintf(stderr, "\n");
507 FATAL("floating point exception %d", n);
510 extern int bracecnt, brackcnt, parencnt;
512 void bracecheck(void)
515 static int beenhere = 0;
519 while ((c = input()) != EOF && c != '\0')
521 bcheck2(bracecnt, '{', '}');
522 bcheck2(brackcnt, '[', ']');
523 bcheck2(parencnt, '(', ')');
526 void bcheck2(int n, int c1, int c2)
529 fprintf(stderr, "\tmissing %c\n", c2);
531 fprintf(stderr, "\t%d missing %c's\n", n, c2);
533 fprintf(stderr, "\textra %c\n", c2);
535 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
538 void FATAL(char *fmt, ...)
540 extern char *cmdname;
544 fprintf(stderr, "%s: ", cmdname);
546 vfprintf(stderr, fmt, varg);
549 if (dbg > 1) /* core dump if serious debugging on */
554 void WARNING(char *fmt, ...)
556 extern char *cmdname;
560 fprintf(stderr, "%s: ", cmdname);
562 vfprintf(stderr, fmt, varg);
569 extern Node *curnode;
571 fprintf(stderr, "\n");
572 if (compile_time != 2 && NR && *NR > 0) {
573 fprintf(stderr, " input record number %d", (int) (*FNR));
574 if (strcmp(*FILENAME, "-") != 0)
575 fprintf(stderr, ", file %s", *FILENAME);
576 fprintf(stderr, "\n");
578 if (compile_time != 2 && curnode)
579 fprintf(stderr, " source line number %d", curnode->lineno);
580 else if (compile_time != 2 && lineno)
581 fprintf(stderr, " source line number %d", lineno);
582 if (compile_time == 1 && cursource() != NULL)
583 fprintf(stderr, " source file %s", cursource());
584 fprintf(stderr, "\n");
588 void eprint(void) /* try to print context around error */
592 static int been_here = 0;
593 extern char ebuf[], *ep;
595 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
598 if (p > ebuf && *p == '\n')
600 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
604 fprintf(stderr, " context is\n\t");
605 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
610 fprintf(stderr, " >>> ");
614 fprintf(stderr, " <<< ");
616 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
627 case '{': bracecnt++; break;
628 case '}': bracecnt--; break;
629 case '[': brackcnt++; break;
630 case ']': brackcnt--; break;
631 case '(': parencnt++; break;
632 case ')': parencnt--; break;
636 double errcheck(double x, char *s)
641 WARNING("%s argument out of domain", s);
643 } else if (errno == ERANGE) {
645 WARNING("%s result out of range", s);
651 int isclvar(char *s) /* is s of form var=something ? */
655 if (!isalpha((uschar) *s) && *s != '_')
658 if (!(isalnum((uschar) *s) || *s == '_'))
660 return *s == '=' && s > os && *(s+1) != '=';
663 /* strtod is supposed to be a proper test of what's a valid number */
664 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
665 /* wrong: violates 4.10.1.4 of ansi C standard */
668 int is_number(char *s)
674 if (ep == s || r == HUGE_VAL || errno == ERANGE)
676 while (*ep == ' ' || *ep == '\t' || *ep == '\n')