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"
39 char EMPTY
[] = { '\0' };
41 int innew
; /* 1 = infile has not been read by readrec */
44 int recsize
= RECSIZE
;
46 int fieldssize
= RECSIZE
;
48 Cell
**fldtab
; /* pointers to Cells */
50 static size_t len_inputFS
= 0;
51 static char *inputFS
= NULL
;
54 int nfields
= MAXFLD
; /* last allocated slot for $i */
56 int donefld
; /* 1 = implies rec broken into fields */
57 int donerec
; /* 1 = record is valid (no flds have changed) */
59 int lastfld
= 0; /* last used field */
60 int argno
= 1; /* current input argument number */
61 extern Awkfloat
*ARGC
;
63 static Cell dollar0
= { OCELL
, CFLD
, NULL
, EMPTY
, 0.0, REC
|STR
|DONTFREE
, NULL
};
64 static Cell dollar1
= { OCELL
, CFLD
, NULL
, EMPTY
, 0.0, FLD
|STR
|DONTFREE
, NULL
};
66 void recinit(unsigned int n
)
68 if ( (record
= malloc(n
)) == NULL
69 || (fields
= malloc(n
+1)) == NULL
70 || (fldtab
= malloc((nfields
+1) * sizeof(*fldtab
))) == NULL
71 || (fldtab
[0] = malloc(sizeof(**fldtab
))) == NULL
)
72 FATAL("out of space for $0 and fields");
74 fldtab
[0]->sval
= record
;
75 fldtab
[0]->nval
= tostring("0");
76 makefields(1, nfields
);
79 void makefields(int n1
, int n2
) /* create $n1..$n2 inclusive */
84 for (i
= n1
; i
<= n2
; i
++) {
85 fldtab
[i
] = malloc(sizeof(**fldtab
));
86 if (fldtab
[i
] == NULL
)
87 FATAL("out of space in makefields %d", i
);
89 snprintf(temp
, sizeof(temp
), "%d", i
);
90 fldtab
[i
]->nval
= tostring(temp
);
99 for (i
= 1; i
< *ARGC
; i
++) {
100 p
= getargv(i
); /* find 1st real filename */
101 if (p
== NULL
|| *p
== '\0') { /* deleted or zapped */
106 setsval(lookup("FILENAME", symtab
), p
);
109 setclvar(p
); /* a commandline assignment before filename */
112 infile
= stdin
; /* no filenames, so use stdin */
116 static int firsttime
= 1;
118 int getrec(uschar
**pbuf
, int *pbufsize
, int isrecord
) /* get next input record */
119 { /* note: cares whether buf == record */
123 int bufsize
= *pbufsize
, savebufsize
= bufsize
;
129 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
130 *RS
, *FS
, *ARGC
, *FILENAME
) );
137 while (argno
< *ARGC
|| infile
== stdin
) {
138 dprintf( ("argno=%d, file=|%s|\n", argno
, file
) );
139 if (infile
== NULL
) { /* have to open a new file */
140 file
= getargv(argno
);
141 if (file
== NULL
|| *file
== '\0') { /* deleted or zapped */
145 if (isclvar(file
)) { /* a var=value arg */
151 dprintf( ("opening file %s\n", file
) );
152 if (*file
== '-' && *(file
+1) == '\0')
154 else if ((infile
= fopen(file
, "r")) == NULL
)
155 FATAL("can't open file %s", file
);
157 setfval(fnrloc
, 0.0);
159 c
= readrec(&buf
, &bufsize
, infile
, innew
);
162 if (c
!= 0 || buf
[0] != '\0') { /* normal record */
164 if (freeable(fldtab
[0]))
165 xfree(fldtab
[0]->sval
);
166 fldtab
[0]->sval
= buf
; /* buf == record */
167 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
168 if (is_number(fldtab
[0]->sval
)) {
169 fldtab
[0]->fval
= atof(fldtab
[0]->sval
);
170 fldtab
[0]->tval
|= NUM
;
173 setfval(nrloc
, nrloc
->fval
+1);
174 setfval(fnrloc
, fnrloc
->fval
+1);
179 /* EOF arrived on this file; set up next */
187 *pbufsize
= savebufsize
;
188 return 0; /* true end of file */
193 if (infile
!= NULL
&& infile
!= stdin
)
199 int readrec(uschar
**pbuf
, int *pbufsize
, FILE *inf
, int newflag
) /* read one record into buf */
201 int sep
, c
, isrec
, found
, tempstat
;
202 uschar
*rr
, *buf
= *pbuf
;
203 int bufsize
= *pbufsize
;
206 if ((len
= strlen(*FS
)) < len_inputFS
) {
207 strcpy(inputFS
, *FS
); /* for subsequent field splitting */
209 len_inputFS
= len
+ 1;
210 inputFS
= realloc(inputFS
, len_inputFS
);
212 FATAL("field separator %.10s... is too long", *FS
);
213 memcpy(inputFS
, *FS
, len_inputFS
);
215 /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
216 if (**RS
&& (*RS
)[1]) {
217 fa
*pfa
= makedfa(*RS
, 1);
219 found
= fnematch(pfa
, inf
, &buf
, &bufsize
, recsize
);
221 tempstat
= pfa
->initstat
;
223 found
= fnematch(pfa
, inf
, &buf
, &bufsize
, recsize
);
224 pfa
->initstat
= tempstat
;
229 if ((sep
= **RS
) == 0) {
231 while ((c
=getc(inf
)) == '\n' && c
!= EOF
) /* skip leading \n's */
237 for (; (c
=getc(inf
)) != sep
&& c
!= EOF
; ) {
238 if (rr
-buf
+1 > bufsize
)
239 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
,
240 recsize
, &rr
, "readrec 1"))
241 FATAL("input record `%.30s...'"
245 if (**RS
== sep
|| c
== EOF
)
247 if ((c
= getc(inf
)) == '\n' || c
== EOF
)
250 if (!adjbuf(&buf
, &bufsize
, 2+rr
-buf
, recsize
, &rr
,
252 FATAL("input record `%.30s...' too long", buf
);
256 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
, recsize
, &rr
, "readrec 3"))
257 FATAL("input record `%.30s...' too long", buf
);
262 isrec
= *buf
|| !feof(inf
);
263 dprintf( ("readrec saw <%s>, returns %d\n", buf
, isrec
) );
267 char *getargv(int n
) /* get ARGV[n] */
271 extern Array
*ARGVtab
;
273 snprintf(temp
, sizeof(temp
), "%d", n
);
274 if (lookup(temp
, ARGVtab
) == NULL
)
276 x
= setsymtab(temp
, "", 0.0, STR
, ARGVtab
);
278 dprintf( ("getargv(%d) returns |%s|\n", n
, s
) );
282 void setclvar(char *s
) /* set var=value from s */
287 for (p
=s
; *p
!= '='; p
++)
290 p
= qstring(p
, '\0');
291 q
= setsymtab(s
, p
, 0.0, STR
, symtab
);
293 if (is_number(q
->sval
)) {
294 q
->fval
= atof(q
->sval
);
297 dprintf( ("command line set %s to |%s|\n", s
, p
) );
301 void fldbld(void) /* create fields from current record */
303 /* this relies on having fields[] the same length as $0 */
304 /* the fields are all stored in this one array with \0's */
305 /* possibly with a final trailing \0 not associated with any field */
312 if (!isstr(fldtab
[0]))
316 if (n
> fieldssize
) {
318 if ((fields
= malloc(n
+2)) == NULL
) /* possibly 2 final \0s */
319 FATAL("out of space for fields in fldbld %d", n
);
323 i
= 0; /* number of fields accumulated here */
326 } else if (inputFS
[0] && inputFS
[1]) { /* it's a regular expression */
327 i
= refldbld(r
, inputFS
);
328 } else if ((sep
= *inputFS
) == ' ') { /* default whitespace */
330 while (*r
== ' ' || *r
== '\t' || *r
== '\n')
337 if (freeable(fldtab
[i
]))
338 xfree(fldtab
[i
]->sval
);
339 fldtab
[i
]->sval
= fr
;
340 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
343 while (*r
!= ' ' && *r
!= '\t' && *r
!= '\n' && *r
!= '\0');
347 } else if ((sep
= *inputFS
) == 0) { /* new: FS="" => 1 char/field */
348 for (i
= 0; *r
!= 0; r
++) {
353 if (freeable(fldtab
[i
]))
354 xfree(fldtab
[i
]->sval
);
357 fldtab
[i
]->sval
= tostring(buf
);
358 fldtab
[i
]->tval
= FLD
| STR
;
361 } else if (*r
!= 0) { /* if 0, it's a null field */
362 /* subtlecase : if length(FS) == 1 && length(RS > 0)
363 * \n is NOT a field separator (cf awk book 61,84).
364 * this variable is tested in the inner while loop.
366 int rtest
= '\n'; /* normal case */
373 if (freeable(fldtab
[i
]))
374 xfree(fldtab
[i
]->sval
);
375 fldtab
[i
]->sval
= fr
;
376 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
377 while (*r
!= sep
&& *r
!= rtest
&& *r
!= '\0') /* \n is always a separator */
386 FATAL("record `%.30s...' has too many fields; can't happen", r
);
387 cleanfld(i
+1, lastfld
); /* clean out junk from previous record */
390 for (j
= 1; j
<= lastfld
; j
++) {
392 if(is_number(p
->sval
)) {
393 p
->fval
= atof(p
->sval
);
397 setfval(nfloc
, (Awkfloat
) lastfld
);
398 donerec
= 1; /* restore */
400 for (j
= 0; j
<= lastfld
; j
++) {
402 printf("field %d (%s): |%s|\n", j
, p
->nval
, p
->sval
);
407 void cleanfld(int n1
, int n2
) /* clean out fields n1 .. n2 inclusive */
408 { /* nvals remain intact */
412 for (i
= n1
; i
<= n2
; i
++) {
417 p
->tval
= FLD
| STR
| DONTFREE
;
421 void newfld(int n
) /* add field n after end of existing lastfld */
425 cleanfld(lastfld
+1, n
);
427 setfval(nfloc
, (Awkfloat
) n
);
430 void setlastfld(int n
) /* set lastfld cleaning fldtab cells if necessary */
436 cleanfld(lastfld
+1, n
);
438 cleanfld(n
+1, lastfld
);
443 Cell
*fieldadr(int n
) /* get nth field */
446 FATAL("trying to access out of range field %d", n
);
447 if (n
> nfields
) /* fields after NF are empty */
448 growfldtab(n
); /* but does not increase NF */
452 void growfldtab(int n
) /* make new fields up to at least $n */
454 int nf
= 2 * nfields
;
459 s
= (nf
+1) * (sizeof (struct Cell
*)); /* freebsd: how much do we need? */
460 if (s
/ sizeof(struct Cell
*) - 1 == (size_t)nf
) /* didn't overflow */
461 fldtab
= realloc(fldtab
, s
);
462 else /* overflow sizeof int */
463 xfree(fldtab
); /* make it null */
465 FATAL("out of space creating %d fields", nf
);
466 makefields(nfields
+1, nf
);
470 int refldbld(const char *rec
, const char *fs
) /* build fields from reg expr in FS */
472 /* this relies on having fields[] the same length as $0 */
473 /* the fields are all stored in this one array with \0's */
479 if (n
> fieldssize
) {
481 if ((fields
= malloc(n
+1)) == NULL
)
482 FATAL("out of space for fields in refldbld %d", n
);
489 pfa
= makedfa(fs
, 1);
490 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec
, fs
) );
491 tempstat
= pfa
->initstat
;
495 if (freeable(fldtab
[i
]))
496 xfree(fldtab
[i
]->sval
);
497 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
498 fldtab
[i
]->sval
= fr
;
499 dprintf( ("refldbld: i=%d\n", i
) );
500 if (nematch(pfa
, rec
)) {
501 pfa
->initstat
= 2; /* horrible coupling to b.c */
502 dprintf( ("match %s (%d chars)\n", patbeg
, patlen
) );
503 strncpy(fr
, rec
, ((const char*)patbeg
)-rec
);
504 fr
+= ((const char*)patbeg
) - rec
+ 1;
506 rec
= patbeg
+ patlen
;
508 dprintf( ("no match %s\n", rec
) );
510 pfa
->initstat
= tempstat
;
517 void recbld(void) /* create $0 from $1..$NF if necessary */
526 for (i
= 1; i
<= *NF
; i
++) {
527 p
= getsval(fldtab
[i
]);
528 if (!adjbuf(&record
, &recsize
, 1+strlen(p
)+r
-record
, recsize
, &r
, "recbld 1"))
529 FATAL("created $0 `%.30s...' too long", record
);
530 while ((*r
= *p
++) != 0)
533 if (!adjbuf(&record
, &recsize
, 2+strlen(*OFS
)+r
-record
, recsize
, &r
, "recbld 2"))
534 FATAL("created $0 `%.30s...' too long", record
);
535 for (p
= *OFS
; (*r
= *p
++) != 0; )
539 if (!adjbuf(&record
, &recsize
, 2+r
-record
, recsize
, &r
, "recbld 3"))
540 FATAL("built giant record `%.30s...'", record
);
542 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, fldtab
[0]) );
544 if (freeable(fldtab
[0]))
545 xfree(fldtab
[0]->sval
);
546 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
547 fldtab
[0]->sval
= record
;
549 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, fldtab
[0]) );
550 dprintf( ("recbld = |%s|\n", record
) );
556 void yyerror(const char *s
)
561 void SYNTAX(const char *fmt
, ...)
563 extern char *cmdname
, *curfname
;
564 static int been_here
= 0;
569 fprintf(stderr
, "%s: ", cmdname
);
571 vfprintf(stderr
, fmt
, varg
);
573 fprintf(stderr
, " at source line %d", lineno
);
574 if (curfname
!= NULL
)
575 fprintf(stderr
, " in function %s", curfname
);
576 if (compile_time
== 1 && cursource() != NULL
)
577 fprintf(stderr
, " source file %s", cursource());
578 fprintf(stderr
, "\n");
583 extern int bracecnt
, brackcnt
, parencnt
;
585 void bracecheck(void)
588 static int beenhere
= 0;
592 while ((c
= input()) != EOF
&& c
!= '\0')
594 bcheck2(bracecnt
, '{', '}');
595 bcheck2(brackcnt
, '[', ']');
596 bcheck2(parencnt
, '(', ')');
599 void bcheck2(int n
, int c1
, int c2
)
602 fprintf(stderr
, "\tmissing %c\n", c2
);
604 fprintf(stderr
, "\t%d missing %c's\n", n
, c2
);
606 fprintf(stderr
, "\textra %c\n", c2
);
608 fprintf(stderr
, "\t%d extra %c's\n", -n
, c2
);
611 void FATAL(const char *fmt
, ...)
613 extern char *cmdname
;
617 fprintf(stderr
, "%s: ", cmdname
);
619 vfprintf(stderr
, fmt
, varg
);
622 if (dbg
> 1) /* core dump if serious debugging on */
627 void WARNING(const char *fmt
, ...)
629 extern char *cmdname
;
633 fprintf(stderr
, "%s: ", cmdname
);
635 vfprintf(stderr
, fmt
, varg
);
642 extern Node
*curnode
;
644 fprintf(stderr
, "\n");
645 if (compile_time
!= 2 && NR
&& *NR
> 0) {
646 fprintf(stderr
, " input record number %d", (int) (*FNR
));
647 if (strcmp(*FILENAME
, "-") != 0)
648 fprintf(stderr
, ", file %s", *FILENAME
);
649 fprintf(stderr
, "\n");
651 if (compile_time
!= 2 && curnode
)
652 fprintf(stderr
, " source line number %d", curnode
->lineno
);
653 else if (compile_time
!= 2 && lineno
)
654 fprintf(stderr
, " source line number %d", lineno
);
655 if (compile_time
== 1 && cursource() != NULL
)
656 fprintf(stderr
, " source file %s", cursource());
657 fprintf(stderr
, "\n");
661 void eprint(void) /* try to print context around error */
664 static int been_here
= 0;
665 extern char ebuf
[], *ep
;
667 if (compile_time
== 2 || compile_time
== 0 || been_here
++ > 0)
670 if (p
> ebuf
&& *p
== '\n')
672 for ( ; p
> ebuf
&& *p
!= '\n' && *p
!= '\0'; p
--)
676 fprintf(stderr
, " context is\n\t");
677 for (q
=ep
-1; q
>=p
&& *q
!=' ' && *q
!='\t' && *q
!='\n'; q
--)
682 fprintf(stderr
, " >>> ");
686 fprintf(stderr
, " <<< ");
689 * The following code was used to print the rest of the line of
690 * error context. It naively counts brackets, parens and braces in
691 * order to minimize the parsing effect of dropping the rest of the
692 * line but it does not work in all the cases. It is too much work
693 * to save the current program input point and restore it in all the
694 * cases just for the benefit of error printing so for now this
695 * code is disabled. In particular this code is confused if the
696 * [ { ( ) } ] is inside a quoted string or a pattern.
700 while ((c
= input()) != '\n' && c
!= '\0' && c
!= EOF
) {
713 case '{': bracecnt
++; break;
714 case '}': bracecnt
--; break;
715 case '[': brackcnt
++; break;
716 case ']': brackcnt
--; break;
717 case '(': parencnt
++; break;
718 case ')': parencnt
--; break;
722 double errcheck(double x
, const char *s
)
727 WARNING("%s argument out of domain", s
);
729 } else if (errno
== ERANGE
) {
731 WARNING("%s result out of range", s
);
737 int isclvar(const char *s
) /* is s of form var=something ? */
741 if (!isalpha((uschar
) *s
) && *s
!= '_')
744 if (!(isalnum((uschar
) *s
) || *s
== '_'))
746 return *s
== '=' && s
> os
&& *(s
+1) != '=';
749 /* strtod is supposed to be a proper test of what's a valid number */
750 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
751 /* wrong: violates 4.10.1.4 of ansi C standard */
754 int is_number(const char *s
)
758 (void)strtod(s
, &ep
);
759 if (ep
== s
|| errno
== ERANGE
)
761 if (ep
- s
>= 3 && strncasecmp(ep
- 3, "nan", 3) == 0)
763 while (*ep
== ' ' || *ep
== '\t' || *ep
== '\n')