lib.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
lib.c (16713B) | |
--- | |
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 #define DEBUG | |
26 #include <stdio.h> | |
27 #include <string.h> | |
28 #include <ctype.h> | |
29 #include <errno.h> | |
30 #include <stdlib.h> | |
31 #include <stdarg.h> | |
32 #include "awk.h" | |
33 #include "y.tab.h" | |
34 | |
35 FILE *infile = NULL; | |
36 char *file = ""; | |
37 char *record; | |
38 int recsize = RECSIZE; | |
39 char *fields; | |
40 int fieldssize = RECSIZE; | |
41 | |
42 Cell **fldtab; /* pointers to Cells */ | |
43 char inputFS[100] = " "; | |
44 | |
45 #define MAXFLD 200 | |
46 int nfields = MAXFLD; /* last allocated slot for $i… | |
47 | |
48 int donefld; /* 1 = implies rec broken into fields */ | |
49 int donerec; /* 1 = record is valid (no flds have changed)… | |
50 | |
51 int lastfld = 0; /* last used field */ | |
52 int argno = 1; /* current input argument number */ | |
53 extern Awkfloat *ARGC; | |
54 | |
55 static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE }; | |
56 static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; | |
57 | |
58 void recinit(unsigned int n) | |
59 { | |
60 record = (char *) malloc(n); | |
61 fields = (char *) malloc(n); | |
62 fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *)); | |
63 if (record == NULL || fields == NULL || fldtab == NULL) | |
64 FATAL("out of space for $0 and fields"); | |
65 fldtab[0] = (Cell *) malloc(sizeof (Cell)); | |
66 *fldtab[0] = dollar0; | |
67 fldtab[0]->sval = record; | |
68 fldtab[0]->nval = tostring("0"); | |
69 makefields(1, nfields); | |
70 } | |
71 | |
72 void makefields(int n1, int n2) /* create $n1..$n2 inclus… | |
73 { | |
74 char temp[50]; | |
75 int i; | |
76 | |
77 for (i = n1; i <= n2; i++) { | |
78 fldtab[i] = (Cell *) malloc(sizeof (struct Cell)); | |
79 if (fldtab[i] == NULL) | |
80 FATAL("out of space in makefields %d", i); | |
81 *fldtab[i] = dollar1; | |
82 sprintf(temp, "%d", i); | |
83 fldtab[i]->nval = tostring(temp); | |
84 } | |
85 } | |
86 | |
87 void initgetrec(void) | |
88 { | |
89 int i; | |
90 char *p; | |
91 | |
92 for (i = 1; i < *ARGC; i++) { | |
93 if (!isclvar(p = getargv(i))) { /* find 1st real … | |
94 setsval(lookup("FILENAME", symtab), getargv(i)); | |
95 return; | |
96 } | |
97 setclvar(p); /* a commandline assignment before f… | |
98 argno++; | |
99 } | |
100 infile = stdin; /* no filenames, so use stdin */ | |
101 } | |
102 | |
103 int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next … | |
104 { /* note: cares whether buf == record */ | |
105 int c; | |
106 static int firsttime = 1; | |
107 char *buf = *pbuf; | |
108 int bufsize = *pbufsize; | |
109 | |
110 if (firsttime) { | |
111 firsttime = 0; | |
112 initgetrec(); | |
113 } | |
114 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", | |
115 *RS, *FS, *ARGC, *FILENAME) ); | |
116 if (isrecord) { | |
117 donefld = 0; | |
118 donerec = 1; | |
119 } | |
120 buf[0] = 0; | |
121 while (argno < *ARGC || infile == stdin) { | |
122 dprintf( ("argno=%d, file=|%s|\n", argno, file) ); | |
123 if (infile == NULL) { /* have to open a new file … | |
124 file = getargv(argno); | |
125 if (*file == '\0') { /* it's been zapped … | |
126 argno++; | |
127 continue; | |
128 } | |
129 if (isclvar(file)) { /* a var=value arg */ | |
130 setclvar(file); | |
131 argno++; | |
132 continue; | |
133 } | |
134 *FILENAME = file; | |
135 dprintf( ("opening file %s\n", file) ); | |
136 if (*file == '-' && *(file+1) == '\0') | |
137 infile = stdin; | |
138 else if ((infile = fopen(file, "r")) == NULL) | |
139 FATAL("can't open file %s", file); | |
140 setfval(fnrloc, 0.0); | |
141 } | |
142 c = readrec(&buf, &bufsize, infile); | |
143 if (c != 0 || buf[0] != '\0') { /* normal record … | |
144 if (isrecord) { | |
145 if (freeable(fldtab[0])) | |
146 xfree(fldtab[0]->sval); | |
147 fldtab[0]->sval = buf; /* buf == … | |
148 fldtab[0]->tval = REC | STR | DONTFREE; | |
149 if (is_number(fldtab[0]->sval)) { | |
150 fldtab[0]->fval = atof(fldtab[0]… | |
151 fldtab[0]->tval |= NUM; | |
152 } | |
153 } | |
154 setfval(nrloc, nrloc->fval+1); | |
155 setfval(fnrloc, fnrloc->fval+1); | |
156 *pbuf = buf; | |
157 *pbufsize = bufsize; | |
158 return 1; | |
159 } | |
160 /* EOF arrived on this file; set up next */ | |
161 if (infile != stdin) | |
162 fclose(infile); | |
163 infile = NULL; | |
164 argno++; | |
165 } | |
166 *pbuf = buf; | |
167 *pbufsize = bufsize; | |
168 return 0; /* true end of file */ | |
169 } | |
170 | |
171 void nextfile(void) | |
172 { | |
173 if (infile != stdin) | |
174 fclose(infile); | |
175 infile = NULL; | |
176 argno++; | |
177 } | |
178 | |
179 int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one re… | |
180 { | |
181 int sep, c; | |
182 char *rr, *buf = *pbuf; | |
183 int bufsize = *pbufsize; | |
184 | |
185 if (strlen(*FS) >= sizeof(inputFS)) | |
186 FATAL("field separator %.10s... is too long", *FS); | |
187 strcpy(inputFS, *FS); /* for subsequent field splitting */ | |
188 if ((sep = **RS) == 0) { | |
189 sep = '\n'; | |
190 while ((c=getc(inf)) == '\n' && c != EOF) /* skip… | |
191 ; | |
192 if (c != EOF) | |
193 ungetc(c, inf); | |
194 } | |
195 for (rr = buf; ; ) { | |
196 for (; (c=getc(inf)) != sep && c != EOF; ) { | |
197 if (rr-buf+1 > bufsize) | |
198 if (!adjbuf(&buf, &bufsize, 1+rr-buf, re… | |
199 FATAL("input record `%.30s...' t… | |
200 *rr++ = c; | |
201 } | |
202 if (**RS == sep || c == EOF) | |
203 break; | |
204 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ | |
205 break; | |
206 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "rea… | |
207 FATAL("input record `%.30s...' too long", buf); | |
208 *rr++ = '\n'; | |
209 *rr++ = c; | |
210 } | |
211 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) | |
212 FATAL("input record `%.30s...' too long", buf); | |
213 *rr = 0; | |
214 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && … | |
215 *pbuf = buf; | |
216 *pbufsize = bufsize; | |
217 return c == EOF && rr == buf ? 0 : 1; | |
218 } | |
219 | |
220 char *getargv(int n) /* get ARGV[n] */ | |
221 { | |
222 Cell *x; | |
223 char *s, temp[50]; | |
224 extern Array *ARGVtab; | |
225 | |
226 sprintf(temp, "%d", n); | |
227 x = setsymtab(temp, "", 0.0, STR, ARGVtab); | |
228 s = getsval(x); | |
229 dprintf( ("getargv(%d) returns |%s|\n", n, s) ); | |
230 return s; | |
231 } | |
232 | |
233 void setclvar(char *s) /* set var=value from s */ | |
234 { | |
235 char *p; | |
236 Cell *q; | |
237 | |
238 for (p=s; *p != '='; p++) | |
239 ; | |
240 *p++ = 0; | |
241 p = qstring(p, '\0'); | |
242 q = setsymtab(s, p, 0.0, STR, symtab); | |
243 setsval(q, p); | |
244 if (is_number(q->sval)) { | |
245 q->fval = atof(q->sval); | |
246 q->tval |= NUM; | |
247 } | |
248 dprintf( ("command line set %s to |%s|\n", s, p) ); | |
249 } | |
250 | |
251 | |
252 void fldbld(void) /* create fields from current record */ | |
253 { | |
254 /* this relies on having fields[] the same length as $0 */ | |
255 /* the fields are all stored in this one array with \0's */ | |
256 char *r, *fr, sep; | |
257 Cell *p; | |
258 int i, j, n; | |
259 | |
260 if (donefld) | |
261 return; | |
262 if (!isstr(fldtab[0])) | |
263 getsval(fldtab[0]); | |
264 r = fldtab[0]->sval; | |
265 n = strlen(r); | |
266 if (n > fieldssize) { | |
267 xfree(fields); | |
268 if ((fields = (char *) malloc(n+1)) == NULL) | |
269 FATAL("out of space for fields in fldbld %d", n); | |
270 fieldssize = n; | |
271 } | |
272 fr = fields; | |
273 i = 0; /* number of fields accumulated here */ | |
274 if (strlen(inputFS) > 1) { /* it's a regular expression */ | |
275 i = refldbld(r, inputFS); | |
276 } else if ((sep = *inputFS) == ' ') { /* default whitespa… | |
277 for (i = 0; ; ) { | |
278 while (*r == ' ' || *r == '\t' || *r == '\n') | |
279 r++; | |
280 if (*r == 0) | |
281 break; | |
282 i++; | |
283 if (i > nfields) | |
284 growfldtab(i); | |
285 if (freeable(fldtab[i])) | |
286 xfree(fldtab[i]->sval); | |
287 fldtab[i]->sval = fr; | |
288 fldtab[i]->tval = FLD | STR | DONTFREE; | |
289 do | |
290 *fr++ = *r++; | |
291 while (*r != ' ' && *r != '\t' && *r != '\n' && … | |
292 *fr++ = 0; | |
293 } | |
294 *fr = 0; | |
295 } else if ((sep = *inputFS) == 0) { /* new: FS=""… | |
296 for (i = 0; *r != 0; r++) { | |
297 char buf[2]; | |
298 i++; | |
299 if (i > nfields) | |
300 growfldtab(i); | |
301 if (freeable(fldtab[i])) | |
302 xfree(fldtab[i]->sval); | |
303 buf[0] = *r; | |
304 buf[1] = 0; | |
305 fldtab[i]->sval = tostring(buf); | |
306 fldtab[i]->tval = FLD | STR; | |
307 } | |
308 *fr = 0; | |
309 } else if (*r != 0) { /* if 0, it's a null field */ | |
310 for (;;) { | |
311 i++; | |
312 if (i > nfields) | |
313 growfldtab(i); | |
314 if (freeable(fldtab[i])) | |
315 xfree(fldtab[i]->sval); | |
316 fldtab[i]->sval = fr; | |
317 fldtab[i]->tval = FLD | STR | DONTFREE; | |
318 while (*r != sep && *r != '\n' && *r != '\0') … | |
319 *fr++ = *r++; | |
320 *fr++ = 0; | |
321 if (*r++ == 0) | |
322 break; | |
323 } | |
324 *fr = 0; | |
325 } | |
326 if (i > nfields) | |
327 FATAL("record `%.30s...' has too many fields; can't happ… | |
328 cleanfld(i+1, lastfld); /* clean out junk from previous r… | |
329 lastfld = i; | |
330 donefld = 1; | |
331 for (j = 1; j <= lastfld; j++) { | |
332 p = fldtab[j]; | |
333 if(is_number(p->sval)) { | |
334 p->fval = atof(p->sval); | |
335 p->tval |= NUM; | |
336 } | |
337 } | |
338 setfval(nfloc, (Awkfloat) lastfld); | |
339 if (dbg) { | |
340 for (j = 0; j <= lastfld; j++) { | |
341 p = fldtab[j]; | |
342 printf("field %d (%s): |%s|\n", j, p->nval, p->s… | |
343 } | |
344 } | |
345 } | |
346 | |
347 void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclus… | |
348 { /* nvals remain intact */ | |
349 Cell *p; | |
350 int i; | |
351 | |
352 for (i = n1; i <= n2; i++) { | |
353 p = fldtab[i]; | |
354 if (freeable(p)) | |
355 xfree(p->sval); | |
356 p->sval = ""; | |
357 p->tval = FLD | STR | DONTFREE; | |
358 } | |
359 } | |
360 | |
361 void newfld(int n) /* add field n after end of existing lastfld */ | |
362 { | |
363 if (n > nfields) | |
364 growfldtab(n); | |
365 cleanfld(lastfld+1, n); | |
366 lastfld = n; | |
367 setfval(nfloc, (Awkfloat) n); | |
368 } | |
369 | |
370 Cell *fieldadr(int n) /* get nth field */ | |
371 { | |
372 if (n < 0) | |
373 FATAL("trying to access field %d", n); | |
374 if (n > nfields) /* fields after NF are empty */ | |
375 growfldtab(n); /* but does not increase NF */ | |
376 return(fldtab[n]); | |
377 } | |
378 | |
379 void growfldtab(int n) /* make new fields up to at least $n */ | |
380 { | |
381 int nf = 2 * nfields; | |
382 | |
383 if (n > nf) | |
384 nf = n; | |
385 fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell… | |
386 if (fldtab == NULL) | |
387 FATAL("out of space creating %d fields", nf); | |
388 makefields(nfields+1, nf); | |
389 nfields = nf; | |
390 } | |
391 | |
392 int refldbld(char *rec, char *fs) /* build fields from reg expr i… | |
393 { | |
394 /* this relies on having fields[] the same length as $0 */ | |
395 /* the fields are all stored in this one array with \0's */ | |
396 char *fr; | |
397 void *p; | |
398 int i, n; | |
399 | |
400 n = strlen(rec); | |
401 if (n > fieldssize) { | |
402 xfree(fields); | |
403 if ((fields = (char *) malloc(n+1)) == NULL) | |
404 FATAL("out of space for fields in refldbld %d", … | |
405 fieldssize = n; | |
406 } | |
407 fr = fields; | |
408 *fr = '\0'; | |
409 if (*rec == '\0') | |
410 return 0; | |
411 p = compre(fs); | |
412 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs)… | |
413 for (i = 1; ; i++) { | |
414 if (i > nfields) | |
415 growfldtab(i); | |
416 if (freeable(fldtab[i])) | |
417 xfree(fldtab[i]->sval); | |
418 fldtab[i]->tval = FLD | STR | DONTFREE; | |
419 fldtab[i]->sval = fr; | |
420 dprintf( ("refldbld: i=%d\n", i) ); | |
421 if (nematch(p, rec, rec)) { | |
422 dprintf( ("match %s (%d chars)\n", patbeg, pa… | |
423 strncpy(fr, rec, patbeg-rec); | |
424 fr += patbeg - rec + 1; | |
425 *(fr-1) = '\0'; | |
426 rec = patbeg + patlen; | |
427 } else { | |
428 dprintf( ("no match %s\n", rec) ); | |
429 strcpy(fr, rec); | |
430 break; | |
431 } | |
432 } | |
433 return i; | |
434 } | |
435 | |
436 void recbld(void) /* create $0 from $1..$NF if necessary */ | |
437 { | |
438 int i; | |
439 char *r, *p; | |
440 | |
441 if (donerec == 1) | |
442 return; | |
443 r = record; | |
444 for (i = 1; i <= *NF; i++) { | |
445 p = getsval(fldtab[i]); | |
446 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, rec… | |
447 FATAL("created $0 `%.30s...' too long", record); | |
448 while ((*r = *p++) != 0) | |
449 r++; | |
450 if (i < *NF) { | |
451 if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-… | |
452 FATAL("created $0 `%.30s...' too long", … | |
453 for (p = *OFS; (*r = *p++) != 0; ) | |
454 r++; | |
455 } | |
456 } | |
457 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld … | |
458 FATAL("built giant record `%.30s...'", record); | |
459 *r = '\0'; | |
460 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fl… | |
461 | |
462 if (freeable(fldtab[0])) | |
463 xfree(fldtab[0]->sval); | |
464 fldtab[0]->tval = REC | STR | DONTFREE; | |
465 fldtab[0]->sval = record; | |
466 | |
467 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fl… | |
468 dprintf( ("recbld = |%s|\n", record) ); | |
469 donerec = 1; | |
470 } | |
471 | |
472 int errorflag = 0; | |
473 | |
474 void yyerror(char *s) | |
475 { | |
476 SYNTAX(s); | |
477 } | |
478 | |
479 void SYNTAX(char *fmt, ...) | |
480 { | |
481 extern char *cmdname, *curfname; | |
482 static int been_here = 0; | |
483 va_list varg; | |
484 | |
485 if (been_here++ > 2) | |
486 return; | |
487 fprintf(stderr, "%s: ", cmdname); | |
488 va_start(varg, fmt); | |
489 vfprintf(stderr, fmt, varg); | |
490 va_end(varg); | |
491 if(compile_time == 1 && cursource() != NULL) | |
492 fprintf(stderr, " at %s:%d", cursource(), lineno); | |
493 else | |
494 fprintf(stderr, " at line %d", lineno); | |
495 if (curfname != NULL) | |
496 fprintf(stderr, " in function %s", curfname); | |
497 fprintf(stderr, "\n"); | |
498 errorflag = 2; | |
499 eprint(); | |
500 } | |
501 | |
502 void fpecatch(int n) | |
503 { | |
504 FATAL("floating point exception %d", n); | |
505 } | |
506 | |
507 extern int bracecnt, brackcnt, parencnt; | |
508 | |
509 void bracecheck(void) | |
510 { | |
511 int c; | |
512 static int beenhere = 0; | |
513 | |
514 if (beenhere++) | |
515 return; | |
516 while ((c = input()) != EOF && c != '\0') | |
517 bclass(c); | |
518 bcheck2(bracecnt, '{', '}'); | |
519 bcheck2(brackcnt, '[', ']'); | |
520 bcheck2(parencnt, '(', ')'); | |
521 } | |
522 | |
523 void bcheck2(int n, int c1, int c2) | |
524 { | |
525 if (n == 1) | |
526 fprintf(stderr, "\tmissing %c\n", c2); | |
527 else if (n > 1) | |
528 fprintf(stderr, "\t%d missing %c's\n", n, c2); | |
529 else if (n == -1) | |
530 fprintf(stderr, "\textra %c\n", c2); | |
531 else if (n < -1) | |
532 fprintf(stderr, "\t%d extra %c's\n", -n, c2); | |
533 } | |
534 | |
535 void FATAL(char *fmt, ...) | |
536 { | |
537 extern char *cmdname; | |
538 va_list varg; | |
539 | |
540 fflush(stdout); | |
541 fprintf(stderr, "%s: ", cmdname); | |
542 va_start(varg, fmt); | |
543 vfprintf(stderr, fmt, varg); | |
544 va_end(varg); | |
545 error(); | |
546 if (dbg > 1) /* core dump if serious debugging on… | |
547 abort(); | |
548 exit(2); | |
549 } | |
550 | |
551 void WARNING(char *fmt, ...) | |
552 { | |
553 extern char *cmdname; | |
554 va_list varg; | |
555 | |
556 fflush(stdout); | |
557 fprintf(stderr, "%s: ", cmdname); | |
558 va_start(varg, fmt); | |
559 vfprintf(stderr, fmt, varg); | |
560 va_end(varg); | |
561 error(); | |
562 } | |
563 | |
564 void error() | |
565 { | |
566 extern Node *curnode; | |
567 int line; | |
568 | |
569 fprintf(stderr, "\n"); | |
570 if (compile_time != 2 && NR && *NR > 0) { | |
571 if (strcmp(*FILENAME, "-") != 0) | |
572 fprintf(stderr, " input record %s:%d", *FILENAME… | |
573 else | |
574 fprintf(stderr, " input record number %d", (int)… | |
575 fprintf(stderr, "\n"); | |
576 } | |
577 if (compile_time != 2 && curnode) | |
578 line = curnode->lineno; | |
579 else if (compile_time != 2 && lineno) | |
580 line = lineno; | |
581 else | |
582 line = -1; | |
583 if (compile_time == 1 && cursource() != NULL){ | |
584 if(line >= 0) | |
585 fprintf(stderr, " source %s:%d", cursource(), li… | |
586 else | |
587 fprintf(stderr, " source file %s", cursource()); | |
588 }else if(line >= 0) | |
589 fprintf(stderr, " source line %d", line); | |
590 fprintf(stderr, "\n"); | |
591 eprint(); | |
592 } | |
593 | |
594 void eprint(void) /* try to print context around error */ | |
595 { | |
596 char *p, *q; | |
597 int c; | |
598 static int been_here = 0; | |
599 extern char ebuf[], *ep; | |
600 | |
601 if (compile_time == 2 || compile_time == 0 || been_here++ > 0) | |
602 return; | |
603 p = ep - 1; | |
604 if (p > ebuf && *p == '\n') | |
605 p--; | |
606 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) | |
607 ; | |
608 while (*p == '\n') | |
609 p++; | |
610 fprintf(stderr, " context is\n\t"); | |
611 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) | |
612 ; | |
613 for ( ; p < q; p++) | |
614 if (*p) | |
615 putc(*p, stderr); | |
616 fprintf(stderr, " >>> "); | |
617 for ( ; p < ep; p++) | |
618 if (*p) | |
619 putc(*p, stderr); | |
620 fprintf(stderr, " <<< "); | |
621 if (*ep) | |
622 while ((c = input()) != '\n' && c != '\0' && c != EOF) { | |
623 putc(c, stderr); | |
624 bclass(c); | |
625 } | |
626 putc('\n', stderr); | |
627 ep = ebuf; | |
628 } | |
629 | |
630 void bclass(int c) | |
631 { | |
632 switch (c) { | |
633 case '{': bracecnt++; break; | |
634 case '}': bracecnt--; break; | |
635 case '[': brackcnt++; break; | |
636 case ']': brackcnt--; break; | |
637 case '(': parencnt++; break; | |
638 case ')': parencnt--; break; | |
639 } | |
640 } | |
641 | |
642 double errcheck(double x, char *s) | |
643 { | |
644 | |
645 if (errno == EDOM) { | |
646 errno = 0; | |
647 WARNING("%s argument out of domain", s); | |
648 x = 1; | |
649 } else if (errno == ERANGE) { | |
650 errno = 0; | |
651 WARNING("%s result out of range", s); | |
652 x = 1; | |
653 } | |
654 return x; | |
655 } | |
656 | |
657 int isclvar(char *s) /* is s of form var=something ? */ | |
658 { | |
659 char *os = s; | |
660 | |
661 if (!isalpha(*s) && *s != '_') | |
662 return 0; | |
663 for ( ; *s; s++) | |
664 if (!(isalnum(*s) || *s == '_')) | |
665 break; | |
666 return *s == '=' && s > os && *(s+1) != '='; | |
667 } | |
668 | |
669 /* strtod is supposed to be a proper test of what's a valid number */ | |
670 | |
671 #include <math.h> | |
672 int is_number(char *s) | |
673 { | |
674 double r; | |
675 char *ep; | |
676 | |
677 /* | |
678 * fast could-it-be-a-number check before calling strtod, | |
679 * which takes a surprisingly long time to reject non-numbers. | |
680 */ | |
681 switch (*s) { | |
682 case '0': case '1': case '2': case '3': case '4': | |
683 case '5': case '6': case '7': case '8': case '9': | |
684 case '\t': | |
685 case '\n': | |
686 case '\v': | |
687 case '\f': | |
688 case '\r': | |
689 case ' ': | |
690 case '-': | |
691 case '+': | |
692 case '.': | |
693 case 'n': /* nans */ | |
694 case 'N': | |
695 case 'i': /* infs */ | |
696 case 'I': | |
697 break; | |
698 default: | |
699 return 0; /* can't be a number */ | |
700 } | |
701 | |
702 errno = 0; | |
703 r = strtod(s, &ep); | |
704 if (ep == s || r == HUGE_VAL || errno == ERANGE) | |
705 return 0; | |
706 while (*ep == ' ' || *ep == '\t' || *ep == '\n') | |
707 ep++; | |
708 if (*ep == '\0') | |
709 return 1; | |
710 else | |
711 return 0; | |
712 } | |
713 |