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+2) * 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;
193 char *rs = getsval(rsloc);
195 if (strlen(getsval(fsloc)) >= sizeof (inputFS))
196 FATAL("field separator %.10s... is too long", *FS);
197 /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
198 strcpy(inputFS, *FS); /* for subsequent field splitting */
199 if ((sep = *rs) == 0) {
201 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
207 for (; (c=getc(inf)) != sep && c != EOF; ) {
208 if (rr-buf+1 > bufsize)
209 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
210 FATAL("input record `%.30s...' too long", buf);
213 if (*rs == sep || c == EOF)
215 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
217 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
218 FATAL("input record `%.30s...' too long", buf);
222 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
223 FATAL("input record `%.30s...' too long", buf);
225 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
228 return c == EOF && rr == buf ? 0 : 1;
231 char *getargv(int n) /* get ARGV[n] */
235 extern Array *ARGVtab;
237 sprintf(temp, "%d", n);
238 if (lookup(temp, ARGVtab) == NULL)
240 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
242 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
246 void setclvar(char *s) /* set var=value from s */
251 for (p=s; *p != '='; p++)
254 p = qstring(p, '\0');
255 q = setsymtab(s, p, 0.0, STR, symtab);
257 if (is_number(q->sval)) {
258 q->fval = atof(q->sval);
261 dprintf( ("command line set %s to |%s|\n", s, p) );
265 void fldbld(void) /* create fields from current record */
267 /* this relies on having fields[] the same length as $0 */
268 /* the fields are all stored in this one array with \0's */
269 /* possibly with a final trailing \0 not associated with any field */
276 if (!isstr(fldtab[0]))
280 if (n > fieldssize) {
282 if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
283 FATAL("out of space for fields in fldbld %d", n);
287 i = 0; /* number of fields accumulated here */
288 if (strlen(getsval(fsloc)) >= sizeof (inputFS))
289 FATAL("field separator %.10s... is too long", *FS);
290 strcpy(inputFS, *FS);
291 if (strlen(inputFS) > 1) { /* it's a regular expression */
292 i = refldbld(r, inputFS);
293 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
295 while (*r == ' ' || *r == '\t' || *r == '\n')
302 if (freeable(fldtab[i]))
303 xfree(fldtab[i]->sval);
304 fldtab[i]->sval = fr;
305 fldtab[i]->tval = FLD | STR | DONTFREE;
308 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
312 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
313 for (i = 0; *r != 0; r++) {
318 if (freeable(fldtab[i]))
319 xfree(fldtab[i]->sval);
322 fldtab[i]->sval = tostring(buf);
323 fldtab[i]->tval = FLD | STR;
326 } else if (*r != 0) { /* if 0, it's a null field */
327 /* subtlecase : if length(FS) == 1 && length(RS > 0)
328 * \n is NOT a field separator (cf awk book 61,84).
329 * this variable is tested in the inner while loop.
331 int rtest = '\n'; /* normal case */
338 if (freeable(fldtab[i]))
339 xfree(fldtab[i]->sval);
340 fldtab[i]->sval = fr;
341 fldtab[i]->tval = FLD | STR | DONTFREE;
342 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
351 FATAL("record `%.30s...' has too many fields; can't happen", r);
352 cleanfld(i+1, lastfld); /* clean out junk from previous record */
355 for (j = 1; j <= lastfld; j++) {
357 if(is_number(p->sval)) {
358 p->fval = atof(p->sval);
362 setfval(nfloc, (Awkfloat) lastfld);
363 donerec = 1; /* restore */
365 for (j = 0; j <= lastfld; j++) {
367 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
372 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
373 { /* nvals remain intact */
377 for (i = n1; i <= n2; i++) {
382 p->tval = FLD | STR | DONTFREE;
386 void newfld(int n) /* add field n after end of existing lastfld */
390 cleanfld(lastfld+1, n);
392 setfval(nfloc, (Awkfloat) n);
395 void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
398 FATAL("cannot set NF to a negative value");
403 cleanfld(lastfld+1, n);
405 cleanfld(n+1, lastfld);
410 Cell *fieldadr(int n) /* get nth field */
413 FATAL("trying to access out of range field %d", n);
414 if (n > nfields) /* fields after NF are empty */
415 growfldtab(n); /* but does not increase NF */
419 void growfldtab(int n) /* make new fields up to at least $n */
421 int nf = 2 * nfields;
426 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
427 if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
428 fldtab = (Cell **) realloc(fldtab, s);
429 else /* overflow sizeof int */
430 xfree(fldtab); /* make it null */
432 FATAL("out of space creating %d fields", nf);
433 makefields(nfields+1, nf);
437 int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
439 /* this relies on having fields[] the same length as $0 */
440 /* the fields are all stored in this one array with \0's */
446 if (n > fieldssize) {
448 if ((fields = (char *) malloc(n+1)) == NULL)
449 FATAL("out of space for fields in refldbld %d", n);
456 pfa = makedfa(fs, 1);
457 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
458 tempstat = pfa->initstat;
462 if (freeable(fldtab[i]))
463 xfree(fldtab[i]->sval);
464 fldtab[i]->tval = FLD | STR | DONTFREE;
465 fldtab[i]->sval = fr;
466 dprintf( ("refldbld: i=%d\n", i) );
467 if (nematch(pfa, rec)) {
468 pfa->initstat = 2; /* horrible coupling to b.c */
469 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
470 strncpy(fr, rec, patbeg-rec);
471 fr += patbeg - rec + 1;
473 rec = patbeg + patlen;
475 dprintf( ("no match %s\n", rec) );
477 pfa->initstat = tempstat;
484 void recbld(void) /* create $0 from $1..$NF if necessary */
488 char *sep = getsval(ofsloc);
493 for (i = 1; i <= *NF; i++) {
494 p = getsval(fldtab[i]);
495 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
496 FATAL("created $0 `%.30s...' too long", record);
497 while ((*r = *p++) != 0)
500 if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
501 FATAL("created $0 `%.30s...' too long", record);
502 for (p = sep; (*r = *p++) != 0; )
506 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
507 FATAL("built giant record `%.30s...'", record);
509 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
511 if (freeable(fldtab[0]))
512 xfree(fldtab[0]->sval);
513 fldtab[0]->tval = REC | STR | DONTFREE;
514 fldtab[0]->sval = record;
516 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
517 dprintf( ("recbld = |%s|\n", record) );
523 void yyerror(const char *s)
528 void SYNTAX(const char *fmt, ...)
530 extern char *cmdname, *curfname;
531 static int been_here = 0;
536 fprintf(stderr, "%s: ", cmdname);
538 vfprintf(stderr, fmt, varg);
540 fprintf(stderr, " at source line %d", lineno);
541 if (curfname != NULL)
542 fprintf(stderr, " in function %s", curfname);
543 if (compile_time == 1 && cursource() != NULL)
544 fprintf(stderr, " source file %s", cursource());
545 fprintf(stderr, "\n");
552 FATAL("floating point exception %d", n);
555 extern int bracecnt, brackcnt, parencnt;
557 void bracecheck(void)
560 static int beenhere = 0;
564 while ((c = input()) != EOF && c != '\0')
566 bcheck2(bracecnt, '{', '}');
567 bcheck2(brackcnt, '[', ']');
568 bcheck2(parencnt, '(', ')');
571 void bcheck2(int n, int c1, int c2)
574 fprintf(stderr, "\tmissing %c\n", c2);
576 fprintf(stderr, "\t%d missing %c's\n", n, c2);
578 fprintf(stderr, "\textra %c\n", c2);
580 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
583 void FATAL(const char *fmt, ...)
585 extern char *cmdname;
589 fprintf(stderr, "%s: ", cmdname);
591 vfprintf(stderr, fmt, varg);
594 if (dbg > 1) /* core dump if serious debugging on */
599 void WARNING(const char *fmt, ...)
601 extern char *cmdname;
605 fprintf(stderr, "%s: ", cmdname);
607 vfprintf(stderr, fmt, varg);
614 extern Node *curnode;
616 fprintf(stderr, "\n");
617 if (compile_time != 2 && NR && *NR > 0) {
618 fprintf(stderr, " input record number %d", (int) (*FNR));
619 if (strcmp(*FILENAME, "-") != 0)
620 fprintf(stderr, ", file %s", *FILENAME);
621 fprintf(stderr, "\n");
623 if (compile_time != 2 && curnode)
624 fprintf(stderr, " source line number %d", curnode->lineno);
625 else if (compile_time != 2 && lineno)
626 fprintf(stderr, " source line number %d", lineno);
627 if (compile_time == 1 && cursource() != NULL)
628 fprintf(stderr, " source file %s", cursource());
629 fprintf(stderr, "\n");
633 void eprint(void) /* try to print context around error */
637 static int been_here = 0;
638 extern char ebuf[], *ep;
640 if (compile_time == 2 || compile_time == 0 || been_here++ > 0 || ebuf == ep)
645 if (p > ebuf && *p == '\n')
647 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
651 fprintf(stderr, " context is\n\t");
652 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
657 fprintf(stderr, " >>> ");
661 fprintf(stderr, " <<< ");
663 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
674 case '{': bracecnt++; break;
675 case '}': bracecnt--; break;
676 case '[': brackcnt++; break;
677 case ']': brackcnt--; break;
678 case '(': parencnt++; break;
679 case ')': parencnt--; break;
683 double errcheck(double x, const char *s)
688 WARNING("%s argument out of domain", s);
690 } else if (errno == ERANGE) {
692 WARNING("%s result out of range", s);
698 int isclvar(const char *s) /* is s of form var=something ? */
702 if (!isalpha((uschar) *s) && *s != '_')
705 if (!(isalnum((uschar) *s) || *s == '_'))
707 return *s == '=' && s > os;
710 /* strtod is supposed to be a proper test of what's a valid number */
711 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
712 /* wrong: violates 4.10.1.4 of ansi C standard */
715 int is_number(const char *s)
721 if (ep == s || r == HUGE_VAL || errno == ERANGE)
723 while (*ep == ' ' || *ep == '\t' || *ep == '\n')