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");
65 fldtab[0] = (Cell *) malloc(sizeof (Cell));
67 fldtab[0]->sval = record;
68 fldtab[0]->nval = tostring("0");
69 makefields(1, nfields);
72 void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
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);
82 sprintf(temp, "%d", i);
83 fldtab[i]->nval = tostring(temp);
92 for (i = 1; i < *ARGC; i++) {
93 if (!isclvar(p = getargv(i))) { /* find 1st real filename */
94 setsval(lookup("FILENAME", symtab), getargv(i));
97 setclvar(p); /* a commandline assignment before filename */
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 */
106 static int firsttime = 1;
108 int bufsize = *pbufsize;
114 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
115 *RS, *FS, *ARGC, *FILENAME) );
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 */
129 if (isclvar(file)) { /* a var=value arg */
135 dprintf( ("opening file %s\n", file) );
136 if (*file == '-' && *(file+1) == '\0')
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 */
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);
160 /* EOF arrived on this file; set up next */
168 return 0; /* true end of file */
179 int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
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) {
190 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
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);
202 if (**RS == sep || c == EOF)
204 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
206 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
207 FATAL("input record `%.30s...' too long", buf);
211 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
212 FATAL("input record `%.30s...' too long", buf);
214 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
217 return c == EOF && rr == buf ? 0 : 1;
220 char *getargv(int n) /* get ARGV[n] */
224 extern Array *ARGVtab;
226 sprintf(temp, "%d", n);
227 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
229 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
233 void setclvar(char *s) /* set var=value from s */
238 for (p=s; *p != '='; p++)
241 p = qstring(p, '\0');
242 q = setsymtab(s, p, 0.0, STR, symtab);
244 if (is_number(q->sval)) {
245 q->fval = atof(q->sval);
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 */
262 if (!isstr(fldtab[0]))
266 if (n > fieldssize) {
268 if ((fields = (char *) malloc(n+1)) == NULL)
269 FATAL("out of space for fields in fldbld %d", n);
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 */
278 while (*r == ' ' || *r == '\t' || *r == '\n')
285 if (freeable(fldtab[i]))
286 xfree(fldtab[i]->sval);
287 fldtab[i]->sval = fr;
288 fldtab[i]->tval = FLD | STR | DONTFREE;
291 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
295 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
296 for (i = 0; *r != 0; r++) {
301 if (freeable(fldtab[i]))
302 xfree(fldtab[i]->sval);
305 fldtab[i]->sval = tostring(buf);
306 fldtab[i]->tval = FLD | STR;
309 } else if (*r != 0) { /* if 0, it's a null field */
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 */
327 FATAL("record `%.30s...' has too many fields; can't happen", r);
328 cleanfld(i+1, lastfld); /* clean out junk from previous record */
331 for (j = 1; j <= lastfld; j++) {
333 if(is_number(p->sval)) {
334 p->fval = atof(p->sval);
338 setfval(nfloc, (Awkfloat) lastfld);
340 for (j = 0; j <= lastfld; 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 */
352 for (i = n1; i <= n2; i++) {
357 p->tval = FLD | STR | DONTFREE;
361 void newfld(int n) /* add field n after end of existing lastfld */
365 cleanfld(lastfld+1, n);
367 setfval(nfloc, (Awkfloat) n);
370 Cell *fieldadr(int n) /* get nth field */
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 */
379 void growfldtab(int n) /* make new fields up to at least $n */
381 int nf = 2 * nfields;
385 fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
387 FATAL("out of space creating %d fields", nf);
388 makefields(nfields+1, 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 */
401 if (n > fieldssize) {
403 if ((fields = (char *) malloc(n+1)) == NULL)
404 FATAL("out of space for fields in refldbld %d", n);
412 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
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;
426 rec = patbeg + patlen;
428 dprintf( ("no match %s\n", rec) );
436 void recbld(void) /* create $0 from $1..$NF if necessary */
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)
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; )
457 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
458 FATAL("built giant record `%.30s...'", record);
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) );
474 void yyerror(char *s)
479 void SYNTAX(char *fmt, ...)
481 extern char *cmdname, *curfname;
482 static int been_here = 0;
487 fprintf(stderr, "%s: ", cmdname);
489 vfprintf(stderr, fmt, varg);
491 if(compile_time == 1 && cursource() != NULL)
492 fprintf(stderr, " at %s:%d", cursource(), lineno);
494 fprintf(stderr, " at line %d", lineno);
495 if (curfname != NULL)
496 fprintf(stderr, " in function %s", curfname);
497 fprintf(stderr, "\n");
504 FATAL("floating point exception %d", n);
507 extern int bracecnt, brackcnt, parencnt;
509 void bracecheck(void)
512 static int beenhere = 0;
516 while ((c = input()) != EOF && c != '\0')
518 bcheck2(bracecnt, '{', '}');
519 bcheck2(brackcnt, '[', ']');
520 bcheck2(parencnt, '(', ')');
523 void bcheck2(int n, int c1, int c2)
526 fprintf(stderr, "\tmissing %c\n", c2);
528 fprintf(stderr, "\t%d missing %c's\n", n, c2);
530 fprintf(stderr, "\textra %c\n", c2);
532 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
535 void FATAL(char *fmt, ...)
537 extern char *cmdname;
541 fprintf(stderr, "%s: ", cmdname);
543 vfprintf(stderr, fmt, varg);
546 if (dbg > 1) /* core dump if serious debugging on */
551 void WARNING(char *fmt, ...)
553 extern char *cmdname;
557 fprintf(stderr, "%s: ", cmdname);
559 vfprintf(stderr, fmt, varg);
566 extern Node *curnode;
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));
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)
583 if (compile_time == 1 && cursource() != NULL){
585 fprintf(stderr, " source %s:%d", cursource(), line);
587 fprintf(stderr, " source file %s", cursource());
589 fprintf(stderr, " source line %d", line);
590 fprintf(stderr, "\n");
594 void eprint(void) /* try to print context around error */
598 static int been_here = 0;
599 extern char ebuf[], *ep;
601 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
604 if (p > ebuf && *p == '\n')
606 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
610 fprintf(stderr, " context is\n\t");
611 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
616 fprintf(stderr, " >>> ");
620 fprintf(stderr, " <<< ");
622 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
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)
647 WARNING("%s argument out of domain", s);
649 } else if (errno == ERANGE) {
651 WARNING("%s result out of range", s);
657 int isclvar(char *s) /* is s of form var=something ? */
661 if (!isalpha(*s) && *s != '_')
664 if (!(isalnum(*s) || *s == '_'))
666 return *s == '=' && s > os && *(s+1) != '=';
669 /* strtod is supposed to be a proper test of what's a valid number */
672 int is_number(char *s)
678 * fast could-it-be-a-number check before calling strtod,
679 * which takes a surprisingly long time to reject non-numbers.
682 case '0': case '1': case '2': case '3': case '4':
683 case '5': case '6': case '7': case '8': case '9':
699 return 0; /* can't be a number */
704 if (ep == s || r == HUGE_VAL || errno == ERANGE)
706 while (*ep == ' ' || *ep == '\t' || *ep == '\n')