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 if ( (record = (char *) malloc(n)) == NULL
61 || (fields = (char *) malloc(n+1)) == NULL
62 || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL
63 || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
64 FATAL("out of space for $0 and fields");
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 p = getargv(i); /* find 1st real filename */
94 if (p == NULL || *p == '\0') { /* deleted or zapped */
99 setsval(lookup("FILENAME", symtab), p);
102 setclvar(p); /* a commandline assignment before filename */
105 infile = stdin; /* no filenames, so use stdin */
108 static int firsttime = 1;
110 int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
111 { /* note: cares whether buf == record */
115 int bufsize = *pbufsize, savebufsize = bufsize;
121 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
122 *RS, *FS, *ARGC, *FILENAME) );
129 while (argno < *ARGC || infile == stdin) {
130 dprintf( ("argno=%d, file=|%s|\n", argno, file) );
131 if (infile == NULL) { /* have to open a new file */
132 file = getargv(argno);
133 if (file == NULL || *file == '\0') { /* deleted or zapped */
137 if (isclvar(file)) { /* a var=value arg */
143 dprintf( ("opening file %s\n", file) );
144 if (*file == '-' && *(file+1) == '\0')
146 else if ((infile = fopen(file, "r")) == NULL)
147 FATAL("can't open file %s", file);
148 setfval(fnrloc, 0.0);
150 c = readrec(&buf, &bufsize, infile);
151 if (c != 0 || buf[0] != '\0') { /* normal record */
153 if (freeable(fldtab[0]))
154 xfree(fldtab[0]->sval);
155 fldtab[0]->sval = buf; /* buf == record */
156 fldtab[0]->tval = REC | STR | DONTFREE;
157 if (is_number(fldtab[0]->sval)) {
158 fldtab[0]->fval = atof(fldtab[0]->sval);
159 fldtab[0]->tval |= NUM;
162 setfval(nrloc, nrloc->fval+1);
163 setfval(fnrloc, fnrloc->fval+1);
168 /* EOF arrived on this file; set up next */
176 *pbufsize = savebufsize;
177 return 0; /* true end of file */
182 if (infile != NULL && infile != stdin)
188 int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
191 char *rr, *buf = *pbuf;
192 int bufsize = *pbufsize;
194 if (strlen(*FS) >= sizeof(inputFS))
195 FATAL("field separator %.10s... is too long", *FS);
196 /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
197 strcpy(inputFS, *FS); /* for subsequent field splitting */
198 if ((sep = **RS) == 0) {
200 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
206 for (; (c=getc(inf)) != sep && c != EOF; ) {
207 if (rr-buf+1 > bufsize)
208 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
209 FATAL("input record `%.30s...' too long", buf);
212 if (**RS == sep || c == EOF)
214 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
216 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
217 FATAL("input record `%.30s...' too long", buf);
221 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
222 FATAL("input record `%.30s...' too long", buf);
224 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
227 return c == EOF && rr == buf ? 0 : 1;
230 char *getargv(int n) /* get ARGV[n] */
234 extern Array *ARGVtab;
236 sprintf(temp, "%d", n);
237 if (lookup(temp, ARGVtab) == NULL)
239 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
241 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
245 void setclvar(char *s) /* set var=value from s */
250 for (p=s; *p != '='; p++)
253 p = qstring(p, '\0');
254 q = setsymtab(s, p, 0.0, STR, symtab);
256 if (is_number(q->sval)) {
257 q->fval = atof(q->sval);
260 dprintf( ("command line set %s to |%s|\n", s, p) );
264 void fldbld(void) /* create fields from current record */
266 /* this relies on having fields[] the same length as $0 */
267 /* the fields are all stored in this one array with \0's */
268 /* possibly with a final trailing \0 not associated with any field */
275 if (!isstr(fldtab[0]))
279 if (n > fieldssize) {
281 if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
282 FATAL("out of space for fields in fldbld %d", n);
286 i = 0; /* number of fields accumulated here */
287 strcpy(inputFS, *FS);
288 if (strlen(inputFS) > 1) { /* it's a regular expression */
289 i = refldbld(r, inputFS);
290 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
292 while (*r == ' ' || *r == '\t' || *r == '\n')
299 if (freeable(fldtab[i]))
300 xfree(fldtab[i]->sval);
301 fldtab[i]->sval = fr;
302 fldtab[i]->tval = FLD | STR | DONTFREE;
305 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
309 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
310 for (i = 0; *r != 0; r++) {
315 if (freeable(fldtab[i]))
316 xfree(fldtab[i]->sval);
319 fldtab[i]->sval = tostring(buf);
320 fldtab[i]->tval = FLD | STR;
323 } else if (*r != 0) { /* if 0, it's a null field */
324 /* subtlecase : if length(FS) == 1 && length(RS > 0)
325 * \n is NOT a field separator (cf awk book 61,84).
326 * this variable is tested in the inner while loop.
328 int rtest = '\n'; /* normal case */
335 if (freeable(fldtab[i]))
336 xfree(fldtab[i]->sval);
337 fldtab[i]->sval = fr;
338 fldtab[i]->tval = FLD | STR | DONTFREE;
339 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
348 FATAL("record `%.30s...' has too many fields; can't happen", r);
349 cleanfld(i+1, lastfld); /* clean out junk from previous record */
352 for (j = 1; j <= lastfld; j++) {
354 if(is_number(p->sval)) {
355 p->fval = atof(p->sval);
359 setfval(nfloc, (Awkfloat) lastfld);
361 for (j = 0; j <= lastfld; j++) {
363 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
368 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
369 { /* nvals remain intact */
373 for (i = n1; i <= n2; i++) {
378 p->tval = FLD | STR | DONTFREE;
382 void newfld(int n) /* add field n after end of existing lastfld */
386 cleanfld(lastfld+1, n);
388 setfval(nfloc, (Awkfloat) n);
391 Cell *fieldadr(int n) /* get nth field */
394 FATAL("trying to access out of range field %d", n);
395 if (n > nfields) /* fields after NF are empty */
396 growfldtab(n); /* but does not increase NF */
400 void growfldtab(int n) /* make new fields up to at least $n */
402 int nf = 2 * nfields;
407 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
408 if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
409 fldtab = (Cell **) realloc(fldtab, s);
410 else /* overflow sizeof int */
411 xfree(fldtab); /* make it null */
413 FATAL("out of space creating %d fields", nf);
414 makefields(nfields+1, nf);
418 int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
420 /* this relies on having fields[] the same length as $0 */
421 /* the fields are all stored in this one array with \0's */
427 if (n > fieldssize) {
429 if ((fields = (char *) malloc(n+1)) == NULL)
430 FATAL("out of space for fields in refldbld %d", n);
437 pfa = makedfa(fs, 1);
438 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
439 tempstat = pfa->initstat;
443 if (freeable(fldtab[i]))
444 xfree(fldtab[i]->sval);
445 fldtab[i]->tval = FLD | STR | DONTFREE;
446 fldtab[i]->sval = fr;
447 dprintf( ("refldbld: i=%d\n", i) );
448 if (nematch(pfa, rec)) {
449 pfa->initstat = 2; /* horrible coupling to b.c */
450 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
451 strncpy(fr, rec, patbeg-rec);
452 fr += patbeg - rec + 1;
454 rec = patbeg + patlen;
456 dprintf( ("no match %s\n", rec) );
458 pfa->initstat = tempstat;
465 void recbld(void) /* create $0 from $1..$NF if necessary */
473 for (i = 1; i <= *NF; i++) {
474 p = getsval(fldtab[i]);
475 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
476 FATAL("created $0 `%.30s...' too long", record);
477 while ((*r = *p++) != 0)
480 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
481 FATAL("created $0 `%.30s...' too long", record);
482 for (p = *OFS; (*r = *p++) != 0; )
486 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
487 FATAL("built giant record `%.30s...'", record);
489 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
491 if (freeable(fldtab[0]))
492 xfree(fldtab[0]->sval);
493 fldtab[0]->tval = REC | STR | DONTFREE;
494 fldtab[0]->sval = record;
496 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
497 dprintf( ("recbld = |%s|\n", record) );
503 void yyerror(const char *s)
508 void SYNTAX(const char *fmt, ...)
510 extern char *cmdname, *curfname;
511 static int been_here = 0;
516 fprintf(stderr, "%s: ", cmdname);
518 vfprintf(stderr, fmt, varg);
520 fprintf(stderr, " at source line %d", lineno);
521 if (curfname != NULL)
522 fprintf(stderr, " in function %s", curfname);
523 if (compile_time == 1 && cursource() != NULL)
524 fprintf(stderr, " source file %s", cursource());
525 fprintf(stderr, "\n");
532 FATAL("floating point exception %d", n);
535 extern int bracecnt, brackcnt, parencnt;
537 void bracecheck(void)
540 static int beenhere = 0;
544 while ((c = input()) != EOF && c != '\0')
546 bcheck2(bracecnt, '{', '}');
547 bcheck2(brackcnt, '[', ']');
548 bcheck2(parencnt, '(', ')');
551 void bcheck2(int n, int c1, int c2)
554 fprintf(stderr, "\tmissing %c\n", c2);
556 fprintf(stderr, "\t%d missing %c's\n", n, c2);
558 fprintf(stderr, "\textra %c\n", c2);
560 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
563 void FATAL(const char *fmt, ...)
565 extern char *cmdname;
569 fprintf(stderr, "%s: ", cmdname);
571 vfprintf(stderr, fmt, varg);
574 if (dbg > 1) /* core dump if serious debugging on */
579 void WARNING(const char *fmt, ...)
581 extern char *cmdname;
585 fprintf(stderr, "%s: ", cmdname);
587 vfprintf(stderr, fmt, varg);
594 extern Node *curnode;
596 fprintf(stderr, "\n");
597 if (compile_time != 2 && NR && *NR > 0) {
598 fprintf(stderr, " input record number %d", (int) (*FNR));
599 if (strcmp(*FILENAME, "-") != 0)
600 fprintf(stderr, ", file %s", *FILENAME);
601 fprintf(stderr, "\n");
603 if (compile_time != 2 && curnode)
604 fprintf(stderr, " source line number %d", curnode->lineno);
605 else if (compile_time != 2 && lineno)
606 fprintf(stderr, " source line number %d", lineno);
607 if (compile_time == 1 && cursource() != NULL)
608 fprintf(stderr, " source file %s", cursource());
609 fprintf(stderr, "\n");
613 void eprint(void) /* try to print context around error */
617 static int been_here = 0;
618 extern char ebuf[], *ep;
620 if (compile_time == 2 || compile_time == 0 || been_here++ > 0 || ebuf == ep)
623 if (p > ebuf && *p == '\n')
625 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
629 fprintf(stderr, " context is\n\t");
630 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
635 fprintf(stderr, " >>> ");
639 fprintf(stderr, " <<< ");
641 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
652 case '{': bracecnt++; break;
653 case '}': bracecnt--; break;
654 case '[': brackcnt++; break;
655 case ']': brackcnt--; break;
656 case '(': parencnt++; break;
657 case ')': parencnt--; break;
661 double errcheck(double x, const char *s)
666 WARNING("%s argument out of domain", s);
668 } else if (errno == ERANGE) {
670 WARNING("%s result out of range", s);
676 int isclvar(const char *s) /* is s of form var=something ? */
680 if (!isalpha((uschar) *s) && *s != '_')
683 if (!(isalnum((uschar) *s) || *s == '_'))
685 return *s == '=' && s > os && *(s+1) != '=';
688 /* strtod is supposed to be a proper test of what's a valid number */
689 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
690 /* wrong: violates 4.10.1.4 of ansi C standard */
693 int is_number(const char *s)
699 if (ep == s || r == HUGE_VAL || errno == ERANGE)
701 while (*ep == ' ' || *ep == '\t' || *ep == '\n')