Blame node.c

Packit Service f629e6
/*
Packit Service f629e6
 * node.c -- routines for node management
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 1986, 1988, 1989, 1991-2001, 2003-2015, 2017, 2018,
Packit Service f629e6
 * the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
#include "awk.h"
Packit Service f629e6
#include "math.h"
Packit Service f629e6
#include "floatmagic.h"	/* definition of isnan */
Packit Service f629e6
Packit Service f629e6
static int is_ieee_magic_val(const char *val);
Packit Service f629e6
static NODE *r_make_number(double x);
Packit Service f629e6
static AWKNUM get_ieee_magic_val(char *val);
Packit Service f629e6
extern NODE **fmt_list;          /* declared in eval.c */
Packit Service f629e6
Packit Service f629e6
NODE *(*make_number)(double) = r_make_number;
Packit Service f629e6
NODE *(*str2number)(NODE *) = r_force_number;
Packit Service f629e6
NODE *(*format_val)(const char *, int, NODE *) = r_format_val;
Packit Service f629e6
int (*cmp_numbers)(const NODE *, const NODE *) = cmp_awknums;
Packit Service f629e6
Packit Service f629e6
/* is_hex --- return true if a string looks like a hex value */
Packit Service f629e6
Packit Service f629e6
static bool
Packit Service f629e6
is_hex(const char *str, const char *cpend)
Packit Service f629e6
{
Packit Service f629e6
	/* on entry, we know the string length is >= 1 */
Packit Service f629e6
	if (*str == '-' || *str == '+')
Packit Service f629e6
		str++;
Packit Service f629e6
Packit Service f629e6
	if (str + 1 < cpend && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
Packit Service f629e6
		return true;
Packit Service f629e6
Packit Service f629e6
	return false;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* force_number --- force a value to be numeric */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
r_force_number(NODE *n)
Packit Service f629e6
{
Packit Service f629e6
	char *cp;
Packit Service f629e6
	char *cpend;
Packit Service f629e6
	char save;
Packit Service f629e6
	char *ptr;
Packit Service f629e6
	extern double strtod();
Packit Service f629e6
Packit Service f629e6
	if ((n->flags & NUMCUR) != 0)
Packit Service f629e6
		return n;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * We should always set NUMCUR. If USER_INPUT is set and it's a
Packit Service f629e6
	 * numeric string, we clear STRING and enable NUMBER, but if it's not
Packit Service f629e6
	 * numeric, we disable USER_INPUT.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	/* All the conditionals are an attempt to avoid the expensive strtod */
Packit Service f629e6
Packit Service f629e6
	n->flags |= NUMCUR;
Packit Service f629e6
	n->numbr = 0.0;
Packit Service f629e6
Packit Service f629e6
	/* Trim leading white space, bailing out if there's nothing else */
Packit Service f629e6
	for (cp = n->stptr, cpend = cp + n->stlen;
Packit Service f629e6
	     cp < cpend && isspace((unsigned char) *cp); cp++)
Packit Service f629e6
		continue;
Packit Service f629e6
Packit Service f629e6
	if (cp == cpend)
Packit Service f629e6
		goto badnum;
Packit Service f629e6
Packit Service f629e6
	/* At this point, we know the string is not entirely white space */
Packit Service f629e6
	/* Trim trailing white space */
Packit Service f629e6
	while (isspace((unsigned char) cpend[-1]))
Packit Service f629e6
		cpend--;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * 2/2007:
Packit Service f629e6
	 * POSIX, by way of severe language lawyering, seems to
Packit Service f629e6
	 * allow things like "inf" and "nan" to mean something.
Packit Service f629e6
	 * So if do_posix, the user gets what he deserves.
Packit Service f629e6
	 * This also allows hexadecimal floating point. Ugh.
Packit Service f629e6
	 */
Packit Service f629e6
	if (! do_posix) {
Packit Service f629e6
		if (is_alpha((unsigned char) *cp))
Packit Service f629e6
			goto badnum;
Packit Service f629e6
		else if (cpend == cp+4 && is_ieee_magic_val(cp)) {
Packit Service f629e6
			n->numbr = get_ieee_magic_val(cp);
Packit Service f629e6
			goto goodnum;
Packit Service f629e6
		}
Packit Service f629e6
		/* else
Packit Service f629e6
			fall through */
Packit Service f629e6
	}
Packit Service f629e6
	/* else POSIX, so
Packit Service f629e6
		fall through */
Packit Service f629e6
Packit Service f629e6
	if (   (! do_posix		/* not POSIXLY paranoid and */
Packit Service f629e6
	        && (is_alpha((unsigned char) *cp)	/* letter, or */
Packit Service f629e6
					/* CANNOT do non-decimal and saw 0x */
Packit Service f629e6
		    || (! do_non_decimal_data && is_hex(cp, cpend))))) {
Packit Service f629e6
		goto badnum;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (cpend - cp == 1) {		/* only one character */
Packit Service f629e6
		if (isdigit((unsigned char) *cp)) {	/* it's a digit! */
Packit Service f629e6
			n->numbr = (AWKNUM)(*cp - '0');
Packit Service f629e6
			if (n->stlen == 1)		/* no white space */
Packit Service f629e6
				n->flags |= NUMINT;
Packit Service f629e6
			goto goodnum;
Packit Service f629e6
		}
Packit Service f629e6
		goto badnum;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	errno = 0;
Packit Service f629e6
	if (do_non_decimal_data		/* main.c assures false if do_posix */
Packit Service f629e6
		&& ! do_traditional && get_numbase(cp, cpend - cp, true) != 10) {
Packit Service f629e6
		/* nondec2awknum() saves and restores the byte after the string itself */
Packit Service f629e6
		n->numbr = nondec2awknum(cp, cpend - cp, &ptr);
Packit Service f629e6
	} else {
Packit Service f629e6
		save = *cpend;
Packit Service f629e6
		*cpend = '\0';
Packit Service f629e6
		n->numbr = (AWKNUM) strtod((const char *) cp, &ptr);
Packit Service f629e6
		*cpend = save;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (errno == 0) {
Packit Service f629e6
		if (ptr == cpend)
Packit Service f629e6
			goto goodnum;
Packit Service f629e6
		/* else keep the leading numeric value without updating flags */
Packit Service f629e6
		/* fall through to badnum */
Packit Service f629e6
	} else {
Packit Service f629e6
		errno = 0;
Packit Service f629e6
		/*
Packit Service f629e6
		 * N.B. For subnormal values, strtod may return the
Packit Service f629e6
		 * floating-point representation while setting errno to ERANGE.
Packit Service f629e6
		 * We force the numeric value to 0 in such cases.
Packit Service f629e6
		 */
Packit Service f629e6
		n->numbr = 0;
Packit Service f629e6
		/*
Packit Service f629e6
		 * Or should we accept it as a NUMBER even though strtod
Packit Service f629e6
		 * threw an error?
Packit Service f629e6
		 */
Packit Service f629e6
		/* fall through to badnum */
Packit Service f629e6
	}
Packit Service f629e6
badnum:
Packit Service f629e6
	n->flags &= ~USER_INPUT;
Packit Service f629e6
	return n;
Packit Service f629e6
Packit Service f629e6
goodnum:
Packit Service f629e6
	if ((n->flags & USER_INPUT) != 0) {
Packit Service f629e6
		/* leave USER_INPUT enabled to indicate that this is a strnum */
Packit Service f629e6
		n->flags &= ~STRING;
Packit Service f629e6
		n->flags |= NUMBER;
Packit Service f629e6
	}
Packit Service f629e6
	return n;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * The following lookup table is used as an optimization in force_string;
Packit Service f629e6
 * (more complicated) variations on this theme didn't seem to pay off, but
Packit Service f629e6
 * systematic testing might be in order at some point.
Packit Service f629e6
 */
Packit Service f629e6
static const char *values[] = {
Packit Service f629e6
	"0",
Packit Service f629e6
	"1",
Packit Service f629e6
	"2",
Packit Service f629e6
	"3",
Packit Service f629e6
	"4",
Packit Service f629e6
	"5",
Packit Service f629e6
	"6",
Packit Service f629e6
	"7",
Packit Service f629e6
	"8",
Packit Service f629e6
	"9",
Packit Service f629e6
};
Packit Service f629e6
#define	NVAL	(sizeof(values)/sizeof(values[0]))
Packit Service f629e6
Packit Service f629e6
/* r_format_val --- format a numeric value based on format */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
r_format_val(const char *format, int index, NODE *s)
Packit Service f629e6
{
Packit Service f629e6
	char buf[BUFSIZ];
Packit Service f629e6
	char *sp = buf;
Packit Service f629e6
	double val;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * 2/2007: Simplify our lives here. Instead of worrying about
Packit Service f629e6
	 * whether or not the value will fit into a long just so we
Packit Service f629e6
	 * can use sprintf("%ld", val) on it, always format it ourselves.
Packit Service f629e6
	 * The only thing to worry about is that integral values always
Packit Service f629e6
	 * format as integers. %.0f does that very well.
Packit Service f629e6
	 *
Packit Service f629e6
	 * 6/2008: Would that things were so simple. Always using %.0f
Packit Service f629e6
	 * imposes a notable performance penalty for applications that
Packit Service f629e6
	 * do a lot of conversion of integers to strings. So, we reinstate
Packit Service f629e6
	 * the old code, but use %.0f for integral values that are outside
Packit Service f629e6
	 * the range of a long.  This seems a reasonable compromise.
Packit Service f629e6
	 *
Packit Service f629e6
	 * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
Packit Service f629e6
	 * < and > so that things work correctly on systems with 64 bit integers.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	/* not an integral value, or out of range */
Packit Service f629e6
	if ((val = double_to_int(s->numbr)) != s->numbr
Packit Service f629e6
			|| val <= LONG_MIN || val >= LONG_MAX
Packit Service f629e6
	) {
Packit Service f629e6
		/*
Packit Service f629e6
		 * Once upon a time, we just blindly did this:
Packit Service f629e6
		 *	sprintf(sp, format, s->numbr);
Packit Service f629e6
		 *	s->stlen = strlen(sp);
Packit Service f629e6
		 *	s->stfmt = index;
Packit Service f629e6
		 * but that's no good if, e.g., OFMT is %s. So we punt,
Packit Service f629e6
		 * and just always format the value ourselves.
Packit Service f629e6
		 */
Packit Service f629e6
Packit Service f629e6
		NODE *dummy[2], *r;
Packit Service f629e6
		unsigned int oflags;
Packit Service f629e6
Packit Service f629e6
		/* create dummy node for a sole use of format_tree */
Packit Service f629e6
		dummy[1] = s;
Packit Service f629e6
		oflags = s->flags;
Packit Service f629e6
Packit Service f629e6
		if (val == s->numbr) {
Packit Service f629e6
			/* integral value, but outside range of %ld, use %.0f */
Packit Service f629e6
			r = format_tree("%.0f", 4, dummy, 2);
Packit Service f629e6
			s->stfmt = STFMT_UNUSED;
Packit Service f629e6
		} else {
Packit Service f629e6
			r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
Packit Service f629e6
			assert(r != NULL);
Packit Service f629e6
			s->stfmt = index;
Packit Service f629e6
		}
Packit Service f629e6
		s->flags = oflags;
Packit Service f629e6
		s->stlen = r->stlen;
Packit Service f629e6
		if ((s->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
Packit Service f629e6
			efree(s->stptr);
Packit Service f629e6
		s->stptr = r->stptr;
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
		s->strndmode = MPFR_round_mode;
Packit Service f629e6
#endif
Packit Service f629e6
		freenode(r);	/* Do not unref(r)! We want to keep s->stptr == r->stpr.  */
Packit Service f629e6
Packit Service f629e6
		goto no_malloc;
Packit Service f629e6
	} else {
Packit Service f629e6
		/*
Packit Service f629e6
		 * integral value; force conversion to long only once.
Packit Service f629e6
		 */
Packit Service f629e6
		long num = (long) val;
Packit Service f629e6
Packit Service f629e6
		if (num < NVAL && num >= 0) {
Packit Service f629e6
			sp = (char *) values[num];
Packit Service f629e6
			s->stlen = 1;
Packit Service f629e6
		} else {
Packit Service f629e6
			(void) sprintf(sp, "%ld", num);
Packit Service f629e6
			s->stlen = strlen(sp);
Packit Service f629e6
		}
Packit Service f629e6
		s->stfmt = STFMT_UNUSED;
Packit Service f629e6
		if ((s->flags & INTIND) != 0) {
Packit Service f629e6
			s->flags &= ~(INTIND|NUMBER);
Packit Service f629e6
			s->flags |= STRING;
Packit Service f629e6
		}
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
		s->strndmode = MPFR_round_mode;
Packit Service f629e6
#endif
Packit Service f629e6
	}
Packit Service f629e6
	if ((s->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
Packit Service f629e6
		efree(s->stptr);
Packit Service f629e6
	emalloc(s->stptr, char *, s->stlen + 1, "format_val");
Packit Service f629e6
	memcpy(s->stptr, sp, s->stlen + 1);
Packit Service f629e6
no_malloc:
Packit Service f629e6
	s->flags |= STRCUR;
Packit Service f629e6
	free_wstr(s);
Packit Service f629e6
	return s;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* r_dupnode --- duplicate a node */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
r_dupnode(NODE *n)
Packit Service f629e6
{
Packit Service f629e6
	NODE *r;
Packit Service f629e6
Packit Service f629e6
	assert(n->type == Node_val);
Packit Service f629e6
Packit Service f629e6
#ifdef GAWKDEBUG
Packit Service f629e6
	if ((n->flags & MALLOC) != 0) {
Packit Service f629e6
		n->valref++;
Packit Service f629e6
		return n;
Packit Service f629e6
	}
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	getnode(r);
Packit Service f629e6
	*r = *n;
Packit Service f629e6
	r->flags |= MALLOC;
Packit Service f629e6
	r->valref = 1;
Packit Service f629e6
	/*
Packit Service f629e6
	 * DON'T call free_wstr(r) here!
Packit Service f629e6
	 * r->wstptr still points at n->wstptr's value, and we
Packit Service f629e6
	 * don't want to free it!
Packit Service f629e6
	 */
Packit Service f629e6
	r->wstptr = NULL;
Packit Service f629e6
	r->wstlen = 0;
Packit Service f629e6
Packit Service f629e6
	if ((n->flags & STRCUR) != 0) {
Packit Service f629e6
		emalloc(r->stptr, char *, n->stlen + 1, "r_dupnode");
Packit Service f629e6
		memcpy(r->stptr, n->stptr, n->stlen);
Packit Service f629e6
		r->stptr[n->stlen] = '\0';
Packit Service f629e6
		if ((n->flags & WSTRCUR) != 0) {
Packit Service f629e6
			r->wstlen = n->wstlen;
Packit Service f629e6
			emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 1), "r_dupnode");
Packit Service f629e6
			memcpy(r->wstptr, n->wstptr, n->wstlen * sizeof(wchar_t));
Packit Service f629e6
			r->wstptr[n->wstlen] = L'\0';
Packit Service f629e6
			r->flags |= WSTRCUR;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return r;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* r_make_number --- allocate a node with defined number */
Packit Service f629e6
Packit Service f629e6
static NODE *
Packit Service f629e6
r_make_number(double x)
Packit Service f629e6
{
Packit Service f629e6
	NODE *r = make_number_node(0);
Packit Service f629e6
	r->numbr = x;
Packit Service f629e6
	return r;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* cmp_awknums --- compare two AWKNUMs */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
cmp_awknums(const NODE *t1, const NODE *t2)
Packit Service f629e6
{
Packit Service f629e6
	/*
Packit Service f629e6
	 * This routine is also used to sort numeric array indices or values.
Packit Service f629e6
	 * For the purposes of sorting, NaN is considered greater than
Packit Service f629e6
	 * any other value, and all NaN values are considered equivalent and equal.
Packit Service f629e6
	 * This isn't in compliance with IEEE standard, but compliance w.r.t. NaN
Packit Service f629e6
	 * comparison at the awk level is a different issue, and needs to be dealt
Packit Service f629e6
	 * with in the interpreter for each opcode seperately.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	if (isnan(t1->numbr))
Packit Service f629e6
		return ! isnan(t2->numbr);
Packit Service f629e6
	if (isnan(t2->numbr))
Packit Service f629e6
		return -1;
Packit Service f629e6
	/* don't subtract, in case one or both are infinite */
Packit Service f629e6
	if (t1->numbr == t2->numbr)
Packit Service f629e6
		return 0;
Packit Service f629e6
	if (t1->numbr < t2->numbr)
Packit Service f629e6
		return -1;
Packit Service f629e6
	return 1;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* make_str_node --- make a string node */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
make_str_node(const char *s, size_t len, int flags)
Packit Service f629e6
{
Packit Service f629e6
	NODE *r;
Packit Service f629e6
	getnode(r);
Packit Service f629e6
	r->type = Node_val;
Packit Service f629e6
	r->numbr = 0;
Packit Service f629e6
	r->flags = (MALLOC|STRING|STRCUR);
Packit Service f629e6
	r->valref = 1;
Packit Service f629e6
	r->stfmt = STFMT_UNUSED;
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	r->strndmode = MPFR_round_mode;
Packit Service f629e6
#endif
Packit Service f629e6
	r->wstptr = NULL;
Packit Service f629e6
	r->wstlen = 0;
Packit Service f629e6
Packit Service f629e6
	if ((flags & ALREADY_MALLOCED) != 0)
Packit Service f629e6
		r->stptr = (char *) s;
Packit Service f629e6
	else {
Packit Service f629e6
		emalloc(r->stptr, char *, len + 1, "make_str_node");
Packit Service f629e6
		memcpy(r->stptr, s, len);
Packit Service f629e6
	}
Packit Service f629e6
	r->stptr[len] = '\0';
Packit Service f629e6
Packit Service f629e6
	if ((flags & SCAN) != 0) {	/* scan for escape sequences */
Packit Service f629e6
		const char *pf;
Packit Service f629e6
		char *ptm;
Packit Service f629e6
		int c;
Packit Service f629e6
		const char *end;
Packit Service f629e6
		mbstate_t cur_state;
Packit Service f629e6
Packit Service f629e6
		memset(& cur_state, 0, sizeof(cur_state));
Packit Service f629e6
Packit Service f629e6
		end = &(r->stptr[len]);
Packit Service f629e6
		for (pf = ptm = r->stptr; pf < end;) {
Packit Service f629e6
			/*
Packit Service f629e6
			 * Keep multibyte characters together. This avoids
Packit Service f629e6
			 * problems if a subsequent byte of a multibyte
Packit Service f629e6
			 * character happens to be a backslash.
Packit Service f629e6
			 */
Packit Service f629e6
			if (gawk_mb_cur_max > 1) {
Packit Service f629e6
				int mblen = mbrlen(pf, end-pf, &cur_state);
Packit Service f629e6
Packit Service f629e6
				if (mblen > 1) {
Packit Service f629e6
					int i;
Packit Service f629e6
Packit Service f629e6
					for (i = 0; i < mblen; i++)
Packit Service f629e6
						*ptm++ = *pf++;
Packit Service f629e6
					continue;
Packit Service f629e6
				}
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			c = *pf++;
Packit Service f629e6
			if (c == '\\') {
Packit Service f629e6
				c = parse_escape(&pf);
Packit Service f629e6
				if (c < 0) {
Packit Service f629e6
					if (do_lint)
Packit Service f629e6
						lintwarn(_("backslash at end of string"));
Packit Service f629e6
					c = '\\';
Packit Service f629e6
				}
Packit Service f629e6
				*ptm++ = c;
Packit Service f629e6
			} else
Packit Service f629e6
				*ptm++ = c;
Packit Service f629e6
		}
Packit Service f629e6
		len = ptm - r->stptr;
Packit Service f629e6
		erealloc(r->stptr, char *, len + 1, "make_str_node");
Packit Service f629e6
		r->stptr[len] = '\0';
Packit Service f629e6
	}
Packit Service f629e6
	r->stlen = len;
Packit Service f629e6
Packit Service f629e6
	return r;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* make_typed_regex --- make a typed regex node */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
make_typed_regex(const char *re, size_t len)
Packit Service f629e6
{
Packit Service f629e6
	NODE *n, *exp, *n2;
Packit Service f629e6
Packit Service f629e6
	exp = make_str_node(re, len, ALREADY_MALLOCED);
Packit Service f629e6
	n = make_regnode(Node_regex, exp);
Packit Service f629e6
	if (n == NULL)
Packit Service f629e6
		fatal(_("could not make typed regex"));
Packit Service f629e6
Packit Service f629e6
	n2 = make_string(re, len);
Packit Service f629e6
	n2->typed_re = n;
Packit Service f629e6
	n2->numbr = 0;
Packit Service f629e6
	n2->flags |= NUMCUR|STRCUR|REGEX; 
Packit Service f629e6
	n2->flags &= ~(STRING|NUMBER);
Packit Service f629e6
Packit Service f629e6
	return n2;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* unref --- remove reference to a particular node */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
r_unref(NODE *tmp)
Packit Service f629e6
{
Packit Service f629e6
#ifdef GAWKDEBUG
Packit Service f629e6
	if (tmp == NULL)
Packit Service f629e6
		return;
Packit Service f629e6
	if ((tmp->flags & MALLOC) != 0) {
Packit Service f629e6
		if (tmp->valref > 1) {
Packit Service f629e6
			tmp->valref--;
Packit Service f629e6
			return;
Packit Service f629e6
		}
Packit Service f629e6
		if ((tmp->flags & STRCUR) != 0)
Packit Service f629e6
			efree(tmp->stptr);
Packit Service f629e6
	}
Packit Service f629e6
#else
Packit Service f629e6
	if ((tmp->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
Packit Service f629e6
		efree(tmp->stptr);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	mpfr_unset(tmp);
Packit Service f629e6
Packit Service f629e6
	free_wstr(tmp);
Packit Service f629e6
	freenode(tmp);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * parse_escape:
Packit Service f629e6
 *
Packit Service f629e6
 * Parse a C escape sequence.  STRING_PTR points to a variable containing a
Packit Service f629e6
 * pointer to the string to parse.  That pointer is updated past the
Packit Service f629e6
 * characters we use.  The value of the escape sequence is returned.
Packit Service f629e6
 *
Packit Service f629e6
 * A negative value means the sequence \ newline was seen, which is supposed to
Packit Service f629e6
 * be equivalent to nothing at all.
Packit Service f629e6
 *
Packit Service f629e6
 * If \ is followed by a null character, we return a negative value and leave
Packit Service f629e6
 * the string pointer pointing at the null character.
Packit Service f629e6
 *
Packit Service f629e6
 * If \ is followed by 000, we return 0 and leave the string pointer after the
Packit Service f629e6
 * zeros.  A value of 0 does not mean end of string.
Packit Service f629e6
 *
Packit Service f629e6
 * POSIX doesn't allow \x.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
parse_escape(const char **string_ptr)
Packit Service f629e6
{
Packit Service f629e6
	int c = *(*string_ptr)++;
Packit Service f629e6
	int i;
Packit Service f629e6
	int count;
Packit Service f629e6
	int j;
Packit Service f629e6
	const char *start;
Packit Service f629e6
Packit Service f629e6
	if (do_lint_old) {
Packit Service f629e6
		switch (c) {
Packit Service f629e6
		case 'a':
Packit Service f629e6
		case 'b':
Packit Service f629e6
		case 'f':
Packit Service f629e6
		case 'r':
Packit Service f629e6
			warning(_("old awk does not support the `\\%c' escape sequence"), c);
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	switch (c) {
Packit Service f629e6
	case 'a':
Packit Service f629e6
		return '\a';
Packit Service f629e6
	case 'b':
Packit Service f629e6
		return '\b';
Packit Service f629e6
	case 'f':
Packit Service f629e6
		return '\f';
Packit Service f629e6
	case 'n':
Packit Service f629e6
		return '\n';
Packit Service f629e6
	case 'r':
Packit Service f629e6
		return '\r';
Packit Service f629e6
	case 't':
Packit Service f629e6
		return '\t';
Packit Service f629e6
	case 'v':
Packit Service f629e6
		return '\v';
Packit Service f629e6
	case '\n':
Packit Service f629e6
		return -2;
Packit Service f629e6
	case 0:
Packit Service f629e6
		(*string_ptr)--;
Packit Service f629e6
		return -1;
Packit Service f629e6
	case '0':
Packit Service f629e6
	case '1':
Packit Service f629e6
	case '2':
Packit Service f629e6
	case '3':
Packit Service f629e6
	case '4':
Packit Service f629e6
	case '5':
Packit Service f629e6
	case '6':
Packit Service f629e6
	case '7':
Packit Service f629e6
		i = c - '0';
Packit Service f629e6
		count = 0;
Packit Service f629e6
		while (++count < 3) {
Packit Service f629e6
			if ((c = *(*string_ptr)++) >= '0' && c <= '7') {
Packit Service f629e6
				i *= 8;
Packit Service f629e6
				i += c - '0';
Packit Service f629e6
			} else {
Packit Service f629e6
				(*string_ptr)--;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		return i;
Packit Service f629e6
	case 'x':
Packit Service f629e6
		if (do_lint) {
Packit Service f629e6
			static bool warned = false;
Packit Service f629e6
Packit Service f629e6
			if (! warned) {
Packit Service f629e6
				warned = true;
Packit Service f629e6
				lintwarn(_("POSIX does not allow `\\x' escapes"));
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		if (do_posix)
Packit Service f629e6
			return ('x');
Packit Service f629e6
		if (! isxdigit((unsigned char) (*string_ptr)[0])) {
Packit Service f629e6
			warning(_("no hex digits in `\\x' escape sequence"));
Packit Service f629e6
			return ('x');
Packit Service f629e6
		}
Packit Service f629e6
		start = *string_ptr;
Packit Service f629e6
		for (i = j = 0; j < 2; j++) {
Packit Service f629e6
			/* do outside test to avoid multiple side effects */
Packit Service f629e6
			c = *(*string_ptr)++;
Packit Service f629e6
			if (isxdigit(c)) {
Packit Service f629e6
				i *= 16;
Packit Service f629e6
				if (isdigit(c))
Packit Service f629e6
					i += c - '0';
Packit Service f629e6
				else if (isupper(c))
Packit Service f629e6
					i += c - 'A' + 10;
Packit Service f629e6
				else
Packit Service f629e6
					i += c - 'a' + 10;
Packit Service f629e6
			} else {
Packit Service f629e6
				(*string_ptr)--;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		if (do_lint && j > 2)
Packit Service f629e6
			lintwarn(_("hex escape \\x%.*s of %d characters probably not interpreted the way you expect"), j, start, j);
Packit Service f629e6
		return i;
Packit Service f629e6
	case '\\':
Packit Service f629e6
	case '"':
Packit Service f629e6
		return c;
Packit Service f629e6
	default:
Packit Service f629e6
	{
Packit Service f629e6
		static bool warned[256];
Packit Service f629e6
		unsigned char uc = (unsigned char) c;
Packit Service f629e6
Packit Service f629e6
		/* N.B.: use unsigned char here to avoid Latin-1 problems */
Packit Service f629e6
Packit Service f629e6
		if (! warned[uc]) {
Packit Service f629e6
			warned[uc] = true;
Packit Service f629e6
Packit Service f629e6
			warning(_("escape sequence `\\%c' treated as plain `%c'"), uc, uc);
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
		return c;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* get_numbase --- return the base to use for the number in 's' */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
get_numbase(const char *s, size_t len, bool use_locale)
Packit Service f629e6
{
Packit Service f629e6
	int dec_point = '.';
Packit Service f629e6
	const char *str = s;
Packit Service f629e6
Packit Service f629e6
#if defined(HAVE_LOCALE_H)
Packit Service f629e6
	/*
Packit Service f629e6
	 * loc.decimal_point may not have been initialized yet,
Packit Service f629e6
	 * so double check it before using it.
Packit Service f629e6
	 */
Packit Service f629e6
	if (use_locale && loc.decimal_point != NULL && loc.decimal_point[0] != '\0')
Packit Service f629e6
		dec_point = loc.decimal_point[0];	/* XXX --- assumes one char */
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	if (len < 2 || str[0] != '0')
Packit Service f629e6
		return 10;
Packit Service f629e6
Packit Service f629e6
	/* leading 0x or 0X */
Packit Service f629e6
	if (str[1] == 'x' || str[1] == 'X')
Packit Service f629e6
		return 16;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * Numbers with '.', 'e', or 'E' are decimal.
Packit Service f629e6
	 * Have to check so that things like 00.34 are handled right.
Packit Service f629e6
	 *
Packit Service f629e6
	 * These beasts can have trailing whitespace. Deal with that too.
Packit Service f629e6
	 */
Packit Service f629e6
	for (; len > 0; len--, str++) {
Packit Service f629e6
		if (*str == 'e' || *str == 'E' || *str == dec_point)
Packit Service f629e6
			return 10;
Packit Service f629e6
		else if (! isdigit((unsigned char) *str))
Packit Service f629e6
			break;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! isdigit((unsigned char) s[1])
Packit Service f629e6
			|| s[1] == '8' || s[1] == '9'
Packit Service f629e6
	)
Packit Service f629e6
		return 10;
Packit Service f629e6
	return 8;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* str2wstr --- convert a multibyte string to a wide string */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
str2wstr(NODE *n, size_t **ptr)
Packit Service f629e6
{
Packit Service f629e6
	size_t i, count, src_count;
Packit Service f629e6
	char *sp;
Packit Service f629e6
	mbstate_t mbs;
Packit Service f629e6
	wchar_t wc, *wsp;
Packit Service f629e6
	static bool warned = false;
Packit Service f629e6
Packit Service f629e6
	assert((n->flags & (STRING|STRCUR)) != 0);
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * Don't convert global null string or global null field
Packit Service f629e6
	 * variables to a wide string. They are both zero-length anyway.
Packit Service f629e6
	 * This also avoids future double-free errors while releasing
Packit Service f629e6
	 * shallow copies, eg. *tmp = *Null_field; free_wstr(tmp);
Packit Service f629e6
	 */
Packit Service f629e6
	if (n == Nnull_string || n == Null_field)
Packit Service f629e6
		return n;
Packit Service f629e6
Packit Service f629e6
	if ((n->flags & WSTRCUR) != 0) {
Packit Service f629e6
		if (ptr == NULL)
Packit Service f629e6
			return n;
Packit Service f629e6
		/* otherwise
Packit Service f629e6
			fall through and recompute to fill in the array */
Packit Service f629e6
		free_wstr(n);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * After consideration and consultation, this
Packit Service f629e6
	 * code trades space for time. We allocate
Packit Service f629e6
	 * an array of wchar_t that is n->stlen long.
Packit Service f629e6
	 * This is needed in the worst case anyway, where
Packit Service f629e6
	 * each input byte maps to one wchar_t.  The
Packit Service f629e6
	 * advantage is that we only have to convert the string
Packit Service f629e6
	 * once, instead of twice, once to find out how many
Packit Service f629e6
	 * wide characters, and then again to actually fill in
Packit Service f629e6
	 * the info.  If there's a lot left over, we can
Packit Service f629e6
	 * realloc the wide string down in size.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	emalloc(n->wstptr, wchar_t *, sizeof(wchar_t) * (n->stlen + 1), "str2wstr");
Packit Service f629e6
	wsp = n->wstptr;
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * For use by do_match, create and fill in an array.
Packit Service f629e6
	 * For each byte `i' in n->stptr (the original string),
Packit Service f629e6
	 * a[i] is equal to `j', where `j' is the corresponding wchar_t
Packit Service f629e6
	 * in the converted wide string.
Packit Service f629e6
	 *
Packit Service f629e6
	 * Create the array.
Packit Service f629e6
	 */
Packit Service f629e6
	if (ptr != NULL) {
Packit Service f629e6
		ezalloc(*ptr, size_t *, sizeof(size_t) * n->stlen, "str2wstr");
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	sp = n->stptr;
Packit Service f629e6
	src_count = n->stlen;
Packit Service f629e6
	memset(& mbs, 0, sizeof(mbs));
Packit Service f629e6
	for (i = 0; src_count > 0; i++) {
Packit Service f629e6
		/*
Packit Service f629e6
		 * 9/2010: Check the current byte; if it's a valid character,
Packit Service f629e6
		 * then it doesn't start a multibyte sequence. This brings a
Packit Service f629e6
		 * big speed up. Thanks to Ulrich Drepper for the tip.
Packit Service f629e6
		 * 11/2010: Thanks to Paolo Bonzini for some even faster code.
Packit Service f629e6
		 */
Packit Service f629e6
		if (is_valid_character(*sp)) {
Packit Service f629e6
			count = 1;
Packit Service f629e6
			wc = btowc_cache(*sp);
Packit Service f629e6
		} else
Packit Service f629e6
			count = mbrtowc(& wc, sp, src_count, & mbs);
Packit Service f629e6
		switch (count) {
Packit Service f629e6
		case (size_t) -2:
Packit Service f629e6
		case (size_t) -1:
Packit Service f629e6
			/*
Packit Service f629e6
			 * mbrtowc(3) says the state of mbs becomes undefined
Packit Service f629e6
			 * after a bad character, so reset it.
Packit Service f629e6
			 */
Packit Service f629e6
			memset(& mbs, 0, sizeof(mbs));
Packit Service f629e6
Packit Service f629e6
			/* Warn the user something's wrong */
Packit Service f629e6
			if (! warned) {
Packit Service f629e6
				warned = true;
Packit Service f629e6
				warning(_("Invalid multibyte data detected. There may be a mismatch between your data and your locale."));
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			/*
Packit Service f629e6
			 * 8/2015: If we're using UTF, then instead of just
Packit Service f629e6
			 * skipping the character, plug in the Unicode
Packit Service f629e6
			 * replacement character. In most cases this gives
Packit Service f629e6
			 * us "better" results, in that character counts
Packit Service f629e6
			 * and string lengths tend to make more sense.
Packit Service f629e6
			 *
Packit Service f629e6
			 * Otherwise, just skip the bad byte and keep going,
Packit Service f629e6
			 * so that we get a more-or-less full string, instead of
Packit Service f629e6
			 * stopping early. This is particularly important
Packit Service f629e6
			 * for match() where we need to build the indices.
Packit Service f629e6
			 */
Packit Service f629e6
			if (using_utf8()) {
Packit Service f629e6
				count = 1;
Packit Service f629e6
				wc = 0xFFFD;	/* unicode replacement character */
Packit Service f629e6
				goto set_wc;
Packit Service f629e6
			} else {
Packit Service f629e6
				/* skip it and keep going */
Packit Service f629e6
				sp++;
Packit Service f629e6
				src_count--;
Packit Service f629e6
			}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 0:
Packit Service f629e6
			count = 1;
Packit Service f629e6
			/* fall through */
Packit Service f629e6
		default:
Packit Service f629e6
		set_wc:
Packit Service f629e6
			*wsp++ = wc;
Packit Service f629e6
			src_count -= count;
Packit Service f629e6
			while (count--)  {
Packit Service f629e6
				if (ptr != NULL)
Packit Service f629e6
					(*ptr)[sp - n->stptr] = i;
Packit Service f629e6
				sp++;
Packit Service f629e6
			}
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	*wsp = L'\0';
Packit Service f629e6
	n->wstlen = wsp - n->wstptr;
Packit Service f629e6
	n->flags |= WSTRCUR;
Packit Service f629e6
#define ARBITRARY_AMOUNT_TO_GIVE_BACK 100
Packit Service f629e6
	if (n->stlen - n->wstlen > ARBITRARY_AMOUNT_TO_GIVE_BACK)
Packit Service f629e6
		erealloc(n->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 1), "str2wstr");
Packit Service f629e6
Packit Service f629e6
	return n;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* wstr2str --- convert a wide string back into multibyte one */
Packit Service f629e6
Packit Service f629e6
NODE *
Packit Service f629e6
wstr2str(NODE *n)
Packit Service f629e6
{
Packit Service f629e6
	size_t result;
Packit Service f629e6
	size_t length;
Packit Service f629e6
	wchar_t *wp;
Packit Service f629e6
	mbstate_t mbs;
Packit Service f629e6
	char *newval, *cp;
Packit Service f629e6
Packit Service f629e6
	assert(n->valref == 1);
Packit Service f629e6
	assert((n->flags & WSTRCUR) != 0);
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * Convert the wide chars in t1->wstptr back into m.b. chars.
Packit Service f629e6
	 * This is pretty grotty, but it's the most straightforward
Packit Service f629e6
	 * way to do things.
Packit Service f629e6
	 */
Packit Service f629e6
	memset(& mbs, 0, sizeof(mbs));
Packit Service f629e6
Packit Service f629e6
	length = n->wstlen;
Packit Service f629e6
	emalloc(newval, char *, (length * gawk_mb_cur_max) + 1, "wstr2str");
Packit Service f629e6
Packit Service f629e6
	wp = n->wstptr;
Packit Service f629e6
	for (cp = newval; length > 0; length--) {
Packit Service f629e6
		result = wcrtomb(cp, *wp, & mbs);
Packit Service f629e6
		if (result == (size_t) -1)	/* what to do? break seems best */
Packit Service f629e6
			break;
Packit Service f629e6
		cp += result;
Packit Service f629e6
		wp++;
Packit Service f629e6
	}
Packit Service f629e6
	*cp = '\0';
Packit Service f629e6
Packit Service f629e6
	/* N.B. caller just created n with make_string, so this free is safe */
Packit Service f629e6
	efree(n->stptr);
Packit Service f629e6
	n->stptr = newval;
Packit Service f629e6
	n->stlen = cp - newval;
Packit Service f629e6
Packit Service f629e6
	return n;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* free_wstr --- release the wide string part of a node */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
r_free_wstr(NODE *n)
Packit Service f629e6
{
Packit Service f629e6
	assert(n->type == Node_val);
Packit Service f629e6
Packit Service f629e6
	if ((n->flags & WSTRCUR) != 0) {
Packit Service f629e6
		assert(n->wstptr != NULL);
Packit Service f629e6
		efree(n->wstptr);
Packit Service f629e6
	}
Packit Service f629e6
	n->wstptr = NULL;
Packit Service f629e6
	n->wstlen = 0;
Packit Service f629e6
	n->flags &= ~WSTRCUR;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
static void __attribute__ ((unused))
Packit Service f629e6
dump_wstr(FILE *fp, const wchar_t *str, size_t len)
Packit Service f629e6
{
Packit Service f629e6
	if (str == NULL || len == 0)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	for (; len--; str++)
Packit Service f629e6
		putwc(*str, fp);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* wstrstr --- walk haystack, looking for needle, wide char version */
Packit Service f629e6
Packit Service f629e6
const wchar_t *
Packit Service f629e6
wstrstr(const wchar_t *haystack, size_t hs_len,
Packit Service f629e6
	const wchar_t *needle, size_t needle_len)
Packit Service f629e6
{
Packit Service f629e6
	size_t i;
Packit Service f629e6
Packit Service f629e6
	if (haystack == NULL || needle == NULL || needle_len > hs_len)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < hs_len; i++) {
Packit Service f629e6
		if (haystack[i] == needle[0]
Packit Service f629e6
		    && i+needle_len-1 < hs_len
Packit Service f629e6
		    && haystack[i+needle_len-1] == needle[needle_len-1]) {
Packit Service f629e6
			/* first & last chars match, check string */
Packit Service f629e6
			if (memcmp(haystack+i, needle, sizeof(wchar_t) * needle_len) == 0) {
Packit Service f629e6
				return haystack + i;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* wcasestrstr --- walk haystack, nocase look for needle, wide char version */
Packit Service f629e6
Packit Service f629e6
const wchar_t *
Packit Service f629e6
wcasestrstr(const wchar_t *haystack, size_t hs_len,
Packit Service f629e6
	const wchar_t *needle, size_t needle_len)
Packit Service f629e6
{
Packit Service f629e6
	size_t i, j;
Packit Service f629e6
Packit Service f629e6
	if (haystack == NULL || needle == NULL || needle_len > hs_len)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < hs_len; i++) {
Packit Service f629e6
		if (towlower(haystack[i]) == towlower(needle[0])
Packit Service f629e6
		    && i+needle_len-1 < hs_len
Packit Service f629e6
		    && towlower(haystack[i+needle_len-1]) == towlower(needle[needle_len-1])) {
Packit Service f629e6
			/* first & last chars match, check string */
Packit Service f629e6
			const wchar_t *start;
Packit Service f629e6
Packit Service f629e6
			start = haystack+i;
Packit Service f629e6
			for (j = 0; j < needle_len; j++, start++) {
Packit Service f629e6
				wchar_t h, n;
Packit Service f629e6
Packit Service f629e6
				h = towlower(*start);
Packit Service f629e6
				n = towlower(needle[j]);
Packit Service f629e6
				if (h != n)
Packit Service f629e6
					goto out;
Packit Service f629e6
			}
Packit Service f629e6
			return haystack + i;
Packit Service f629e6
		}
Packit Service f629e6
out:	;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
is_ieee_magic_val(const char *val)
Packit Service f629e6
{
Packit Service f629e6
	/*
Packit Service f629e6
	 * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
Packit Service f629e6
	 * Assume the length is 4, as the caller checks this.
Packit Service f629e6
	 */
Packit Service f629e6
	return (   (val[0] == '+' || val[0] == '-')
Packit Service f629e6
		&& (   (   (val[1] == 'i' || val[1] == 'I')
Packit Service f629e6
			&& (val[2] == 'n' || val[2] == 'N')
Packit Service f629e6
			&& (val[3] == 'f' || val[3] == 'F'))
Packit Service f629e6
		    || (   (val[1] == 'n' || val[1] == 'N')
Packit Service f629e6
			&& (val[2] == 'a' || val[2] == 'A')
Packit Service f629e6
			&& (val[3] == 'n' || val[3] == 'N'))));
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* get_ieee_magic_val --- return magic value for string */
Packit Service f629e6
Packit Service f629e6
static AWKNUM
Packit Service f629e6
get_ieee_magic_val(char *val)
Packit Service f629e6
{
Packit Service f629e6
	static bool first = true;
Packit Service f629e6
	static AWKNUM inf;
Packit Service f629e6
	static AWKNUM nan;
Packit Service f629e6
	char save;
Packit Service f629e6
Packit Service f629e6
	char *ptr;
Packit Service f629e6
	save = val[4];
Packit Service f629e6
	val[4] = '\0';
Packit Service f629e6
	AWKNUM v = strtod(val, &ptr);
Packit Service f629e6
	val[4] = save;
Packit Service f629e6
Packit Service f629e6
	if (val == ptr) { /* Older strtod implementations don't support inf or nan. */
Packit Service f629e6
		if (first) {
Packit Service f629e6
			first = false;
Packit Service f629e6
			nan = sqrt(-1.0);
Packit Service f629e6
			inf = -log(0.0);
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
Packit Service f629e6
		if (val[0] == '-')
Packit Service f629e6
			v = -v;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return v;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
wint_t btowc_cache[256];
Packit Service f629e6
Packit Service f629e6
/* init_btowc_cache --- initialize the cache */
Packit Service f629e6
Packit Service f629e6
void init_btowc_cache()
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < 255; i++) {
Packit Service f629e6
		btowc_cache[i] = btowc(i);
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#define BLOCKCHUNK 100
Packit Service f629e6
Packit Service f629e6
struct block_header nextfree[BLOCK_MAX] = {
Packit Service f629e6
	{ NULL, sizeof(NODE) },
Packit Service f629e6
	{ NULL, sizeof(BUCKET) },
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	{ NULL, sizeof(mpfr_t) },
Packit Service f629e6
	{ NULL, sizeof(mpz_t) },
Packit Service f629e6
#endif
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* more_blocks --- get more blocks of memory and add to the free list;
Packit Service f629e6
	size of a block must be >= sizeof(struct block_item)
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void *
Packit Service f629e6
more_blocks(int id)
Packit Service f629e6
{
Packit Service f629e6
	struct block_item *freep, *np, *next;
Packit Service f629e6
	char *p, *endp;
Packit Service f629e6
	size_t size;
Packit Service f629e6
Packit Service f629e6
	size = nextfree[id].size;
Packit Service f629e6
Packit Service f629e6
	assert(size >= sizeof(struct block_item));
Packit Service f629e6
	emalloc(freep, struct block_item *, BLOCKCHUNK * size, "more_blocks");
Packit Service f629e6
	p = (char *) freep;
Packit Service f629e6
	endp = p + BLOCKCHUNK * size;
Packit Service f629e6
Packit Service f629e6
	for (np = freep; ; np = next) {
Packit Service f629e6
		next = (struct block_item *) (p += size);
Packit Service f629e6
		if (p >= endp) {
Packit Service f629e6
			np->freep = NULL;
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
		np->freep = next;
Packit Service f629e6
	}
Packit Service f629e6
	nextfree[id].freep = freep->freep;
Packit Service f629e6
	return freep;
Packit Service f629e6
}