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
[10] = " ";
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
)) == 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 if (!isclvar(p
= getargv(i
))) { /* find 1st real filename */
93 setsval(lookup("FILENAME", symtab
), getargv(i
));
96 setclvar(p
); /* a commandline assignment before filename */
99 infile
= stdin
; /* no filenames, so use stdin */
102 static int firsttime
= 1;
104 int getrec(char **pbuf
, int *pbufsize
, int isrecord
) /* get next input record */
105 { /* note: cares whether buf == record */
109 int bufsize
= *pbufsize
, savebufsize
= bufsize
;
115 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
116 *RS
, *FS
, *ARGC
, *FILENAME
) );
123 while (argno
< *ARGC
|| infile
== stdin
) {
124 dprintf( ("argno=%d, file=|%s|\n", argno
, file
) );
125 if (infile
== NULL
) { /* have to open a new file */
126 file
= getargv(argno
);
127 if (*file
== '\0') { /* it's been zapped */
131 if (isclvar(file
)) { /* a var=value arg */
137 dprintf( ("opening file %s\n", file
) );
138 if (*file
== '-' && *(file
+1) == '\0')
140 else if ((infile
= fopen(file
, "r")) == NULL
)
141 FATAL("can't open file %s", file
);
142 setfval(fnrloc
, 0.0);
144 c
= readrec(&buf
, &bufsize
, infile
);
145 if (c
!= 0 || buf
[0] != '\0') { /* normal record */
147 if (freeable(fldtab
[0]))
148 xfree(fldtab
[0]->sval
);
149 fldtab
[0]->sval
= buf
; /* buf == record */
150 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
151 if (is_number(fldtab
[0]->sval
)) {
152 fldtab
[0]->fval
= atof(fldtab
[0]->sval
);
153 fldtab
[0]->tval
|= NUM
;
156 setfval(nrloc
, nrloc
->fval
+1);
157 setfval(fnrloc
, fnrloc
->fval
+1);
162 /* EOF arrived on this file; set up next */
170 *pbufsize
= savebufsize
;
171 return 0; /* true end of file */
176 if (infile
!= NULL
&& infile
!= stdin
)
182 int readrec(char **pbuf
, int *pbufsize
, FILE *inf
) /* read one record into buf */
185 char *rr
, *buf
= *pbuf
;
186 int bufsize
= *pbufsize
;
188 if (strlen(*FS
) >= sizeof(inputFS
))
189 FATAL("field separator %.10s... is too long", *FS
);
190 strcpy(inputFS
, *FS
); /* for subsequent field splitting */
191 if ((sep
= **RS
) == 0) {
193 while ((c
=getc(inf
)) == '\n' && c
!= EOF
) /* skip leading \n's */
199 for (; (c
=getc(inf
)) != sep
&& c
!= EOF
; ) {
200 if (rr
-buf
+1 > bufsize
)
201 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
, recsize
, &rr
, "readrec 1"))
202 FATAL("input record `%.30s...' too long", buf
);
205 if (**RS
== sep
|| c
== EOF
)
207 if ((c
= getc(inf
)) == '\n' || c
== EOF
) /* 2 in a row */
209 if (!adjbuf(&buf
, &bufsize
, 2+rr
-buf
, recsize
, &rr
, "readrec 2"))
210 FATAL("input record `%.30s...' too long", buf
);
214 if (!adjbuf(&buf
, &bufsize
, 1+rr
-buf
, recsize
, &rr
, "readrec 3"))
215 FATAL("input record `%.30s...' too long", buf
);
217 dprintf( ("readrec saw <%s>, returns %d\n", buf
, c
== EOF
&& rr
== buf
? 0 : 1) );
220 return c
== EOF
&& rr
== buf
? 0 : 1;
223 char *getargv(int n
) /* get ARGV[n] */
227 extern Array
*ARGVtab
;
229 sprintf(temp
, "%d", n
);
230 x
= setsymtab(temp
, "", 0.0, STR
, ARGVtab
);
232 dprintf( ("getargv(%d) returns |%s|\n", n
, s
) );
236 void setclvar(char *s
) /* set var=value from s */
241 for (p
=s
; *p
!= '='; p
++)
244 p
= qstring(p
, '\0');
245 q
= setsymtab(s
, p
, 0.0, STR
, symtab
);
247 if (is_number(q
->sval
)) {
248 q
->fval
= atof(q
->sval
);
251 dprintf( ("command line set %s to |%s|\n", s
, p
) );
255 void fldbld(void) /* create fields from current record */
257 /* this relies on having fields[] the same length as $0 */
258 /* the fields are all stored in this one array with \0's */
265 if (!isstr(fldtab
[0]))
269 if (n
> fieldssize
) {
271 if ((fields
= (char *) malloc(n
+1)) == NULL
)
272 FATAL("out of space for fields in fldbld %d", n
);
276 i
= 0; /* number of fields accumulated here */
277 if (strlen(inputFS
) > 1) { /* it's a regular expression */
278 i
= refldbld(r
, inputFS
);
279 } else if ((sep
= *inputFS
) == ' ') { /* default whitespace */
281 while (*r
== ' ' || *r
== '\t' || *r
== '\n')
288 if (freeable(fldtab
[i
]))
289 xfree(fldtab
[i
]->sval
);
290 fldtab
[i
]->sval
= fr
;
291 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
294 while (*r
!= ' ' && *r
!= '\t' && *r
!= '\n' && *r
!= '\0');
298 } else if ((sep
= *inputFS
) == 0) { /* new: FS="" => 1 char/field */
299 for (i
= 0; *r
!= 0; r
++) {
304 if (freeable(fldtab
[i
]))
305 xfree(fldtab
[i
]->sval
);
308 fldtab
[i
]->sval
= tostring(buf
);
309 fldtab
[i
]->tval
= FLD
| STR
;
312 } else if (*r
!= 0) { /* if 0, it's a null field */
313 /* subtlecase : if length(FS) == 1 && length(RS > 0)
314 * \n is NOT a field separator (cf awk book 61,84).
315 * this variable is tested in the inner while loop.
317 int rtest
= '\n'; /* normal case */
324 if (freeable(fldtab
[i
]))
325 xfree(fldtab
[i
]->sval
);
326 fldtab
[i
]->sval
= fr
;
327 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
328 while (*r
!= sep
&& *r
!= rtest
&& *r
!= '\0') /* \n is always a separator */
337 FATAL("record `%.30s...' has too many fields; can't happen", r
);
338 cleanfld(i
+1, lastfld
); /* clean out junk from previous record */
341 for (j
= 1; j
<= lastfld
; j
++) {
343 if(is_number(p
->sval
)) {
344 p
->fval
= atof(p
->sval
);
348 setfval(nfloc
, (Awkfloat
) lastfld
);
350 for (j
= 0; j
<= lastfld
; j
++) {
352 printf("field %d (%s): |%s|\n", j
, p
->nval
, p
->sval
);
357 void cleanfld(int n1
, int n2
) /* clean out fields n1 .. n2 inclusive */
358 { /* nvals remain intact */
362 for (i
= n1
; i
<= n2
; i
++) {
367 p
->tval
= FLD
| STR
| DONTFREE
;
371 void newfld(int n
) /* add field n after end of existing lastfld */
375 cleanfld(lastfld
+1, n
);
377 setfval(nfloc
, (Awkfloat
) n
);
380 Cell
*fieldadr(int n
) /* get nth field */
383 FATAL("trying to access out of range field %d", n
);
384 if (n
> nfields
) /* fields after NF are empty */
385 growfldtab(n
); /* but does not increase NF */
389 void growfldtab(int n
) /* make new fields up to at least $n */
391 int nf
= 2 * nfields
;
396 s
= (nf
+1) * (sizeof (struct Cell
*)); /* freebsd: how much do we need? */
397 if (s
/ sizeof(struct Cell
*) - 1 == nf
) /* didn't overflow */
398 fldtab
= (Cell
**) realloc(fldtab
, s
);
399 else /* overflow sizeof int */
400 xfree(fldtab
); /* make it null */
402 FATAL("out of space creating %d fields", nf
);
403 makefields(nfields
+1, nf
);
407 int refldbld(const char *rec
, const char *fs
) /* build fields from reg expr in FS */
409 /* this relies on having fields[] the same length as $0 */
410 /* the fields are all stored in this one array with \0's */
416 if (n
> fieldssize
) {
418 if ((fields
= (char *) malloc(n
+1)) == NULL
)
419 FATAL("out of space for fields in refldbld %d", n
);
426 pfa
= makedfa(fs
, 1);
427 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec
, fs
) );
428 tempstat
= pfa
->initstat
;
432 if (freeable(fldtab
[i
]))
433 xfree(fldtab
[i
]->sval
);
434 fldtab
[i
]->tval
= FLD
| STR
| DONTFREE
;
435 fldtab
[i
]->sval
= fr
;
436 dprintf( ("refldbld: i=%d\n", i
) );
437 if (nematch(pfa
, rec
)) {
438 pfa
->initstat
= 2; /* horrible coupling to b.c */
439 dprintf( ("match %s (%d chars)\n", patbeg
, patlen
) );
440 strncpy(fr
, rec
, patbeg
-rec
);
441 fr
+= patbeg
- rec
+ 1;
443 rec
= patbeg
+ patlen
;
445 dprintf( ("no match %s\n", rec
) );
447 pfa
->initstat
= tempstat
;
454 void recbld(void) /* create $0 from $1..$NF if necessary */
462 for (i
= 1; i
<= *NF
; i
++) {
463 p
= getsval(fldtab
[i
]);
464 if (!adjbuf(&record
, &recsize
, 1+strlen(p
)+r
-record
, recsize
, &r
, "recbld 1"))
465 FATAL("created $0 `%.30s...' too long", record
);
466 while ((*r
= *p
++) != 0)
469 if (!adjbuf(&record
, &recsize
, 2+strlen(*OFS
)+r
-record
, recsize
, &r
, "recbld 2"))
470 FATAL("created $0 `%.30s...' too long", record
);
471 for (p
= *OFS
; (*r
= *p
++) != 0; )
475 if (!adjbuf(&record
, &recsize
, 2+r
-record
, recsize
, &r
, "recbld 3"))
476 FATAL("built giant record `%.30s...'", record
);
478 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, fldtab
[0]) );
480 if (freeable(fldtab
[0]))
481 xfree(fldtab
[0]->sval
);
482 fldtab
[0]->tval
= REC
| STR
| DONTFREE
;
483 fldtab
[0]->sval
= record
;
485 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, fldtab
[0]) );
486 dprintf( ("recbld = |%s|\n", record
) );
492 void yyerror(const char *s
)
497 void SYNTAX(const char *fmt
, ...)
499 extern char *cmdname
, *curfname
;
500 static int been_here
= 0;
505 fprintf(stderr
, "%s: ", cmdname
);
507 vfprintf(stderr
, fmt
, varg
);
509 fprintf(stderr
, " at source line %d", lineno
);
510 if (curfname
!= NULL
)
511 fprintf(stderr
, " in function %s", curfname
);
512 if (compile_time
== 1 && cursource() != NULL
)
513 fprintf(stderr
, " source file %s", cursource());
514 fprintf(stderr
, "\n");
521 FATAL("floating point exception %d", n
);
524 extern int bracecnt
, brackcnt
, parencnt
;
526 void bracecheck(void)
529 static int beenhere
= 0;
533 while ((c
= input()) != EOF
&& c
!= '\0')
535 bcheck2(bracecnt
, '{', '}');
536 bcheck2(brackcnt
, '[', ']');
537 bcheck2(parencnt
, '(', ')');
540 void bcheck2(int n
, int c1
, int c2
)
543 fprintf(stderr
, "\tmissing %c\n", c2
);
545 fprintf(stderr
, "\t%d missing %c's\n", n
, c2
);
547 fprintf(stderr
, "\textra %c\n", c2
);
549 fprintf(stderr
, "\t%d extra %c's\n", -n
, c2
);
552 void FATAL(const char *fmt
, ...)
554 extern char *cmdname
;
558 fprintf(stderr
, "%s: ", cmdname
);
560 vfprintf(stderr
, fmt
, varg
);
563 if (dbg
> 1) /* core dump if serious debugging on */
568 void WARNING(const char *fmt
, ...)
570 extern char *cmdname
;
574 fprintf(stderr
, "%s: ", cmdname
);
576 vfprintf(stderr
, fmt
, varg
);
583 extern Node
*curnode
;
585 fprintf(stderr
, "\n");
586 if (compile_time
!= 2 && NR
&& *NR
> 0) {
587 fprintf(stderr
, " input record number %d", (int) (*FNR
));
588 if (strcmp(*FILENAME
, "-") != 0)
589 fprintf(stderr
, ", file %s", *FILENAME
);
590 fprintf(stderr
, "\n");
592 if (compile_time
!= 2 && curnode
)
593 fprintf(stderr
, " source line number %d", curnode
->lineno
);
594 else if (compile_time
!= 2 && lineno
)
595 fprintf(stderr
, " source line number %d", lineno
);
596 if (compile_time
== 1 && cursource() != NULL
)
597 fprintf(stderr
, " source file %s", cursource());
598 fprintf(stderr
, "\n");
602 void eprint(void) /* try to print context around error */
606 static int been_here
= 0;
607 extern char ebuf
[], *ep
;
609 if (compile_time
== 2 || compile_time
== 0 || been_here
++ > 0)
612 if (p
> ebuf
&& *p
== '\n')
614 for ( ; p
> ebuf
&& *p
!= '\n' && *p
!= '\0'; p
--)
618 fprintf(stderr
, " context is\n\t");
619 for (q
=ep
-1; q
>=p
&& *q
!=' ' && *q
!='\t' && *q
!='\n'; q
--)
624 fprintf(stderr
, " >>> ");
628 fprintf(stderr
, " <<< ");
630 while ((c
= input()) != '\n' && c
!= '\0' && c
!= EOF
) {
641 case '{': bracecnt
++; break;
642 case '}': bracecnt
--; break;
643 case '[': brackcnt
++; break;
644 case ']': brackcnt
--; break;
645 case '(': parencnt
++; break;
646 case ')': parencnt
--; break;
650 double errcheck(double x
, const char *s
)
655 WARNING("%s argument out of domain", s
);
657 } else if (errno
== ERANGE
) {
659 WARNING("%s result out of range", s
);
665 int isclvar(const char *s
) /* is s of form var=something ? */
669 if (!isalpha((uschar
) *s
) && *s
!= '_')
672 if (!(isalnum((uschar
) *s
) || *s
== '_'))
674 return *s
== '=' && s
> os
&& *(s
+1) != '=';
677 /* strtod is supposed to be a proper test of what's a valid number */
678 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
679 /* wrong: violates 4.10.1.4 of ansi C standard */
682 int is_number(const char *s
)
688 if (ep
== s
|| r
== HUGE_VAL
|| errno
== ERANGE
)
690 while (*ep
== ' ' || *ep
== '\t' || *ep
== '\n')