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");
66 fldtab[0]->sval = record;
67 fldtab[0]->nval = tostring("0");
68 makefields(1, nfields);
71 void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
76 for (i = n1; i <= n2; i++) {
77 fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
78 if (fldtab[i] == NULL)
79 FATAL("out of space in makefields %d", i);
81 sprintf(temp, "%d", i);
82 fldtab[i]->nval = tostring(temp);
91 for (i = 1; i < *ARGC; i++) {
92 if (!isclvar(p = getargv(i))) { /* find 1st real filename */
93 setsval(lookup("FILENAME", symtab), getargv(i));
96 setclvar(p); /* a commandline assignment before filename */
99 infile = stdin; /* no filenames, so use stdin */
102 static int firsttime = 1;
104 int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
105 { /* note: cares whether buf == record */
109 int bufsize = *pbufsize, savebufsize = bufsize;
115 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
116 *RS, *FS, *ARGC, *FILENAME) );
123 while (argno < *ARGC || infile == stdin) {
124 dprintf( ("argno=%d, file=|%s|\n", argno, file) );
125 if (infile == NULL) { /* have to open a new file */
126 file = getargv(argno);
127 if (*file == '\0') { /* it's been zapped */
131 if (isclvar(file)) { /* a var=value arg */
137 dprintf( ("opening file %s\n", file) );
138 if (*file == '-' && *(file+1) == '\0')
140 else if ((infile = fopen(file, "r")) == NULL)
141 FATAL("can't open file %s", file);
142 setfval(fnrloc, 0.0);
144 c = readrec(&buf, &bufsize, infile);
145 if (c != 0 || buf[0] != '\0') { /* normal record */
147 if (freeable(fldtab[0]))
148 xfree(fldtab[0]->sval);
149 fldtab[0]->sval = buf; /* buf == record */
150 fldtab[0]->tval = REC | STR | DONTFREE;
151 if (is_number(fldtab[0]->sval)) {
152 fldtab[0]->fval = atof(fldtab[0]->sval);
153 fldtab[0]->tval |= NUM;
156 setfval(nrloc, nrloc->fval+1);
157 setfval(fnrloc, fnrloc->fval+1);
162 /* EOF arrived on this file; set up next */
170 *pbufsize = savebufsize;
171 return 0; /* true end of file */
176 if (infile != NULL && infile != stdin)
182 int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
185 char *rr, *buf = *pbuf;
186 int bufsize = *pbufsize;
188 if (strlen(*FS) >= sizeof(inputFS))
189 FATAL("field separator %.10s... is too long", *FS);
190 strcpy(inputFS, *FS); /* for subsequent field splitting */
191 if ((sep = **RS) == 0) {
193 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
199 for (; (c=getc(inf)) != sep && c != EOF; ) {
200 if (rr-buf+1 > bufsize)
201 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
202 FATAL("input record `%.30s...' too long", buf);
205 if (**RS == sep || c == EOF)
207 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
209 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
210 FATAL("input record `%.30s...' too long", buf);
214 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
215 FATAL("input record `%.30s...' too long", buf);
217 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
220 return c == EOF && rr == buf ? 0 : 1;
223 char *getargv(int n) /* get ARGV[n] */
227 extern Array *ARGVtab;
229 sprintf(temp, "%d", n);
230 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
232 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
236 void setclvar(char *s) /* set var=value from s */
241 for (p=s; *p != '='; p++)
244 p = qstring(p, '\0');
245 q = setsymtab(s, p, 0.0, STR, symtab);
247 if (is_number(q->sval)) {
248 q->fval = atof(q->sval);
251 dprintf( ("command line set %s to |%s|\n", s, p) );
255 void fldbld(void) /* create fields from current record */
257 /* this relies on having fields[] the same length as $0 */
258 /* the fields are all stored in this one array with \0's */
259 /* possibly with a final trailing \0 not associated with any field */
266 if (!isstr(fldtab[0]))
270 if (n > fieldssize) {
272 if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
273 FATAL("out of space for fields in fldbld %d", n);
277 i = 0; /* number of fields accumulated here */
278 strcpy(inputFS, *FS);
279 if (strlen(inputFS) > 1) { /* it's a regular expression */
280 i = refldbld(r, inputFS);
281 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
283 while (*r == ' ' || *r == '\t' || *r == '\n')
290 if (freeable(fldtab[i]))
291 xfree(fldtab[i]->sval);
292 fldtab[i]->sval = fr;
293 fldtab[i]->tval = FLD | STR | DONTFREE;
296 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
300 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
301 for (i = 0; *r != 0; r++) {
306 if (freeable(fldtab[i]))
307 xfree(fldtab[i]->sval);
310 fldtab[i]->sval = tostring(buf);
311 fldtab[i]->tval = FLD | STR;
314 } else if (*r != 0) { /* if 0, it's a null field */
315 /* subtlecase : if length(FS) == 1 && length(RS > 0)
316 * \n is NOT a field separator (cf awk book 61,84).
317 * this variable is tested in the inner while loop.
319 int rtest = '\n'; /* normal case */
326 if (freeable(fldtab[i]))
327 xfree(fldtab[i]->sval);
328 fldtab[i]->sval = fr;
329 fldtab[i]->tval = FLD | STR | DONTFREE;
330 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
339 FATAL("record `%.30s...' has too many fields; can't happen", r);
340 cleanfld(i+1, lastfld); /* clean out junk from previous record */
343 for (j = 1; j <= lastfld; j++) {
345 if(is_number(p->sval)) {
346 p->fval = atof(p->sval);
350 setfval(nfloc, (Awkfloat) lastfld);
352 for (j = 0; j <= lastfld; j++) {
354 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
359 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
360 { /* nvals remain intact */
364 for (i = n1; i <= n2; i++) {
369 p->tval = FLD | STR | DONTFREE;
373 void newfld(int n) /* add field n after end of existing lastfld */
377 cleanfld(lastfld+1, n);
379 setfval(nfloc, (Awkfloat) n);
382 Cell *fieldadr(int n) /* get nth field */
385 FATAL("trying to access out of range field %d", n);
386 if (n > nfields) /* fields after NF are empty */
387 growfldtab(n); /* but does not increase NF */
391 void growfldtab(int n) /* make new fields up to at least $n */
393 int nf = 2 * nfields;
398 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
399 if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
400 fldtab = (Cell **) realloc(fldtab, s);
401 else /* overflow sizeof int */
402 xfree(fldtab); /* make it null */
404 FATAL("out of space creating %d fields", nf);
405 makefields(nfields+1, nf);
409 int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
411 /* this relies on having fields[] the same length as $0 */
412 /* the fields are all stored in this one array with \0's */
418 if (n > fieldssize) {
420 if ((fields = (char *) malloc(n+1)) == NULL)
421 FATAL("out of space for fields in refldbld %d", n);
428 pfa = makedfa(fs, 1);
429 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
430 tempstat = pfa->initstat;
434 if (freeable(fldtab[i]))
435 xfree(fldtab[i]->sval);
436 fldtab[i]->tval = FLD | STR | DONTFREE;
437 fldtab[i]->sval = fr;
438 dprintf( ("refldbld: i=%d\n", i) );
439 if (nematch(pfa, rec)) {
440 pfa->initstat = 2; /* horrible coupling to b.c */
441 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
442 strncpy(fr, rec, patbeg-rec);
443 fr += patbeg - rec + 1;
445 rec = patbeg + patlen;
447 dprintf( ("no match %s\n", rec) );
449 pfa->initstat = tempstat;
456 void recbld(void) /* create $0 from $1..$NF if necessary */
464 for (i = 1; i <= *NF; i++) {
465 p = getsval(fldtab[i]);
466 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
467 FATAL("created $0 `%.30s...' too long", record);
468 while ((*r = *p++) != 0)
471 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
472 FATAL("created $0 `%.30s...' too long", record);
473 for (p = *OFS; (*r = *p++) != 0; )
477 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
478 FATAL("built giant record `%.30s...'", record);
480 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
482 if (freeable(fldtab[0]))
483 xfree(fldtab[0]->sval);
484 fldtab[0]->tval = REC | STR | DONTFREE;
485 fldtab[0]->sval = record;
487 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
488 dprintf( ("recbld = |%s|\n", record) );
494 void yyerror(const char *s)
499 void SYNTAX(const char *fmt, ...)
501 extern char *cmdname, *curfname;
502 static int been_here = 0;
507 fprintf(stderr, "%s: ", cmdname);
509 vfprintf(stderr, fmt, varg);
511 fprintf(stderr, " at source line %d", lineno);
512 if (curfname != NULL)
513 fprintf(stderr, " in function %s", curfname);
514 if (compile_time == 1 && cursource() != NULL)
515 fprintf(stderr, " source file %s", cursource());
516 fprintf(stderr, "\n");
523 FATAL("floating point exception %d", n);
526 extern int bracecnt, brackcnt, parencnt;
528 void bracecheck(void)
531 static int beenhere = 0;
535 while ((c = input()) != EOF && c != '\0')
537 bcheck2(bracecnt, '{', '}');
538 bcheck2(brackcnt, '[', ']');
539 bcheck2(parencnt, '(', ')');
542 void bcheck2(int n, int c1, int c2)
545 fprintf(stderr, "\tmissing %c\n", c2);
547 fprintf(stderr, "\t%d missing %c's\n", n, c2);
549 fprintf(stderr, "\textra %c\n", c2);
551 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
554 void FATAL(const char *fmt, ...)
556 extern char *cmdname;
560 fprintf(stderr, "%s: ", cmdname);
562 vfprintf(stderr, fmt, varg);
565 if (dbg > 1) /* core dump if serious debugging on */
570 void WARNING(const char *fmt, ...)
572 extern char *cmdname;
576 fprintf(stderr, "%s: ", cmdname);
578 vfprintf(stderr, fmt, varg);
585 extern Node *curnode;
587 fprintf(stderr, "\n");
588 if (compile_time != 2 && NR && *NR > 0) {
589 fprintf(stderr, " input record number %d", (int) (*FNR));
590 if (strcmp(*FILENAME, "-") != 0)
591 fprintf(stderr, ", file %s", *FILENAME);
592 fprintf(stderr, "\n");
594 if (compile_time != 2 && curnode)
595 fprintf(stderr, " source line number %d", curnode->lineno);
596 else if (compile_time != 2 && lineno)
597 fprintf(stderr, " source line number %d", lineno);
598 if (compile_time == 1 && cursource() != NULL)
599 fprintf(stderr, " source file %s", cursource());
600 fprintf(stderr, "\n");
604 void eprint(void) /* try to print context around error */
608 static int been_here = 0;
609 extern char ebuf[], *ep;
611 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
614 if (p > ebuf && *p == '\n')
616 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
620 fprintf(stderr, " context is\n\t");
621 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
626 fprintf(stderr, " >>> ");
630 fprintf(stderr, " <<< ");
632 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
643 case '{': bracecnt++; break;
644 case '}': bracecnt--; break;
645 case '[': brackcnt++; break;
646 case ']': brackcnt--; break;
647 case '(': parencnt++; break;
648 case ')': parencnt--; break;
652 double errcheck(double x, const char *s)
657 WARNING("%s argument out of domain", s);
659 } else if (errno == ERANGE) {
661 WARNING("%s result out of range", s);
667 int isclvar(const char *s) /* is s of form var=something ? */
671 if (!isalpha((uschar) *s) && *s != '_')
674 if (!(isalnum((uschar) *s) || *s == '_'))
676 return *s == '=' && s > os && *(s+1) != '=';
679 /* strtod is supposed to be a proper test of what's a valid number */
680 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
681 /* wrong: violates 4.10.1.4 of ansi C standard */
684 int is_number(const char *s)
690 if (ep == s || r == HUGE_VAL || errno == ERANGE)
692 while (*ep == ' ' || *ep == '\t' || *ep == '\n')