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 ****************************************************************/
25 #if HAVE_NBTOOL_CONFIG_H
26 #include "nbtool_config.h"
42 int recsize
= RECSIZE
;
44 int fieldssize
= RECSIZE
;
46 Cell
**fldtab
; /* pointers to Cells */
48 static char static_inputFS
[16] = " ";
49 static size_t len_inputFS
= sizeof(static_inputFS
) - 1;
50 static char *inputFS
= static_inputFS
;
53 int nfields
= MAXFLD
; /* last allocated slot for $i */
55 int donefld
; /* 1 = implies rec broken into fields */
56 int donerec
; /* 1 = record is valid (no flds have changed) */
58 int lastfld
= 0; /* last used field */
59 int argno
= 1; /* current input argument number */
60 extern Awkfloat
*ARGC
;
62 static Cell dollar0
= { OCELL
, CFLD
, NULL
, "", 0.0, REC
|STR
|DONTFREE
};
63 static Cell dollar1
= { OCELL
, CFLD
, NULL
, "", 0.0, FLD
|STR
|DONTFREE
};
65 void recinit(unsigned int n
)
67 if ( (record
= (char *) malloc(n
)) == NULL
68 || (fields
= (char *) malloc(n
)) == NULL
69 || (fldtab
= (Cell
**) malloc((nfields
+1) * sizeof(Cell
*))) == NULL
70 || (fldtab
[0] = (Cell
*) malloc(sizeof(Cell
))) == NULL
)
71 FATAL("out of space for $0 and fields");
73 fldtab
[0]->sval
= record
;
74 fldtab
[0]->nval
= tostring("0");
75 makefields(1, nfields
);
78 void makefields(int n1
, int n2
) /* create $n1..$n2 inclusive */
83 for (i
= n1
; i
<= n2
; i
++) {
84 fldtab
[i
] = (Cell
*) malloc(sizeof (struct Cell
));
85 if (fldtab
[i
] == NULL
)
86 FATAL("out of space in makefields %d", i
);
88 snprintf(temp
, sizeof(temp
), "%d", i
);
89 fldtab
[i
]->nval
= tostring(temp
);
98 for (i
= 1; i
< *ARGC
; i
++) {
99 if (!isclvar(p
= getargv(i
))) { /* find 1st real filename */
100 setsval(lookup("FILENAME", symtab
), getargv(i
));
103 setclvar(p
); /* a commandline assignment before filename */
106 infile
= stdin
; /* no filenames, so use stdin */
109 static int firsttime
= 1;
111 int getrec(uschar
**pbuf
, int *pbufsize
, int isrecord
) /* get next input record */
112 { /* note: cares whether buf == record */
116 int bufsize
= *pbufsize
, savebufsize
= bufsize
;
122 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
123 *RS
, *FS
, *ARGC
, *FILENAME
) );
130 while (argno
< *ARGC
|| infile
== stdin
) {
131 dprintf( ("argno=%d, file=|%s|\n", argno
, file
) );
132 if (infile
== NULL
) { /* have to open a new file */
133 file
= getargv(argno
);
134 if (*file
== '\0') { /* it's been zapped */
138 if (isclvar(file
)) { /* a var=value arg */
144 dprintf( ("opening file %s\n", file
) );
145 if (*file
== '-' && *(file
+1) == '\0')
147 else if ((infile
= fopen(file
, "r")) == NULL
)
148 FATAL("can't open file %s", file
);
149 setfval(fnrloc
, 0.0);
151 c
= readrec(&buf
, &bufsize
, infile
);
152 if (c
!= 0 || buf
[0] != '\0') { /* normal record */
154 if (freeable(fldtab
[0]))
155 xfree(fldtab
[0]->sval
);
156 fldtab
[0]->sval
= buf
; /* buf == record */
157 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
158 if (is_number(fldtab
[0]->sval
)) {
159 fldtab
[0]->fval
= atof(fldtab
[0]->sval
);
160 fldtab
[0]->tval
|= NUM
;
163 setfval(nrloc
, nrloc
->fval
+1);
164 setfval(fnrloc
, fnrloc
->fval
+1);
169 /* EOF arrived on this file; set up next */
177 *pbufsize
= savebufsize
;
178 return 0; /* true end of file */
183 if (infile
!= NULL
&& infile
!= stdin
)
189 int readrec(uschar
**pbuf
, int *pbufsize
, FILE *inf
) /* read one record into buf */
192 uschar
*rr
, *buf
= *pbuf
;
193 int bufsize
= *pbufsize
;
196 if ((len
= strlen(*FS
)) <= len_inputFS
) {
197 strcpy(inputFS
, *FS
); /* for subsequent field splitting */
199 if (inputFS
!= static_inputFS
)
201 inputFS
= malloc(len
+ 1);
203 FATAL("field separator %.10s... is too long", *FS
);
205 memcpy(inputFS
, *FS
, len
+ 1);
207 if ((sep
= **RS
) == 0) {
209 while ((c
=getc(inf
)) == '\n' && c
!= EOF
) /* skip leading \n's */
213 } else if ((*RS
)[1]) {
214 fa
*pfa
= makedfa(*RS
, 1);
215 int tempstat
= pfa
->initstat
;
220 while ((c
= getc(inf
)) != EOF
) {
221 if (rr
-buf
+3 > bufsize
)
222 if (!adjbuf(&buf
, &bufsize
, 3+rr
-buf
,
223 recsize
, &rr
, "readrec 2"))
224 FATAL("input record `%.30s...'"
228 if (!(x
= nematch(pfa
, brr
))) {
229 pfa
->initstat
= tempstat
;
237 brr
= rrr
= rr
= patbeg
;
242 if ((c
= getc(inf
)) == '\n' || c
== EOF
)
250 for (; (c
=getc(inf
)) != sep
&& c
!= EOF
; ) {
251 if (rr
-buf
+1 > bufsize
)
252 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
,
253 recsize
, &rr
, "readrec 1"))
254 FATAL("input record `%.30s...'"
258 if (**RS
== sep
|| c
== EOF
)
260 if ((c
= getc(inf
)) == '\n' || c
== EOF
)
263 if (!adjbuf(&buf
, &bufsize
, 2+rr
-buf
, recsize
, &rr
,
265 FATAL("input record `%.30s...' too long", buf
);
270 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
, recsize
, &rr
, "readrec 3"))
271 FATAL("input record `%.30s...' too long", buf
);
273 dprintf( ("readrec saw <%s>, returns %d\n", buf
, c
== EOF
&& rr
== buf
? 0 : 1) );
276 return c
== EOF
&& rr
== buf
? 0 : 1;
279 char *getargv(int n
) /* get ARGV[n] */
283 extern Array
*ARGVtab
;
285 snprintf(temp
, sizeof(temp
), "%d", n
);
286 x
= setsymtab(temp
, "", 0.0, STR
, ARGVtab
);
288 dprintf( ("getargv(%d) returns |%s|\n", n
, s
) );
292 void setclvar(char *s
) /* set var=value from s */
297 for (p
=s
; *p
!= '='; p
++)
300 p
= qstring(p
, '\0');
301 q
= setsymtab(s
, p
, 0.0, STR
, symtab
);
303 if (is_number(q
->sval
)) {
304 q
->fval
= atof(q
->sval
);
307 dprintf( ("command line set %s to |%s|\n", s
, p
) );
311 void fldbld(void) /* create fields from current record */
313 /* this relies on having fields[] the same length as $0 */
314 /* the fields are all stored in this one array with \0's */
321 if (!isstr(fldtab
[0]))
325 if (n
> fieldssize
) {
327 if ((fields
= (char *) malloc(n
+1)) == NULL
)
328 FATAL("out of space for fields in fldbld %d", n
);
332 i
= 0; /* number of fields accumulated here */
333 if (inputFS
[0] && inputFS
[1]) { /* it's a regular expression */
334 i
= refldbld(r
, inputFS
);
335 } else if ((sep
= *inputFS
) == ' ') { /* default whitespace */
337 while (*r
== ' ' || *r
== '\t' || *r
== '\n')
344 if (freeable(fldtab
[i
]))
345 xfree(fldtab
[i
]->sval
);
346 fldtab
[i
]->sval
= fr
;
347 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
350 while (*r
!= ' ' && *r
!= '\t' && *r
!= '\n' && *r
!= '\0');
354 } else if ((sep
= *inputFS
) == 0) { /* new: FS="" => 1 char/field */
355 for (i
= 0; *r
!= 0; r
++) {
360 if (freeable(fldtab
[i
]))
361 xfree(fldtab
[i
]->sval
);
364 fldtab
[i
]->sval
= tostring(buf
);
365 fldtab
[i
]->tval
= FLD
| STR
;
368 } else if (*r
!= 0) { /* if 0, it's a null field */
369 /* subtlecase : if length(FS) == 1 && length(RS > 0)
370 * \n is NOT a field separator (cf awk book 61,84).
371 * this variable is tested in the inner while loop.
373 int rtest
= '\n'; /* normal case */
380 if (freeable(fldtab
[i
]))
381 xfree(fldtab
[i
]->sval
);
382 fldtab
[i
]->sval
= fr
;
383 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
384 while (*r
!= sep
&& *r
!= rtest
&& *r
!= '\0') /* \n is always a separator */
393 FATAL("record `%.30s...' has too many fields; can't happen", r
);
394 cleanfld(i
+1, lastfld
); /* clean out junk from previous record */
397 for (j
= 1; j
<= lastfld
; j
++) {
399 if(is_number(p
->sval
)) {
400 p
->fval
= atof(p
->sval
);
404 setfval(nfloc
, (Awkfloat
) lastfld
);
406 for (j
= 0; j
<= lastfld
; j
++) {
408 printf("field %d (%s): |%s|\n", j
, p
->nval
, p
->sval
);
413 void cleanfld(int n1
, int n2
) /* clean out fields n1 .. n2 inclusive */
414 { /* nvals remain intact */
418 for (i
= n1
; i
<= n2
; i
++) {
423 p
->tval
= FLD
| STR
| DONTFREE
;
427 void newfld(int n
) /* add field n after end of existing lastfld */
431 cleanfld(lastfld
+1, n
);
433 setfval(nfloc
, (Awkfloat
) n
);
436 Cell
*fieldadr(int n
) /* get nth field */
439 FATAL("trying to access out of range field %d", n
);
440 if (n
> nfields
) /* fields after NF are empty */
441 growfldtab(n
); /* but does not increase NF */
445 void growfldtab(int n
) /* make new fields up to at least $n */
447 int nf
= 2 * nfields
;
452 s
= (nf
+1) * (sizeof (struct Cell
*)); /* freebsd: how much do we need? */
453 if (s
/ sizeof(struct Cell
*) - 1 == nf
) /* didn't overflow */
454 fldtab
= (Cell
**) realloc(fldtab
, s
);
455 else /* overflow sizeof int */
456 xfree(fldtab
); /* make it null */
458 FATAL("out of space creating %d fields", nf
);
459 makefields(nfields
+1, nf
);
463 int refldbld(const char *rec
, const char *fs
) /* build fields from reg expr in FS */
465 /* this relies on having fields[] the same length as $0 */
466 /* the fields are all stored in this one array with \0's */
472 if (n
> fieldssize
) {
474 if ((fields
= (char *) malloc(n
+1)) == NULL
)
475 FATAL("out of space for fields in refldbld %d", n
);
482 pfa
= makedfa(fs
, 1);
483 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec
, fs
) );
484 tempstat
= pfa
->initstat
;
488 if (freeable(fldtab
[i
]))
489 xfree(fldtab
[i
]->sval
);
490 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
491 fldtab
[i
]->sval
= fr
;
492 dprintf( ("refldbld: i=%d\n", i
) );
493 if (nematch(pfa
, rec
)) {
494 pfa
->initstat
= 2; /* horrible coupling to b.c */
495 dprintf( ("match %s (%d chars)\n", patbeg
, patlen
) );
496 strncpy(fr
, rec
, ((char*)patbeg
)-rec
);
497 fr
+= ((char*)patbeg
) - rec
+ 1;
499 rec
= patbeg
+ patlen
;
501 dprintf( ("no match %s\n", rec
) );
503 pfa
->initstat
= tempstat
;
510 void recbld(void) /* create $0 from $1..$NF if necessary */
519 for (i
= 1; i
<= *NF
; i
++) {
520 p
= getsval(fldtab
[i
]);
521 if (!adjbuf(&record
, &recsize
, 1+strlen(p
)+r
-record
, recsize
, &r
, "recbld 1"))
522 FATAL("created $0 `%.30s...' too long", record
);
523 while ((*r
= *p
++) != 0)
526 if (!adjbuf(&record
, &recsize
, 2+strlen(*OFS
)+r
-record
, recsize
, &r
, "recbld 2"))
527 FATAL("created $0 `%.30s...' too long", record
);
528 for (p
= *OFS
; (*r
= *p
++) != 0; )
532 if (!adjbuf(&record
, &recsize
, 2+r
-record
, recsize
, &r
, "recbld 3"))
533 FATAL("built giant record `%.30s...'", record
);
535 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, fldtab
[0]) );
537 if (freeable(fldtab
[0]))
538 xfree(fldtab
[0]->sval
);
539 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
540 fldtab
[0]->sval
= record
;
542 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, fldtab
[0]) );
543 dprintf( ("recbld = |%s|\n", record
) );
549 void yyerror(const char *s
)
554 void SYNTAX(const char *fmt
, ...)
556 extern char *cmdname
, *curfname
;
557 static int been_here
= 0;
562 fprintf(stderr
, "%s: ", cmdname
);
564 vfprintf(stderr
, fmt
, varg
);
566 fprintf(stderr
, " at source line %d", lineno
);
567 if (curfname
!= NULL
)
568 fprintf(stderr
, " in function %s", curfname
);
569 if (compile_time
== 1 && cursource() != NULL
)
570 fprintf(stderr
, " source file %s", cursource());
571 fprintf(stderr
, "\n");
576 extern int bracecnt
, brackcnt
, parencnt
;
578 void bracecheck(void)
581 static int beenhere
= 0;
585 while ((c
= input()) != EOF
&& c
!= '\0')
587 bcheck2(bracecnt
, '{', '}');
588 bcheck2(brackcnt
, '[', ']');
589 bcheck2(parencnt
, '(', ')');
592 void bcheck2(int n
, int c1
, int c2
)
595 fprintf(stderr
, "\tmissing %c\n", c2
);
597 fprintf(stderr
, "\t%d missing %c's\n", n
, c2
);
599 fprintf(stderr
, "\textra %c\n", c2
);
601 fprintf(stderr
, "\t%d extra %c's\n", -n
, c2
);
604 void FATAL(const char *fmt
, ...)
606 extern char *cmdname
;
610 fprintf(stderr
, "%s: ", cmdname
);
612 vfprintf(stderr
, fmt
, varg
);
615 if (dbg
> 1) /* core dump if serious debugging on */
620 void WARNING(const char *fmt
, ...)
622 extern char *cmdname
;
626 fprintf(stderr
, "%s: ", cmdname
);
628 vfprintf(stderr
, fmt
, varg
);
635 extern Node
*curnode
;
637 fprintf(stderr
, "\n");
638 if (compile_time
!= 2 && NR
&& *NR
> 0) {
639 fprintf(stderr
, " input record number %d", (int) (*FNR
));
640 if (strcmp(*FILENAME
, "-") != 0)
641 fprintf(stderr
, ", file %s", *FILENAME
);
642 fprintf(stderr
, "\n");
644 if (compile_time
!= 2 && curnode
)
645 fprintf(stderr
, " source line number %d", curnode
->lineno
);
646 else if (compile_time
!= 2 && lineno
)
647 fprintf(stderr
, " source line number %d", lineno
);
648 if (compile_time
== 1 && cursource() != NULL
)
649 fprintf(stderr
, " source file %s", cursource());
650 fprintf(stderr
, "\n");
654 void eprint(void) /* try to print context around error */
657 static int been_here
= 0;
658 extern char ebuf
[], *ep
;
660 if (compile_time
== 2 || compile_time
== 0 || been_here
++ > 0)
663 if (p
> ebuf
&& *p
== '\n')
665 for ( ; p
> ebuf
&& *p
!= '\n' && *p
!= '\0'; p
--)
669 fprintf(stderr
, " context is\n\t");
670 for (q
=ep
-1; q
>=p
&& *q
!=' ' && *q
!='\t' && *q
!='\n'; q
--)
675 fprintf(stderr
, " >>> ");
679 fprintf(stderr
, " <<< ");
682 * The following code was used to print the rest of the line of
683 * error context. It naively counts brackets, parens and braces in
684 * order to minimize the parsing effect of dropping the rest of the
685 * line but it does not work in all the cases. It is too much work
686 * to save the current program input point and restore it in all the
687 * cases just for the benefit of error printing so for now this
688 * code is disabled. In particular this code is confused if the
689 * [ { ( ) } ] is inside a quoted string or a pattern.
693 while ((c
= input()) != '\n' && c
!= '\0' && c
!= EOF
) {
706 case '{': bracecnt
++; break;
707 case '}': bracecnt
--; break;
708 case '[': brackcnt
++; break;
709 case ']': brackcnt
--; break;
710 case '(': parencnt
++; break;
711 case ')': parencnt
--; break;
715 double errcheck(double x
, const char *s
)
720 WARNING("%s argument out of domain", s
);
722 } else if (errno
== ERANGE
) {
724 WARNING("%s result out of range", s
);
730 int isclvar(const char *s
) /* is s of form var=something ? */
734 if (!isalpha((uschar
) *s
) && *s
!= '_')
737 if (!(isalnum((uschar
) *s
) || *s
== '_'))
739 return *s
== '=' && s
> os
&& *(s
+1) != '=';
742 /* strtod is supposed to be a proper test of what's a valid number */
743 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
744 /* wrong: violates 4.10.1.4 of ansi C standard */
747 int is_number(const char *s
)
753 if (ep
== s
|| errno
== ERANGE
)
755 if (ep
- s
>= 3 && strncasecmp(ep
- 3, "nan", 3) == 0)
757 while (*ep
== ' ' || *ep
== '\t' || *ep
== '\n')