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 p
= getargv(i
); /* find 1st real filename */
93 if (p
== NULL
|| *p
== '\0') { /* deleted or zapped */
98 setsval(lookup("FILENAME", symtab
), p
);
101 setclvar(p
); /* a commandline assignment before filename */
104 infile
= stdin
; /* no filenames, so use stdin */
107 static int firsttime
= 1;
109 int getrec(char **pbuf
, int *pbufsize
, int isrecord
) /* get next input record */
110 { /* note: cares whether buf == record */
114 int bufsize
= *pbufsize
, savebufsize
= bufsize
;
120 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
121 *RS
, *FS
, *ARGC
, *FILENAME
) );
128 while (argno
< *ARGC
|| infile
== stdin
) {
129 dprintf( ("argno=%d, file=|%s|\n", argno
, file
) );
130 if (infile
== NULL
) { /* have to open a new file */
131 file
= getargv(argno
);
132 if (file
== NULL
|| *file
== '\0') { /* deleted or zapped */
136 if (isclvar(file
)) { /* a var=value arg */
142 dprintf( ("opening file %s\n", file
) );
143 if (*file
== '-' && *(file
+1) == '\0')
145 else if ((infile
= fopen(file
, "r")) == NULL
)
146 FATAL("can't open file %s", file
);
147 setfval(fnrloc
, 0.0);
149 c
= readrec(&buf
, &bufsize
, infile
);
150 if (c
!= 0 || buf
[0] != '\0') { /* normal record */
152 if (freeable(fldtab
[0]))
153 xfree(fldtab
[0]->sval
);
154 fldtab
[0]->sval
= buf
; /* buf == record */
155 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
156 if (is_number(fldtab
[0]->sval
)) {
157 fldtab
[0]->fval
= atof(fldtab
[0]->sval
);
158 fldtab
[0]->tval
|= NUM
;
161 setfval(nrloc
, nrloc
->fval
+1);
162 setfval(fnrloc
, fnrloc
->fval
+1);
167 /* EOF arrived on this file; set up next */
175 *pbufsize
= savebufsize
;
176 return 0; /* true end of file */
181 if (infile
!= NULL
&& infile
!= stdin
)
187 int readrec(char **pbuf
, int *pbufsize
, FILE *inf
) /* read one record into buf */
190 char *rr
, *buf
= *pbuf
;
191 int bufsize
= *pbufsize
;
193 if (strlen(*FS
) >= sizeof(inputFS
))
194 FATAL("field separator %.10s... is too long", *FS
);
195 /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
196 strcpy(inputFS
, *FS
); /* for subsequent field splitting */
197 if ((sep
= **RS
) == 0) {
199 while ((c
=getc(inf
)) == '\n' && c
!= EOF
) /* skip leading \n's */
205 for (; (c
=getc(inf
)) != sep
&& c
!= EOF
; ) {
206 if (rr
-buf
+1 > bufsize
)
207 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
, recsize
, &rr
, "readrec 1"))
208 FATAL("input record `%.30s...' too long", buf
);
211 if (**RS
== sep
|| c
== EOF
)
213 if ((c
= getc(inf
)) == '\n' || c
== EOF
) /* 2 in a row */
215 if (!adjbuf(&buf
, &bufsize
, 2+rr
-buf
, recsize
, &rr
, "readrec 2"))
216 FATAL("input record `%.30s...' too long", buf
);
220 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
, recsize
, &rr
, "readrec 3"))
221 FATAL("input record `%.30s...' too long", buf
);
223 dprintf( ("readrec saw <%s>, returns %d\n", buf
, c
== EOF
&& rr
== buf
? 0 : 1) );
226 return c
== EOF
&& rr
== buf
? 0 : 1;
229 char *getargv(int n
) /* get ARGV[n] */
233 extern Array
*ARGVtab
;
235 sprintf(temp
, "%d", n
);
236 if (lookup(temp
, ARGVtab
) == NULL
)
238 x
= setsymtab(temp
, "", 0.0, STR
, ARGVtab
);
240 dprintf( ("getargv(%d) returns |%s|\n", n
, s
) );
244 void setclvar(char *s
) /* set var=value from s */
249 for (p
=s
; *p
!= '='; p
++)
252 p
= qstring(p
, '\0');
253 q
= setsymtab(s
, p
, 0.0, STR
, symtab
);
255 if (is_number(q
->sval
)) {
256 q
->fval
= atof(q
->sval
);
259 dprintf( ("command line set %s to |%s|\n", s
, p
) );
263 void fldbld(void) /* create fields from current record */
265 /* this relies on having fields[] the same length as $0 */
266 /* the fields are all stored in this one array with \0's */
267 /* possibly with a final trailing \0 not associated with any field */
274 if (!isstr(fldtab
[0]))
278 if (n
> fieldssize
) {
280 if ((fields
= (char *) malloc(n
+2)) == NULL
) /* possibly 2 final \0s */
281 FATAL("out of space for fields in fldbld %d", n
);
285 i
= 0; /* number of fields accumulated here */
286 strcpy(inputFS
, *FS
);
287 if (strlen(inputFS
) > 1) { /* it's a regular expression */
288 i
= refldbld(r
, inputFS
);
289 } else if ((sep
= *inputFS
) == ' ') { /* default whitespace */
291 while (*r
== ' ' || *r
== '\t' || *r
== '\n')
298 if (freeable(fldtab
[i
]))
299 xfree(fldtab
[i
]->sval
);
300 fldtab
[i
]->sval
= fr
;
301 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
304 while (*r
!= ' ' && *r
!= '\t' && *r
!= '\n' && *r
!= '\0');
308 } else if ((sep
= *inputFS
) == 0) { /* new: FS="" => 1 char/field */
309 for (i
= 0; *r
!= 0; r
++) {
314 if (freeable(fldtab
[i
]))
315 xfree(fldtab
[i
]->sval
);
318 fldtab
[i
]->sval
= tostring(buf
);
319 fldtab
[i
]->tval
= FLD
| STR
;
322 } else if (*r
!= 0) { /* if 0, it's a null field */
323 /* subtlecase : if length(FS) == 1 && length(RS > 0)
324 * \n is NOT a field separator (cf awk book 61,84).
325 * this variable is tested in the inner while loop.
327 int rtest
= '\n'; /* normal case */
334 if (freeable(fldtab
[i
]))
335 xfree(fldtab
[i
]->sval
);
336 fldtab
[i
]->sval
= fr
;
337 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
338 while (*r
!= sep
&& *r
!= rtest
&& *r
!= '\0') /* \n is always a separator */
347 FATAL("record `%.30s...' has too many fields; can't happen", r
);
348 cleanfld(i
+1, lastfld
); /* clean out junk from previous record */
351 for (j
= 1; j
<= lastfld
; j
++) {
353 if(is_number(p
->sval
)) {
354 p
->fval
= atof(p
->sval
);
358 setfval(nfloc
, (Awkfloat
) lastfld
);
360 for (j
= 0; j
<= lastfld
; j
++) {
362 printf("field %d (%s): |%s|\n", j
, p
->nval
, p
->sval
);
367 void cleanfld(int n1
, int n2
) /* clean out fields n1 .. n2 inclusive */
368 { /* nvals remain intact */
372 for (i
= n1
; i
<= n2
; i
++) {
377 p
->tval
= FLD
| STR
| DONTFREE
;
381 void newfld(int n
) /* add field n after end of existing lastfld */
385 cleanfld(lastfld
+1, n
);
387 setfval(nfloc
, (Awkfloat
) n
);
390 Cell
*fieldadr(int n
) /* get nth field */
393 FATAL("trying to access out of range field %d", n
);
394 if (n
> nfields
) /* fields after NF are empty */
395 growfldtab(n
); /* but does not increase NF */
399 void growfldtab(int n
) /* make new fields up to at least $n */
401 int nf
= 2 * nfields
;
406 s
= (nf
+1) * (sizeof (struct Cell
*)); /* freebsd: how much do we need? */
407 if (s
/ sizeof(struct Cell
*) - 1 == nf
) /* didn't overflow */
408 fldtab
= (Cell
**) realloc(fldtab
, s
);
409 else /* overflow sizeof int */
410 xfree(fldtab
); /* make it null */
412 FATAL("out of space creating %d fields", nf
);
413 makefields(nfields
+1, nf
);
417 int refldbld(const char *rec
, const char *fs
) /* build fields from reg expr in FS */
419 /* this relies on having fields[] the same length as $0 */
420 /* the fields are all stored in this one array with \0's */
426 if (n
> fieldssize
) {
428 if ((fields
= (char *) malloc(n
+1)) == NULL
)
429 FATAL("out of space for fields in refldbld %d", n
);
436 pfa
= makedfa(fs
, 1);
437 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec
, fs
) );
438 tempstat
= pfa
->initstat
;
442 if (freeable(fldtab
[i
]))
443 xfree(fldtab
[i
]->sval
);
444 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
445 fldtab
[i
]->sval
= fr
;
446 dprintf( ("refldbld: i=%d\n", i
) );
447 if (nematch(pfa
, rec
)) {
448 pfa
->initstat
= 2; /* horrible coupling to b.c */
449 dprintf( ("match %s (%d chars)\n", patbeg
, patlen
) );
450 strncpy(fr
, rec
, patbeg
-rec
);
451 fr
+= patbeg
- rec
+ 1;
453 rec
= patbeg
+ patlen
;
455 dprintf( ("no match %s\n", rec
) );
457 pfa
->initstat
= tempstat
;
464 void recbld(void) /* create $0 from $1..$NF if necessary */
472 for (i
= 1; i
<= *NF
; i
++) {
473 p
= getsval(fldtab
[i
]);
474 if (!adjbuf(&record
, &recsize
, 1+strlen(p
)+r
-record
, recsize
, &r
, "recbld 1"))
475 FATAL("created $0 `%.30s...' too long", record
);
476 while ((*r
= *p
++) != 0)
479 if (!adjbuf(&record
, &recsize
, 2+strlen(*OFS
)+r
-record
, recsize
, &r
, "recbld 2"))
480 FATAL("created $0 `%.30s...' too long", record
);
481 for (p
= *OFS
; (*r
= *p
++) != 0; )
485 if (!adjbuf(&record
, &recsize
, 2+r
-record
, recsize
, &r
, "recbld 3"))
486 FATAL("built giant record `%.30s...'", record
);
488 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, (void*)fldtab
[0]) );
490 if (freeable(fldtab
[0]))
491 xfree(fldtab
[0]->sval
);
492 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
493 fldtab
[0]->sval
= record
;
495 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, (void*)fldtab
[0]) );
496 dprintf( ("recbld = |%s|\n", record
) );
502 void yyerror(const char *s
)
507 void SYNTAX(const char *fmt
, ...)
509 extern char *cmdname
, *curfname
;
510 static int been_here
= 0;
515 fprintf(stderr
, "%s: ", cmdname
);
517 vfprintf(stderr
, fmt
, varg
);
519 fprintf(stderr
, " at source line %d", lineno
);
520 if (curfname
!= NULL
)
521 fprintf(stderr
, " in function %s", curfname
);
522 if (compile_time
== 1 && cursource() != NULL
)
523 fprintf(stderr
, " source file %s", cursource());
524 fprintf(stderr
, "\n");
531 FATAL("floating point exception %d", n
);
534 extern int bracecnt
, brackcnt
, parencnt
;
536 void bracecheck(void)
539 static int beenhere
= 0;
543 while ((c
= input()) != EOF
&& c
!= '\0')
545 bcheck2(bracecnt
, '{', '}');
546 bcheck2(brackcnt
, '[', ']');
547 bcheck2(parencnt
, '(', ')');
550 void bcheck2(int n
, int c1
, int c2
)
553 fprintf(stderr
, "\tmissing %c\n", c2
);
555 fprintf(stderr
, "\t%d missing %c's\n", n
, c2
);
557 fprintf(stderr
, "\textra %c\n", c2
);
559 fprintf(stderr
, "\t%d extra %c's\n", -n
, c2
);
562 void FATAL(const char *fmt
, ...)
564 extern char *cmdname
;
568 fprintf(stderr
, "%s: ", cmdname
);
570 vfprintf(stderr
, fmt
, varg
);
573 if (dbg
> 1) /* core dump if serious debugging on */
578 void WARNING(const char *fmt
, ...)
580 extern char *cmdname
;
584 fprintf(stderr
, "%s: ", cmdname
);
586 vfprintf(stderr
, fmt
, varg
);
593 extern Node
*curnode
;
595 fprintf(stderr
, "\n");
596 if (compile_time
!= 2 && NR
&& *NR
> 0) {
597 fprintf(stderr
, " input record number %d", (int) (*FNR
));
598 if (strcmp(*FILENAME
, "-") != 0)
599 fprintf(stderr
, ", file %s", *FILENAME
);
600 fprintf(stderr
, "\n");
602 if (compile_time
!= 2 && curnode
)
603 fprintf(stderr
, " source line number %d", curnode
->lineno
);
604 else if (compile_time
!= 2 && lineno
)
605 fprintf(stderr
, " source line number %d", lineno
);
606 if (compile_time
== 1 && cursource() != NULL
)
607 fprintf(stderr
, " source file %s", cursource());
608 fprintf(stderr
, "\n");
612 void eprint(void) /* try to print context around error */
616 static int been_here
= 0;
617 extern char ebuf
[], *ep
;
619 if (compile_time
== 2 || compile_time
== 0 || been_here
++ > 0)
622 if (p
> ebuf
&& *p
== '\n')
624 for ( ; p
> ebuf
&& *p
!= '\n' && *p
!= '\0'; p
--)
628 fprintf(stderr
, " context is\n\t");
629 for (q
=ep
-1; q
>=p
&& *q
!=' ' && *q
!='\t' && *q
!='\n'; q
--)
634 fprintf(stderr
, " >>> ");
638 fprintf(stderr
, " <<< ");
640 while ((c
= input()) != '\n' && c
!= '\0' && c
!= EOF
) {
651 case '{': bracecnt
++; break;
652 case '}': bracecnt
--; break;
653 case '[': brackcnt
++; break;
654 case ']': brackcnt
--; break;
655 case '(': parencnt
++; break;
656 case ')': parencnt
--; break;
660 double errcheck(double x
, const char *s
)
665 WARNING("%s argument out of domain", s
);
667 } else if (errno
== ERANGE
) {
669 WARNING("%s result out of range", s
);
675 int isclvar(const char *s
) /* is s of form var=something ? */
679 if (!isalpha((uschar
) *s
) && *s
!= '_')
682 if (!(isalnum((uschar
) *s
) || *s
== '_'))
684 return *s
== '=' && s
> os
&& *(s
+1) != '=';
687 /* strtod is supposed to be a proper test of what's a valid number */
688 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
689 /* wrong: violates 4.10.1.4 of ansi C standard */
692 int is_number(const char *s
)
698 if (ep
== s
|| r
== HUGE_VAL
|| errno
== ERANGE
)
700 while (*ep
== ' ' || *ep
== '\t' || *ep
== '\n')