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 ****************************************************************/
35 int recsize = RECSIZE;
37 int fieldssize = RECSIZE;
39 Cell **fldtab; /* pointers to Cells */
40 char inputFS[100] = " ";
43 int nfields = MAXFLD; /* last allocated slot for $i */
45 int donefld; /* 1 = implies rec broken into fields */
46 int donerec; /* 1 = record is valid (no flds have changed) */
48 int lastfld = 0; /* last used field */
49 int argno = 1; /* current input argument number */
50 extern Awkfloat *AARGC;
52 static Cell dollar0 = { OCELL, CFLD, nil, "", 0.0, REC|STR|DONTFREE };
53 static Cell dollar1 = { OCELL, CFLD, nil, "", 0.0, FLD|STR|DONTFREE };
55 void recinit(unsigned int n)
57 record = (char *) malloc(n);
58 fields = (char *) malloc(n);
59 fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
60 if (record == nil || fields == nil || fldtab == nil)
61 FATAL("out of space for $0 and fields");
62 fldtab[0] = (Cell *) malloc(sizeof (Cell));
64 fldtab[0]->sval = record;
65 fldtab[0]->nval = tostring("0");
66 makefields(1, nfields);
69 void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
74 for (i = n1; i <= n2; i++) {
75 fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
77 FATAL("out of space in makefields %d", i);
79 sprint(temp, "%d", i);
80 fldtab[i]->nval = tostring(temp);
89 for (i = 1; i < *AARGC; i++) {
90 if (!isclvar(p = getargv(i))) { /* find 1st real filename */
91 setsval(lookup("FILENAME", symtab), p);
94 setclvar(p); /* a commandline assignment before filename */
97 infile = &stdin; /* no filenames, so use &stdin */
100 int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
101 { /* note: cares whether buf == record */
103 static int firsttime = 1;
105 int bufsize = *pbufsize;
111 dprint( ("RS=<%s>, FS=<%s>, AARGC=%g, FILENAME=%s\n",
112 *RS, *FS, *AARGC, *FILENAME) );
118 while (argno < *AARGC || infile == &stdin) {
119 dprint( ("argno=%d, file=|%s|\n", argno, file) );
120 if (infile == nil) { /* have to open a new file */
121 file = getargv(argno);
122 if (*file == '\0') { /* it's been zapped */
126 if (isclvar(file)) { /* a var=value arg */
132 dprint( ("opening file %s\n", file) );
133 if (*file == '-' && *(file+1) == '\0')
135 else if ((infile = Bopen(file, OREAD)) == nil)
136 FATAL("can't open file %s", file);
137 setfval(fnrloc, 0.0);
139 c = readrec(&buf, &bufsize, infile);
140 if (c != 0 || buf[0] != '\0') { /* normal record */
142 if (freeable(fldtab[0]))
143 xfree(fldtab[0]->sval);
144 fldtab[0]->sval = buf; /* buf == record */
145 fldtab[0]->tval = REC | STR | DONTFREE;
146 if (is_number(fldtab[0]->sval)) {
147 fldtab[0]->fval = atof(fldtab[0]->sval);
148 fldtab[0]->tval |= NUM;
151 setfval(nrloc, nrloc->fval+1);
152 setfval(fnrloc, fnrloc->fval+1);
157 /* Beof arrived on this file; set up next */
162 return 0; /* true end of file */
167 if (infile != nil && infile != &stdin)
173 int readrec(char **pbuf, int *pbufsize, Biobuf *inf) /* read one record into buf */
176 char *rr, *buf = *pbuf;
177 int bufsize = *pbufsize;
179 if (strlen(*FS) >= sizeof(inputFS))
180 FATAL("field separator %.10s... is too long", *FS);
181 strcpy(inputFS, *FS); /* for subsequent field splitting */
182 if ((sep = **RS) == 0) {
184 while ((c=Bgetc(inf)) == '\n' && c != Beof) /* skip leading \n's */
190 for (; (c=Bgetc(inf)) != sep && c != Beof; ) {
191 if (rr-buf+1 > bufsize)
192 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
193 FATAL("input record `%.30s...' too long", buf);
196 if (**RS == sep || c == Beof)
198 if ((c = Bgetc(inf)) == '\n' || c == Beof) /* 2 in a row */
200 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
201 FATAL("input record `%.30s...' too long", buf);
205 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
206 FATAL("input record `%.30s...' too long", buf);
208 dprint( ("readrec saw <%s>, returns %d\n", buf, c == Beof && rr == buf ? 0 : 1) );
211 return c == Beof && rr == buf ? 0 : 1;
214 char *getargv(int n) /* get ARGV[n] */
218 extern Array *ARGVtab;
220 sprint(temp, "%d", n);
221 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
223 dprint( ("getargv(%d) returns |%s|\n", n, s) );
227 void setclvar(char *s) /* set var=value from s */
232 for (p=s; *p != '='; p++)
235 p = qstring(p, '\0');
236 q = setsymtab(s, p, 0.0, STR, symtab);
238 if (is_number(q->sval)) {
239 q->fval = atof(q->sval);
242 dprint( ("command line set %s to |%s|\n", s, p) );
246 void fldbld(void) /* create fields from current record */
248 /* this relies on having fields[] the same length as $0 */
249 /* the fields are all stored in this one array with \0's */
256 if (!isstr(fldtab[0]))
260 if (n > fieldssize) {
262 if ((fields = (char *) malloc(n+1)) == nil)
263 FATAL("out of space for fields in fldbld %d", n);
267 i = 0; /* number of fields accumulated here */
268 if (strlen(inputFS) > 1) { /* it's a regular expression */
269 i = refldbld(r, inputFS);
270 } else if (*inputFS == ' ') { /* default whitespace */
272 while (*r == ' ' || *r == '\t' || *r == '\n')
279 if (freeable(fldtab[i]))
280 xfree(fldtab[i]->sval);
281 fldtab[i]->sval = fr;
282 fldtab[i]->tval = FLD | STR | DONTFREE;
285 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
289 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
290 for (i = 0; *r != 0; r++) {
295 if (freeable(fldtab[i]))
296 xfree(fldtab[i]->sval);
299 fldtab[i]->sval = tostring(buf);
300 fldtab[i]->tval = FLD | STR;
303 } else if (*r != 0) { /* if 0, it's a null field */
308 if (freeable(fldtab[i]))
309 xfree(fldtab[i]->sval);
310 fldtab[i]->sval = fr;
311 fldtab[i]->tval = FLD | STR | DONTFREE;
312 while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */
321 FATAL("record `%.30s...' has too many fields; can't happen", r);
322 cleanfld(i+1, lastfld); /* clean out junk from previous record */
325 for (j = 1; j <= lastfld; j++) {
327 if(is_number(p->sval)) {
328 p->fval = atof(p->sval);
332 setfval(nfloc, (Awkfloat) lastfld);
334 for (j = 0; j <= lastfld; j++) {
336 print("field %d (%s): |%s|\n", j, p->nval, p->sval);
341 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
342 { /* nvals remain intact */
346 for (i = n1; i <= n2; i++) {
351 p->tval = FLD | STR | DONTFREE;
355 void newfld(int n) /* add field n after end of existing lastfld */
359 cleanfld(lastfld+1, n);
361 setfval(nfloc, (Awkfloat) n);
364 Cell *fieldadr(int n) /* get nth field */
367 FATAL("trying to access field %d", n);
368 if (n > nfields) /* fields after NF are empty */
369 growfldtab(n); /* but does not increase NF */
373 void growfldtab(int n) /* make new fields up to at least $n */
375 int nf = 2 * nfields;
379 fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
381 FATAL("out of space creating %d fields", nf);
382 makefields(nfields+1, nf);
386 int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */
388 /* this relies on having fields[] the same length as $0 */
389 /* the fields are all stored in this one array with \0's */
395 if (n > fieldssize) {
397 if ((fields = (char *) malloc(n+1)) == nil)
398 FATAL("out of space for fields in refldbld %d", n);
406 dprint( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
410 if (freeable(fldtab[i]))
411 xfree(fldtab[i]->sval);
412 fldtab[i]->tval = FLD | STR | DONTFREE;
413 fldtab[i]->sval = fr;
414 dprint( ("refldbld: i=%d\n", i) );
415 if (nematch(p, rec, rec)) {
416 dprint( ("match %s (%d chars)\n", patbeg, patlen) );
417 strncpy(fr, rec, patbeg-rec);
418 fr += patbeg - rec + 1;
420 rec = patbeg + patlen;
422 dprint( ("no match %s\n", rec) );
430 void recbld(void) /* create $0 from $1..$NF if necessary */
438 for (i = 1; i <= *NF; i++) {
439 p = getsval(fldtab[i]);
440 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
441 FATAL("created $0 `%.30s...' too long", record);
442 while ((*r = *p++) != 0)
445 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
446 FATAL("created $0 `%.30s...' too long", record);
447 for (p = *OFS; (*r = *p++) != 0; )
451 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
452 FATAL("built giant record `%.30s...'", record);
454 dprint( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
456 if (freeable(fldtab[0]))
457 xfree(fldtab[0]->sval);
458 fldtab[0]->tval = REC | STR | DONTFREE;
459 fldtab[0]->sval = record;
461 dprint( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
462 dprint( ("recbld = |%s|\n", record) );
466 char *exitstatus = nil;
468 void yyerror(char *s)
473 void SYNTAX(char *fmt, ...)
475 extern char *cmdname, *curfname;
476 static int been_here = 0;
481 Bprint(&stderr, "%s: ", cmdname);
483 Bvprint(&stderr, fmt, varg);
485 if(compile_time == 1 && cursource() != nil)
486 Bprint(&stderr, " at %s:%d", cursource(), lineno);
488 Bprint(&stderr, " at line %d", lineno);
490 Bprint(&stderr, " in function %s", curfname);
491 Bprint(&stderr, "\n");
492 exitstatus = "syntax error";
496 int handler(void *, char *err)
499 fprint(2, "%s\n", err);
503 extern int bracecnt, brackcnt, parencnt;
505 void bracecheck(void)
508 static int beenhere = 0;
512 while ((c = input()) != Beof && c != '\0')
514 bcheck2(bracecnt, '{', '}');
515 bcheck2(brackcnt, '[', ']');
516 bcheck2(parencnt, '(', ')');
519 void bcheck2(int n, int, int c2)
522 Bprint(&stderr, "\tmissing %c\n", c2);
524 Bprint(&stderr, "\t%d missing %c's\n", n, c2);
526 Bprint(&stderr, "\textra %c\n", c2);
528 Bprint(&stderr, "\t%d extra %c's\n", -n, c2);
531 void FATAL(char *fmt, ...)
533 extern char *cmdname;
537 Bprint(&stderr, "%s: ", cmdname);
539 Bvprint(&stderr, fmt, varg);
542 if (dbg > 1) /* core dump if serious debugging on */
547 void WARNING(char *fmt, ...)
549 extern char *cmdname;
553 Bprint(&stderr, "%s: ", cmdname);
555 Bvprint(&stderr, fmt, varg);
562 extern Node *curnode;
565 Bprint(&stderr, "\n");
566 if (compile_time != 2 && NR && *NR > 0) {
567 if (strcmp(*FILENAME, "-") != 0)
568 Bprint(&stderr, " input record %s:%d", *FILENAME, (int) (*FNR));
570 Bprint(&stderr, " input record number %d", (int) (*FNR));
571 Bprint(&stderr, "\n");
573 if (compile_time != 2 && curnode)
574 line = curnode->lineno;
575 else if (compile_time != 2 && lineno)
579 if (compile_time == 1 && cursource() != nil){
581 Bprint(&stderr, " source %s:%d", cursource(), line);
583 Bprint(&stderr, " source file %s", cursource());
585 Bprint(&stderr, " source line %d", line);
586 Bprint(&stderr, "\n");
590 void eprint(void) /* try to print context around error */
594 static int been_here = 0;
595 extern char ebuf[], *ep;
597 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
600 if (p > ebuf && *p == '\n')
602 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
606 Bprint(&stderr, " context is\n\t");
607 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
612 Bprint(&stderr, " >>> ");
616 Bprint(&stderr, " <<< ");
618 while ((c = input()) != '\n' && c != '\0' && c != Beof) {
622 Bputc(&stderr, '\n');
629 case '{': bracecnt++; break;
630 case '}': bracecnt--; break;
631 case '[': brackcnt++; break;
632 case ']': brackcnt--; break;
633 case '(': parencnt++; break;
634 case ')': parencnt--; break;
638 double errcheck(double x, char *s)
642 WARNING("%s argument out of domain", s);
644 } else if (isInf(x, 1) || isInf(x, -1)) {
645 WARNING("%s result out of range", s);
651 int isclvar(char *s) /* is s of form var=something ? */
655 if (!isalpha(*s) && *s != '_')
658 if (!(isalnum(*s) || *s == '_'))
660 return *s == '=' && s > os && *(s+1) != '=';
663 /* strtod is supposed to be a proper test of what's a valid number */
665 int is_number(char *s)
671 * fast could-it-be-a-number check before calling strtod,
672 * which takes a surprisingly long time to reject non-numbers.
675 case '0': case '1': case '2': case '3': case '4':
676 case '5': case '6': case '7': case '8': case '9':
692 return 0; /* can't be a number */
696 if (ep == s || isInf(r, 1) || isInf(r, -1) || isNaN(r))
698 while (*ep == ' ' || *ep == '\t' || *ep == '\n')