15ea9e707SThomas Veerman /****************************************************************
25ea9e707SThomas Veerman Copyright (C) Lucent Technologies 1997
35ea9e707SThomas Veerman All Rights Reserved
45ea9e707SThomas Veerman
55ea9e707SThomas Veerman Permission to use, copy, modify, and distribute this software and
65ea9e707SThomas Veerman its documentation for any purpose and without fee is hereby
75ea9e707SThomas Veerman granted, provided that the above copyright notice appear in all
85ea9e707SThomas Veerman copies and that both that the copyright notice and this
95ea9e707SThomas Veerman permission notice and warranty disclaimer appear in supporting
105ea9e707SThomas Veerman documentation, and that the name Lucent Technologies or any of
115ea9e707SThomas Veerman its entities not be used in advertising or publicity pertaining
125ea9e707SThomas Veerman to distribution of the software without specific, written prior
135ea9e707SThomas Veerman permission.
145ea9e707SThomas Veerman
155ea9e707SThomas Veerman LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
165ea9e707SThomas Veerman INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
175ea9e707SThomas Veerman IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
185ea9e707SThomas Veerman SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
195ea9e707SThomas Veerman WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
205ea9e707SThomas Veerman IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
215ea9e707SThomas Veerman ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
225ea9e707SThomas Veerman THIS SOFTWARE.
235ea9e707SThomas Veerman ****************************************************************/
245ea9e707SThomas Veerman
255ea9e707SThomas Veerman #if HAVE_NBTOOL_CONFIG_H
265ea9e707SThomas Veerman #include "nbtool_config.h"
275ea9e707SThomas Veerman #endif
285ea9e707SThomas Veerman
295ea9e707SThomas Veerman #define DEBUG
305ea9e707SThomas Veerman #include <stdio.h>
315ea9e707SThomas Veerman #include <string.h>
325ea9e707SThomas Veerman #include <ctype.h>
335ea9e707SThomas Veerman #include <errno.h>
345ea9e707SThomas Veerman #include <stdlib.h>
355ea9e707SThomas Veerman #include <stdarg.h>
365ea9e707SThomas Veerman #include "awk.h"
375ea9e707SThomas Veerman #include "awkgram.h"
385ea9e707SThomas Veerman
395ea9e707SThomas Veerman char EMPTY[] = { '\0' };
405ea9e707SThomas Veerman FILE *infile = NULL;
415ea9e707SThomas Veerman int innew; /* 1 = infile has not been read by readrec */
425ea9e707SThomas Veerman char *file = EMPTY;
435ea9e707SThomas Veerman uschar *record;
445ea9e707SThomas Veerman int recsize = RECSIZE;
455ea9e707SThomas Veerman char *fields;
465ea9e707SThomas Veerman int fieldssize = RECSIZE;
475ea9e707SThomas Veerman
485ea9e707SThomas Veerman Cell **fldtab; /* pointers to Cells */
495ea9e707SThomas Veerman
505ea9e707SThomas Veerman static size_t len_inputFS = 0;
515ea9e707SThomas Veerman static char *inputFS = NULL;
525ea9e707SThomas Veerman
535ea9e707SThomas Veerman #define MAXFLD 2
545ea9e707SThomas Veerman int nfields = MAXFLD; /* last allocated slot for $i */
555ea9e707SThomas Veerman
565ea9e707SThomas Veerman int donefld; /* 1 = implies rec broken into fields */
575ea9e707SThomas Veerman int donerec; /* 1 = record is valid (no flds have changed) */
585ea9e707SThomas Veerman
595ea9e707SThomas Veerman int lastfld = 0; /* last used field */
605ea9e707SThomas Veerman int argno = 1; /* current input argument number */
615ea9e707SThomas Veerman extern Awkfloat *ARGC;
625ea9e707SThomas Veerman
635ea9e707SThomas Veerman static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL };
645ea9e707SThomas Veerman static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL };
655ea9e707SThomas Veerman
recinit(unsigned int n)665ea9e707SThomas Veerman void recinit(unsigned int n)
675ea9e707SThomas Veerman {
685ea9e707SThomas Veerman if ( (record = malloc(n)) == NULL
695ea9e707SThomas Veerman || (fields = malloc(n+1)) == NULL
705ea9e707SThomas Veerman || (fldtab = malloc((nfields+1) * sizeof(*fldtab))) == NULL
715ea9e707SThomas Veerman || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL )
725ea9e707SThomas Veerman FATAL("out of space for $0 and fields");
735ea9e707SThomas Veerman *fldtab[0] = dollar0;
745ea9e707SThomas Veerman fldtab[0]->sval = record;
755ea9e707SThomas Veerman fldtab[0]->nval = tostring("0");
765ea9e707SThomas Veerman makefields(1, nfields);
775ea9e707SThomas Veerman }
785ea9e707SThomas Veerman
makefields(int n1,int n2)795ea9e707SThomas Veerman void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
805ea9e707SThomas Veerman {
815ea9e707SThomas Veerman char temp[50];
825ea9e707SThomas Veerman int i;
835ea9e707SThomas Veerman
845ea9e707SThomas Veerman for (i = n1; i <= n2; i++) {
855ea9e707SThomas Veerman fldtab[i] = malloc(sizeof(**fldtab));
865ea9e707SThomas Veerman if (fldtab[i] == NULL)
875ea9e707SThomas Veerman FATAL("out of space in makefields %d", i);
885ea9e707SThomas Veerman *fldtab[i] = dollar1;
895ea9e707SThomas Veerman snprintf(temp, sizeof(temp), "%d", i);
905ea9e707SThomas Veerman fldtab[i]->nval = tostring(temp);
915ea9e707SThomas Veerman }
925ea9e707SThomas Veerman }
935ea9e707SThomas Veerman
initgetrec(void)945ea9e707SThomas Veerman void initgetrec(void)
955ea9e707SThomas Veerman {
965ea9e707SThomas Veerman int i;
975ea9e707SThomas Veerman char *p;
985ea9e707SThomas Veerman
995ea9e707SThomas Veerman for (i = 1; i < *ARGC; i++) {
100*84d9c625SLionel Sambuc p = getargv(i); /* find 1st real filename */
101*84d9c625SLionel Sambuc if (p == NULL || *p == '\0') { /* deleted or zapped */
102*84d9c625SLionel Sambuc argno++;
103*84d9c625SLionel Sambuc continue;
104*84d9c625SLionel Sambuc }
105*84d9c625SLionel Sambuc if (!isclvar(p)) {
106*84d9c625SLionel Sambuc setsval(lookup("FILENAME", symtab), p);
1075ea9e707SThomas Veerman return;
1085ea9e707SThomas Veerman }
1095ea9e707SThomas Veerman setclvar(p); /* a commandline assignment before filename */
1105ea9e707SThomas Veerman argno++;
1115ea9e707SThomas Veerman }
1125ea9e707SThomas Veerman infile = stdin; /* no filenames, so use stdin */
1135ea9e707SThomas Veerman innew = 1;
1145ea9e707SThomas Veerman }
1155ea9e707SThomas Veerman
1165ea9e707SThomas Veerman static int firsttime = 1;
1175ea9e707SThomas Veerman
getrec(uschar ** pbuf,int * pbufsize,int isrecord)1185ea9e707SThomas Veerman int getrec(uschar **pbuf, int *pbufsize, int isrecord) /* get next input record */
1195ea9e707SThomas Veerman { /* note: cares whether buf == record */
1205ea9e707SThomas Veerman int c;
1215ea9e707SThomas Veerman uschar *buf = *pbuf;
1225ea9e707SThomas Veerman uschar saveb0;
1235ea9e707SThomas Veerman int bufsize = *pbufsize, savebufsize = bufsize;
1245ea9e707SThomas Veerman
1255ea9e707SThomas Veerman if (firsttime) {
1265ea9e707SThomas Veerman firsttime = 0;
1275ea9e707SThomas Veerman initgetrec();
1285ea9e707SThomas Veerman }
1295ea9e707SThomas Veerman dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
1305ea9e707SThomas Veerman *RS, *FS, *ARGC, *FILENAME) );
1315ea9e707SThomas Veerman if (isrecord) {
1325ea9e707SThomas Veerman donefld = 0;
1335ea9e707SThomas Veerman donerec = 1;
1345ea9e707SThomas Veerman }
1355ea9e707SThomas Veerman saveb0 = buf[0];
1365ea9e707SThomas Veerman buf[0] = 0;
1375ea9e707SThomas Veerman while (argno < *ARGC || infile == stdin) {
1385ea9e707SThomas Veerman dprintf( ("argno=%d, file=|%s|\n", argno, file) );
1395ea9e707SThomas Veerman if (infile == NULL) { /* have to open a new file */
1405ea9e707SThomas Veerman file = getargv(argno);
141*84d9c625SLionel Sambuc if (file == NULL || *file == '\0') { /* deleted or zapped */
1425ea9e707SThomas Veerman argno++;
1435ea9e707SThomas Veerman continue;
1445ea9e707SThomas Veerman }
1455ea9e707SThomas Veerman if (isclvar(file)) { /* a var=value arg */
1465ea9e707SThomas Veerman setclvar(file);
1475ea9e707SThomas Veerman argno++;
1485ea9e707SThomas Veerman continue;
1495ea9e707SThomas Veerman }
1505ea9e707SThomas Veerman *FILENAME = file;
1515ea9e707SThomas Veerman dprintf( ("opening file %s\n", file) );
1525ea9e707SThomas Veerman if (*file == '-' && *(file+1) == '\0')
1535ea9e707SThomas Veerman infile = stdin;
1545ea9e707SThomas Veerman else if ((infile = fopen(file, "r")) == NULL)
1555ea9e707SThomas Veerman FATAL("can't open file %s", file);
1565ea9e707SThomas Veerman innew = 1;
1575ea9e707SThomas Veerman setfval(fnrloc, 0.0);
1585ea9e707SThomas Veerman }
1595ea9e707SThomas Veerman c = readrec(&buf, &bufsize, infile, innew);
1605ea9e707SThomas Veerman if (innew)
1615ea9e707SThomas Veerman innew = 0;
1625ea9e707SThomas Veerman if (c != 0 || buf[0] != '\0') { /* normal record */
1635ea9e707SThomas Veerman if (isrecord) {
1645ea9e707SThomas Veerman if (freeable(fldtab[0]))
1655ea9e707SThomas Veerman xfree(fldtab[0]->sval);
1665ea9e707SThomas Veerman fldtab[0]->sval = buf; /* buf == record */
1675ea9e707SThomas Veerman fldtab[0]->tval = REC | STR | DONTFREE;
1685ea9e707SThomas Veerman if (is_number(fldtab[0]->sval)) {
1695ea9e707SThomas Veerman fldtab[0]->fval = atof(fldtab[0]->sval);
1705ea9e707SThomas Veerman fldtab[0]->tval |= NUM;
1715ea9e707SThomas Veerman }
1725ea9e707SThomas Veerman }
1735ea9e707SThomas Veerman setfval(nrloc, nrloc->fval+1);
1745ea9e707SThomas Veerman setfval(fnrloc, fnrloc->fval+1);
1755ea9e707SThomas Veerman *pbuf = buf;
1765ea9e707SThomas Veerman *pbufsize = bufsize;
1775ea9e707SThomas Veerman return 1;
1785ea9e707SThomas Veerman }
1795ea9e707SThomas Veerman /* EOF arrived on this file; set up next */
1805ea9e707SThomas Veerman if (infile != stdin)
1815ea9e707SThomas Veerman fclose(infile);
1825ea9e707SThomas Veerman infile = NULL;
1835ea9e707SThomas Veerman argno++;
1845ea9e707SThomas Veerman }
1855ea9e707SThomas Veerman buf[0] = saveb0;
1865ea9e707SThomas Veerman *pbuf = buf;
1875ea9e707SThomas Veerman *pbufsize = savebufsize;
1885ea9e707SThomas Veerman return 0; /* true end of file */
1895ea9e707SThomas Veerman }
1905ea9e707SThomas Veerman
nextfile(void)1915ea9e707SThomas Veerman void nextfile(void)
1925ea9e707SThomas Veerman {
1935ea9e707SThomas Veerman if (infile != NULL && infile != stdin)
1945ea9e707SThomas Veerman fclose(infile);
1955ea9e707SThomas Veerman infile = NULL;
1965ea9e707SThomas Veerman argno++;
1975ea9e707SThomas Veerman }
1985ea9e707SThomas Veerman
readrec(uschar ** pbuf,int * pbufsize,FILE * inf,int newflag)1995ea9e707SThomas Veerman int readrec(uschar **pbuf, int *pbufsize, FILE *inf, int newflag) /* read one record into buf */
2005ea9e707SThomas Veerman {
2015ea9e707SThomas Veerman int sep, c, isrec, found, tempstat;
2025ea9e707SThomas Veerman uschar *rr, *buf = *pbuf;
2035ea9e707SThomas Veerman int bufsize = *pbufsize;
2045ea9e707SThomas Veerman size_t len;
2055ea9e707SThomas Veerman
2065ea9e707SThomas Veerman if ((len = strlen(*FS)) < len_inputFS) {
2075ea9e707SThomas Veerman strcpy(inputFS, *FS); /* for subsequent field splitting */
2085ea9e707SThomas Veerman } else {
2095ea9e707SThomas Veerman len_inputFS = len + 1;
2105ea9e707SThomas Veerman inputFS = realloc(inputFS, len_inputFS);
2115ea9e707SThomas Veerman if (inputFS == NULL)
2125ea9e707SThomas Veerman FATAL("field separator %.10s... is too long", *FS);
2135ea9e707SThomas Veerman memcpy(inputFS, *FS, len_inputFS);
2145ea9e707SThomas Veerman }
215*84d9c625SLionel Sambuc /*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
2165ea9e707SThomas Veerman if (**RS && (*RS)[1]) {
2175ea9e707SThomas Veerman fa *pfa = makedfa(*RS, 1);
2185ea9e707SThomas Veerman if (newflag)
2195ea9e707SThomas Veerman found = fnematch(pfa, inf, &buf, &bufsize, recsize);
2205ea9e707SThomas Veerman else {
2215ea9e707SThomas Veerman tempstat = pfa->initstat;
2225ea9e707SThomas Veerman pfa->initstat = 2;
2235ea9e707SThomas Veerman found = fnematch(pfa, inf, &buf, &bufsize, recsize);
2245ea9e707SThomas Veerman pfa->initstat = tempstat;
2255ea9e707SThomas Veerman }
2265ea9e707SThomas Veerman if (found)
2275ea9e707SThomas Veerman *patbeg = 0;
2285ea9e707SThomas Veerman } else {
2295ea9e707SThomas Veerman if ((sep = **RS) == 0) {
2305ea9e707SThomas Veerman sep = '\n';
2315ea9e707SThomas Veerman while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
2325ea9e707SThomas Veerman ;
2335ea9e707SThomas Veerman if (c != EOF)
2345ea9e707SThomas Veerman ungetc(c, inf);
2355ea9e707SThomas Veerman }
2365ea9e707SThomas Veerman for (rr = buf; ; ) {
2375ea9e707SThomas Veerman for (; (c=getc(inf)) != sep && c != EOF; ) {
2385ea9e707SThomas Veerman if (rr-buf+1 > bufsize)
2395ea9e707SThomas Veerman if (!adjbuf(&buf, &bufsize, 1+rr-buf,
2405ea9e707SThomas Veerman recsize, &rr, "readrec 1"))
2415ea9e707SThomas Veerman FATAL("input record `%.30s...'"
2425ea9e707SThomas Veerman " too long", buf);
2435ea9e707SThomas Veerman *rr++ = c;
2445ea9e707SThomas Veerman }
2455ea9e707SThomas Veerman if (**RS == sep || c == EOF)
2465ea9e707SThomas Veerman break;
2475ea9e707SThomas Veerman if ((c = getc(inf)) == '\n' || c == EOF)
2485ea9e707SThomas Veerman /* 2 in a row */
2495ea9e707SThomas Veerman break;
2505ea9e707SThomas Veerman if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
2515ea9e707SThomas Veerman "readrec 2"))
2525ea9e707SThomas Veerman FATAL("input record `%.30s...' too long", buf);
2535ea9e707SThomas Veerman *rr++ = '\n';
2545ea9e707SThomas Veerman *rr++ = c;
2555ea9e707SThomas Veerman }
2565ea9e707SThomas Veerman if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
2575ea9e707SThomas Veerman FATAL("input record `%.30s...' too long", buf);
2585ea9e707SThomas Veerman *rr = 0;
2595ea9e707SThomas Veerman }
2605ea9e707SThomas Veerman *pbuf = buf;
2615ea9e707SThomas Veerman *pbufsize = bufsize;
2625ea9e707SThomas Veerman isrec = *buf || !feof(inf);
2635ea9e707SThomas Veerman dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) );
2645ea9e707SThomas Veerman return isrec;
2655ea9e707SThomas Veerman }
2665ea9e707SThomas Veerman
getargv(int n)2675ea9e707SThomas Veerman char *getargv(int n) /* get ARGV[n] */
2685ea9e707SThomas Veerman {
2695ea9e707SThomas Veerman Cell *x;
2705ea9e707SThomas Veerman char *s, temp[50];
2715ea9e707SThomas Veerman extern Array *ARGVtab;
2725ea9e707SThomas Veerman
2735ea9e707SThomas Veerman snprintf(temp, sizeof(temp), "%d", n);
274*84d9c625SLionel Sambuc if (lookup(temp, ARGVtab) == NULL)
275*84d9c625SLionel Sambuc return NULL;
2765ea9e707SThomas Veerman x = setsymtab(temp, "", 0.0, STR, ARGVtab);
2775ea9e707SThomas Veerman s = getsval(x);
2785ea9e707SThomas Veerman dprintf( ("getargv(%d) returns |%s|\n", n, s) );
2795ea9e707SThomas Veerman return s;
2805ea9e707SThomas Veerman }
2815ea9e707SThomas Veerman
setclvar(char * s)2825ea9e707SThomas Veerman void setclvar(char *s) /* set var=value from s */
2835ea9e707SThomas Veerman {
2845ea9e707SThomas Veerman char *p;
2855ea9e707SThomas Veerman Cell *q;
2865ea9e707SThomas Veerman
2875ea9e707SThomas Veerman for (p=s; *p != '='; p++)
2885ea9e707SThomas Veerman ;
2895ea9e707SThomas Veerman *p++ = 0;
2905ea9e707SThomas Veerman p = qstring(p, '\0');
2915ea9e707SThomas Veerman q = setsymtab(s, p, 0.0, STR, symtab);
2925ea9e707SThomas Veerman setsval(q, p);
2935ea9e707SThomas Veerman if (is_number(q->sval)) {
2945ea9e707SThomas Veerman q->fval = atof(q->sval);
2955ea9e707SThomas Veerman q->tval |= NUM;
2965ea9e707SThomas Veerman }
2975ea9e707SThomas Veerman dprintf( ("command line set %s to |%s|\n", s, p) );
2985ea9e707SThomas Veerman }
2995ea9e707SThomas Veerman
3005ea9e707SThomas Veerman
fldbld(void)3015ea9e707SThomas Veerman void fldbld(void) /* create fields from current record */
3025ea9e707SThomas Veerman {
3035ea9e707SThomas Veerman /* this relies on having fields[] the same length as $0 */
3045ea9e707SThomas Veerman /* the fields are all stored in this one array with \0's */
305*84d9c625SLionel Sambuc /* possibly with a final trailing \0 not associated with any field */
3065ea9e707SThomas Veerman char *r, *fr, sep;
3075ea9e707SThomas Veerman Cell *p;
3085ea9e707SThomas Veerman int i, j, n;
3095ea9e707SThomas Veerman
3105ea9e707SThomas Veerman if (donefld)
3115ea9e707SThomas Veerman return;
3125ea9e707SThomas Veerman if (!isstr(fldtab[0]))
3135ea9e707SThomas Veerman getsval(fldtab[0]);
3145ea9e707SThomas Veerman r = fldtab[0]->sval;
3155ea9e707SThomas Veerman n = strlen(r);
3165ea9e707SThomas Veerman if (n > fieldssize) {
3175ea9e707SThomas Veerman xfree(fields);
318*84d9c625SLionel Sambuc if ((fields = malloc(n+2)) == NULL) /* possibly 2 final \0s */
3195ea9e707SThomas Veerman FATAL("out of space for fields in fldbld %d", n);
3205ea9e707SThomas Veerman fieldssize = n;
3215ea9e707SThomas Veerman }
3225ea9e707SThomas Veerman fr = fields;
3235ea9e707SThomas Veerman i = 0; /* number of fields accumulated here */
3245ea9e707SThomas Veerman if (!inputFS) {
3255ea9e707SThomas Veerman /* do nothing */
3265ea9e707SThomas Veerman } else if (inputFS[0] && inputFS[1]) { /* it's a regular expression */
3275ea9e707SThomas Veerman i = refldbld(r, inputFS);
3285ea9e707SThomas Veerman } else if ((sep = *inputFS) == ' ') { /* default whitespace */
3295ea9e707SThomas Veerman for (i = 0; ; ) {
3305ea9e707SThomas Veerman while (*r == ' ' || *r == '\t' || *r == '\n')
3315ea9e707SThomas Veerman r++;
3325ea9e707SThomas Veerman if (*r == 0)
3335ea9e707SThomas Veerman break;
3345ea9e707SThomas Veerman i++;
3355ea9e707SThomas Veerman if (i > nfields)
3365ea9e707SThomas Veerman growfldtab(i);
3375ea9e707SThomas Veerman if (freeable(fldtab[i]))
3385ea9e707SThomas Veerman xfree(fldtab[i]->sval);
3395ea9e707SThomas Veerman fldtab[i]->sval = fr;
3405ea9e707SThomas Veerman fldtab[i]->tval = FLD | STR | DONTFREE;
3415ea9e707SThomas Veerman do
3425ea9e707SThomas Veerman *fr++ = *r++;
3435ea9e707SThomas Veerman while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
3445ea9e707SThomas Veerman *fr++ = 0;
3455ea9e707SThomas Veerman }
3465ea9e707SThomas Veerman *fr = 0;
3475ea9e707SThomas Veerman } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
3485ea9e707SThomas Veerman for (i = 0; *r != 0; r++) {
3495ea9e707SThomas Veerman char buf[2];
3505ea9e707SThomas Veerman i++;
3515ea9e707SThomas Veerman if (i > nfields)
3525ea9e707SThomas Veerman growfldtab(i);
3535ea9e707SThomas Veerman if (freeable(fldtab[i]))
3545ea9e707SThomas Veerman xfree(fldtab[i]->sval);
3555ea9e707SThomas Veerman buf[0] = *r;
3565ea9e707SThomas Veerman buf[1] = 0;
3575ea9e707SThomas Veerman fldtab[i]->sval = tostring(buf);
3585ea9e707SThomas Veerman fldtab[i]->tval = FLD | STR;
3595ea9e707SThomas Veerman }
3605ea9e707SThomas Veerman *fr = 0;
3615ea9e707SThomas Veerman } else if (*r != 0) { /* if 0, it's a null field */
3625ea9e707SThomas Veerman /* subtlecase : if length(FS) == 1 && length(RS > 0)
3635ea9e707SThomas Veerman * \n is NOT a field separator (cf awk book 61,84).
3645ea9e707SThomas Veerman * this variable is tested in the inner while loop.
3655ea9e707SThomas Veerman */
3665ea9e707SThomas Veerman int rtest = '\n'; /* normal case */
3675ea9e707SThomas Veerman if (strlen(*RS) > 0)
3685ea9e707SThomas Veerman rtest = '\0';
3695ea9e707SThomas Veerman for (;;) {
3705ea9e707SThomas Veerman i++;
3715ea9e707SThomas Veerman if (i > nfields)
3725ea9e707SThomas Veerman growfldtab(i);
3735ea9e707SThomas Veerman if (freeable(fldtab[i]))
3745ea9e707SThomas Veerman xfree(fldtab[i]->sval);
3755ea9e707SThomas Veerman fldtab[i]->sval = fr;
3765ea9e707SThomas Veerman fldtab[i]->tval = FLD | STR | DONTFREE;
3775ea9e707SThomas Veerman while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
3785ea9e707SThomas Veerman *fr++ = *r++;
3795ea9e707SThomas Veerman *fr++ = 0;
3805ea9e707SThomas Veerman if (*r++ == 0)
3815ea9e707SThomas Veerman break;
3825ea9e707SThomas Veerman }
3835ea9e707SThomas Veerman *fr = 0;
3845ea9e707SThomas Veerman }
3855ea9e707SThomas Veerman if (i > nfields)
3865ea9e707SThomas Veerman FATAL("record `%.30s...' has too many fields; can't happen", r);
3875ea9e707SThomas Veerman cleanfld(i+1, lastfld); /* clean out junk from previous record */
3885ea9e707SThomas Veerman lastfld = i;
3895ea9e707SThomas Veerman donefld = 1;
3905ea9e707SThomas Veerman for (j = 1; j <= lastfld; j++) {
3915ea9e707SThomas Veerman p = fldtab[j];
3925ea9e707SThomas Veerman if(is_number(p->sval)) {
3935ea9e707SThomas Veerman p->fval = atof(p->sval);
3945ea9e707SThomas Veerman p->tval |= NUM;
3955ea9e707SThomas Veerman }
3965ea9e707SThomas Veerman }
3975ea9e707SThomas Veerman setfval(nfloc, (Awkfloat) lastfld);
3985ea9e707SThomas Veerman donerec = 1; /* restore */
3995ea9e707SThomas Veerman if (dbg) {
4005ea9e707SThomas Veerman for (j = 0; j <= lastfld; j++) {
4015ea9e707SThomas Veerman p = fldtab[j];
4025ea9e707SThomas Veerman printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
4035ea9e707SThomas Veerman }
4045ea9e707SThomas Veerman }
4055ea9e707SThomas Veerman }
4065ea9e707SThomas Veerman
cleanfld(int n1,int n2)4075ea9e707SThomas Veerman void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
4085ea9e707SThomas Veerman { /* nvals remain intact */
4095ea9e707SThomas Veerman Cell *p;
4105ea9e707SThomas Veerman int i;
4115ea9e707SThomas Veerman
4125ea9e707SThomas Veerman for (i = n1; i <= n2; i++) {
4135ea9e707SThomas Veerman p = fldtab[i];
4145ea9e707SThomas Veerman if (freeable(p))
4155ea9e707SThomas Veerman xfree(p->sval);
4165ea9e707SThomas Veerman p->sval = EMPTY;
4175ea9e707SThomas Veerman p->tval = FLD | STR | DONTFREE;
4185ea9e707SThomas Veerman }
4195ea9e707SThomas Veerman }
4205ea9e707SThomas Veerman
newfld(int n)4215ea9e707SThomas Veerman void newfld(int n) /* add field n after end of existing lastfld */
4225ea9e707SThomas Veerman {
4235ea9e707SThomas Veerman if (n > nfields)
4245ea9e707SThomas Veerman growfldtab(n);
4255ea9e707SThomas Veerman cleanfld(lastfld+1, n);
4265ea9e707SThomas Veerman lastfld = n;
4275ea9e707SThomas Veerman setfval(nfloc, (Awkfloat) n);
4285ea9e707SThomas Veerman }
4295ea9e707SThomas Veerman
setlastfld(int n)4305ea9e707SThomas Veerman void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
4315ea9e707SThomas Veerman {
4325ea9e707SThomas Veerman if (n > nfields)
4335ea9e707SThomas Veerman growfldtab(n);
4345ea9e707SThomas Veerman
4355ea9e707SThomas Veerman if (lastfld < n)
4365ea9e707SThomas Veerman cleanfld(lastfld+1, n);
4375ea9e707SThomas Veerman else
4385ea9e707SThomas Veerman cleanfld(n+1, lastfld);
4395ea9e707SThomas Veerman
4405ea9e707SThomas Veerman lastfld = n;
4415ea9e707SThomas Veerman }
4425ea9e707SThomas Veerman
fieldadr(int n)4435ea9e707SThomas Veerman Cell *fieldadr(int n) /* get nth field */
4445ea9e707SThomas Veerman {
4455ea9e707SThomas Veerman if (n < 0)
4465ea9e707SThomas Veerman FATAL("trying to access out of range field %d", n);
4475ea9e707SThomas Veerman if (n > nfields) /* fields after NF are empty */
4485ea9e707SThomas Veerman growfldtab(n); /* but does not increase NF */
4495ea9e707SThomas Veerman return(fldtab[n]);
4505ea9e707SThomas Veerman }
4515ea9e707SThomas Veerman
growfldtab(int n)4525ea9e707SThomas Veerman void growfldtab(int n) /* make new fields up to at least $n */
4535ea9e707SThomas Veerman {
4545ea9e707SThomas Veerman int nf = 2 * nfields;
4555ea9e707SThomas Veerman size_t s;
4565ea9e707SThomas Veerman
4575ea9e707SThomas Veerman if (n > nf)
4585ea9e707SThomas Veerman nf = n;
4595ea9e707SThomas Veerman s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
4605ea9e707SThomas Veerman if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
4615ea9e707SThomas Veerman fldtab = realloc(fldtab, s);
4625ea9e707SThomas Veerman else /* overflow sizeof int */
4635ea9e707SThomas Veerman xfree(fldtab); /* make it null */
4645ea9e707SThomas Veerman if (fldtab == NULL)
4655ea9e707SThomas Veerman FATAL("out of space creating %d fields", nf);
4665ea9e707SThomas Veerman makefields(nfields+1, nf);
4675ea9e707SThomas Veerman nfields = nf;
4685ea9e707SThomas Veerman }
4695ea9e707SThomas Veerman
refldbld(const char * rec,const char * fs)4705ea9e707SThomas Veerman int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
4715ea9e707SThomas Veerman {
4725ea9e707SThomas Veerman /* this relies on having fields[] the same length as $0 */
4735ea9e707SThomas Veerman /* the fields are all stored in this one array with \0's */
4745ea9e707SThomas Veerman char *fr;
4755ea9e707SThomas Veerman int i, tempstat, n;
4765ea9e707SThomas Veerman fa *pfa;
4775ea9e707SThomas Veerman
4785ea9e707SThomas Veerman n = strlen(rec);
4795ea9e707SThomas Veerman if (n > fieldssize) {
4805ea9e707SThomas Veerman xfree(fields);
4815ea9e707SThomas Veerman if ((fields = malloc(n+1)) == NULL)
4825ea9e707SThomas Veerman FATAL("out of space for fields in refldbld %d", n);
4835ea9e707SThomas Veerman fieldssize = n;
4845ea9e707SThomas Veerman }
4855ea9e707SThomas Veerman fr = fields;
4865ea9e707SThomas Veerman *fr = '\0';
4875ea9e707SThomas Veerman if (*rec == '\0')
4885ea9e707SThomas Veerman return 0;
4895ea9e707SThomas Veerman pfa = makedfa(fs, 1);
4905ea9e707SThomas Veerman dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
4915ea9e707SThomas Veerman tempstat = pfa->initstat;
4925ea9e707SThomas Veerman for (i = 1; ; i++) {
4935ea9e707SThomas Veerman if (i > nfields)
4945ea9e707SThomas Veerman growfldtab(i);
4955ea9e707SThomas Veerman if (freeable(fldtab[i]))
4965ea9e707SThomas Veerman xfree(fldtab[i]->sval);
4975ea9e707SThomas Veerman fldtab[i]->tval = FLD | STR | DONTFREE;
4985ea9e707SThomas Veerman fldtab[i]->sval = fr;
4995ea9e707SThomas Veerman dprintf( ("refldbld: i=%d\n", i) );
5005ea9e707SThomas Veerman if (nematch(pfa, rec)) {
5015ea9e707SThomas Veerman pfa->initstat = 2; /* horrible coupling to b.c */
5025ea9e707SThomas Veerman dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
5035ea9e707SThomas Veerman strncpy(fr, rec, ((const char*)patbeg)-rec);
5045ea9e707SThomas Veerman fr += ((const char*)patbeg) - rec + 1;
5055ea9e707SThomas Veerman *(fr-1) = '\0';
5065ea9e707SThomas Veerman rec = patbeg + patlen;
5075ea9e707SThomas Veerman } else {
5085ea9e707SThomas Veerman dprintf( ("no match %s\n", rec) );
5095ea9e707SThomas Veerman strcpy(fr, rec);
5105ea9e707SThomas Veerman pfa->initstat = tempstat;
5115ea9e707SThomas Veerman break;
5125ea9e707SThomas Veerman }
5135ea9e707SThomas Veerman }
5145ea9e707SThomas Veerman return i;
5155ea9e707SThomas Veerman }
5165ea9e707SThomas Veerman
recbld(void)5175ea9e707SThomas Veerman void recbld(void) /* create $0 from $1..$NF if necessary */
5185ea9e707SThomas Veerman {
5195ea9e707SThomas Veerman int i;
5205ea9e707SThomas Veerman uschar *r;
5215ea9e707SThomas Veerman char *p;
5225ea9e707SThomas Veerman
5235ea9e707SThomas Veerman if (donerec == 1)
5245ea9e707SThomas Veerman return;
5255ea9e707SThomas Veerman r = record;
5265ea9e707SThomas Veerman for (i = 1; i <= *NF; i++) {
5275ea9e707SThomas Veerman p = getsval(fldtab[i]);
5285ea9e707SThomas Veerman if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
5295ea9e707SThomas Veerman FATAL("created $0 `%.30s...' too long", record);
5305ea9e707SThomas Veerman while ((*r = *p++) != 0)
5315ea9e707SThomas Veerman r++;
5325ea9e707SThomas Veerman if (i < *NF) {
5335ea9e707SThomas Veerman if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
5345ea9e707SThomas Veerman FATAL("created $0 `%.30s...' too long", record);
5355ea9e707SThomas Veerman for (p = *OFS; (*r = *p++) != 0; )
5365ea9e707SThomas Veerman r++;
5375ea9e707SThomas Veerman }
5385ea9e707SThomas Veerman }
5395ea9e707SThomas Veerman if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
5405ea9e707SThomas Veerman FATAL("built giant record `%.30s...'", record);
5415ea9e707SThomas Veerman *r = '\0';
5425ea9e707SThomas Veerman dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
5435ea9e707SThomas Veerman
5445ea9e707SThomas Veerman if (freeable(fldtab[0]))
5455ea9e707SThomas Veerman xfree(fldtab[0]->sval);
5465ea9e707SThomas Veerman fldtab[0]->tval = REC | STR | DONTFREE;
5475ea9e707SThomas Veerman fldtab[0]->sval = record;
5485ea9e707SThomas Veerman
5495ea9e707SThomas Veerman dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
5505ea9e707SThomas Veerman dprintf( ("recbld = |%s|\n", record) );
5515ea9e707SThomas Veerman donerec = 1;
5525ea9e707SThomas Veerman }
5535ea9e707SThomas Veerman
5545ea9e707SThomas Veerman int errorflag = 0;
5555ea9e707SThomas Veerman
yyerror(const char * s)5565ea9e707SThomas Veerman void yyerror(const char *s)
5575ea9e707SThomas Veerman {
5585ea9e707SThomas Veerman SYNTAX("%s", s);
5595ea9e707SThomas Veerman }
5605ea9e707SThomas Veerman
SYNTAX(const char * fmt,...)5615ea9e707SThomas Veerman void SYNTAX(const char *fmt, ...)
5625ea9e707SThomas Veerman {
5635ea9e707SThomas Veerman extern char *cmdname, *curfname;
5645ea9e707SThomas Veerman static int been_here = 0;
5655ea9e707SThomas Veerman va_list varg;
5665ea9e707SThomas Veerman
5675ea9e707SThomas Veerman if (been_here++ > 2)
5685ea9e707SThomas Veerman return;
5695ea9e707SThomas Veerman fprintf(stderr, "%s: ", cmdname);
5705ea9e707SThomas Veerman va_start(varg, fmt);
5715ea9e707SThomas Veerman vfprintf(stderr, fmt, varg);
5725ea9e707SThomas Veerman va_end(varg);
5735ea9e707SThomas Veerman fprintf(stderr, " at source line %d", lineno);
5745ea9e707SThomas Veerman if (curfname != NULL)
5755ea9e707SThomas Veerman fprintf(stderr, " in function %s", curfname);
5765ea9e707SThomas Veerman if (compile_time == 1 && cursource() != NULL)
5775ea9e707SThomas Veerman fprintf(stderr, " source file %s", cursource());
5785ea9e707SThomas Veerman fprintf(stderr, "\n");
5795ea9e707SThomas Veerman errorflag = 2;
5805ea9e707SThomas Veerman eprint();
5815ea9e707SThomas Veerman }
5825ea9e707SThomas Veerman
5835ea9e707SThomas Veerman extern int bracecnt, brackcnt, parencnt;
5845ea9e707SThomas Veerman
bracecheck(void)5855ea9e707SThomas Veerman void bracecheck(void)
5865ea9e707SThomas Veerman {
5875ea9e707SThomas Veerman int c;
5885ea9e707SThomas Veerman static int beenhere = 0;
5895ea9e707SThomas Veerman
5905ea9e707SThomas Veerman if (beenhere++)
5915ea9e707SThomas Veerman return;
5925ea9e707SThomas Veerman while ((c = input()) != EOF && c != '\0')
5935ea9e707SThomas Veerman bclass(c);
5945ea9e707SThomas Veerman bcheck2(bracecnt, '{', '}');
5955ea9e707SThomas Veerman bcheck2(brackcnt, '[', ']');
5965ea9e707SThomas Veerman bcheck2(parencnt, '(', ')');
5975ea9e707SThomas Veerman }
5985ea9e707SThomas Veerman
bcheck2(int n,int c1,int c2)5995ea9e707SThomas Veerman void bcheck2(int n, int c1, int c2)
6005ea9e707SThomas Veerman {
6015ea9e707SThomas Veerman if (n == 1)
6025ea9e707SThomas Veerman fprintf(stderr, "\tmissing %c\n", c2);
6035ea9e707SThomas Veerman else if (n > 1)
6045ea9e707SThomas Veerman fprintf(stderr, "\t%d missing %c's\n", n, c2);
6055ea9e707SThomas Veerman else if (n == -1)
6065ea9e707SThomas Veerman fprintf(stderr, "\textra %c\n", c2);
6075ea9e707SThomas Veerman else if (n < -1)
6085ea9e707SThomas Veerman fprintf(stderr, "\t%d extra %c's\n", -n, c2);
6095ea9e707SThomas Veerman }
6105ea9e707SThomas Veerman
FATAL(const char * fmt,...)6115ea9e707SThomas Veerman void FATAL(const char *fmt, ...)
6125ea9e707SThomas Veerman {
6135ea9e707SThomas Veerman extern char *cmdname;
6145ea9e707SThomas Veerman va_list varg;
6155ea9e707SThomas Veerman
6165ea9e707SThomas Veerman fflush(stdout);
6175ea9e707SThomas Veerman fprintf(stderr, "%s: ", cmdname);
6185ea9e707SThomas Veerman va_start(varg, fmt);
6195ea9e707SThomas Veerman vfprintf(stderr, fmt, varg);
6205ea9e707SThomas Veerman va_end(varg);
6215ea9e707SThomas Veerman error();
6225ea9e707SThomas Veerman if (dbg > 1) /* core dump if serious debugging on */
6235ea9e707SThomas Veerman abort();
6245ea9e707SThomas Veerman exit(2);
6255ea9e707SThomas Veerman }
6265ea9e707SThomas Veerman
WARNING(const char * fmt,...)6275ea9e707SThomas Veerman void WARNING(const char *fmt, ...)
6285ea9e707SThomas Veerman {
6295ea9e707SThomas Veerman extern char *cmdname;
6305ea9e707SThomas Veerman va_list varg;
6315ea9e707SThomas Veerman
6325ea9e707SThomas Veerman fflush(stdout);
6335ea9e707SThomas Veerman fprintf(stderr, "%s: ", cmdname);
6345ea9e707SThomas Veerman va_start(varg, fmt);
6355ea9e707SThomas Veerman vfprintf(stderr, fmt, varg);
6365ea9e707SThomas Veerman va_end(varg);
6375ea9e707SThomas Veerman error();
6385ea9e707SThomas Veerman }
6395ea9e707SThomas Veerman
error()6405ea9e707SThomas Veerman void error()
6415ea9e707SThomas Veerman {
6425ea9e707SThomas Veerman extern Node *curnode;
6435ea9e707SThomas Veerman
6445ea9e707SThomas Veerman fprintf(stderr, "\n");
6455ea9e707SThomas Veerman if (compile_time != 2 && NR && *NR > 0) {
6465ea9e707SThomas Veerman fprintf(stderr, " input record number %d", (int) (*FNR));
6475ea9e707SThomas Veerman if (strcmp(*FILENAME, "-") != 0)
6485ea9e707SThomas Veerman fprintf(stderr, ", file %s", *FILENAME);
6495ea9e707SThomas Veerman fprintf(stderr, "\n");
6505ea9e707SThomas Veerman }
6515ea9e707SThomas Veerman if (compile_time != 2 && curnode)
6525ea9e707SThomas Veerman fprintf(stderr, " source line number %d", curnode->lineno);
6535ea9e707SThomas Veerman else if (compile_time != 2 && lineno)
6545ea9e707SThomas Veerman fprintf(stderr, " source line number %d", lineno);
6555ea9e707SThomas Veerman if (compile_time == 1 && cursource() != NULL)
6565ea9e707SThomas Veerman fprintf(stderr, " source file %s", cursource());
6575ea9e707SThomas Veerman fprintf(stderr, "\n");
6585ea9e707SThomas Veerman eprint();
6595ea9e707SThomas Veerman }
6605ea9e707SThomas Veerman
eprint(void)6615ea9e707SThomas Veerman void eprint(void) /* try to print context around error */
6625ea9e707SThomas Veerman {
6635ea9e707SThomas Veerman char *p, *q;
6645ea9e707SThomas Veerman static int been_here = 0;
6655ea9e707SThomas Veerman extern char ebuf[], *ep;
6665ea9e707SThomas Veerman
6675ea9e707SThomas Veerman if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
6685ea9e707SThomas Veerman return;
6695ea9e707SThomas Veerman p = ep - 1;
6705ea9e707SThomas Veerman if (p > ebuf && *p == '\n')
6715ea9e707SThomas Veerman p--;
6725ea9e707SThomas Veerman for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
6735ea9e707SThomas Veerman ;
6745ea9e707SThomas Veerman while (*p == '\n')
6755ea9e707SThomas Veerman p++;
6765ea9e707SThomas Veerman fprintf(stderr, " context is\n\t");
6775ea9e707SThomas Veerman for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
6785ea9e707SThomas Veerman ;
6795ea9e707SThomas Veerman for ( ; p < q; p++)
6805ea9e707SThomas Veerman if (*p)
6815ea9e707SThomas Veerman putc(*p, stderr);
6825ea9e707SThomas Veerman fprintf(stderr, " >>> ");
6835ea9e707SThomas Veerman for ( ; p < ep; p++)
6845ea9e707SThomas Veerman if (*p)
6855ea9e707SThomas Veerman putc(*p, stderr);
6865ea9e707SThomas Veerman fprintf(stderr, " <<< ");
6875ea9e707SThomas Veerman #if 0
6885ea9e707SThomas Veerman /*
6895ea9e707SThomas Veerman * The following code was used to print the rest of the line of
6905ea9e707SThomas Veerman * error context. It naively counts brackets, parens and braces in
6915ea9e707SThomas Veerman * order to minimize the parsing effect of dropping the rest of the
6925ea9e707SThomas Veerman * line but it does not work in all the cases. It is too much work
6935ea9e707SThomas Veerman * to save the current program input point and restore it in all the
6945ea9e707SThomas Veerman * cases just for the benefit of error printing so for now this
6955ea9e707SThomas Veerman * code is disabled. In particular this code is confused if the
6965ea9e707SThomas Veerman * [ { ( ) } ] is inside a quoted string or a pattern.
6975ea9e707SThomas Veerman */
6985ea9e707SThomas Veerman if (*ep) {
6995ea9e707SThomas Veerman int c;
7005ea9e707SThomas Veerman while ((c = input()) != '\n' && c != '\0' && c != EOF) {
7015ea9e707SThomas Veerman putc(c, stderr);
7025ea9e707SThomas Veerman bclass(c);
7035ea9e707SThomas Veerman }
7045ea9e707SThomas Veerman }
7055ea9e707SThomas Veerman #endif
7065ea9e707SThomas Veerman putc('\n', stderr);
7075ea9e707SThomas Veerman ep = ebuf;
7085ea9e707SThomas Veerman }
7095ea9e707SThomas Veerman
bclass(int c)7105ea9e707SThomas Veerman void bclass(int c)
7115ea9e707SThomas Veerman {
7125ea9e707SThomas Veerman switch (c) {
7135ea9e707SThomas Veerman case '{': bracecnt++; break;
7145ea9e707SThomas Veerman case '}': bracecnt--; break;
7155ea9e707SThomas Veerman case '[': brackcnt++; break;
7165ea9e707SThomas Veerman case ']': brackcnt--; break;
7175ea9e707SThomas Veerman case '(': parencnt++; break;
7185ea9e707SThomas Veerman case ')': parencnt--; break;
7195ea9e707SThomas Veerman }
7205ea9e707SThomas Veerman }
7215ea9e707SThomas Veerman
errcheck(double x,const char * s)7225ea9e707SThomas Veerman double errcheck(double x, const char *s)
7235ea9e707SThomas Veerman {
7245ea9e707SThomas Veerman
7255ea9e707SThomas Veerman if (errno == EDOM) {
7265ea9e707SThomas Veerman errno = 0;
7275ea9e707SThomas Veerman WARNING("%s argument out of domain", s);
7285ea9e707SThomas Veerman x = 1;
7295ea9e707SThomas Veerman } else if (errno == ERANGE) {
7305ea9e707SThomas Veerman errno = 0;
7315ea9e707SThomas Veerman WARNING("%s result out of range", s);
7325ea9e707SThomas Veerman x = 1;
7335ea9e707SThomas Veerman }
7345ea9e707SThomas Veerman return x;
7355ea9e707SThomas Veerman }
7365ea9e707SThomas Veerman
isclvar(const char * s)7375ea9e707SThomas Veerman int isclvar(const char *s) /* is s of form var=something ? */
7385ea9e707SThomas Veerman {
7395ea9e707SThomas Veerman const char *os = s;
7405ea9e707SThomas Veerman
7415ea9e707SThomas Veerman if (!isalpha((uschar) *s) && *s != '_')
7425ea9e707SThomas Veerman return 0;
7435ea9e707SThomas Veerman for ( ; *s; s++)
7445ea9e707SThomas Veerman if (!(isalnum((uschar) *s) || *s == '_'))
7455ea9e707SThomas Veerman break;
7465ea9e707SThomas Veerman return *s == '=' && s > os && *(s+1) != '=';
7475ea9e707SThomas Veerman }
7485ea9e707SThomas Veerman
7495ea9e707SThomas Veerman /* strtod is supposed to be a proper test of what's a valid number */
7505ea9e707SThomas Veerman /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
7515ea9e707SThomas Veerman /* wrong: violates 4.10.1.4 of ansi C standard */
7525ea9e707SThomas Veerman
7535ea9e707SThomas Veerman #include <math.h>
is_number(const char * s)7545ea9e707SThomas Veerman int is_number(const char *s)
7555ea9e707SThomas Veerman {
7565ea9e707SThomas Veerman char *ep;
7575ea9e707SThomas Veerman errno = 0;
758*84d9c625SLionel Sambuc (void)strtod(s, &ep);
7595ea9e707SThomas Veerman if (ep == s || errno == ERANGE)
7605ea9e707SThomas Veerman return 0;
7615ea9e707SThomas Veerman if (ep - s >= 3 && strncasecmp(ep - 3, "nan", 3) == 0)
7625ea9e707SThomas Veerman return 0;
7635ea9e707SThomas Veerman while (*ep == ' ' || *ep == '\t' || *ep == '\n')
7645ea9e707SThomas Veerman ep++;
7655ea9e707SThomas Veerman if (*ep == '\0')
7665ea9e707SThomas Veerman return 1;
7675ea9e707SThomas Veerman else
7685ea9e707SThomas Veerman return 0;
7695ea9e707SThomas Veerman }
770