Blame eval.c

Packit 575503
/*
Packit 575503
 * eval.c - gawk bytecode interpreter
Packit 575503
 */
Packit 575503
Packit 575503
/*
Packit 575503
 * Copyright (C) 1986, 1988, 1989, 1991-2017 the Free Software Foundation, Inc.
Packit 575503
 *
Packit 575503
 * This file is part of GAWK, the GNU implementation of the
Packit 575503
 * AWK Programming Language.
Packit 575503
 *
Packit 575503
 * GAWK is free software; you can redistribute it and/or modify
Packit 575503
 * it under the terms of the GNU General Public License as published by
Packit 575503
 * the Free Software Foundation; either version 3 of the License, or
Packit 575503
 * (at your option) any later version.
Packit 575503
 *
Packit 575503
 * GAWK is distributed in the hope that it will be useful,
Packit 575503
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 575503
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 575503
 * GNU General Public License for more details.
Packit 575503
 *
Packit 575503
 * You should have received a copy of the GNU General Public License
Packit 575503
 * along with this program; if not, write to the Free Software
Packit 575503
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit 575503
 */
Packit 575503
Packit 575503
#include "awk.h"
Packit 575503
Packit 575503
extern double pow(double x, double y);
Packit 575503
extern double modf(double x, double *yp);
Packit 575503
extern double fmod(double x, double y);
Packit 575503
NODE **fcall_list = NULL;
Packit 575503
long fcall_count = 0;
Packit 575503
int currule = 0;
Packit 575503
IOBUF *curfile = NULL;		/* current data file */
Packit 575503
bool exiting = false;
Packit 575503
Packit 575503
int (*interpret)(INSTRUCTION *);
Packit 575503
#define MAX_EXEC_HOOKS	10
Packit 575503
static int num_exec_hook = 0;
Packit 575503
static Func_pre_exec pre_execute[MAX_EXEC_HOOKS];
Packit 575503
static Func_post_exec post_execute = NULL;
Packit 575503
Packit 575503
extern void frame_popped();
Packit 575503
Packit 575503
int OFSlen;
Packit 575503
int ORSlen;
Packit 575503
int OFMTidx;
Packit 575503
int CONVFMTidx;
Packit 575503
Packit 575503
static NODE *node_Boolean[2];
Packit 575503
Packit 575503
/* This rather ugly macro is for VMS C */
Packit 575503
#ifdef C
Packit 575503
#undef C
Packit 575503
#endif
Packit 575503
#define C(c) ((char)c)
Packit 575503
/*
Packit 575503
 * This table is used by the regexp routines to do case independent
Packit 575503
 * matching. Basically, every ascii character maps to itself, except
Packit 575503
 * uppercase letters map to lower case ones. This table has 256
Packit 575503
 * entries, for ISO 8859-1. Note also that if the system this
Packit 575503
 * is compiled on doesn't use 7-bit ascii, casetable[] should not be
Packit 575503
 * defined to the linker, so gawk should not load.
Packit 575503
 *
Packit 575503
 * Do NOT make this array static, it is used in several spots, not
Packit 575503
 * just in this file.
Packit 575503
 *
Packit 575503
 * 6/2004:
Packit 575503
 * This table is also used for IGNORECASE for == and !=, and index().
Packit 575503
 * Although with GLIBC, we could use tolower() everywhere and RE_ICASE
Packit 575503
 * for the regex matcher, precomputing this table once gives us a
Packit 575503
 * performance improvement.  I also think it's better for portability
Packit 575503
 * to non-GLIBC systems.  All the world is not (yet :-) GNU/Linux.
Packit 575503
 */
Packit 575503
#if 'a' == 97	/* it's ascii */
Packit 575503
char casetable[] = {
Packit 575503
	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
Packit 575503
	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
Packit 575503
	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
Packit 575503
	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
Packit 575503
	/* ' '     '!'     '"'     '#'     '$'     '%'     '&'     ''' */
Packit 575503
	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
Packit 575503
	/* '('     ')'     '*'     '+'     ','     '-'     '.'     '/' */
Packit 575503
	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
Packit 575503
	/* '0'     '1'     '2'     '3'     '4'     '5'     '6'     '7' */
Packit 575503
	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
Packit 575503
	/* '8'     '9'     ':'     ';'     '<'     '='     '>'     '?' */
Packit 575503
	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
Packit 575503
	/* '@'     'A'     'B'     'C'     'D'     'E'     'F'     'G' */
Packit 575503
	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
Packit 575503
	/* 'H'     'I'     'J'     'K'     'L'     'M'     'N'     'O' */
Packit 575503
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
Packit 575503
	/* 'P'     'Q'     'R'     'S'     'T'     'U'     'V'     'W' */
Packit 575503
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
Packit 575503
	/* 'X'     'Y'     'Z'     '['     '\'     ']'     '^'     '_' */
Packit 575503
	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
Packit 575503
	/* '`'     'a'     'b'     'c'     'd'     'e'     'f'     'g' */
Packit 575503
	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
Packit 575503
	/* 'h'     'i'     'j'     'k'     'l'     'm'     'n'     'o' */
Packit 575503
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
Packit 575503
	/* 'p'     'q'     'r'     's'     't'     'u'     'v'     'w' */
Packit 575503
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
Packit 575503
	/* 'x'     'y'     'z'     '{'     '|'     '}'     '~' */
Packit 575503
	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
Packit 575503
Packit 575503
	/* Latin 1: */
Packit 575503
	C('\200'), C('\201'), C('\202'), C('\203'), C('\204'), C('\205'), C('\206'), C('\207'),
Packit 575503
	C('\210'), C('\211'), C('\212'), C('\213'), C('\214'), C('\215'), C('\216'), C('\217'),
Packit 575503
	C('\220'), C('\221'), C('\222'), C('\223'), C('\224'), C('\225'), C('\226'), C('\227'),
Packit 575503
	C('\230'), C('\231'), C('\232'), C('\233'), C('\234'), C('\235'), C('\236'), C('\237'),
Packit 575503
	C('\240'), C('\241'), C('\242'), C('\243'), C('\244'), C('\245'), C('\246'), C('\247'),
Packit 575503
	C('\250'), C('\251'), C('\252'), C('\253'), C('\254'), C('\255'), C('\256'), C('\257'),
Packit 575503
	C('\260'), C('\261'), C('\262'), C('\263'), C('\264'), C('\265'), C('\266'), C('\267'),
Packit 575503
	C('\270'), C('\271'), C('\272'), C('\273'), C('\274'), C('\275'), C('\276'), C('\277'),
Packit 575503
	C('\340'), C('\341'), C('\342'), C('\343'), C('\344'), C('\345'), C('\346'), C('\347'),
Packit 575503
	C('\350'), C('\351'), C('\352'), C('\353'), C('\354'), C('\355'), C('\356'), C('\357'),
Packit 575503
	C('\360'), C('\361'), C('\362'), C('\363'), C('\364'), C('\365'), C('\366'), C('\327'),
Packit 575503
	C('\370'), C('\371'), C('\372'), C('\373'), C('\374'), C('\375'), C('\376'), C('\337'),
Packit 575503
	C('\340'), C('\341'), C('\342'), C('\343'), C('\344'), C('\345'), C('\346'), C('\347'),
Packit 575503
	C('\350'), C('\351'), C('\352'), C('\353'), C('\354'), C('\355'), C('\356'), C('\357'),
Packit 575503
	C('\360'), C('\361'), C('\362'), C('\363'), C('\364'), C('\365'), C('\366'), C('\367'),
Packit 575503
	C('\370'), C('\371'), C('\372'), C('\373'), C('\374'), C('\375'), C('\376'), C('\377'),
Packit 575503
};
Packit 575503
#elif defined(USE_EBCDIC)
Packit 575503
char casetable[] = {
Packit 575503
 /*00  NU    SH    SX    EX    PF    HT    LC    DL */
Packit 575503
      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
Packit 575503
 /*08              SM    VT    FF    CR    SO    SI */
Packit 575503
      0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
Packit 575503
 /*10  DE    D1    D2    TM    RS    NL    BS    IL */
Packit 575503
      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
Packit 575503
 /*18  CN    EM    CC    C1    FS    GS    RS    US */
Packit 575503
      0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
Packit 575503
 /*20  DS    SS    FS          BP    LF    EB    EC */
Packit 575503
      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
Packit 575503
 /*28              SM    C2    EQ    AK    BL       */
Packit 575503
      0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
Packit 575503
 /*30              SY          PN    RS    UC    ET */
Packit 575503
      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
Packit 575503
 /*38                    C3    D4    NK          SU */
Packit 575503
      0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
Packit 575503
 /*40  SP                                           */
Packit 575503
      0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
Packit 575503
 /*48             CENT    .     <     (     +     | */
Packit 575503
      0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
Packit 575503
 /*50   &                                           */
Packit 575503
      0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
Packit 575503
 /*58               !     $     *     )     ;     ^ */
Packit 575503
      0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
Packit 575503
 /*60   -     /                                     */
Packit 575503
      0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
Packit 575503
 /*68               |     ,     %     _     >     ? */
Packit 575503
      0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
Packit 575503
 /*70                                               */
Packit 575503
      0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
Packit 575503
 /*78         `     :     #     @     '     =     " */
Packit 575503
      0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
Packit 575503
 /*80         a     b     c     d     e     f     g */
Packit 575503
      0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
Packit 575503
 /*88   h     i           {                         */
Packit 575503
      0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
Packit 575503
 /*90         j     k     l     m     n     o     p */
Packit 575503
      0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
Packit 575503
 /*98   q     r           }                         */
Packit 575503
      0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
Packit 575503
 /*A0         ~     s     t     u     v     w     x */
Packit 575503
      0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
Packit 575503
 /*A8   y     z                       [             */
Packit 575503
      0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
Packit 575503
 /*B0                                               */
Packit 575503
      0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
Packit 575503
 /*B8                                 ]             */
Packit 575503
      0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
Packit 575503
 /*C0   {     A     B     C     D     E     F     G */
Packit 575503
      0xC0, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
Packit 575503
 /*C8   H     I                                     */
Packit 575503
      0x88, 0x89, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
Packit 575503
 /*D0   }     J     K     L     M     N     O     P */
Packit 575503
      0xD0, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
Packit 575503
 /*D8   Q     R                                     */
Packit 575503
      0x98, 0x99, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
Packit 575503
 /*E0   \           S     T     U     V     W     X */
Packit 575503
      0xE0, 0xE1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
Packit 575503
 /*E8   Y     Z                                     */
Packit 575503
      0xA8, 0xA9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
Packit 575503
 /*F0   0     1     2     3     4     5     6     7 */
Packit 575503
      0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
Packit 575503
 /*F8   8     9                                     */
Packit 575503
      0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
Packit 575503
};
Packit 575503
#else
Packit 575503
#include "You lose. You will need a translation table for your character set."
Packit 575503
#endif
Packit 575503
Packit 575503
#undef C
Packit 575503
Packit 575503
/* load_casetable --- for a non-ASCII locale, redo the table */
Packit 575503
Packit 575503
void
Packit 575503
load_casetable(void)
Packit 575503
{
Packit 575503
#if defined(LC_CTYPE)
Packit 575503
	int i;
Packit 575503
	char *cp;
Packit 575503
	static bool loaded = false;
Packit 575503
Packit 575503
	if (loaded || do_traditional)
Packit 575503
		return;
Packit 575503
Packit 575503
	loaded = true;
Packit 575503
	cp = setlocale(LC_CTYPE, NULL);
Packit 575503
Packit 575503
	/* this is not per standard, but it's pretty safe */
Packit 575503
	if (cp == NULL || strcmp(cp, "C") == 0 || strcmp(cp, "POSIX") == 0)
Packit 575503
		return;
Packit 575503
Packit 575503
#ifndef USE_EBCDIC
Packit 575503
	/* use of isalpha is ok here (see is_alpha in awkgram.y) */
Packit 575503
	for (i = 0200; i <= 0377; i++) {
Packit 575503
		if (isalpha(i) && islower(i) && i != toupper(i))
Packit 575503
			casetable[i] = toupper(i);
Packit 575503
		else
Packit 575503
			casetable[i] = i;
Packit 575503
	}
Packit 575503
#endif
Packit 575503
#endif
Packit 575503
}
Packit 575503
Packit 575503
/*
Packit 575503
 * This table maps node types to strings for debugging.
Packit 575503
 * KEEP IN SYNC WITH awk.h!!!!
Packit 575503
 */
