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