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 void
yyerror(const char * s)653 yyerror(const char *s)
654 {
655 SYNTAX("%s", s);
656 }
657
658 void
SYNTAX(const char * fmt,...)659 SYNTAX(const char *fmt, ...)
660 {
661 extern char *cmdname, *curfname;
662 static int been_here = 0;
663 va_list varg;
664
665 if (been_here++ > 2)
666 return;
667 (void) fprintf(stderr, "%s: ", cmdname);
668 va_start(varg, fmt);
669 (void) vfprintf(stderr, fmt, varg);
670 va_end(varg);
671 (void) fprintf(stderr, " at source line %lld", lineno);
672 if (curfname != NULL)
673 (void) fprintf(stderr, " in function %s", curfname);
674 if (compile_time == 1 && cursource() != NULL)
675 (void) fprintf(stderr, " source file %s", cursource());
676 (void) fprintf(stderr, "\n");
677 errorflag = 2;
678 eprint();
679 }
680
681 void
fpecatch(int n)682 fpecatch(int n)
683 {
684 FATAL("floating point exception %d", n);
685 }
686
687 extern int bracecnt, brackcnt, parencnt;
688
689 void
bracecheck(void)690 bracecheck(void)
691 {
692 int c;
693 static int beenhere = 0;
694
695 if (beenhere++)
696 return;
697 while ((c = input()) != EOF && c != '\0')
698 bclass(c);
699 bcheck2(bracecnt, '{', '}');
700 bcheck2(brackcnt, '[', ']');
701 bcheck2(parencnt, '(', ')');
702 }
703
704 /*ARGSUSED*/
705 static void
bcheck2(int n,int c1,int c2)706 bcheck2(int n, int c1, int c2)
707 {
708 if (n == 1)
709 (void) fprintf(stderr, gettext("\tmissing %c\n"), c2);
710 else if (n > 1)
711 (void) fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2);
712 else if (n == -1)
713 (void) fprintf(stderr, gettext("\textra %c\n"), c2);
714 else if (n < -1)
715 (void) fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2);
716 }
717
718 void
FATAL(const char * fmt,...)719 FATAL(const char *fmt, ...)
720 {
721 extern char *cmdname;
722 va_list varg;
723
724 (void) fflush(stdout);
725 (void) fprintf(stderr, "%s: ", cmdname);
726 va_start(varg, fmt);
727 (void) vfprintf(stderr, fmt, varg);
728 va_end(varg);
729 error();
730 if (dbg > 1) /* core dump if serious debugging on */
731 abort();
732 exit(2);
733 }
734
735 void
WARNING(const char * fmt,...)736 WARNING(const char *fmt, ...)
737 {
738 extern char *cmdname;
739 va_list varg;
740
741 (void) fflush(stdout);
742 (void) fprintf(stderr, "%s: ", cmdname);
743 va_start(varg, fmt);
744 (void) vfprintf(stderr, fmt, varg);
745 va_end(varg);
746 error();
747 }
748
749 void
error(void)750 error(void)
751 {
752 extern Node *curnode;
753
754 (void) fprintf(stderr, "\n");
755 if (compile_time != 2 && NR && *NR > 0) {
756 (void) fprintf(stderr,
757 gettext(" input record number %g"), *FNR);
758 if (strcmp(*FILENAME, "-") != 0)
759 (void) fprintf(stderr, gettext(", file %s"), *FILENAME);
760 (void) fprintf(stderr, "\n");
761 }
762 if (compile_time != 2 && curnode)
763 (void) fprintf(stderr, gettext(" source line number %lld"),
764 curnode->lineno);
765 else if (compile_time != 2 && lineno) {
766 (void) fprintf(stderr,
767 gettext(" source line number %lld"), lineno);
768 }
769 if (compile_time == 1 && cursource() != NULL)
770 (void) fprintf(stderr, gettext(" source file %s"), cursource());
771 (void) fprintf(stderr, "\n");
772 eprint();
773 }
774
775 static void
eprint(void)776 eprint(void) /* try to print context around error */
777 {
778 char *p, *q;
779 int c;
780 static int been_here = 0;
781 extern char ebuf[], *ep;
782
783 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
784 return;
785 if (ebuf == ep)
786 return;
787 p = ep - 1;
788 if (p > ebuf && *p == '\n')
789 p--;
790 for (; p > ebuf && *p != '\n' && *p != '\0'; p--)
791 ;
792 while (*p == '\n')
793 p++;
794 (void) fprintf(stderr, gettext(" context is\n\t"));
795 for (q = ep-1; q >= p && *q != ' ' && *q != '\t' && *q != '\n'; q--)
796 ;
797 for (; p < q; p++)
798 if (*p)
799 (void) putc(*p, stderr);
800 (void) fprintf(stderr, " >>> ");
801 for (; p < ep; p++)
802 if (*p)
803 (void) putc(*p, stderr);
804 (void) fprintf(stderr, " <<< ");
805 if (*ep)
806 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
807 (void) putc(c, stderr);
808 bclass(c);
809 }
810 (void) putc('\n', stderr);
811 ep = ebuf;
812 }
813
814 static void
bclass(int c)815 bclass(int c)
816 {
817 switch (c) {
818 case '{': bracecnt++; break;
819 case '}': bracecnt--; break;
820 case '[': brackcnt++; break;
821 case ']': brackcnt--; break;
822 case '(': parencnt++; break;
823 case ')': parencnt--; break;
824 }
825 }
826
827 double
errcheck(double x,const char * s)828 errcheck(double x, const char *s)
829 {
830 if (errno == EDOM) {
831 errno = 0;
832 WARNING("%s argument out of domain", s);
833 x = 1;
834 } else if (errno == ERANGE) {
835 errno = 0;
836 WARNING("%s result out of range", s);
837 x = 1;
838 }
839 return (x);
840 }
841
842 int
isclvar(const char * s)843 isclvar(const char *s) /* is s of form var=something ? */
844 {
845 if (s != NULL) {
846
847 /* Must begin with an underscore or alphabetic character */
848 if (isalpha(*s) || (*s == '_')) {
849
850 for (s++; *s; s++) {
851 /*
852 * followed by a sequence of underscores,
853 * digits, and alphabetics
854 */
855 if (!(isalnum(*s) || *s == '_')) {
856 break;
857 }
858 }
859 return (*s == '=' && *(s + 1) != '=');
860 }
861 }
862
863 return (0);
864 }
865
866 #include <math.h>
867 int
is_number(const char * s)868 is_number(const char *s)
869 {
870 double r;
871 char *ep;
872 errno = 0;
873 r = strtod(s, &ep);
874 if (ep == s || r == HUGE_VAL || errno == ERANGE)
875 return (0);
876 while (*ep == ' ' || *ep == '\t' || *ep == '\n')
877 ep++;
878 if (*ep == '\0')
879 return (1);
880 else
881 return (0);
882 }
883
884 void
r_expand_buf(char ** optr,size_t * sizep,size_t req)885 r_expand_buf(char **optr, size_t *sizep, size_t req)
886 {
887 char *nptr;
888 size_t amt, size = *sizep;
889
890 if (size != 0 && req < (size - 1))
891 return;
892 amt = req + 1 - size;
893 amt = (amt / LINE_INCR + 1) * LINE_INCR;
894
895 if ((nptr = realloc(*optr, size + amt)) == NULL)
896 FATAL("out of space in expand_buf");
897 /* initial buffer should have NULL terminated */
898 if (size == 0)
899 *nptr = '\0';
900 *sizep += amt;
901 *optr = nptr;
902 }
903