Annotation of rpl/rplawk/lib.c, revision 1.2

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

CVSweb interface <joel.bertrand@systella.fr>