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 */
311 /* subtlecase : if length(FS) == 1 && length(RS > 0)
312 * \n is NOT a field separator (cf awk book 61,84).
313 * this variable is tested in the inner while loop.
315 int rtest = '\n'; /* normal case */
322 if (freeable(fldtab[i]))
323 xfree(fldtab[i]->sval);
324 fldtab[i]->sval = fr;
325 fldtab[i]->tval = FLD | STR | DONTFREE;
326 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
335 FATAL("record `%.30s...' has too many fields; can't happen", r);
336 cleanfld(i+1, lastfld); /* clean out junk from previous record */
339 for (j = 1; j <= lastfld; j++) {
341 if(is_number(p->sval)) {
342 p->fval = atof(p->sval);
346 setfval(nfloc, (Awkfloat) lastfld);
348 for (j = 0; j <= lastfld; j++) {
350 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
355 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
356 { /* nvals remain intact */
360 for (i = n1; i <= n2; i++) {
365 p->tval = FLD | STR | DONTFREE;
369 void newfld(int n) /* add field n after end of existing lastfld */
373 cleanfld(lastfld+1, n);
375 setfval(nfloc, (Awkfloat) n);
378 Cell *fieldadr(int n) /* get nth field */
381 FATAL("trying to access field %d", n);
382 if (n > nfields) /* fields after NF are empty */
383 growfldtab(n); /* but does not increase NF */
387 void growfldtab(int n) /* make new fields up to at least $n */
389 int nf = 2 * nfields;
393 fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
395 FATAL("out of space creating %d fields", nf);
396 makefields(nfields+1, nf);
400 int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
402 /* this relies on having fields[] the same length as $0 */
403 /* the fields are all stored in this one array with \0's */
409 if (n > fieldssize) {
411 if ((fields = (char *) malloc(n+1)) == NULL)
412 FATAL("out of space for fields in refldbld %d", n);
419 pfa = makedfa(fs, 1);
420 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
421 tempstat = pfa->initstat;
425 if (freeable(fldtab[i]))
426 xfree(fldtab[i]->sval);
427 fldtab[i]->tval = FLD | STR | DONTFREE;
428 fldtab[i]->sval = fr;
429 dprintf( ("refldbld: i=%d\n", i) );
430 if (nematch(pfa, rec)) {
431 pfa->initstat = 2; /* horrible coupling to b.c */
432 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
433 strncpy(fr, rec, patbeg-rec);
434 fr += patbeg - rec + 1;
436 rec = patbeg + patlen;
438 dprintf( ("no match %s\n", rec) );
440 pfa->initstat = tempstat;
447 void recbld(void) /* create $0 from $1..$NF if necessary */
455 for (i = 1; i <= *NF; i++) {
456 p = getsval(fldtab[i]);
457 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
458 FATAL("created $0 `%.30s...' too long", record);
459 while ((*r = *p++) != 0)
462 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
463 FATAL("created $0 `%.30s...' too long", record);
464 for (p = *OFS; (*r = *p++) != 0; )
468 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
469 FATAL("built giant record `%.30s...'", record);
471 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
473 if (freeable(fldtab[0]))
474 xfree(fldtab[0]->sval);
475 fldtab[0]->tval = REC | STR | DONTFREE;
476 fldtab[0]->sval = record;
478 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
479 dprintf( ("recbld = |%s|\n", record) );
485 void yyerror(const char *s)
490 void SYNTAX(const char *fmt, ...)
492 extern char *cmdname, *curfname;
493 static int been_here = 0;
498 fprintf(stderr, "%s: ", cmdname);
500 vfprintf(stderr, fmt, varg);
502 fprintf(stderr, " at source line %d", lineno);
503 if (curfname != NULL)
504 fprintf(stderr, " in function %s", curfname);
505 if (compile_time == 1 && cursource() != NULL)
506 fprintf(stderr, " source file %s", cursource());
507 fprintf(stderr, "\n");
514 FATAL("floating point exception %d", n);
517 extern int bracecnt, brackcnt, parencnt;
519 void bracecheck(void)
522 static int beenhere = 0;
526 while ((c = input()) != EOF && c != '\0')
528 bcheck2(bracecnt, '{', '}');
529 bcheck2(brackcnt, '[', ']');
530 bcheck2(parencnt, '(', ')');
533 void bcheck2(int n, int c1, int c2)
536 fprintf(stderr, "\tmissing %c\n", c2);
538 fprintf(stderr, "\t%d missing %c's\n", n, c2);
540 fprintf(stderr, "\textra %c\n", c2);
542 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
545 void FATAL(const char *fmt, ...)
547 extern char *cmdname;
551 fprintf(stderr, "%s: ", cmdname);
553 vfprintf(stderr, fmt, varg);
556 if (dbg > 1) /* core dump if serious debugging on */
561 void WARNING(const char *fmt, ...)
563 extern char *cmdname;
567 fprintf(stderr, "%s: ", cmdname);
569 vfprintf(stderr, fmt, varg);
576 extern Node *curnode;
578 fprintf(stderr, "\n");
579 if (compile_time != 2 && NR && *NR > 0) {
580 fprintf(stderr, " input record number %d", (int) (*FNR));
581 if (strcmp(*FILENAME, "-") != 0)
582 fprintf(stderr, ", file %s", *FILENAME);
583 fprintf(stderr, "\n");
585 if (compile_time != 2 && curnode)
586 fprintf(stderr, " source line number %d", curnode->lineno);
587 else if (compile_time != 2 && lineno)
588 fprintf(stderr, " source line number %d", lineno);
589 if (compile_time == 1 && cursource() != NULL)
590 fprintf(stderr, " source file %s", cursource());
591 fprintf(stderr, "\n");
595 void eprint(void) /* try to print context around error */
599 static int been_here = 0;
600 extern char ebuf[], *ep;
602 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
605 if (p > ebuf && *p == '\n')
607 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
611 fprintf(stderr, " context is\n\t");
612 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
617 fprintf(stderr, " >>> ");
621 fprintf(stderr, " <<< ");
623 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
634 case '{': bracecnt++; break;
635 case '}': bracecnt--; break;
636 case '[': brackcnt++; break;
637 case ']': brackcnt--; break;
638 case '(': parencnt++; break;
639 case ')': parencnt--; break;
643 double errcheck(double x, const char *s)
648 WARNING("%s argument out of domain", s);
650 } else if (errno == ERANGE) {
652 WARNING("%s result out of range", s);
658 int isclvar(const char *s) /* is s of form var=something ? */
662 if (!isalpha((uschar) *s) && *s != '_')
665 if (!(isalnum((uschar) *s) || *s == '_'))
667 return *s == '=' && s > os && *(s+1) != '=';
670 /* strtod is supposed to be a proper test of what's a valid number */
671 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
672 /* wrong: violates 4.10.1.4 of ansi C standard */
675 int is_number(const char *s)
681 if (ep == s || r == HUGE_VAL || errno == ERANGE)
683 while (*ep == ' ' || *ep == '\t' || *ep == '\n')