1 /* $OpenBSD: lib.c,v 1.20 2011/09/28 19:27:18 millert Exp $ */
2 /****************************************************************
3 Copyright (C) Lucent Technologies 1997
4 All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and
7 its documentation for any purpose and without fee is hereby
8 granted, provided that the above copyright notice appear in all
9 copies and that both that the copyright notice and this
10 permission notice and warranty disclaimer appear in supporting
11 documentation, and that the name Lucent Technologies or any of
12 its entities not be used in advertising or publicity pertaining
13 to distribution of the software without specific, written prior
14 permission.
15
16 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23 THIS SOFTWARE.
24 ****************************************************************/
25
26 #define DEBUG
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <stdarg.h>
34 #include "awk.h"
35 #include "awkgram.h"
36
37 __RCSID("$MirOS: src/usr.bin/awk/lib.c,v 1.3 2014/03/13 00:37:36 tg Exp $");
38
39 extern Node *curnode;
40 extern char *cmdname, *curfname;
41
42 FILE *infile = NULL;
43 static char file_i[] = "";
44 char *file = file_i;
45 char *record;
46 int recsize = RECSIZE;
47 char *fields;
48 int fieldssize = RECSIZE;
49
50 Cell **fldtab; /* pointers to Cells */
51 char inputFS[100] = " ";
52
53 #define MAXFLD 2
54 int nfields = MAXFLD; /* last allocated slot for $i */
55
56 int donefld; /* 1 = implies rec broken into fields */
57 int donerec; /* 1 = record is valid (no flds have changed) */
58
59 int lastfld = 0; /* last used field */
60 int argno = 1; /* current input argument number */
61 extern Awkfloat *ARGC;
62
63 static char dollar0_sval[] = "";
64 static char dollar1_sval[] = "";
65 static Cell dollar0 = { OCELL, CFLD, NULL, dollar0_sval, 0.0, REC|STR|DONTFREE, NULL };
66 static Cell dollar1 = { OCELL, CFLD, NULL, dollar1_sval, 0.0, FLD|STR|DONTFREE, NULL };
67
recinit(unsigned int n)68 void recinit(unsigned int n)
69 {
70 if ( (record = (char *) malloc(n)) == NULL
71 || (fields = (char *) malloc(n+1)) == NULL
72 || (fldtab = (Cell **) calloc(nfields+1, sizeof(Cell *))) == NULL
73 || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
74 FATAL("out of space for $0 and fields");
75 *fldtab[0] = dollar0;
76 fldtab[0]->sval = record;
77 fldtab[0]->nval = tostring("0");
78 makefields(1, nfields);
79 }
80
makefields(int n1,int n2)81 void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
82 {
83 char temp[50];
84 int i;
85
86 for (i = n1; i <= n2; i++) {
87 fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
88 if (fldtab[i] == NULL)
89 FATAL("out of space in makefields %d", i);
90 *fldtab[i] = dollar1;
91 snprintf(temp, sizeof temp, "%d", i);
92 fldtab[i]->nval = tostring(temp);
93 }
94 }
95
initgetrec(void)96 void initgetrec(void)
97 {
98 int i;
99 char *p;
100
101 for (i = 1; i < *ARGC; i++) {
102 p = getargv(i); /* find 1st real filename */
103 if (p == NULL || *p == '\0') { /* deleted or zapped */
104 argno++;
105 continue;
106 }
107 if (!isclvar(p)) {
108 setsval(lookup("FILENAME", symtab), p);
109 return;
110 }
111 setclvar(p); /* a commandline assignment before filename */
112 argno++;
113 }
114 infile = stdin; /* no filenames, so use stdin */
115 }
116
117 static int firsttime = 1;
118
getrec(char ** pbuf,int * pbufsize,int isrecord)119 int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
120 { /* note: cares whether buf == record */
121 int c;
122 char *buf = *pbuf;
123 uschar saveb0;
124 int bufsize = *pbufsize, savebufsize = bufsize;
125
126 if (firsttime) {
127 firsttime = 0;
128 initgetrec();
129 }
130 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
131 *RS, *FS, *ARGC, *FILENAME) );
132 if (isrecord) {
133 donefld = 0;
134 donerec = 1;
135 }
136 saveb0 = buf[0];
137 buf[0] = 0;
138 while (argno < *ARGC || infile == stdin) {
139 dprintf( ("argno=%d, file=|%s|\n", argno, file) );
140 if (infile == NULL) { /* have to open a new file */
141 file = getargv(argno);
142 if (file == NULL || *file == '\0') { /* deleted or zapped */
143 argno++;
144 continue;
145 }
146 if (isclvar(file)) { /* a var=value arg */
147 setclvar(file);
148 argno++;
149 continue;
150 }
151 *FILENAME = file;
152 dprintf( ("opening file %s\n", file) );
153 if (*file == '-' && *(file+1) == '\0')
154 infile = stdin;
155 else if ((infile = fopen(file, "r")) == NULL)
156 FATAL("can't open file %s", file);
157 setfval(fnrloc, 0.0);
158 }
159 c = readrec(&buf, &bufsize, infile);
160 if (c != 0 || buf[0] != '\0') { /* normal record */
161 if (isrecord) {
162 if (freeable(fldtab[0]))
163 xfree(fldtab[0]->sval);
164 fldtab[0]->sval = buf; /* buf == record */
165 fldtab[0]->tval = REC | STR | DONTFREE;
166 if (is_number(fldtab[0]->sval)) {
167 fldtab[0]->fval = atof(fldtab[0]->sval);
168 fldtab[0]->tval |= NUM;
169 }
170 }
171 setfval(nrloc, nrloc->fval+1);
172 setfval(fnrloc, fnrloc->fval+1);
173 *pbuf = buf;
174 *pbufsize = bufsize;
175 return 1;
176 }
177 /* EOF arrived on this file; set up next */
178 if (infile != stdin)
179 fclose(infile);
180 infile = NULL;
181 argno++;
182 }
183 buf[0] = saveb0;
184 *pbuf = buf;
185 *pbufsize = savebufsize;
186 return 0; /* true end of file */
187 }
188
nextfile(void)189 void nextfile(void)
190 {
191 if (infile != NULL && infile != stdin)
192 fclose(infile);
193 infile = NULL;
194 argno++;
195 }
196
readrec(char ** pbuf,int * pbufsize,FILE * inf)197 int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
198 {
199 int sep, c;
200 char *rr, *buf = *pbuf;
201 int bufsize = *pbufsize;
202
203 if (strlen(*FS) >= sizeof(inputFS))
204 FATAL("field separator %.10s... is too long", *FS);
205 /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
206 strlcpy(inputFS, *FS, sizeof inputFS); /* for subsequent field splitting */
207 if ((sep = **RS) == 0) {
208 sep = '\n';
209 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
210 ;
211 if (c != EOF)
212 ungetc(c, inf);
213 }
214 for (rr = buf; ; ) {
215 for (; (c=getc(inf)) != sep && c != EOF; ) {
216 if (rr-buf+1 > bufsize)
217 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
218 FATAL("input record `%.30s...' too long", buf);
219 *rr++ = c;
220 }
221 if (**RS == sep || c == EOF)
222 break;
223 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
224 break;
225 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
226 FATAL("input record `%.30s...' too long", buf);
227 *rr++ = '\n';
228 *rr++ = c;
229 }
230 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
231 FATAL("input record `%.30s...' too long", buf);
232 *rr = 0;
233 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
234 *pbuf = buf;
235 *pbufsize = bufsize;
236 return c == EOF && rr == buf ? 0 : 1;
237 }
238
getargv(int n)239 char *getargv(int n) /* get ARGV[n] */
240 {
241 Cell *x;
242 char *s, temp[50];
243 extern Array *ARGVtab;
244
245 snprintf(temp, sizeof temp, "%d", n);
246 if (lookup(temp, ARGVtab) == NULL)
247 return NULL;
248 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
249 s = getsval(x);
250 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
251 return s;
252 }
253
setclvar(char * s)254 void setclvar(char *s) /* set var=value from s */
255 {
256 char *p;
257 Cell *q;
258
259 for (p=s; *p != '='; p++)
260 ;
261 *p++ = 0;
262 p = qstring(p, '\0');
263 q = setsymtab(s, p, 0.0, STR, symtab);
264 setsval(q, p);
265 if (is_number(q->sval)) {
266 q->fval = atof(q->sval);
267 q->tval |= NUM;
268 }
269 dprintf( ("command line set %s to |%s|\n", s, p) );
270 }
271
272
fldbld(void)273 void fldbld(void) /* create fields from current record */
274 {
275 /* this relies on having fields[] the same length as $0 */
276 /* the fields are all stored in this one array with \0's */
277 /* possibly with a final trailing \0 not associated with any field */
278 char *r, *fr, sep;
279 Cell *p;
280 int i, j, n;
281
282 if (donefld)
283 return;
284 if (!isstr(fldtab[0]))
285 getsval(fldtab[0]);
286 r = fldtab[0]->sval;
287 n = strlen(r);
288 if (n > fieldssize) {
289 xfree(fields);
290 if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
291 FATAL("out of space for fields in fldbld %d", n);
292 fieldssize = n;
293 }
294 fr = fields;
295 i = 0; /* number of fields accumulated here */
296 strlcpy(inputFS, *FS, sizeof(inputFS));
297 if (strlen(inputFS) > 1) { /* it's a regular expression */
298 i = refldbld(r, inputFS);
299 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
300 for (i = 0; ; ) {
301 while (*r == ' ' || *r == '\t' || *r == '\n')
302 r++;
303 if (*r == 0)
304 break;
305 i++;
306 if (i > nfields)
307 growfldtab(i);
308 if (freeable(fldtab[i]))
309 xfree(fldtab[i]->sval);
310 fldtab[i]->sval = fr;
311 fldtab[i]->tval = FLD | STR | DONTFREE;
312 do
313 *fr++ = *r++;
314 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
315 *fr++ = 0;
316 }
317 *fr = 0;
318 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
319 for (i = 0; *r != 0; r++) {
320 char buf[2];
321 i++;
322 if (i > nfields)
323 growfldtab(i);
324 if (freeable(fldtab[i]))
325 xfree(fldtab[i]->sval);
326 buf[0] = *r;
327 buf[1] = 0;
328 fldtab[i]->sval = tostring(buf);
329 fldtab[i]->tval = FLD | STR;
330 }
331 *fr = 0;
332 } else if (*r != 0) { /* if 0, it's a null field */
333 /* subtlecase : if length(FS) == 1 && length(RS > 0)
334 * \n is NOT a field separator (cf awk book 61,84).
335 * this variable is tested in the inner while loop.
336 */
337 int rtest = '\n'; /* normal case */
338 if (strlen(*RS) > 0)
339 rtest = '\0';
340 for (;;) {
341 i++;
342 if (i > nfields)
343 growfldtab(i);
344 if (freeable(fldtab[i]))
345 xfree(fldtab[i]->sval);
346 fldtab[i]->sval = fr;
347 fldtab[i]->tval = FLD | STR | DONTFREE;
348 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
349 *fr++ = *r++;
350 *fr++ = 0;
351 if (*r++ == 0)
352 break;
353 }
354 *fr = 0;
355 }
356 if (i > nfields)
357 FATAL("record `%.30s...' has too many fields; can't happen", r);
358 cleanfld(i+1, lastfld); /* clean out junk from previous record */
359 lastfld = i;
360 donefld = 1;
361 for (j = 1; j <= lastfld; j++) {
362 p = fldtab[j];
363 if(is_number(p->sval)) {
364 p->fval = atof(p->sval);
365 p->tval |= NUM;
366 }
367 }
368 setfval(nfloc, (Awkfloat) lastfld);
369 if (dbg) {
370 for (j = 0; j <= lastfld; j++) {
371 p = fldtab[j];
372 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
373 }
374 }
375 }
376
cleanfld(int n1,int n2)377 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
378 { /* nvals remain intact */
379 Cell *p;
380 int i;
381
382 for (i = n1; i <= n2; i++) {
383 p = fldtab[i];
384 if (freeable(p))
385 xfree(p->sval);
386 p->sval = strdup("");
387 p->tval = FLD | STR | DONTFREE;
388 }
389 }
390
newfld(int n)391 void newfld(int n) /* add field n after end of existing lastfld */
392 {
393 if (n > nfields)
394 growfldtab(n);
395 cleanfld(lastfld+1, n);
396 lastfld = n;
397 setfval(nfloc, (Awkfloat) n);
398 }
399
fieldadr(int n)400 Cell *fieldadr(int n) /* get nth field */
401 {
402 if (n < 0)
403 FATAL("trying to access out of range field %d", n);
404 if (n > nfields) /* fields after NF are empty */
405 growfldtab(n); /* but does not increase NF */
406 return(fldtab[n]);
407 }
408
growfldtab(int n)409 void growfldtab(int n) /* make new fields up to at least $n */
410 {
411 int nf = 2 * nfields;
412 size_t s;
413
414 if (n > nf)
415 nf = n;
416 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
417 if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
418 fldtab = (Cell **) realloc(fldtab, s);
419 else /* overflow sizeof int */
420 xfree(fldtab); /* make it null */
421 if (fldtab == NULL)
422 FATAL("out of space creating %d fields", nf);
423 makefields(nfields+1, nf);
424 nfields = nf;
425 }
426
refldbld(const char * rec,const char * fs)427 int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
428 {
429 /* this relies on having fields[] the same length as $0 */
430 /* the fields are all stored in this one array with \0's */
431 char *fr;
432 int i, tempstat, n;
433 fa *pfa;
434
435 n = strlen(rec);
436 if (n > fieldssize) {
437 xfree(fields);
438 if ((fields = (char *) malloc(n+1)) == NULL)
439 FATAL("out of space for fields in refldbld %d", n);
440 fieldssize = n;
441 }
442 fr = fields;
443 *fr = '\0';
444 if (*rec == '\0')
445 return 0;
446 pfa = makedfa(fs, 1);
447 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
448 tempstat = pfa->initstat;
449 for (i = 1; ; i++) {
450 if (i > nfields)
451 growfldtab(i);
452 if (freeable(fldtab[i]))
453 xfree(fldtab[i]->sval);
454 fldtab[i]->tval = FLD | STR | DONTFREE;
455 fldtab[i]->sval = fr;
456 dprintf( ("refldbld: i=%d\n", i) );
457 if (nematch(pfa, rec)) {
458 pfa->initstat = 2; /* horrible coupling to b.c */
459 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
460 strncpy(fr, rec, patbeg-rec);
461 fr += patbeg - rec + 1;
462 *(fr-1) = '\0';
463 rec = patbeg + patlen;
464 } else {
465 dprintf( ("no match %s\n", rec) );
466 strlcpy(fr, rec, fields + fieldssize - fr);
467 pfa->initstat = tempstat;
468 break;
469 }
470 }
471 return i;
472 }
473
recbld(void)474 void recbld(void) /* create $0 from $1..$NF if necessary */
475 {
476 int i;
477 char *r, *p;
478
479 if (donerec == 1)
480 return;
481 r = record;
482 for (i = 1; i <= *NF; i++) {
483 p = getsval(fldtab[i]);
484 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
485 FATAL("created $0 `%.30s...' too long", record);
486 while ((*r = *p++) != 0)
487 r++;
488 if (i < *NF) {
489 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
490 FATAL("created $0 `%.30s...' too long", record);
491 for (p = *OFS; (*r = *p++) != 0; )
492 r++;
493 }
494 }
495 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
496 FATAL("built giant record `%.30s...'", record);
497 *r = '\0';
498 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
499
500 if (freeable(fldtab[0]))
501 xfree(fldtab[0]->sval);
502 fldtab[0]->tval = REC | STR | DONTFREE;
503 fldtab[0]->sval = record;
504
505 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
506 dprintf( ("recbld = |%s|\n", record) );
507 donerec = 1;
508 }
509
510 int errorflag = 0;
511
yyerror(const char * s)512 void yyerror(const char *s)
513 {
514 SYNTAX("%s", s);
515 }
516
SYNTAX(const char * fmt,...)517 void SYNTAX(const char *fmt, ...)
518 {
519 static int been_here = 0;
520 va_list varg;
521
522 if (been_here++ > 2)
523 return;
524 fprintf(stderr, "%s: ", cmdname);
525 va_start(varg, fmt);
526 vfprintf(stderr, fmt, varg);
527 va_end(varg);
528 fprintf(stderr, " at source line %d", lineno);
529 if (curfname != NULL)
530 fprintf(stderr, " in function %s", curfname);
531 if (compile_time == 1 && cursource() != NULL)
532 fprintf(stderr, " source file %s", cursource());
533 fprintf(stderr, "\n");
534 errorflag = 2;
535 eprint();
536 }
537
fpecatch(int sig __unused)538 void fpecatch(int sig __unused)
539 {
540 char buf[1024];
541
542 snprintf(buf, sizeof buf, "floating point exception\n");
543 write(STDERR_FILENO, buf, strlen(buf));
544
545 if (compile_time != 2 && NR && *NR > 0) {
546 snprintf(buf, sizeof buf, " input record number %d", (int) (*FNR));
547 write(STDERR_FILENO, buf, strlen(buf));
548
549 if (strcmp(*FILENAME, "-") != 0) {
550 snprintf(buf, sizeof buf, ", file %s", *FILENAME);
551 write(STDERR_FILENO, buf, strlen(buf));
552 }
553 write(STDERR_FILENO, "\n", 1);
554 }
555 if (compile_time != 2 && curnode) {
556 snprintf(buf, sizeof buf, " source line number %d", curnode->lineno);
557 write(STDERR_FILENO, buf, strlen(buf));
558 } else if (compile_time != 2 && lineno) {
559 snprintf(buf, sizeof buf, " source line number %d", lineno);
560 write(STDERR_FILENO, buf, strlen(buf));
561 }
562 if (compile_time == 1 && cursource() != NULL) {
563 snprintf(buf, sizeof buf, " source file %s", cursource());
564 write(STDERR_FILENO, buf, strlen(buf));
565 }
566 write(STDERR_FILENO, "\n", 1);
567 if (dbg > 1) /* core dump if serious debugging on */
568 abort();
569 _exit(1);
570 }
571
572 extern int bracecnt, brackcnt, parencnt;
573
bracecheck(void)574 void bracecheck(void)
575 {
576 int c;
577 static int beenhere = 0;
578
579 if (beenhere++)
580 return;
581 while ((c = input()) != EOF && c != '\0')
582 bclass(c);
583 bcheck2(bracecnt, /*'{',*/ '}');
584 bcheck2(brackcnt, /*'[',*/ ']');
585 bcheck2(parencnt, /*'(',*/ ')');
586 }
587
bcheck2(int n,int c2)588 void bcheck2(int n, /*int c1,*/ int c2)
589 {
590 if (n == 1)
591 fprintf(stderr, "\tmissing %c\n", c2);
592 else if (n > 1)
593 fprintf(stderr, "\t%d missing %c's\n", n, c2);
594 else if (n == -1)
595 fprintf(stderr, "\textra %c\n", c2);
596 else if (n < -1)
597 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
598 }
599
FATAL(const char * fmt,...)600 void FATAL(const char *fmt, ...)
601 {
602 va_list varg;
603
604 fflush(stdout);
605 fprintf(stderr, "%s: ", cmdname);
606 va_start(varg, fmt);
607 vfprintf(stderr, fmt, varg);
608 va_end(varg);
609 error();
610 if (dbg > 1) /* core dump if serious debugging on */
611 abort();
612 exit(2);
613 }
614
WARNING(const char * fmt,...)615 void WARNING(const char *fmt, ...)
616 {
617 va_list varg;
618
619 fflush(stdout);
620 fprintf(stderr, "%s: ", cmdname);
621 va_start(varg, fmt);
622 vfprintf(stderr, fmt, varg);
623 va_end(varg);
624 error();
625 }
626
error(void)627 void error(void)
628 {
629 fprintf(stderr, "\n");
630 if (compile_time != 2 && NR && *NR > 0) {
631 fprintf(stderr, " input record number %d", (int) (*FNR));
632 if (strcmp(*FILENAME, "-") != 0)
633 fprintf(stderr, ", file %s", *FILENAME);
634 fprintf(stderr, "\n");
635 }
636 if (compile_time != 2 && curnode)
637 fprintf(stderr, " source line number %d", curnode->lineno);
638 else if (compile_time != 2 && lineno)
639 fprintf(stderr, " source line number %d", lineno);
640 if (compile_time == 1 && cursource() != NULL)
641 fprintf(stderr, " source file %s", cursource());
642 fprintf(stderr, "\n");
643 eprint();
644 }
645
eprint(void)646 void eprint(void) /* try to print context around error */
647 {
648 char *p, *q;
649 int c;
650 static int been_here = 0;
651 extern char ebuf[], *ep;
652
653 if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
654 return;
655 p = ep - 1;
656 if (p > ebuf && *p == '\n')
657 p--;
658 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
659 ;
660 while (*p == '\n')
661 p++;
662 fprintf(stderr, " context is\n\t");
663 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
664 ;
665 for ( ; p < q; p++)
666 if (*p)
667 putc(*p, stderr);
668 fprintf(stderr, " >>> ");
669 for ( ; p < ep; p++)
670 if (*p)
671 putc(*p, stderr);
672 fprintf(stderr, " <<< ");
673 if (*ep)
674 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
675 putc(c, stderr);
676 bclass(c);
677 }
678 putc('\n', stderr);
679 ep = ebuf;
680 }
681
bclass(int c)682 void bclass(int c)
683 {
684 switch (c) {
685 case '{': bracecnt++; break;
686 case '}': bracecnt--; break;
687 case '[': brackcnt++; break;
688 case ']': brackcnt--; break;
689 case '(': parencnt++; break;
690 case ')': parencnt--; break;
691 }
692 }
693
errcheck(double x,const char * s)694 double errcheck(double x, const char *s)
695 {
696
697 if (errno == EDOM) {
698 errno = 0;
699 WARNING("%s argument out of domain", s);
700 x = 1;
701 } else if (errno == ERANGE) {
702 errno = 0;
703 WARNING("%s result out of range", s);
704 x = 1;
705 }
706 return x;
707 }
708
isclvar(const char * s)709 int isclvar(const char *s) /* is s of form var=something ? */
710 {
711 const char *os = s;
712
713 if (!isalpha((uschar) *s) && *s != '_')
714 return 0;
715 for ( ; *s; s++)
716 if (!(isalnum((uschar) *s) || *s == '_'))
717 break;
718 return *s == '=' && s > os && *(s+1) != '=';
719 }
720
721 /* strtod is supposed to be a proper test of what's a valid number */
722 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
723 /* wrong: violates 4.10.1.4 of ansi C standard */
724
725 #include <math.h>
is_number(const char * s)726 int is_number(const char *s)
727 {
728 double r;
729 char *ep;
730 errno = 0;
731 r = strtod(s, &ep);
732 if (ep == s || r == HUGE_VAL || errno == ERANGE)
733 return 0;
734 while (*ep == ' ' || *ep == '\t' || *ep == '\n')
735 ep++;
736 if (*ep == '\0')
737 return 1;
738 else
739 return 0;
740 }
741