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 ****************************************************************/
39 int recsize = RECSIZE;
41 int fieldssize = RECSIZE;
43 Cell **fldtab; /* pointers to Cells */
44 char inputFS[100] = " ";
47 int nfields = MAXFLD; /* last allocated slot for $i */
49 int donefld; /* 1 = implies rec broken into fields */
50 int donerec; /* 1 = record is valid (no flds have changed) */
52 int lastfld = 0; /* last used field */
53 int argno = 1; /* current input argument number */
54 extern Awkfloat *ARGC;
56 static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
57 static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
59 void recinit(unsigned int n)
61 record = (char *) malloc(n);
62 fields = (char *) malloc(n);
63 fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
64 if (record == NULL || fields == NULL || fldtab == NULL)
65 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 */
298 for (i = 0; *r != 0; r += nb) {
305 if (freeable(fldtab[i]))
306 xfree(fldtab[i]->sval);
307 nb = chartorune(&rr, r);
310 fldtab[i]->sval = tostring(buf);
311 fldtab[i]->tval = FLD | STR;
314 } else if (*r != 0) { /* if 0, it's a null field */
319 if (freeable(fldtab[i]))
320 xfree(fldtab[i]->sval);
321 fldtab[i]->sval = fr;
322 fldtab[i]->tval = FLD | STR | DONTFREE;
323 while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */
332 FATAL("record `%.30s...' has too many fields; can't happen", r);
333 cleanfld(i+1, lastfld); /* clean out junk from previous record */
336 for (j = 1; j <= lastfld; j++) {
338 if(is_number(p->sval)) {
339 p->fval = atof(p->sval);
343 setfval(nfloc, (Awkfloat) lastfld);
345 for (j = 0; j <= lastfld; j++) {
347 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
352 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
353 { /* nvals remain intact */
357 for (i = n1; i <= n2; i++) {
362 p->tval = FLD | STR | DONTFREE;
366 void newfld(int n) /* add field n after end of existing lastfld */
370 cleanfld(lastfld+1, n);
372 setfval(nfloc, (Awkfloat) n);
375 Cell *fieldadr(int n) /* get nth field */
378 FATAL("trying to access field %d", n);
379 if (n > nfields) /* fields after NF are empty */
380 growfldtab(n); /* but does not increase NF */
384 void growfldtab(int n) /* make new fields up to at least $n */
386 int nf = 2 * nfields;
390 fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
392 FATAL("out of space creating %d fields", nf);
393 makefields(nfields+1, nf);
397 int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */
399 /* this relies on having fields[] the same length as $0 */
400 /* the fields are all stored in this one array with \0's */
406 if (n > fieldssize) {
408 if ((fields = (char *) malloc(n+1)) == NULL)
409 FATAL("out of space for fields in refldbld %d", n);
417 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
421 if (freeable(fldtab[i]))
422 xfree(fldtab[i]->sval);
423 fldtab[i]->tval = FLD | STR | DONTFREE;
424 fldtab[i]->sval = fr;
425 dprintf( ("refldbld: i=%d\n", i) );
426 if (nematch(p, rec, rec)) {
427 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
428 strncpy(fr, rec, patbeg-rec);
429 fr += patbeg - rec + 1;
431 rec = patbeg + patlen;
433 dprintf( ("no match %s\n", rec) );
441 void recbld(void) /* create $0 from $1..$NF if necessary */
449 for (i = 1; i <= *NF; i++) {
450 p = getsval(fldtab[i]);
451 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
452 FATAL("created $0 `%.30s...' too long", record);
453 while ((*r = *p++) != 0)
456 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
457 FATAL("created $0 `%.30s...' too long", record);
458 for (p = *OFS; (*r = *p++) != 0; )
462 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
463 FATAL("built giant record `%.30s...'", record);
465 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
467 if (freeable(fldtab[0]))
468 xfree(fldtab[0]->sval);
469 fldtab[0]->tval = REC | STR | DONTFREE;
470 fldtab[0]->sval = record;
472 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
473 dprintf( ("recbld = |%s|\n", record) );
479 void yyerror(char *s)
484 void SYNTAX(char *fmt, ...)
486 extern char *cmdname, *curfname;
487 static int been_here = 0;
492 fprintf(stderr, "%s: ", cmdname);
494 vfprintf(stderr, fmt, varg);
496 if(compile_time == 1 && cursource() != NULL)
497 fprintf(stderr, " at %s:%d", cursource(), lineno);
499 fprintf(stderr, " at line %d", lineno);
500 if (curfname != NULL)
501 fprintf(stderr, " in function %s", curfname);
502 fprintf(stderr, "\n");
509 FATAL("floating point exception %d", n);
512 extern int bracecnt, brackcnt, parencnt;
514 void bracecheck(void)
517 static int beenhere = 0;
521 while ((c = input()) != EOF && c != '\0')
523 bcheck2(bracecnt, '{', '}');
524 bcheck2(brackcnt, '[', ']');
525 bcheck2(parencnt, '(', ')');
528 void bcheck2(int n, int c1, int c2)
531 fprintf(stderr, "\tmissing %c\n", c2);
533 fprintf(stderr, "\t%d missing %c's\n", n, c2);
535 fprintf(stderr, "\textra %c\n", c2);
537 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
540 void FATAL(char *fmt, ...)
542 extern char *cmdname;
546 fprintf(stderr, "%s: ", cmdname);
548 vfprintf(stderr, fmt, varg);
551 if (dbg > 1) /* core dump if serious debugging on */
556 void WARNING(char *fmt, ...)
558 extern char *cmdname;
562 fprintf(stderr, "%s: ", cmdname);
564 vfprintf(stderr, fmt, varg);
571 extern Node *curnode;
574 fprintf(stderr, "\n");
575 if (compile_time != 2 && NR && *NR > 0) {
576 if (strcmp(*FILENAME, "-") != 0)
577 fprintf(stderr, " input record %s:%d", *FILENAME, (int) (*FNR));
579 fprintf(stderr, " input record number %d", (int) (*FNR));
580 fprintf(stderr, "\n");
582 if (compile_time != 2 && curnode)
583 line = curnode->lineno;
584 else if (compile_time != 2 && lineno)
588 if (compile_time == 1 && cursource() != NULL){
590 fprintf(stderr, " source %s:%d", cursource(), line);
592 fprintf(stderr, " source file %s", cursource());
594 fprintf(stderr, " source line %d", line);
595 fprintf(stderr, "\n");
599 void eprint(void) /* try to print context around error */
603 static int been_here = 0;
604 extern char ebuf[], *ep;
606 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
609 if (p > ebuf && *p == '\n')
611 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
615 fprintf(stderr, " context is\n\t");
616 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
621 fprintf(stderr, " >>> ");
625 fprintf(stderr, " <<< ");
627 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
638 case '{': bracecnt++; break;
639 case '}': bracecnt--; break;
640 case '[': brackcnt++; break;
641 case ']': brackcnt--; break;
642 case '(': parencnt++; break;
643 case ')': parencnt--; break;
647 double errcheck(double x, char *s)
652 WARNING("%s argument out of domain", s);
654 } else if (errno == ERANGE) {
656 WARNING("%s result out of range", s);
662 int isclvar(char *s) /* is s of form var=something ? */
666 if (!isalpha(*s) && *s != '_')
669 if (!(isalnum(*s) || *s == '_'))
671 return *s == '=' && s > os && *(s+1) != '=';
674 /* strtod is supposed to be a proper test of what's a valid number */
677 int is_number(char *s)
683 * fast could-it-be-a-number check before calling strtod,
684 * which takes a surprisingly long time to reject non-numbers.
687 case '0': case '1': case '2': case '3': case '4':
688 case '5': case '6': case '7': case '8': case '9':
704 return 0; /* can't be a number */
709 if (ep == s || r == HUGE_VAL || errno == ERANGE)
711 while (*ep == ' ' || *ep == '\t' || *ep == '\n')