Packit 575503
Packit 575503
static const char *const nodetypes[] = {
Packit 575503
	"Node_illegal",
Packit 575503
	"Node_val",
Packit 575503
	"Node_regex",
Packit 575503
	"Node_dynregex",
Packit 575503
	"Node_var",
Packit 575503
	"Node_var_array",
Packit 575503
	"Node_var_new",
Packit 575503
	"Node_param_list",
Packit 575503
	"Node_func",
Packit 575503
	"Node_ext_func",
Packit 575503
	"Node_builtin_func",
Packit 575503
	"Node_array_ref",
Packit 575503
	"Node_array_tree",
Packit 575503
	"Node_array_leaf",
Packit 575503
	"Node_dump_array",
Packit 575503
	"Node_arrayfor",
Packit 575503
	"Node_frame",
Packit 575503
	"Node_instruction",
Packit 575503
	"Node_final --- this should never appear",
Packit 575503
	NULL
Packit 575503
};
Packit 575503
Packit 575503
Packit 575503
/*
Packit 575503
 * This table maps Op codes to strings.
Packit 575503
 * KEEP IN SYNC WITH awk.h!!!!
Packit 575503
 */
Packit 575503
Packit 575503
static struct optypetab {
Packit 575503
	char *desc;
Packit 575503
	char *operator;
Packit 575503
} optypes[] = {
Packit 575503
	{ "Op_illegal", NULL },
Packit 575503
	{ "Op_times", " * " },
Packit 575503
	{ "Op_times_i", " * " },
Packit 575503
	{ "Op_quotient", " / " },
Packit 575503
	{ "Op_quotient_i", " / " },
Packit 575503
	{ "Op_mod", " % " },
Packit 575503
	{ "Op_mod_i", " % " },
Packit 575503
	{ "Op_plus", " + " },
Packit 575503
	{ "Op_plus_i", " + " },
Packit 575503
	{ "Op_minus", " - " },
Packit 575503
	{ "Op_minus_i", " - " },
Packit 575503
	{ "Op_exp", " ^ " },
Packit 575503
	{ "Op_exp_i", " ^ " },
Packit 575503
	{ "Op_concat", " " },
Packit 575503
	{ "Op_line_range", NULL },
Packit 575503
	{ "Op_cond_pair", ", " },
Packit 575503
	{ "Op_subscript", "[]" },
Packit 575503
	{ "Op_sub_array", "[]" },
Packit 575503
	{ "Op_preincrement", "++" },
Packit 575503
	{ "Op_predecrement", "--" },
Packit 575503
	{ "Op_postincrement", "++" },
Packit 575503
	{ "Op_postdecrement", "--" },
Packit 575503
	{ "Op_unary_minus", "-" },
Packit 575503
	{ "Op_unary_plus", "+" },
Packit 575503
	{ "Op_field_spec", "$" },
Packit 575503
	{ "Op_not", "! " },
Packit 575503
	{ "Op_assign", " = " },
Packit 575503
	{ "Op_store_var", " = " },
Packit 575503
	{ "Op_store_sub", " = " },
Packit 575503
	{ "Op_store_field", " = " },
Packit 575503
	{ "Op_assign_times", " *= " },
Packit 575503
	{ "Op_assign_quotient", " /= " },
Packit 575503
	{ "Op_assign_mod", " %= " },
Packit 575503
	{ "Op_assign_plus", " += " },
Packit 575503
	{ "Op_assign_minus", " -= " },
Packit 575503
	{ "Op_assign_exp", " ^= " },
Packit 575503
	{ "Op_assign_concat", " " },
Packit 575503
	{ "Op_and", " && " },
Packit 575503
	{ "Op_and_final", NULL },
Packit 575503
	{ "Op_or", " || " },
Packit 575503
	{ "Op_or_final", NULL },
Packit 575503
	{ "Op_equal", " == " },
Packit 575503
	{ "Op_notequal", " != " },
Packit 575503
	{ "Op_less", " < " },
Packit 575503
	{ "Op_greater", " > " },
Packit 575503
	{ "Op_leq", " <= " },
Packit 575503
	{ "Op_geq", " >= " },
Packit 575503
	{ "Op_match", " ~ " },
Packit 575503
	{ "Op_match_rec", NULL },
Packit 575503
	{ "Op_nomatch", " !~ " },
Packit 575503
	{ "Op_rule", NULL },
Packit 575503
	{ "Op_K_case", "case" },
Packit 575503
	{ "Op_K_default", "default" },
Packit 575503
	{ "Op_K_break", "break" },
Packit 575503
	{ "Op_K_continue", "continue" },
Packit 575503
	{ "Op_K_print", "print" },
Packit 575503
	{ "Op_K_print_rec", "print" },
Packit 575503
	{ "Op_K_printf", "printf" },
Packit 575503
	{ "Op_K_next", "next" },
Packit 575503
	{ "Op_K_exit", "exit" },
Packit 575503
	{ "Op_K_return", "return" },
Packit 575503
	{ "Op_K_delete", "delete" },
Packit 575503
	{ "Op_K_delete_loop", NULL },
Packit 575503
	{ "Op_K_getline_redir", "getline" },
Packit 575503
	{ "Op_K_getline", "getline" },
Packit 575503
	{ "Op_K_nextfile", "nextfile" },
Packit 575503
	{ "Op_builtin", NULL },
Packit 575503
	{ "Op_sub_builtin", NULL },
Packit 575503
	{ "Op_ext_builtin", NULL },
Packit 575503
	{ "Op_in_array", " in " },
Packit 575503
	{ "Op_func_call", NULL },
Packit 575503
	{ "Op_indirect_func_call", NULL },
Packit 575503
	{ "Op_push", NULL },
Packit 575503
	{ "Op_push_arg", NULL },
Packit 575503
	{ "Op_push_arg_untyped", NULL },
Packit 575503
	{ "Op_push_i", NULL },
Packit 575503
	{ "Op_push_re", NULL },
Packit 575503
	{ "Op_push_array", NULL },
Packit 575503
	{ "Op_push_param", NULL },
Packit 575503
	{ "Op_push_lhs", NULL },
Packit 575503
	{ "Op_subscript_lhs", "[]" },
Packit 575503
	{ "Op_field_spec_lhs", "$" },
Packit 575503
	{ "Op_no_op", NULL },
Packit 575503
	{ "Op_pop", NULL },
Packit 575503
	{ "Op_jmp", NULL },
Packit 575503
	{ "Op_jmp_true", NULL },
Packit 575503
	{ "Op_jmp_false", NULL },
Packit 575503
	{ "Op_get_record", NULL },
Packit 575503
	{ "Op_newfile", NULL },
Packit 575503
	{ "Op_arrayfor_init", NULL },
Packit 575503
	{ "Op_arrayfor_incr", NULL },
Packit 575503
	{ "Op_arrayfor_final", NULL },
Packit 575503
	{ "Op_var_update", NULL },
Packit 575503
	{ "Op_var_assign", NULL },
Packit 575503
	{ "Op_field_assign", NULL },
Packit 575503
	{ "Op_subscript_assign", NULL },
Packit 575503
	{ "Op_after_beginfile", NULL },
Packit 575503
	{ "Op_after_endfile", NULL },
Packit 575503
	{ "Op_func", NULL },
Packit 575503
	{ "Op_comment", NULL },
Packit 575503
	{ "Op_exec_count", NULL },
Packit 575503
	{ "Op_breakpoint", NULL },
Packit 575503
	{ "Op_lint", NULL },
Packit 575503
	{ "Op_atexit", NULL },
Packit 575503
	{ "Op_stop", NULL },
Packit 575503
	{ "Op_token", NULL },
Packit 575503
	{ "Op_symbol", NULL },
Packit 575503
	{ "Op_list", NULL },
Packit 575503
	{ "Op_K_do", "do" },
Packit 575503
	{ "Op_K_for", "for" },
Packit 575503
	{ "Op_K_arrayfor", "for" },
Packit 575503
	{ "Op_K_while", "while" },
Packit 575503
	{ "Op_K_switch", "switch" },
Packit 575503
	{ "Op_K_if", "if" },
Packit 575503
	{ "Op_K_else", "else" },
Packit 575503
	{ "Op_K_function", "function" },
Packit 575503
	{ "Op_cond_exp", NULL },
Packit 575503
	{ "Op_parens", NULL },
Packit 575503
	{ "Op_final --- this should never appear", NULL },
Packit 575503
	{ NULL, NULL },
Packit 575503
};
Packit 575503
Packit 575503
/* nodetype2str --- convert a node type into a printable value */
Packit 575503
Packit 575503
const char *
Packit 575503
nodetype2str(NODETYPE type)
Packit 575503
{
Packit 575503
	static char buf[40];
Packit 575503
Packit 575503
	if (type >= Node_illegal && type <= Node_final)
Packit 575503
		return nodetypes[(int) type];
Packit 575503
Packit 575503
	sprintf(buf, _("unknown nodetype %d"), (int) type);
Packit 575503
	return buf;
Packit 575503
}
Packit 575503
Packit 575503
/* opcode2str --- convert a opcode type into a printable value */
Packit 575503
Packit 575503
const char *
Packit 575503
opcode2str(OPCODE op)
Packit 575503
{
Packit 575503
	if (op >= Op_illegal && op < Op_final)
Packit 575503
		return optypes[(int) op].desc;
Packit 575503
	fatal(_("unknown opcode %d"), (int) op);
Packit 575503
	return NULL;
Packit 575503
}
Packit 575503
Packit 575503
const char *
Packit 575503
op2str(OPCODE op)
Packit 575503
{
Packit 575503
	if (op >= Op_illegal && op < Op_final) {
Packit 575503
		if (optypes[(int) op].operator != NULL)
Packit 575503
			return optypes[(int) op].operator;
Packit 575503
		else
Packit 575503
			fatal(_("opcode %s not an operator or keyword"),
Packit 575503
					optypes[(int) op].desc);
Packit 575503
	} else
Packit 575503
		fatal(_("unknown opcode %d"), (int) op);
Packit 575503
	return NULL;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* flags2str --- make a flags value readable */
Packit 575503
Packit 575503
const char *
Packit 575503
flags2str(int flagval)
Packit 575503
{
Packit 575503
	static const struct flagtab values[] = {
Packit 575503
		{ MALLOC, "MALLOC" },
Packit 575503
		{ STRING, "STRING" },
Packit 575503
		{ STRCUR, "STRCUR" },
Packit 575503
		{ NUMCUR, "NUMCUR" },
Packit 575503
		{ NUMBER, "NUMBER" },
Packit 575503
		{ USER_INPUT, "USER_INPUT" },
Packit 575503
		{ INTLSTR, "INTLSTR" },
Packit 575503
		{ NUMINT, "NUMINT" },
Packit 575503
		{ INTIND, "INTIND" },
Packit 575503
		{ WSTRCUR, "WSTRCUR" },
Packit 575503
		{ MPFN,	"MPFN" },
Packit 575503
		{ MPZN,	"MPZN" },
Packit 575503
		{ NO_EXT_SET, "NO_EXT_SET" },
Packit 575503
		{ NULL_FIELD, "NULL_FIELD" },
Packit 575503
		{ ARRAYMAXED, "ARRAYMAXED" },
Packit 575503
		{ HALFHAT, "HALFHAT" },
Packit 575503
		{ XARRAY, "XARRAY" },
Packit 575503
		{ NUMCONSTSTR, "NUMCONSTSTR" },
Packit 575503
		{ REGEX, "REGEX" },
Packit 575503
		{ 0,	NULL },
Packit 575503
	};
Packit 575503
Packit 575503
	return genflags2str(flagval, values);
Packit 575503
}
Packit 575503
Packit 575503
/* genflags2str --- general routine to convert a flag value to a string */
Packit 575503
Packit 575503
const char *
Packit 575503
genflags2str(int flagval, const struct flagtab *tab)
Packit 575503
{
Packit 575503
	static char buffer[BUFSIZ];
Packit 575503
	char *sp;
Packit 575503
	int i, space_left, space_needed;
Packit 575503
Packit 575503
	sp = buffer;
Packit 575503
	space_left = BUFSIZ;
Packit 575503
	for (i = 0; tab[i].name != NULL; i++) {
Packit 575503
		if ((flagval & tab[i].val) != 0) {
Packit 575503
			/*
Packit 575503
			 * note the trick, we want 1 or 0 for whether we need
Packit 575503
			 * the '|' character.
Packit 575503
			 */
Packit 575503
			space_needed = (strlen(tab[i].name) + (sp != buffer));
Packit 575503
			if (space_left <= space_needed)
Packit 575503
				fatal(_("buffer overflow in genflags2str"));
Packit 575503
Packit 575503
			if (sp != buffer) {
Packit 575503
				*sp++ = '|';
Packit 575503
				space_left--;
Packit 575503
			}
Packit 575503
			strcpy(sp, tab[i].name);
Packit 575503
			/* note ordering! */
Packit 575503
			space_left -= strlen(sp);
Packit 575503
			sp += strlen(sp);
Packit 575503
		}
Packit 575503
	}
Packit 575503
Packit 575503
	*sp = '\0';
Packit 575503
	return buffer;
Packit 575503
}
Packit 575503
Packit 575503
/* posix_compare --- compare strings using strcoll */
Packit 575503
Packit 575503
static int
Packit 575503
posix_compare(NODE *s1, NODE *s2)
Packit 575503
{
Packit 575503
	int ret = 0;
Packit 575503
	char save1, save2;
Packit 575503
	size_t l = 0;
Packit 575503
Packit 575503
	save1 = s1->stptr[s1->stlen];
Packit 575503
	s1->stptr[s1->stlen] = '\0';
Packit 575503
Packit 575503
	save2 = s2->stptr[s2->stlen];
Packit 575503
	s2->stptr[s2->stlen] = '\0';
Packit 575503
Packit 575503
	if (gawk_mb_cur_max == 1) {
Packit 575503
		if (strlen(s1->stptr) == s1->stlen && strlen(s2->stptr) == s2->stlen)
Packit 575503
			ret = strcoll(s1->stptr, s2->stptr);
Packit 575503
		else {
Packit 575503
			char b1[2], b2[2];
Packit 575503
			char *p1, *p2;
Packit 575503
			size_t i;
Packit 575503
Packit 575503
			if (s1->stlen < s2->stlen)
Packit 575503
				l = s1->stlen;
Packit 575503
			else
Packit 575503
				l = s2->stlen;
Packit 575503
Packit 575503
			b1[1] = b2[1] = '\0';
Packit 575503
			for (i = ret = 0, p1 = s1->stptr, p2 = s2->stptr;
Packit 575503
			     ret == 0 && i < l;
Packit 575503
			     p1++, p2++) {
Packit 575503
				b1[0] = *p1;
Packit 575503
				b2[0] = *p2;
Packit 575503
				ret = strcoll(b1, b2);
Packit 575503
			}
Packit 575503
		}
Packit 575503
		/*
Packit 575503
		 * Either worked through the strings or ret != 0.
Packit 575503
		 * In either case, ret will be the right thing to return.
Packit 575503
		 */
Packit 575503
	}
Packit 575503
#if ! defined(__DJGPP__)
Packit 575503
	else {
Packit 575503
		/* Similar logic, using wide characters */
Packit 575503
		(void) force_wstring(s1);
Packit 575503
		(void) force_wstring(s2);
Packit 575503
Packit 575503
		if (wcslen(s1->wstptr) == s1->wstlen && wcslen(s2->wstptr) == s2->wstlen)
Packit 575503
			ret = wcscoll(s1->wstptr, s2->wstptr);
Packit 575503
		else {
Packit 575503
			wchar_t b1[2], b2[2];
Packit 575503
			wchar_t *p1, *p2;
Packit 575503
			size_t i;
Packit 575503
Packit 575503
			if (s1->wstlen < s2->wstlen)
Packit 575503
				l = s1->wstlen;
Packit 575503
			else
Packit 575503
				l = s2->wstlen;
Packit 575503
Packit 575503
			b1[1] = b2[1] = L'\0';
Packit 575503
			for (i = ret = 0, p1 = s1->wstptr, p2 = s2->wstptr;
Packit 575503
			     ret == 0 && i < l;
Packit 575503
			     p1++, p2++) {
Packit 575503
				b1[0] = *p1;
Packit 575503
				b2[0] = *p2;
Packit 575503
				ret = wcscoll(b1, b2);
Packit 575503
			}
Packit 575503
		}
Packit 575503
		/*
Packit 575503
		 * Either worked through the strings or ret != 0.
Packit 575503
		 * In either case, ret will be the right thing to return.
Packit 575503
		 */
Packit 575503
	}
Packit 575503
#endif
Packit 575503
Packit 575503
	s1->stptr[s1->stlen] = save1;
Packit 575503
	s2->stptr[s2->stlen] = save2;
Packit 575503
	return ret;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cmp_nodes --- compare two nodes, returning negative, 0, positive */
Packit 575503
Packit 575503
int
Packit 575503
cmp_nodes(NODE *t1, NODE *t2, bool use_strcmp)
Packit 575503
{
Packit 575503
	int ret = 0;
Packit 575503
	size_t len1, len2;
Packit 575503
	int l, ldiff;
Packit 575503
Packit 575503
	if (t1 == t2)
Packit 575503
		return 0;
Packit 575503
Packit 575503
	(void) fixtype(t1);
Packit 575503
	(void) fixtype(t2);
Packit 575503
Packit 575503
	if ((t1->flags & NUMBER) != 0 && (t2->flags & NUMBER) != 0)
Packit 575503
		return cmp_numbers(t1, t2);
Packit 575503
Packit 575503
	(void) force_string(t1);
Packit 575503
	(void) force_string(t2);
Packit 575503
	len1 = t1->stlen;
Packit 575503
	len2 = t2->stlen;
Packit 575503
	ldiff = len1 - len2;
Packit 575503
	if (len1 == 0 || len2 == 0)
Packit 575503
		return ldiff;
Packit 575503
Packit 575503
	if (do_posix && ! use_strcmp)
Packit 575503
		return posix_compare(t1, t2);
Packit 575503
Packit 575503
	l = (ldiff <= 0 ? len1 : len2);
Packit 575503
	if (IGNORECASE) {
Packit 575503
		const unsigned char *cp1 = (const unsigned char *) t1->stptr;
Packit 575503
		const unsigned char *cp2 = (const unsigned char *) t2->stptr;
Packit 575503
		char save1 = t1->stptr[t1->stlen];
Packit 575503
		char save2 = t2->stptr[t2->stlen];
Packit 575503
Packit 575503
Packit 575503
		if (gawk_mb_cur_max > 1) {
Packit 575503
			t1->stptr[t1->stlen] = t2->stptr[t2->stlen] = '\0';
Packit 575503
			ret = strncasecmpmbs((const unsigned char *) cp1,
Packit 575503
					     (const unsigned char *) cp2, l);
Packit 575503
			t1->stptr[t1->stlen] = save1;
Packit 575503
			t2->stptr[t2->stlen] = save2;
Packit 575503
		} else {
Packit 575503
			/* Could use tolower() here; see discussion above. */
Packit 575503
			for (ret = 0; l-- > 0 && ret == 0; cp1++, cp2++)
Packit 575503
				ret = casetable[*cp1] - casetable[*cp2];
Packit 575503
		}
Packit 575503
	} else
Packit 575503
		ret = memcmp(t1->stptr, t2->stptr, l);
Packit 575503
Packit 575503
	ret = ret == 0 ? ldiff : ret;
Packit 575503
	return ret;
Packit 575503
}
Packit 575503
Packit 575503
/* push_frame --- push a frame NODE onto stack */
Packit 575503
Packit 575503
static void
Packit 575503
push_frame(NODE *f)
Packit 575503
{
Packit 575503
	static long max_fcall;
Packit 575503
Packit 575503
	/* NB: frame numbering scheme as in GDB. frame_ptr => frame #0. */
Packit 575503
Packit 575503
	fcall_count++;
Packit 575503
	if (fcall_list == NULL) {
Packit 575503
		max_fcall = 10;
Packit 575503
		emalloc(fcall_list, NODE **, (max_fcall + 1) * sizeof(NODE *), "push_frame");
Packit 575503
	} else if (fcall_count == max_fcall) {
Packit 575503
		max_fcall *= 2;
Packit 575503
		erealloc(fcall_list, NODE **, (max_fcall + 1) * sizeof(NODE *), "push_frame");
Packit 575503
	}
Packit 575503
Packit 575503
	if (fcall_count > 1)
Packit 575503
		memmove(fcall_list + 2, fcall_list + 1, (fcall_count - 1) * sizeof(NODE *));
Packit 575503
	fcall_list[1] = f;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* pop_frame --- pop off a frame NODE*/
Packit 575503
Packit 575503
static void
Packit 575503
pop_frame()
Packit 575503
{
Packit 575503
	if (fcall_count > 1)
Packit 575503
		memmove(fcall_list + 1, fcall_list + 2, (fcall_count - 1) * sizeof(NODE *));
Packit 575503
	fcall_count--;
Packit 575503
	assert(fcall_count >= 0);
Packit 575503
	if (do_debug)
Packit 575503
		frame_popped();
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* dump_fcall_stack --- print a backtrace of the awk function calls */
Packit 575503
Packit 575503
void
Packit 575503
dump_fcall_stack(FILE *fp)
Packit 575503
{
Packit 575503
	NODE *f, *func;
Packit 575503
	long i = 0, j, k = 0;
Packit 575503
Packit 575503
	if (fcall_count == 0)
Packit 575503
		return;
Packit 575503
	fprintf(fp, _("\n\t# Function Call Stack:\n\n"));
Packit 575503
Packit 575503
	/* current frame */
Packit 575503
	func = frame_ptr->func_node;
Packit 575503
	for (j = 0; j <= frame_ptr->num_tail_calls; j++)
Packit 575503
		fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
Packit 575503
Packit 575503
	/* outer frames except main */
Packit 575503
	for (i = 1; i < fcall_count; i++) {
Packit 575503
		f = fcall_list[i];
Packit 575503
		func = f->func_node;
Packit 575503
		for (j = 0; j <= f->num_tail_calls; j++)
Packit 575503
			fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
Packit 575503
	}
Packit 575503
Packit 575503
	fprintf(fp, "\t# %3ld. -- main --\n", k);
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* set_IGNORECASE --- update IGNORECASE as appropriate */
Packit 575503
Packit 575503
void
Packit 575503
set_IGNORECASE()
Packit 575503
{
Packit 575503
	static bool warned = false;
Packit 575503
Packit 575503
	if ((do_lint || do_traditional) && ! warned) {
Packit 575503
		warned = true;
Packit 575503
		lintwarn(_("`IGNORECASE' is a gawk extension"));
Packit 575503
	}
Packit 575503
	load_casetable();
Packit 575503
	if (do_traditional)
Packit 575503
		IGNORECASE = false;
Packit 575503
   	else
Packit 575503
		IGNORECASE = boolval(IGNORECASE_node->var_value);
Packit 575503
	set_RS();	/* set_RS() calls set_FS() if need be, for us */
Packit 575503
}
Packit 575503
Packit 575503
/* set_BINMODE --- set translation mode (OS/2, DOS, others) */
Packit 575503
Packit 575503
void
Packit 575503
set_BINMODE()
Packit 575503
{
Packit 575503
	static bool warned = false;
Packit 575503
	char *p;
Packit 575503
	NODE *v = fixtype(BINMODE_node->var_value);
Packit 575503
Packit 575503
	if ((do_lint || do_traditional) && ! warned) {
Packit 575503
		warned = true;
Packit 575503
		lintwarn(_("`BINMODE' is a gawk extension"));
Packit 575503
	}
Packit 575503
	if (do_traditional)
Packit 575503
		BINMODE = TEXT_TRANSLATE;
Packit 575503
	else if ((v->flags & NUMBER) != 0) {
Packit 575503
		BINMODE = get_number_si(v);
Packit 575503
		/* Make sure the value is rational. */
Packit 575503
		if (BINMODE < TEXT_TRANSLATE)
Packit 575503
			BINMODE = TEXT_TRANSLATE;
Packit 575503
		else if (BINMODE > BINMODE_BOTH)
Packit 575503
			BINMODE = BINMODE_BOTH;
Packit 575503
	} else if ((v->flags & STRING) != 0) {
Packit 575503
		p = v->stptr;
Packit 575503
Packit 575503
		/*
Packit 575503
		 * Allow only one of the following:
Packit 575503
		 * "0", "1", "2", "3",
Packit 575503
		 * "r", "w", "rw", "wr"
Packit 575503
		 * ANYTHING ELSE goes to 3. So there.
Packit 575503
		 */
Packit 575503
		switch (v->stlen) {
Packit 575503
		case 1:
Packit 575503
			switch (p[0]) {
Packit 575503
			case '0':
Packit 575503
			case '1':
Packit 575503
			case '2':
Packit 575503
			case '3':
Packit 575503
				BINMODE = p[0] - '0';
Packit 575503
				break;
Packit 575503
			case 'r':
Packit 575503
				BINMODE = BINMODE_INPUT;
Packit 575503
				break;
Packit 575503
			case 'w':
Packit 575503
				BINMODE = BINMODE_OUTPUT;
Packit 575503
				break;
Packit 575503
			default:
Packit 575503
				BINMODE = BINMODE_BOTH;
Packit 575503
				goto bad_value;
Packit 575503
				break;
Packit 575503
			}
Packit 575503
			break;
Packit 575503
		case 2:
Packit 575503
			switch (p[0]) {
Packit 575503
			case 'r':
Packit 575503
				BINMODE = BINMODE_BOTH;
Packit 575503
				if (p[1] != 'w')
Packit 575503
					goto bad_value;
Packit 575503
				break;
Packit 575503
			case 'w':
Packit 575503
				BINMODE = BINMODE_BOTH;
Packit 575503
				if (p[1] != 'r')
Packit 575503
					goto bad_value;
Packit 575503
				break;
Packit 575503
			}
Packit 575503
			break;
Packit 575503
		default:
Packit 575503
	bad_value:
Packit 575503
			lintwarn(_("BINMODE value `%s' is invalid, treated as 3"), p);
Packit 575503
			break;
Packit 575503
		}
Packit 575503
	} else
Packit 575503
		BINMODE = 3;		/* shouldn't happen */
Packit 575503
}
Packit 575503
Packit 575503
/* set_OFS --- update OFS related variables when OFS assigned to */
Packit 575503
Packit 575503
void
Packit 575503
set_OFS()
Packit 575503
{
Packit 575503
	static bool first = true;
Packit 575503
	size_t new_ofs_len;
Packit 575503
Packit 575503
	if (first)	/* true when called from init_vars() in main() */
Packit 575503
		first = false;
Packit 575503
	else {
Packit 575503
		/* rebuild $0 using OFS that was current when $0 changed */
Packit 575503
		if (! field0_valid) {
Packit 575503
			get_field(UNLIMITED - 1, NULL);
Packit 575503
			rebuild_record();
Packit 575503
		}
Packit 575503
	}
Packit 575503
Packit 575503
	/*
Packit 575503
	 * Save OFS value for use in building record and in printing.
Packit 575503
	 * Can't just have OFS point into the OFS_node since it's
Packit 575503
	 * already updated when we come into this routine, and we need
Packit 575503
	 * the old value to rebuild the record (see above).
Packit 575503
	 */
Packit 575503
	OFS_node->var_value = force_string(OFS_node->var_value);
Packit 575503
	new_ofs_len = OFS_node->var_value->stlen;
Packit 575503
Packit 575503
	if (OFS == NULL)
Packit 575503
		emalloc(OFS, char *, new_ofs_len + 1, "set_OFS");
Packit 575503
	else if (OFSlen < new_ofs_len)
Packit 575503
		erealloc(OFS, char *, new_ofs_len + 1, "set_OFS");
Packit 575503
Packit 575503
	memcpy(OFS, OFS_node->var_value->stptr, OFS_node->var_value->stlen);
Packit 575503
	OFSlen = new_ofs_len;
Packit 575503
	OFS[OFSlen] = '\0';
Packit 575503
}
Packit 575503
Packit 575503
/* set_ORS --- update ORS related variables when ORS assigned to */
Packit 575503
Packit 575503
void
Packit 575503
set_ORS()
Packit 575503
{
Packit 575503
	ORS_node->var_value = force_string(ORS_node->var_value);
Packit 575503
	ORS = ORS_node->var_value->stptr;
Packit 575503
	ORSlen = ORS_node->var_value->stlen;
Packit 575503
}
Packit 575503
Packit 575503
/* fmt_ok --- is the conversion format a valid one? */
Packit 575503
Packit 575503
NODE **fmt_list = NULL;
Packit 575503
static int fmt_ok(NODE *n);
Packit 575503
static int fmt_index(NODE *n);
Packit 575503
Packit 575503
static int
Packit 575503
fmt_ok(NODE *n)
Packit 575503
{
Packit 575503
	NODE *tmp = force_string(n);
Packit 575503
	const char *p = tmp->stptr;
Packit 575503
Packit 575503
#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
Packit 575503
	static const char float_formats[] = "efgEG";
Packit 575503
#else
Packit 575503
	static const char float_formats[] = "efgEFG";
Packit 575503
#endif
Packit 575503
#if defined(HAVE_LOCALE_H)
Packit 575503
	static const char flags[] = " +-#'";
Packit 575503
#else
Packit 575503
	static const char flags[] = " +-#";
Packit 575503
#endif
Packit 575503
Packit 575503
	// We rely on the caller to zero-terminate n->stptr.
Packit 575503
Packit 575503
	if (*p++ != '%')
Packit 575503
		return 0;
Packit 575503
	while (*p && strchr(flags, *p) != NULL)	/* flags */
Packit 575503
		p++;
Packit 575503
	while (*p && isdigit((unsigned char) *p))	/* width - %*.*g is NOT allowed */
Packit 575503
		p++;
Packit 575503
	if (*p == '\0' || (*p != '.' && ! isdigit((unsigned char) *p)))
Packit 575503
		return 0;
Packit 575503
	if (*p == '.')
Packit 575503
		p++;
Packit 575503
	while (*p && isdigit((unsigned char) *p))	/* precision */
Packit 575503
		p++;
Packit 575503
	if (*p == '\0' || strchr(float_formats, *p) == NULL)
Packit 575503
		return 0;
Packit 575503
	if (*++p != '\0')
Packit 575503
		return 0;
Packit 575503
	return 1;
Packit 575503
}
Packit 575503
Packit 575503
/* fmt_index --- track values of OFMT and CONVFMT to keep semantics correct */
Packit 575503
Packit 575503
static int
Packit 575503
fmt_index(NODE *n)
Packit 575503
{
Packit 575503
	int ix = 0;
Packit 575503
	static int fmt_num = 4;
Packit 575503
	static int fmt_hiwater = 0;
Packit 575503
	char save;
Packit 575503
Packit 575503
	if (fmt_list == NULL)
Packit 575503
		emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index");
Packit 575503
	n = force_string(n);
Packit 575503
Packit 575503
	save = n->stptr[n->stlen];
Packit 575503
	n->stptr[n->stlen] = '\0';
Packit 575503
Packit 575503
	while (ix < fmt_hiwater) {
Packit 575503
		if (cmp_nodes(fmt_list[ix], n, true) == 0)
Packit 575503
			return ix;
Packit 575503
		ix++;
Packit 575503
	}
Packit 575503
Packit 575503
	/* not found */
Packit 575503
	if (do_lint && ! fmt_ok(n))
Packit 575503
		lintwarn(_("bad `%sFMT' specification `%s'"),
Packit 575503
			    n == CONVFMT_node->var_value ? "CONV"
Packit 575503
			  : n == OFMT_node->var_value ? "O"
Packit 575503
			  : "", n->stptr);
Packit 575503
Packit 575503
	n->stptr[n->stlen] = save;
Packit 575503
Packit 575503
	if (fmt_hiwater >= fmt_num) {
Packit 575503
		fmt_num *= 2;
Packit 575503
		erealloc(fmt_list, NODE **, fmt_num * sizeof(*fmt_list), "fmt_index");
Packit 575503
	}
Packit 575503
	fmt_list[fmt_hiwater] = dupnode(n);
Packit 575503
	return fmt_hiwater++;
Packit 575503
}
Packit 575503
Packit 575503
/* set_OFMT --- track OFMT correctly */
Packit 575503
Packit 575503
void
Packit 575503
set_OFMT()
Packit 575503
{
Packit 575503
	OFMTidx = fmt_index(OFMT_node->var_value);
Packit 575503
	OFMT = fmt_list[OFMTidx]->stptr;
Packit 575503
}
Packit 575503
Packit 575503
/* set_CONVFMT --- track CONVFMT correctly */
Packit 575503
Packit 575503
void
Packit 575503
set_CONVFMT()
Packit 575503
{
Packit 575503
	CONVFMTidx = fmt_index(CONVFMT_node->var_value);
Packit 575503
	CONVFMT = fmt_list[CONVFMTidx]->stptr;
Packit 575503
}
Packit 575503
Packit 575503
/* set_LINT --- update LINT as appropriate */
Packit 575503
Packit 575503
void
Packit 575503
set_LINT()
Packit 575503
{
Packit 575503
#ifndef NO_LINT
Packit 575503
	int old_lint = do_lint;
Packit 575503
	NODE *n = fixtype(LINT_node->var_value);
Packit 575503
Packit 575503
	/* start with clean defaults */
Packit 575503
	lintfunc = r_warning;
Packit 575503
	do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
Packit 575503
Packit 575503
	if ((n->flags & STRING) != 0) {
Packit 575503
		const char *lintval;
Packit 575503
		size_t lintlen;
Packit 575503
Packit 575503
		lintval = n->stptr;
Packit 575503
		lintlen = n->stlen;
Packit 575503
		if (lintlen > 0) {
Packit 575503
			if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0)
Packit 575503
				do_flags |= DO_LINT_INVALID;
Packit 575503
			else {
Packit 575503
				do_flags |= DO_LINT_ALL;
Packit 575503
				if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0)
Packit 575503
					lintfunc = r_fatal;
Packit 575503
			}
Packit 575503
		}
Packit 575503
	} else {
Packit 575503
		if (! iszero(n))
Packit 575503
			do_flags |= DO_LINT_ALL;
Packit 575503
	}
Packit 575503
Packit 575503
	/* explicitly use warning() here, in case lintfunc == r_fatal */
Packit 575503
	if (old_lint != do_lint && old_lint && ! do_lint)
Packit 575503
		warning(_("turning off `--lint' due to assignment to `LINT'"));
Packit 575503
Packit 575503
	/* inform plug-in api of change */
Packit 575503
	update_ext_api();
Packit 575503
#endif /* ! NO_LINT */
Packit 575503
}
Packit 575503
Packit 575503
/* set_TEXTDOMAIN --- update TEXTDOMAIN variable when TEXTDOMAIN assigned to */
Packit 575503
Packit 575503
void
Packit 575503
set_TEXTDOMAIN()
Packit 575503
{
Packit 575503
	NODE *tmp;
Packit 575503
Packit 575503
	tmp = TEXTDOMAIN_node->var_value = force_string(TEXTDOMAIN_node->var_value);
Packit 575503
	TEXTDOMAIN = tmp->stptr;
Packit 575503
	/*
Packit 575503
	 * Note: don't call textdomain(); this value is for
Packit 575503
	 * the awk program, not for gawk itself.
Packit 575503
	 */
Packit 575503
}
Packit 575503
Packit 575503
/* update_ERRNO_int --- update the value of ERRNO based on argument */
Packit 575503
Packit 575503
void
Packit 575503
update_ERRNO_int(int errcode)
Packit 575503
{
Packit 575503
	char *cp;
Packit 575503
Packit 575503
	update_PROCINFO_num("errno", errcode);
Packit 575503
	if (errcode) {
Packit 575503
		cp = strerror(errcode);
Packit 575503
		cp = gettext(cp);
Packit 575503
	} else
Packit 575503
		cp = "";
Packit 575503
	unref(ERRNO_node->var_value);
Packit 575503
	ERRNO_node->var_value = make_string(cp, strlen(cp));
Packit 575503
}
Packit 575503
Packit 575503
/* update_ERRNO_string --- update ERRNO */
Packit 575503
Packit 575503
void
Packit 575503
update_ERRNO_string(const char *string)
Packit 575503
{
Packit 575503
	update_PROCINFO_num("errno", 0);
Packit 575503
	unref(ERRNO_node->var_value);
Packit 575503
	ERRNO_node->var_value = make_string(string, strlen(string));
Packit 575503
}
Packit 575503
Packit 575503
/* unset_ERRNO --- eliminate the value of ERRNO */
Packit 575503
Packit 575503
void
Packit 575503
unset_ERRNO(void)
Packit 575503
{
Packit 575503
	update_PROCINFO_num("errno", 0);
Packit 575503
	unref(ERRNO_node->var_value);
Packit 575503
	ERRNO_node->var_value = dupnode(Nnull_string);
Packit 575503
}
Packit 575503
Packit 575503
/* update_NR --- update the value of NR */
Packit 575503
Packit 575503
void
Packit 575503
update_NR()
Packit 575503
{
Packit 575503
#ifdef HAVE_MPFR
Packit 575503
	if (is_mpg_number(NR_node->var_value))
Packit 575503
		(void) mpg_update_var(NR_node);
Packit 575503
	else
Packit 575503
#endif
Packit 575503
	if (NR_node->var_value->numbr != NR) {
Packit 575503
		unref(NR_node->var_value);
Packit 575503
		NR_node->var_value = make_number(NR);
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
/* update_NF --- update the value of NF */
Packit 575503
Packit 575503
void
Packit 575503
update_NF()
Packit 575503
{
Packit 575503
	long l;
Packit 575503
Packit 575503
	l = get_number_si(NF_node->var_value);
Packit 575503
	if (NF == -1 || l != NF) {
Packit 575503
		if (NF == -1)
Packit 575503
			(void) get_field(UNLIMITED - 1, NULL); /* parse record */
Packit 575503
		unref(NF_node->var_value);
Packit 575503
		NF_node->var_value = make_number(NF);
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
/* update_FNR --- update the value of FNR */
Packit 575503
Packit 575503
void
Packit 575503
update_FNR()
Packit 575503
{
Packit 575503
#ifdef HAVE_MPFR
Packit 575503
	if (is_mpg_number(FNR_node->var_value))
Packit 575503
		(void) mpg_update_var(FNR_node);
Packit 575503
	else
Packit 575503
#endif
Packit 575503
	if (FNR_node->var_value->numbr != FNR) {
Packit 575503
		unref(FNR_node->var_value);
Packit 575503
		FNR_node->var_value = make_number(FNR);
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
NODE *frame_ptr;        /* current frame */
Packit 575503
STACK_ITEM *stack_ptr = NULL;
Packit 575503
STACK_ITEM *stack_bottom;
Packit 575503
STACK_ITEM *stack_top;
Packit 575503
static unsigned long STACK_SIZE = 256;    /* initial size of stack */
Packit 575503
int max_args = 0;       /* maximum # of arguments to printf, print, sprintf,
Packit 575503
                         * or # of array subscripts, or adjacent strings
Packit 575503
                         * to be concatenated.
Packit 575503
                         */
Packit 575503
NODE **args_array = NULL;
Packit 575503
Packit 575503
/* grow_stack --- grow the size of runtime stack */
Packit 575503
Packit 575503
/* N.B. stack_ptr points to the topmost occupied location
Packit 575503
 *      on the stack, not the first free location.
Packit 575503
 */
Packit 575503
Packit 575503
STACK_ITEM *
Packit 575503
grow_stack()
Packit 575503
{
Packit 575503
	STACK_SIZE *= 2;
Packit 575503
	erealloc(stack_bottom, STACK_ITEM *, STACK_SIZE * sizeof(STACK_ITEM), "grow_stack");
Packit 575503
	stack_top = stack_bottom + STACK_SIZE - 1;
Packit 575503
	stack_ptr = stack_bottom + STACK_SIZE / 2;
Packit 575503
	return stack_ptr;
Packit 575503
}
Packit 575503
Packit 575503
/*
Packit 575503
 * r_get_lhs:
Packit 575503
 * This returns a POINTER to a node pointer (var's value).
Packit 575503
 * used to store the var's new value.
Packit 575503
 */
Packit 575503
Packit 575503
NODE **
Packit 575503
r_get_lhs(NODE *n, bool reference)
Packit 575503
{
Packit 575503
	bool isparam = false;
Packit 575503
Packit 575503
	if (n->type == Node_param_list) {
Packit 575503
		isparam = true;
Packit 575503
		n = GET_PARAM(n->param_cnt);
Packit 575503
	}
Packit 575503
Packit 575503
	switch (n->type) {
Packit 575503
	case Node_var_array:
Packit 575503
		fatal(_("attempt to use array `%s' in a scalar context"),
Packit 575503
				array_vname(n));
Packit 575503
	case Node_array_ref:
Packit 575503
		if (n->orig_array->type == Node_var_array)
Packit 575503
			fatal(_("attempt to use array `%s' in a scalar context"),
Packit 575503
					array_vname(n));
Packit 575503
		if (n->orig_array->type != Node_var) {
Packit 575503
			n->orig_array->type = Node_var;
Packit 575503
			n->orig_array->var_value = dupnode(Nnull_string);
Packit 575503
		}
Packit 575503
		/* fall through */
Packit 575503
	case Node_var_new:
Packit 575503
		n->type = Node_var;
Packit 575503
		n->var_value = dupnode(Nnull_string);
Packit 575503
		break;
Packit 575503
Packit 575503
	case Node_var:
Packit 575503
		break;
Packit 575503
Packit 575503
	default:
Packit 575503
		cant_happen();
Packit 575503
	}
Packit 575503
Packit 575503
	if (do_lint && reference && var_uninitialized(n))
Packit 575503
		lintwarn((isparam ?
Packit 575503
			_("reference to uninitialized argument `%s'") :
Packit 575503
			_("reference to uninitialized variable `%s'")),
Packit 575503
				n->vname);
Packit 575503
	return & n->var_value;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* r_get_field --- get the address of a field node */
Packit 575503
Packit 575503
NODE **
Packit 575503
r_get_field(NODE *n, Func_ptr *assign, bool reference)
Packit 575503
{
Packit 575503
	long field_num;
Packit 575503
	NODE **lhs;
Packit 575503
Packit 575503
	if (assign)
Packit 575503
		*assign = NULL;
Packit 575503
	if (do_lint) {
Packit 575503
		if ((fixtype(n)->flags & NUMBER) == 0) {
Packit 575503
			lintwarn(_("attempt to field reference from non-numeric value"));
Packit 575503
			if (n->stlen == 0)
Packit 575503
				lintwarn(_("attempt to field reference from null string"));
Packit 575503
		}
Packit 575503
	}
Packit 575503
Packit 575503
	(void) force_number(n);
Packit 575503
	field_num = get_number_si(n);
Packit 575503
Packit 575503
	if (field_num < 0)
Packit 575503
		fatal(_("attempt to access field %ld"), field_num);
Packit 575503
Packit 575503
	if (field_num == 0 && field0_valid) {		/* short circuit */
Packit 575503
		lhs = &fields_arr[0];
Packit 575503
		if (assign)
Packit 575503
			*assign = reset_record;
Packit 575503
	} else
Packit 575503
		lhs = get_field(field_num, assign);
Packit 575503
	if (do_lint && reference && ((*lhs)->flags & NULL_FIELD) != 0)
Packit 575503
		lintwarn(_("reference to uninitialized field `$%ld'"),
Packit 575503
			      field_num);
Packit 575503
	return lhs;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/*
Packit 575503
 * calc_exp_posint --- calculate x^n for positive integral n,
Packit 575503
 * using exponentiation by squaring without recursion.
Packit 575503
 */
Packit 575503
Packit 575503
static AWKNUM
Packit 575503
calc_exp_posint(AWKNUM x, long n)
Packit 575503
{
Packit 575503
	AWKNUM mult = 1;
Packit 575503
Packit 575503
	while (n > 1) {
Packit 575503
		if ((n % 2) == 1)
Packit 575503
			mult *= x;
Packit 575503
		x *= x;
Packit 575503
		n /= 2;
Packit 575503
	}
Packit 575503
	return mult * x;
Packit 575503
}
Packit 575503
Packit 575503
/* calc_exp --- calculate x1^x2 */
Packit 575503
Packit 575503
AWKNUM
Packit 575503
calc_exp(AWKNUM x1, AWKNUM x2)
Packit 575503
{
Packit 575503
	long lx;
Packit 575503
Packit 575503
	if ((lx = x2) == x2) {		/* integer exponent */
Packit 575503
		if (lx == 0)
Packit 575503
			return 1;
Packit 575503
		return (lx > 0) ? calc_exp_posint(x1, lx)
Packit 575503
				: 1.0 / calc_exp_posint(x1, -lx);
Packit 575503
	}
Packit 575503
	return (AWKNUM) pow((double) x1, (double) x2);
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* setup_frame --- setup new frame for function call */
Packit 575503
Packit 575503
static INSTRUCTION *
Packit 575503
setup_frame(INSTRUCTION *pc)
Packit 575503
{
Packit 575503
	NODE *r = NULL;
Packit 575503
	NODE *m, *f, *fp;
Packit 575503
	NODE **sp = NULL;
Packit 575503
	int pcount, arg_count, i, j;
Packit 575503
	bool tail_optimize = false;
Packit 575503
Packit 575503
	f = pc->func_body;
Packit 575503
	pcount = f->param_cnt;
Packit 575503
	fp = f->fparms;
Packit 575503
	arg_count = (pc + 1)->expr_count;
Packit 575503
Packit 575503
	/* tail recursion optimization */
Packit 575503
	tail_optimize =  ((pc + 1)->tail_call && do_optimize
Packit 575503
				&& ! do_debug && ! do_profile);
Packit 575503
Packit 575503
	if (tail_optimize) {
Packit 575503
		/* free local vars of calling frame */
Packit 575503
Packit 575503
		NODE *func;
Packit 575503
		int n;
Packit 575503
Packit 575503
		func = frame_ptr->func_node;
Packit 575503
		for (n = func->param_cnt, sp = frame_ptr->stack; n > 0; n--) {
Packit 575503
			r = *sp++;
Packit 575503
			if (r->type == Node_var)     /* local variable */
Packit 575503
				DEREF(r->var_value);
Packit 575503
			else if (r->type == Node_var_array)     /* local array */
Packit 575503
				assoc_clear(r);
Packit 575503
		}
Packit 575503
		sp = frame_ptr->stack;
Packit 575503
Packit 575503
	} else if (pcount > 0) {
Packit 575503
		ezalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
Packit 575503
	}
Packit 575503
Packit 575503
Packit 575503
	/* check for extra args */
Packit 575503
	if (arg_count > pcount) {
Packit 575503
		warning(
Packit 575503
			_("function `%s' called with more arguments than declared"),
Packit 575503
       			f->vname);
Packit 575503
		do {
Packit 575503
			r = POP();
Packit 575503
			if (r->type == Node_val)
Packit 575503
				DEREF(r);
Packit 575503
		} while (--arg_count > pcount);
Packit 575503
	}
Packit 575503
Packit 575503
	for (i = 0, j = arg_count - 1; i < pcount; i++, j--) {
Packit 575503
		if (tail_optimize)
Packit 575503
			r = sp[i];
Packit 575503
		else {
Packit 575503
			getnode(r);
Packit 575503
			memset(r, 0, sizeof(NODE));
Packit 575503
			sp[i] = r;
Packit 575503
		}
Packit 575503
Packit 575503
		if (i >= arg_count) {
Packit 575503
			/* local variable */
Packit 575503
			r->type = Node_var_new;
Packit 575503
			r->vname = fp[i].param;
Packit 575503
			continue;
Packit 575503
		}
Packit 575503
Packit 575503
		m = PEEK(j); /* arguments in reverse order on runtime stack */
Packit 575503
Packit 575503
		if (m->type == Node_param_list)
Packit 575503
			m = GET_PARAM(m->param_cnt);
Packit 575503
Packit 575503
		/* $0 needs to be passed by value to a function */
Packit 575503
		if (m == fields_arr[0]) {
Packit 575503
			DEREF(m);
Packit 575503
			m = dupnode(m);
Packit 575503
		}
Packit 575503
Packit 575503
		switch (m->type) {
Packit 575503
		case Node_var_new:
Packit 575503
		case Node_var_array:
Packit 575503
			r->type = Node_array_ref;
Packit 575503
			r->orig_array = r->prev_array = m;
Packit 575503
			break;
Packit 575503
Packit 575503
		case Node_array_ref:
Packit 575503
			r->type = Node_array_ref;
Packit 575503
			r->orig_array = m->orig_array;
Packit 575503
			r->prev_array = m;
Packit 575503
			break;
Packit 575503
Packit 575503
		case Node_var:
Packit 575503
			/* Untyped (Node_var_new) variable as param became a
Packit 575503
			 * scalar during evaluation of expression for a
Packit 575503
			 * subsequent param.
Packit 575503
			 */
Packit 575503
			r->type = Node_var;
Packit 575503
			r->var_value = dupnode(Nnull_string);
Packit 575503
			break;
Packit 575503
Packit 575503
		case Node_val:
Packit 575503
			r->type = Node_var;
Packit 575503
			r->var_value = m;
Packit 575503
			break;
Packit 575503
Packit 575503
		default:
Packit 575503
			cant_happen();
Packit 575503
		}
Packit 575503
		r->vname = fp[i].param;
Packit 575503
	}
Packit 575503
Packit 575503
	stack_adj(-arg_count);	/* adjust stack pointer */
Packit 575503
Packit 575503
	if (tail_optimize) {
Packit 575503
		frame_ptr->num_tail_calls++;
Packit 575503
		return f->code_ptr;
Packit 575503
	}
Packit 575503
Packit 575503
	if (pc->opcode == Op_indirect_func_call) {
Packit 575503
		r = POP();	/* indirect var */
Packit 575503
		DEREF(r);
Packit 575503
	}
Packit 575503
Packit 575503
	frame_ptr->vname = source;	/* save current source */
Packit 575503
Packit 575503
	if (do_profile || do_debug)
Packit 575503
		push_frame(frame_ptr);
Packit 575503
Packit 575503
	/* save current frame in stack */
Packit 575503
	PUSH(frame_ptr);
Packit 575503
Packit 575503
	/* setup new frame */
Packit 575503
	getnode(frame_ptr);
Packit 575503
	frame_ptr->type = Node_frame;
Packit 575503
	frame_ptr->stack = sp;
Packit 575503
	frame_ptr->prev_frame_size = (stack_ptr - stack_bottom); /* size of the previous stack frame */
Packit 575503
	frame_ptr->func_node = f;
Packit 575503
	frame_ptr->num_tail_calls = 0;
Packit 575503
	frame_ptr->vname = NULL;
Packit 575503
	frame_ptr->reti = pc; /* on return execute pc->nexti */
Packit 575503
Packit 575503
	return f->code_ptr;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* restore_frame --- clean up the stack and update frame */
Packit 575503
Packit 575503
static INSTRUCTION *
Packit 575503
restore_frame(NODE *fp)
Packit 575503
{
Packit 575503
	NODE *r;
Packit 575503
	NODE **sp;
Packit 575503
	int n;
Packit 575503
	NODE *func;
Packit 575503
	INSTRUCTION *ri;
Packit 575503
Packit 575503
	func = frame_ptr->func_node;
Packit 575503
	n = func->param_cnt;
Packit 575503
	sp = frame_ptr->stack;
Packit 575503
Packit 575503
	for (; n > 0; n--) {
Packit 575503
		r = *sp++;
Packit 575503
		if (r->type == Node_var)     /* local variable */
Packit 575503
			DEREF(r->var_value);
Packit 575503
		else if (r->type == Node_var_array)     /* local array */
Packit 575503
			assoc_clear(r);
Packit 575503
		freenode(r);
Packit 575503
	}
Packit 575503
Packit 575503
	if (frame_ptr->stack != NULL)
Packit 575503
		efree(frame_ptr->stack);
Packit 575503
	ri = frame_ptr->reti;     /* execution in calling frame
Packit 575503
	                           * resumes from ri->nexti.
Packit 575503
	                           */
Packit 575503
	freenode(frame_ptr);
Packit 575503
	if (do_profile || do_debug)
Packit 575503
		pop_frame();
Packit 575503
Packit 575503
	/* restore frame */
Packit 575503
	frame_ptr = fp;
Packit 575503
	/* restore source */
Packit 575503
	source = fp->vname;
Packit 575503
	fp->vname = NULL;
Packit 575503
Packit 575503
	return ri->nexti;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* free_arrayfor --- free 'for (var in array)' related data */
Packit 575503
Packit 575503
static inline void
Packit 575503
free_arrayfor(NODE *r)
Packit 575503
{
Packit 575503
	if (r->for_list != NULL) {
Packit 575503
		NODE *n;
Packit 575503
		size_t num_elems = r->for_list_size;
Packit 575503
		NODE **list = r->for_list;
Packit 575503
		while (num_elems > 0) {
Packit 575503
			n = list[--num_elems];
Packit 575503
			unref(n);
Packit 575503
		}
Packit 575503
		efree(list);
Packit 575503
	}
Packit 575503
	freenode(r);
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/*
Packit 575503
 * unwind_stack --- pop items off the run-time stack;
Packit 575503
 *	'n' is the # of items left in the stack.
Packit 575503
 */
Packit 575503
Packit 575503
INSTRUCTION *
Packit 575503
unwind_stack(long n)
Packit 575503
{
Packit 575503
	NODE *r;
Packit 575503
	INSTRUCTION *cp = NULL;
Packit 575503
	STACK_ITEM *sp;
Packit 575503
Packit 575503
	if (stack_empty())
Packit 575503
		return NULL;
Packit 575503
Packit 575503
	sp = stack_bottom + n;
Packit 575503
Packit 575503
	if (stack_ptr < sp)
Packit 575503
		return NULL;
Packit 575503
Packit 575503
	while ((r = POP()) != NULL) {
Packit 575503
		switch (r->type) {
Packit 575503
		case Node_frame:
Packit 575503
			cp = restore_frame(r);
Packit 575503
			break;
Packit 575503
		case Node_arrayfor:
Packit 575503
			free_arrayfor(r);
Packit 575503
			break;
Packit 575503
		case Node_val:
Packit 575503
			DEREF(r);
Packit 575503
			break;
Packit 575503
		case Node_instruction:
Packit 575503
			freenode(r);
Packit 575503
			break;
Packit 575503
		default:
Packit 575503
			/*
Packit 575503
			 * Check `exiting' and don't produce an error for
Packit 575503
			 * cases like:
Packit 575503
			 *	func     _fn0() { exit }
Packit 575503
			 *	BEGIN { ARRAY[_fn0()] }
Packit 575503
			 */
Packit 575503
			if (in_main_context() && ! exiting)
Packit 575503
				fatal(_("unwind_stack: unexpected type `%s'"),
Packit 575503
						nodetype2str(r->type));
Packit 575503
			/* else
Packit 575503
				* Node_var_array,
Packit 575503
				* Node_param_list,
Packit 575503
				* Node_var (e.g: trying to use scalar for array)
Packit 575503
				* Node_regex/Node_dynregex
Packit 575503
				* ?
Packit 575503
			 */
Packit 575503
			break;
Packit 575503
		}
Packit 575503
Packit 575503
		if (stack_ptr < sp)
Packit 575503
			break;
Packit 575503
	}
Packit 575503
	return cp;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* pop_fcall --- pop off the innermost frame */
Packit 575503
#define pop_fcall()	unwind_stack(frame_ptr->prev_frame_size)
Packit 575503
Packit 575503
/* pop the run-time stack */
Packit 575503
#define pop_stack()	(void) unwind_stack(0)
Packit 575503
Packit 575503
Packit 575503
static inline bool
Packit 575503
eval_condition(NODE *t)
Packit 575503
{
Packit 575503
	if (t == node_Boolean[false])
Packit 575503
		return false;
Packit 575503
Packit 575503
	if (t == node_Boolean[true])
Packit 575503
		return true;
Packit 575503
Packit 575503
	return boolval(t);
Packit 575503
}
Packit 575503
Packit 575503
typedef enum {
Packit 575503
	SCALAR_EQ_NEQ,
Packit 575503
	SCALAR_RELATIONAL
Packit 575503
} scalar_cmp_t;
Packit 575503
Packit 575503
/* cmp_scalars -- compare two nodes on the stack */
Packit 575503
Packit 575503
static inline int
Packit 575503
cmp_scalars(scalar_cmp_t comparison_type)
Packit 575503
{
Packit 575503
	NODE *t1, *t2;
Packit 575503
	int di;
Packit 575503
Packit 575503
	t2 = POP_SCALAR();
Packit 575503
	t1 = TOP();
Packit 575503
	if (t1->type == Node_var_array) {
Packit 575503
		DEREF(t2);
Packit 575503
		fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t1));
Packit 575503
	}
Packit 575503
	di = cmp_nodes(t1, t2, comparison_type == SCALAR_EQ_NEQ);
Packit 575503
	DEREF(t1);
Packit 575503
	DEREF(t2);
Packit 575503
	return di;
Packit 575503
}
Packit 575503
Packit 575503
/* op_assign --- assignment operators excluding = */
Packit 575503
Packit 575503
static void
Packit 575503
op_assign(OPCODE op)
Packit 575503
{
Packit 575503
	NODE **lhs;
Packit 575503
	NODE *t1, *t2;
Packit 575503
	AWKNUM x = 0.0, x1, x2;
Packit 575503
Packit 575503
	lhs = POP_ADDRESS();
Packit 575503
	t1 = *lhs;
Packit 575503
	x1 = force_number(t1)->numbr;
Packit 575503
Packit 575503
	t2 = TOP_SCALAR();
Packit 575503
	x2 = force_number(t2)->numbr;
Packit 575503
	DEREF(t2);
Packit 575503
Packit 575503
	switch (op) {
Packit 575503
	case Op_assign_plus:
Packit 575503
		x = x1 + x2;
Packit 575503
		break;
Packit 575503
	case Op_assign_minus:
Packit 575503
		x = x1 - x2;
Packit 575503
		break;
Packit 575503
	case Op_assign_times:
Packit 575503
		x = x1 * x2;
Packit 575503
		break;
Packit 575503
	case Op_assign_quotient:
Packit 575503
		if (x2 == (AWKNUM) 0) {
Packit 575503
			decr_sp();
Packit 575503
			fatal(_("division by zero attempted in `/='"));
Packit 575503
		}
Packit 575503
		x = x1 / x2;
Packit 575503
		break;
Packit 575503
	case Op_assign_mod:
Packit 575503
		if (x2 == (AWKNUM) 0) {
Packit 575503
			decr_sp();
Packit 575503
			fatal(_("division by zero attempted in `%%='"));
Packit 575503
		}
Packit 575503
#ifdef HAVE_FMOD
Packit 575503
		x = fmod(x1, x2);
Packit 575503
#else   /* ! HAVE_FMOD */
Packit 575503
		(void) modf(x1 / x2, &x);
Packit 575503
		x = x1 - x2 * x;
Packit 575503
#endif  /* ! HAVE_FMOD */
Packit 575503
		break;
Packit 575503
	case Op_assign_exp:
Packit 575503
		x = calc_exp((double) x1, (double) x2);
Packit 575503
		break;
Packit 575503
	default:
Packit 575503
		break;
Packit 575503
	}
Packit 575503
Packit 575503
	if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
Packit 575503
		/* optimization */
Packit 575503
		t1->numbr = x;
Packit 575503
	} else {
Packit 575503
		unref(t1);
Packit 575503
		t1 = *lhs = make_number(x);
Packit 575503
	}
Packit 575503
Packit 575503
	UPREF(t1);
Packit 575503
	REPLACE(t1);
Packit 575503
}
Packit 575503
Packit 575503
/* PUSH_CODE --- push a code onto the runtime stack */
Packit 575503
Packit 575503
void
Packit 575503
PUSH_CODE(INSTRUCTION *cp)
Packit 575503
{
Packit 575503
	NODE *r;
Packit 575503
	getnode(r);
Packit 575503
	r->type = Node_instruction;
Packit 575503
	r->code_ptr = cp;
Packit 575503
	PUSH(r);
Packit 575503
}
Packit 575503
Packit 575503
/* POP_CODE --- pop a code off the runtime stack */
Packit 575503
Packit 575503
INSTRUCTION *
Packit 575503
POP_CODE()
Packit 575503
{
Packit 575503
	NODE *r;
Packit 575503
	INSTRUCTION *cp;
Packit 575503
	r = POP();
Packit 575503
	cp = r->code_ptr;
Packit 575503
	freenode(r);
Packit 575503
	return cp;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/*
Packit 575503
 * Implementation of BEGINFILE and ENDFILE requires saving an execution
Packit 575503
 * state and the ability to return to that state. The state is
Packit 575503
 * defined by the instruction triggering the BEGINFILE/ENDFILE rule, the
Packit 575503
 * run-time stack, the rule and the source file. The source line is available in
Packit 575503
 * the instruction and hence is not considered a part of the execution state.
Packit 575503
 */
Packit 575503
Packit 575503
Packit 575503
typedef struct exec_state {
Packit 575503
	struct exec_state *next;
Packit 575503
Packit 575503
	INSTRUCTION *cptr;  /* either getline (Op_K_getline) or the
Packit 575503
	                     * implicit "open-file, read-record" loop (Op_newfile).
Packit 575503
	                     */
Packit 575503
Packit 575503
	int rule;           /* rule for the INSTRUCTION */
Packit 575503
Packit 575503
	long stack_size;    /* For this particular usage, it is sufficient to save
Packit 575503
	                     * only the size of the call stack. We do not
Packit 575503
	                     * store the actual stack pointer to avoid problems
Packit 575503
	                     * in case the stack gets realloc-ed.
Packit 575503
	                     */
Packit 575503
Packit 575503
	const char *source; /* source file for the INSTRUCTION */
Packit 575503
} EXEC_STATE;
Packit 575503
Packit 575503
static EXEC_STATE exec_state_stack;
Packit 575503
Packit 575503
/* push_exec_state --- save an execution state on stack */
Packit 575503
Packit 575503
static void
Packit 575503
push_exec_state(INSTRUCTION *cp, int rule, char *src, STACK_ITEM *sp)
Packit 575503
{
Packit 575503
	EXEC_STATE *es;
Packit 575503
Packit 575503
	emalloc(es, EXEC_STATE *, sizeof(EXEC_STATE), "push_exec_state");
Packit 575503
	es->rule = rule;
Packit 575503
	es->cptr = cp;
Packit 575503
	es->stack_size = (sp - stack_bottom) + 1;
Packit 575503
	es->source = src;
Packit 575503
	es->next = exec_state_stack.next;
Packit 575503
	exec_state_stack.next = es;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* pop_exec_state --- pop one execution state off the stack */
Packit 575503
Packit 575503
static INSTRUCTION *
Packit 575503
pop_exec_state(int *rule, char **src, long *sz)
Packit 575503
{
Packit 575503
	INSTRUCTION *cp;
Packit 575503
	EXEC_STATE *es;
Packit 575503
Packit 575503
	es = exec_state_stack.next;
Packit 575503
	if (es == NULL)
Packit 575503
		return NULL;
Packit 575503
	cp = es->cptr;
Packit 575503
	if (rule != NULL)
Packit 575503
		*rule = es->rule;
Packit 575503
	if (src != NULL)
Packit 575503
		*src = (char *) es->source;
Packit 575503
	if (sz != NULL)
Packit 575503
		*sz = es->stack_size;
Packit 575503
	exec_state_stack.next = es->next;
Packit 575503
	efree(es);
Packit 575503
	return cp;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* register_exec_hook --- add exec hooks in the interpreter. */
Packit 575503
Packit 575503
int
Packit 575503
register_exec_hook(Func_pre_exec preh, Func_post_exec posth)
Packit 575503
{
Packit 575503
	int pos = 0;
Packit 575503
Packit 575503
	/*
Packit 575503
	 * multiple post-exec hooks aren't supported. post-exec hook is mainly
Packit 575503
	 * for use by the debugger.
Packit 575503
	 */
Packit 575503
Packit 575503
	if (! preh || (post_execute && posth))
Packit 575503
		return false;
Packit 575503
Packit 575503
	if (num_exec_hook == MAX_EXEC_HOOKS)
Packit 575503
		return false;
Packit 575503
Packit 575503
	/*
Packit 575503
	 * Add to the beginning of the array but do not displace the
Packit 575503
	 * debugger hook if it exists.
Packit 575503
	 */
Packit 575503
	if (num_exec_hook > 0) {
Packit 575503
		pos = !! do_debug;
Packit 575503
		if (num_exec_hook > pos)
Packit 575503
			memmove(pre_execute + pos + 1, pre_execute + pos,
Packit 575503
					(num_exec_hook - pos) * sizeof (preh));
Packit 575503
	}
Packit 575503
	pre_execute[pos] = preh;
Packit 575503
	num_exec_hook++;
Packit 575503
Packit 575503
	if (posth)
Packit 575503
		post_execute = posth;
Packit 575503
Packit 575503
	return true;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* interpreter routine when not debugging */
Packit 575503
#include "interpret.h"
Packit 575503
Packit 575503
/* interpreter routine with exec hook(s). Used when debugging and/or with MPFR. */
Packit 575503
#define r_interpret h_interpret
Packit 575503
#define EXEC_HOOK 1
Packit 575503
#include "interpret.h"
Packit 575503
#undef EXEC_HOOK
Packit 575503
#undef r_interpret
Packit 575503
Packit 575503
Packit 575503
void
Packit 575503
init_interpret()
Packit 575503
{
Packit 575503
	long newval;
Packit 575503
Packit 575503
	if ((newval = getenv_long("GAWK_STACKSIZE")) > 0)
Packit 575503
		STACK_SIZE = newval;
Packit 575503
Packit 575503
	emalloc(stack_bottom, STACK_ITEM *, STACK_SIZE * sizeof(STACK_ITEM), "grow_stack");
Packit 575503
	stack_ptr = stack_bottom - 1;
Packit 575503
	stack_top = stack_bottom + STACK_SIZE - 1;
Packit 575503
Packit 575503
	/* initialize frame pointer */
Packit 575503
	getnode(frame_ptr);
Packit 575503
	frame_ptr->type = Node_frame;
Packit 575503
	frame_ptr->stack = NULL;
Packit 575503
	frame_ptr->func_node = NULL;	/* in main */
Packit 575503
	frame_ptr->num_tail_calls = 0;
Packit 575503
	frame_ptr->vname = NULL;
Packit 575503
Packit 575503
	/* initialize true and false nodes */
Packit 575503
	node_Boolean[false] = make_number(0.0);
Packit 575503
	node_Boolean[true] = make_number(1.0);
Packit 575503
	if (! is_mpg_number(node_Boolean[false])) {
Packit 575503
		node_Boolean[false]->flags |= NUMINT;
Packit 575503
		node_Boolean[true]->flags |= NUMINT;
Packit 575503
	}
Packit 575503
Packit 575503
	/*
Packit 575503
	 * Select the interpreter routine. The version without
Packit 575503
	 * any exec hook support (r_interpret) is faster by about
Packit 575503
	 * 5%, or more depending on the opcodes.
Packit 575503
	 */
Packit 575503
Packit 575503
	if (num_exec_hook > 0)
Packit 575503
		interpret = h_interpret;
Packit 575503
	else
Packit 575503
		interpret = r_interpret;
Packit 575503
}
Packit 575503