1 /*
2 * Copyright (C) Lucent Technologies 1997
3 * All Rights Reserved
4 *
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
13 * permission.
14 *
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
22 * THIS SOFTWARE.
23 */
24
25 /*
26 * CDDL HEADER START
27 *
28 * The contents of this file are subject to the terms of the
29 * Common Development and Distribution License (the "License").
30 * You may not use this file except in compliance with the License.
31 *
32 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
33 * or http://www.opensolaris.org/os/licensing.
34 * See the License for the specific language governing permissions
35 * and limitations under the License.
36 *
37 * When distributing Covered Code, include this CDDL HEADER in each
38 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
39 * If applicable, add the following below this CDDL HEADER, with the
40 * fields enclosed by brackets "[]" replaced with your own identifying
41 * information: Portions Copyright [yyyy] [name of copyright owner]
42 *
43 * CDDL HEADER END
44 */
45
46 /*
47 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
48 * Use is subject to license terms.
49 */
50
51 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
52 /* All Rights Reserved */
53
54 /* Copyright (c) Lucent Technologies 1997 */
55 /* All Rights Reserved */
56
57 #include <stdio.h>
58 #include <string.h>
59 #include <ctype.h>
60 #include <errno.h>
61 #include <stdlib.h>
62 #include <stdarg.h>
63 #include "awk.h"
64 #include "y.tab.h"
65
66 static FILE *infile = NULL;
67 static char *file = "";
68 char *record;
69 size_t recsize = RECSIZE;
70 static char *fields;
71 static size_t fieldssize = RECSIZE;
72 static char *rtbuf;
73 static size_t rtbufsize = RECSIZE;
74
75 Cell **fldtab; /* pointers to Cells */
76 char inputFS[100] = " ";
77
78 #define MAXFLD 2
79 int nfields = MAXFLD; /* last allocated slot for $i */
80
81 int donefld; /* 1 = implies rec broken into fields */
82 int donerec; /* 1 = record is valid (no flds have changed) */
83
84 static int lastfld = 0; /* last used field */
85 static int argno = 1; /* current input argument number */
86
87 static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
88 static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
89
90 static char *getargv(int);
91 static void cleanfld(int, int);
92 static int refldbld(const char *, const char *);
93 static void bcheck2(int, int, int);
94 static void eprint(void);
95 static void bclass(int);
96
97 void
recinit(unsigned int n)98 recinit(unsigned int n)
99 {
100 if ((record = (char *)malloc(n)) == NULL ||
101 (fields = (char *)malloc(n+2)) == NULL ||
102 (fldtab = (Cell **)malloc((nfields+1) * sizeof (Cell *))) == NULL ||
103 (fldtab[0] = (Cell *)malloc(sizeof (Cell))) == NULL)
104 FATAL("out of space for $0 and fields");
105 *fldtab[0] = dollar0;
106 fldtab[0]->sval = record;
107 fldtab[0]->nval = tostring("0");
108 makefields(1, nfields);
109 }
110
111 void
makefields(int n1,int n2)112 makefields(int n1, int n2) /* create $n1..$n2 inclusive */
113 {
114 char temp[50];
115 int i;
116
117 for (i = n1; i <= n2; i++) {
118 fldtab[i] = (Cell *)malloc(sizeof (Cell));
119 if (fldtab[i] == NULL)
120 FATAL("out of space in makefields %d", i);
121 *fldtab[i] = dollar1;
122 (void) sprintf(temp, "%d", i);
123 fldtab[i]->nval = tostring(temp);
124 }
125 }
126
127 static void
initgetrec(void)128 initgetrec(void)
129 {
130 int i;
131 char *p;
132
133 for (i = 1; i < *ARGC; i++) {
134 p = getargv(i); /* find 1st real filename */
135 if (p == NULL || *p == '\0') { /* deleted or zapped */
136 argno++;
137 continue;
138 }
139 if (!isclvar(p)) {
140 (void) setsval(lookup("FILENAME", symtab), p);
141 return;
142 }
143 setclvar(p); /* a commandline assignment before filename */
144 argno++;
145 }
146 infile = stdin; /* no filenames, so use stdin */
147 }
148
149 /*
150 * POSIX specifies that fields are supposed to be evaluated as if they were
151 * split using the value of FS at the time that the record's value ($0) was
152 * read.
153 *
154 * Since field-splitting is done lazily, we save the current value of FS
155 * whenever a new record is read in (implicitly or via getline), or when
156 * a new value is assigned to $0.
157 */
158 void
savefs(void)159 savefs(void)
160 {
161 if (strlen(getsval(fsloc)) >= sizeof (inputFS))
162 FATAL("field separator %.10s... is too long", *FS);
163 (void) strcpy(inputFS, *FS);
164 }
165
166 static int firsttime = 1;
167
168 /*
169 * get next input record
170 * note: cares whether buf == record
171 */
172 int
getrec(char ** pbuf,size_t * pbufsize,int isrecord)173 getrec(char **pbuf, size_t *pbufsize, int isrecord)
174 {
175 int c;
176 char *buf = *pbuf;
177 uschar saveb0;
178 size_t bufsize = *pbufsize, savebufsize = bufsize;
179
180 if (firsttime) {
181 firsttime = 0;
182 initgetrec();
183 }
184 dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n",
185 *RS, *FS, *ARGC, *FILENAME));
186 if (isrecord) {
187 donefld = 0;
188 donerec = 1;
189 savefs();
190 }
191 saveb0 = buf[0];
192 buf[0] = '\0';
193 while (argno < *ARGC || infile == stdin) {
194 dprintf(("argno=%d, file=|%s|\n", argno, file));
195 if (infile == NULL) { /* have to open a new file */
196 file = getargv(argno);
197 if (file == NULL || *file == '\0') {
198 /* deleted or zapped */
199 argno++;
200 continue;
201 }
202 if (isclvar(file)) {
203 /* a var=value arg */
204 setclvar(file);
205 argno++;
206 continue;
207 }
208 *FILENAME = file;
209 dprintf(("opening file %s\n", file));
210 if (*file == '-' && *(file+1) == '\0')
211 infile = stdin;
212 else if ((infile = fopen(file, "rF")) == NULL)
213 FATAL("can't open file %s", file);
214 (void) setfval(fnrloc, 0.0);
215 }
216 c = readrec(&buf, &bufsize, infile);
217
218 if (c != 0 || buf[0] != '\0') { /* normal record */
219 if (isrecord) {
220 if (freeable(recloc))
221 xfree(recloc->sval);
222 recloc->sval = buf; /* buf == record */
223 recloc->tval = REC | STR | DONTFREE;
224 if (is_number(recloc->sval)) {
225 recloc->fval =
226 atof(recloc->sval);
227 recloc->tval |= NUM;
228 }
229 }
230 (void) setfval(nrloc, nrloc->fval+1);
231 (void) setfval(fnrloc, fnrloc->fval+1);
232 *pbuf = buf;
233 *pbufsize = bufsize;
234 return (1);
235 }
236 /* EOF arrived on this file; set up next */
237 if (infile != stdin)
238 (void) fclose(infile);
239 infile = NULL;
240 argno++;
241 }
242 buf[0] = saveb0;
243 *pbuf = buf;
244 *pbufsize = savebufsize;
245 return (0); /* true end of file */
246 }
247
248 void
nextfile(void)249 nextfile(void)
250 {
251 if (infile != NULL && infile != stdin)
252 (void) fclose(infile);
253 infile = NULL;
254 argno++;
255 }
256
257 /*
258 * read one record into buf
259 */
260 int
readrec(char ** pbuf,size_t * pbufsize,FILE * inf)261 readrec(char **pbuf, size_t *pbufsize, FILE *inf)
262 {
263 int sep, c;
264 char *rr, *rt, *buf = *pbuf;
265 size_t bufsize = *pbufsize;
266 char *rs = getsval(rsloc);
267
268 if (rtbuf == NULL && (rtbuf = malloc(rtbufsize)) == NULL)
269 FATAL("out of memory in readrec");
270
271 rr = buf;
272 rt = rtbuf;
273
274 if ((sep = *rs) == '\0') {
275 sep = '\n';
276 /* skip leading \n's */
277 while ((c = getc(inf)) == '\n' && c != EOF)
278 ;
279 if (c != EOF)
280 (void) ungetc(c, inf);
281 }
282 while ((c = getc(inf)) != EOF) {
283 if (c != sep) {
284 if (rr-buf+1 > bufsize) {
285 (void) adjbuf(&buf, &bufsize,
286 1+rr-buf, recsize, &rr, "readrec1");
287 }
288 *rr++ = c;
289 continue;
290 }
291
292 /*
293 * Ensure enough space for either a single separator
294 * character, or at least two '\n' chars (when RS is
295 * the empty string).
296 */
297 (void) adjbuf(&rtbuf, &rtbufsize,
298 2+rt-rtbuf, recsize, &rt, "readrec2");
299
300 if (*rs == sep) {
301 *rt++ = sep;
302 break;
303 }
304
305 if ((c = getc(inf)) == '\n') { /* 2 in a row */
306 *rt++ = '\n';
307 *rt++ = '\n';
308 while ((c = getc(inf)) == '\n' && c != EOF) {
309 /* Read any further \n's and add them to RT. */
310 (void) adjbuf(&rtbuf, &rtbufsize,
311 1+rt-rtbuf, recsize, &rt, "readrec3");
312 *rt++ = '\n';
313 }
314 if (c != EOF)
315 (void) ungetc(c, inf);
316 break;
317 }
318
319 if (c == EOF) {
320 *rt++ = '\n';
321 break;
322 }
323
324 (void) adjbuf(&buf, &bufsize,
325 2+rr-buf, recsize, &rr, "readrec4");
326 *rr++ = '\n';
327 *rr++ = c;
328 }
329 (void) adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec5");
330 (void) adjbuf(&rtbuf, &rtbufsize, 1+rt-rtbuf, recsize, &rt, "readrec6");
331 *rr = '\0';
332 *rt = '\0';
333 dprintf(("readrec saw <%s>, returns %d\n",
334 buf, c == EOF && rr == buf ? 0 : 1));
335 *pbuf = buf;
336 *pbufsize = bufsize;
337 if (c == EOF && rr == buf) {
338 return (0);
339 } else {
340 (void) setsval(rtloc, rtbuf);
341 return (1);
342 }
343 }
344
345 /* get ARGV[n] */
346 static char *
getargv(int n)347 getargv(int n)
348 {
349 Cell *x;
350 char *s, temp[50];
351 extern Array *ARGVtab;
352
353 (void) sprintf(temp, "%d", n);
354 if (lookup(temp, ARGVtab) == NULL)
355 return (NULL);
356 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
357 s = getsval(x);
358 dprintf(("getargv(%d) returns |%s|\n", n, s));
359 return (s);
360 }
361
362 void
setclvar(char * s)363 setclvar(char *s) /* set var=value from s */
364 {
365 char *p;
366 Cell *q;
367
368 for (p = s; *p != '='; p++)
369 ;
370 *p++ = 0;
371 p = qstring(p, '\0');
372 q = setsymtab(s, p, 0.0, STR, symtab);
373 (void) setsval(q, p);
374 if (is_number(q->sval)) {
375 q->fval = atof(q->sval);
376 q->tval |= NUM;
377 }
378 dprintf(("command line set %s to |%s|\n", s, p));
379 free(p);
380 }
381
382 void
fldbld(void)383 fldbld(void) /* create fields from current record */
384 {
385 /* this relies on having fields[] the same length as $0 */
386 /* the fields are all stored in this one array with \0's */
387 /* possibly with a final trailing \0 not associated with any field */
388 char *r, *fr, sep;
389 Cell *p;
390 int i, j, n;
391
392 if (donefld)
393 return;
394 if (!isstr(fldtab[0]))
395 (void) getsval(fldtab[0]);
396 r = fldtab[0]->sval;
397 n = strlen(r);
398 if (n > fieldssize) {
399 xfree(fields);
400 /* possibly 2 final \0s */
401 if ((fields = (char *)malloc(n + 2)) == NULL)
402 FATAL("out of space for fields in fldbld %d", n);
403 fieldssize = n;
404 }
405 fr = fields;
406
407 i = 0; /* number of fields accumulated here */
408 if (strlen(inputFS) > 1) { /* it's a regular expression */
409 i = refldbld(r, inputFS);
410 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
411 for (i = 0; ; ) {
412 while (*r == ' ' || *r == '\t' || *r == '\n')
413 r++;
414 if (*r == '\0')
415 break;
416 i++;
417 if (i > nfields)
418 growfldtab(i);
419 if (freeable(fldtab[i]))
420 xfree(fldtab[i]->sval);
421 fldtab[i]->sval = fr;
422 fldtab[i]->tval = FLD | STR | DONTFREE;
423 do
424 *fr++ = *r++;
425 while (*r != ' ' && *r != '\t' && *r != '\n' &&
426 *r != '\0')
427 ;
428 *fr++ = '\0';
429 }
430 *fr = '\0';
431 } else if ((sep = *inputFS) == '\0') {
432 /* new: FS="" => 1 char/field */
433 for (i = 0; *r != '\0'; r++) {
434 char buf[2];
435 i++;
436 if (i > nfields)
437 growfldtab(i);
438 if (freeable(fldtab[i]))
439 xfree(fldtab[i]->sval);
440 buf[0] = *r;
441 buf[1] = '\0';
442 fldtab[i]->sval = tostring(buf);
443 fldtab[i]->tval = FLD | STR;
444 }
445 *fr = '\0';
446 } else if (*r != '\0') { /* if 0, it's a null field */
447 /*
448 * subtlecase : if length(FS) == 1 && length(RS > 0)
449 * \n is NOT a field separator (cf awk book 61,84).
450 * this variable is tested in the inner while loop.
451 */
452 int rtest = '\n'; /* normal case */
453 if (strlen(*RS) > 0)
454 rtest = '\0';
455 for (;;) {
456 i++;
457 if (i > nfields)
458 growfldtab(i);
459 if (freeable(fldtab[i]))
460 xfree(fldtab[i]->sval);
461 fldtab[i]->sval = fr;
462 fldtab[i]->tval = FLD | STR | DONTFREE;
463 /* \n is always a separator */
464 while (*r != sep && *r != rtest && *r != '\0')
465 *fr++ = *r++;
466 *fr++ = '\0';
467 if (*r++ == '\0')
468 break;
469 }
470 *fr = '\0';
471 }
472 if (i > nfields)
473 FATAL("record `%.30s...' has too many fields; can't happen", r);
474 /* clean out junk from previous record */
475 cleanfld(i+1, lastfld);
476 lastfld = i;
477 donefld = 1;
478 for (j = 1; j <= lastfld; j++) {
479 p = fldtab[j];
480 if (is_number(p->sval)) {
481 p->fval = atof(p->sval);
482 p->tval |= NUM;
483 }
484 }
485 (void) setfval(nfloc, (Awkfloat)lastfld);
486 donerec = 1; /* restore */
487 if (dbg) {
488 for (j = 0; j <= lastfld; j++) {
489 p = fldtab[j];
490 (void) printf("field %d (%s): |%s|\n",
491 j, p->nval, p->sval);
492 }
493 }
494 }
495
496 /* clean out fields n1 .. n2 inclusive; nvals remain intact */
497 static void
cleanfld(int n1,int n2)498 cleanfld(int n1, int n2)
499 {
500 Cell *p;
501 int i;
502
503 for (i = n1; i <= n2; i++) {
504 p = fldtab[i];
505 if (freeable(p))
506 xfree(p->sval);
507 p->sval = "";
508 p->tval = FLD | STR | DONTFREE;
509 }
510 }
511
512 void
newfld(int n)513 newfld(int n) /* add field n after end of existing lastfld */
514 {
515 if (n > nfields)
516 growfldtab(n);
517 cleanfld(lastfld+1, n);
518 lastfld = n;
519 (void) setfval(nfloc, (Awkfloat)n);
520 }
521
522 void
setlastfld(int n)523 setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
524 {
525 if (n < 0)
526 FATAL("cannot set NF to a negative value");
527 if (n > nfields)
528 growfldtab(n);
529
530 if (lastfld < n)
531 cleanfld(lastfld+1, n);
532 else
533 cleanfld(n+1, lastfld);
534
535 lastfld = n;
536 }
537
538 Cell *
fieldadr(int n)539 fieldadr(int n) /* get nth field */
540 {
541 if (n < 0)
542 FATAL("trying to access out of range field %d", n);
543 if (n > nfields) /* fields after NF are empty */
544 growfldtab(n); /* but does not increase NF */
545 return (fldtab[n]);
546 }
547
548 void
growfldtab(int n)549 growfldtab(int n) /* make new fields up to at least $n */
550 {
551 int nf = 2 * nfields;
552 size_t s;
553
554 if (n > nf)
555 nf = n;
556 s = (nf+1) * (sizeof (Cell *)); /* freebsd: how much do we need? */
557 if (s / sizeof (Cell *) - 1 == nf) /* didn't overflow */
558 fldtab = (Cell **)realloc(fldtab, s);
559 else /* overflow sizeof int */
560 xfree(fldtab); /* make it null */
561 if (fldtab == NULL)
562 FATAL("out of space creating %d fields", nf);
563 makefields(nfields+1, nf);
564 nfields = nf;
565 }
566
567 /* build fields from reg expr in FS */
568 static int
refldbld(const char * rec,const char * fs)569 refldbld(const char *rec, const char *fs)
570 {
571 /* this relies on having fields[] the same length as $0 */
572 /* the fields are all stored in this one array with \0's */
573 char *fr;
574 int i, tempstat, n;
575 fa *pfa;
576
577 n = strlen(rec);
578 if (n > fieldssize) {
579 xfree(fields);
580 if ((fields = (char *)malloc(n+1)) == NULL)
581 FATAL("out of space for fields in refldbld %d", n);
582 fieldssize = n;
583 }
584 fr = fields;
585 *fr = '\0';
586 if (*rec == '\0')
587 return (0);
588 pfa = makedfa(fs, 1);
589 dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs));
590 tempstat = pfa->initstat;
591 for (i = 1; ; i++) {
592 if (i > nfields)
593 growfldtab(i);
594 if (freeable(fldtab[i]))
595 xfree(fldtab[i]->sval);
596 fldtab[i]->tval = FLD | STR | DONTFREE;
597 fldtab[i]->sval = fr;
598 dprintf(("refldbld: i=%d\n", i));
599 if (nematch(pfa, rec)) {
600 pfa->initstat = 2; /* horrible coupling to b.c */
601 dprintf(("match %s (%d chars)\n", patbeg, patlen));
602 (void) strncpy(fr, rec, patbeg-rec);
603 fr += patbeg - rec + 1;
604 *(fr-1) = '\0';
605 rec = patbeg + patlen;
606 } else {
607 dprintf(("no match %s\n", rec));
608 (void) strcpy(fr, rec);
609 pfa->initstat = tempstat;
610 break;
611 }
612 }
613 return (i);
614 }
615
616 void
recbld(void)617 recbld(void) /* create $0 from $1..$NF if necessary */
618 {
619 int i;
620 char *p;
621 size_t cnt, len, olen;
622 char *sep = getsval(ofsloc);
623
624 if (donerec == 1)
625 return;
626 cnt = 0;
627 olen = strlen(sep);
628 for (i = 1; i <= *NF; i++) {
629 p = getsval(fldtab[i]);
630 len = strlen(p);
631 expand_buf(&record, &recsize, cnt + len + olen);
632 (void) memcpy(&record[cnt], p, len);
633 cnt += len;
634 if (i < *NF) {
635 (void) memcpy(&record[cnt], sep, olen);
636 cnt += olen;
637 }
638 }
639 record[cnt] = '\0';
640 dprintf(("in recbld inputFS=%s, recloc=%p\n", inputFS, (void *)recloc));
641 if (freeable(recloc))
642 xfree(recloc->sval);
643 recloc->tval = REC | STR | DONTFREE;
644 recloc->sval = record;
645 dprintf(("in recbld inputFS=%s, recloc=%p\n", inputFS, (void *)recloc));
646 dprintf(("recbld = |%s|\n", record));
647 donerec = 1;
648 }
649
650 int errorflag = 0;
651
652 int
yyerror(const char * s)653 yyerror(const char *s)
654 {
655 SYNTAX("%s", s);
656 return (0);
657 }
658
659 void
SYNTAX(const char * fmt,...)660 SYNTAX(const char *fmt, ...)
661 {
662 extern char *cmdname, *curfname;
663 static int been_here = 0;
664 va_list varg;
665
666 if (been_here++ > 2)
667 return;
668 (void) fprintf(stderr, "%s: ", cmdname);
669 va_start(varg, fmt);
670 (void) vfprintf(stderr, fmt, varg);
671 va_end(varg);
672 (void) fprintf(stderr, " at source line %lld", lineno);
673 if (curfname != NULL)
674 (void) fprintf(stderr, " in function %s", curfname);
675 if (compile_time == 1 && cursource() != NULL)
676 (void) fprintf(stderr, " source file %s", cursource());
677 (void) fprintf(stderr, "\n");
678 errorflag = 2;
679 eprint();
680 }
681
682 void
fpecatch(int n)683 fpecatch(int n)
684 {
685 FATAL("floating point exception %d", n);
686 }
687
688 extern int bracecnt, brackcnt, parencnt;
689
690 void
bracecheck(void)691 bracecheck(void)
692 {
693 int c;
694 static int beenhere = 0;
695
696 if (beenhere++)
697 return;
698 while ((c = input()) != EOF && c != '\0')
699 bclass(c);
700 bcheck2(bracecnt, '{', '}');
701 bcheck2(brackcnt, '[', ']');
702 bcheck2(parencnt, '(', ')');
703 }
704
705 /*ARGSUSED*/
706 static void
bcheck2(int n,int c1,int c2)707 bcheck2(int n, int c1, int c2)
708 {
709 if (n == 1)
710 (void) fprintf(stderr, gettext("\tmissing %c\n"), c2);
711 else if (n > 1)
712 (void) fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2);
713 else if (n == -1)
714 (void) fprintf(stderr, gettext("\textra %c\n"), c2);
715 else if (n < -1)
716 (void) fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2);
717 }
718
719 void
FATAL(const char * fmt,...)720 FATAL(const char *fmt, ...)
721 {
722 extern char *cmdname;
723 va_list varg;
724
725 (void) fflush(stdout);
726 (void) fprintf(stderr, "%s: ", cmdname);
727 va_start(varg, fmt);
728 (void) vfprintf(stderr, fmt, varg);
729 va_end(varg);
730 error();
731 if (dbg > 1) /* core dump if serious debugging on */
732 abort();
733 exit(2);
734 }
735
736 void
WARNING(const char * fmt,...)737 WARNING(const char *fmt, ...)
738 {
739 extern char *cmdname;
740 va_list varg;
741
742 (void) fflush(stdout);
743 (void) fprintf(stderr, "%s: ", cmdname);
744 va_start(varg, fmt);
745 (void) vfprintf(stderr, fmt, varg);
746 va_end(varg);
747 error();
748 }
749
750 void
error(void)751 error(void)
752 {
753 extern Node *curnode;
754
755 (void) fprintf(stderr, "\n");
756 if (compile_time != 2 && NR && *NR > 0) {
757 (void) fprintf(stderr,
758 gettext(" input record number %g"), *FNR);
759 if (strcmp(*FILENAME, "-") != 0)
760 (void) fprintf(stderr, gettext(", file %s"), *FILENAME);
761 (void) fprintf(stderr, "\n");
762 }
763 if (compile_time != 2 && curnode)
764 (void) fprintf(stderr, gettext(" source line number %lld"),
765 curnode->lineno);
766 else if (compile_time != 2 && lineno) {
767 (void) fprintf(stderr,
768 gettext(" source line number %lld"), lineno);
769 }
770 if (compile_time == 1 && cursource() != NULL)
771 (void) fprintf(stderr, gettext(" source file %s"), cursource());
772 (void) fprintf(stderr, "\n");
773 eprint();
774 }
775
776 static void
eprint(void)777 eprint(void) /* try to print context around error */
778 {
779 char *p, *q;
780 int c;
781 static int been_here = 0;
782 extern char ebuf[], *ep;
783
784 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
785 return;
786 if (ebuf == ep)
787 return;
788 p = ep - 1;
789 if (p > ebuf && *p == '\n')
790 p--;
791 for (; p > ebuf && *p != '\n' && *p != '\0'; p--)
792 ;
793 while (*p == '\n')
794 p++;
795 (void) fprintf(stderr, gettext(" context is\n\t"));
796 for (q = ep-1; q >= p && *q != ' ' && *q != '\t' && *q != '\n'; q--)
797 ;
798 for (; p < q; p++)
799 if (*p)
800 (void) putc(*p, stderr);
801 (void) fprintf(stderr, " >>> ");
802 for (; p < ep; p++)
803 if (*p)
804 (void) putc(*p, stderr);
805 (void) fprintf(stderr, " <<< ");
806 if (*ep)
807 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
808 (void) putc(c, stderr);
809 bclass(c);
810 }
811 (void) putc('\n', stderr);
812 ep = ebuf;
813 }
814
815 static void
bclass(int c)816 bclass(int c)
817 {
818 switch (c) {
819 case '{': bracecnt++; break;
820 case '}': bracecnt--; break;
821 case '[': brackcnt++; break;
822 case ']': brackcnt--; break;
823 case '(': parencnt++; break;
824 case ')': parencnt--; break;
825 }
826 }
827
828 double
errcheck(double x,const char * s)829 errcheck(double x, const char *s)
830 {
831 if (errno == EDOM) {
832 errno = 0;
833 WARNING("%s argument out of domain", s);
834 x = 1;
835 } else if (errno == ERANGE) {
836 errno = 0;
837 WARNING("%s result out of range", s);
838 x = 1;
839 }
840 return (x);
841 }
842
843 int
isclvar(const char * s)844 isclvar(const char *s) /* is s of form var=something ? */
845 {
846 if (s != NULL) {
847
848 /* Must begin with an underscore or alphabetic character */
849 if (isalpha(*s) || (*s == '_')) {
850
851 for (s++; *s; s++) {
852 /*
853 * followed by a sequence of underscores,
854 * digits, and alphabetics
855 */
856 if (!(isalnum(*s) || *s == '_')) {
857 break;
858 }
859 }
860 return (*s == '=' && *(s + 1) != '=');
861 }
862 }
863
864 return (0);
865 }
866
867 #include <math.h>
868 int
is_number(const char * s)869 is_number(const char *s)
870 {
871 double r;
872 char *ep;
873 errno = 0;
874 r = strtod(s, &ep);
875 if (ep == s || r == HUGE_VAL || errno == ERANGE)
876 return (0);
877 while (*ep == ' ' || *ep == '\t' || *ep == '\n')
878 ep++;
879 if (*ep == '\0')
880 return (1);
881 else
882 return (0);
883 }
884
885 void
r_expand_buf(char ** optr,size_t * sizep,size_t req)886 r_expand_buf(char **optr, size_t *sizep, size_t req)
887 {
888 char *nptr;
889 size_t amt, size = *sizep;
890
891 if (size != 0 && req < (size - 1))
892 return;
893 amt = req + 1 - size;
894 amt = (amt / LINE_INCR + 1) * LINE_INCR;
895
896 if ((nptr = realloc(*optr, size + amt)) == NULL)
897 FATAL("out of space in expand_buf");
898 /* initial buffer should have NULL terminated */
899 if (size == 0)
900 *nptr = '\0';
901 *sizep += amt;
902 *optr = nptr;
903 }
904