Blame main.c

Packit Service f629e6
/*
Packit Service f629e6
 * main.c -- Code generator and main program for gawk.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 1986, 1988, 1989, 1991-2018 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
/* FIX THIS BEFORE EVERY RELEASE: */
Packit Service f629e6
#define UPDATE_YEAR	2018
Packit Service f629e6
Packit Service f629e6
#include "awk.h"
Packit Service f629e6
#include "getopt.h"
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_MCHECK_H
Packit Service f629e6
#include <mcheck.h>
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_LIBSIGSEGV
Packit Service f629e6
#include <sigsegv.h>
Packit Service f629e6
#else
Packit Service f629e6
typedef void *stackoverflow_context_t;
Packit Service f629e6
/* the argument to this macro is purposely not used */
Packit Service f629e6
#define sigsegv_install_handler(catchsegv) signal(SIGSEGV, catchsig)
Packit Service f629e6
/* define as 0 rather than empty so that (void) cast on it works */
Packit Service f629e6
#define stackoverflow_install_handler(catchstackoverflow, extra_stack, STACK_SIZE) 0
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#define DEFAULT_PROFILE		"awkprof.out"	/* where to put profile */
Packit Service f629e6
#define DEFAULT_VARFILE		"awkvars.out"	/* where to put vars */
Packit Service f629e6
#define DEFAULT_PREC		53
Packit Service f629e6
#define DEFAULT_ROUNDMODE	"N"		/* round to nearest */
Packit Service f629e6
Packit Service f629e6
static const char *varfile = DEFAULT_VARFILE;
Packit Service f629e6
const char *command_file = NULL;	/* debugger commands */
Packit Service f629e6
Packit Service f629e6
static void usage(int exitval, FILE *fp) ATTRIBUTE_NORETURN;
Packit Service f629e6
static void copyleft(void) ATTRIBUTE_NORETURN;
Packit Service f629e6
static void cmdline_fs(char *str);
Packit Service f629e6
static void init_args(int argc0, int argc, const char *argv0, char **argv);
Packit Service f629e6
static void init_vars(void);
Packit Service f629e6
static NODE *load_environ(void);
Packit Service f629e6
static NODE *load_procinfo(void);
Packit Service f629e6
static void catchsig(int sig);
Packit Service f629e6
#ifdef HAVE_LIBSIGSEGV
Packit Service f629e6
static int catchsegv(void *fault_address, int serious);
Packit Service f629e6
static void catchstackoverflow(int emergency, stackoverflow_context_t scp);
Packit Service f629e6
#endif
Packit Service f629e6
static void nostalgia(void) ATTRIBUTE_NORETURN;
Packit Service f629e6
static void version(void) ATTRIBUTE_NORETURN;
Packit Service f629e6
static void init_fds(void);
Packit Service f629e6
static void init_groupset(void);
Packit Service f629e6
static void save_argv(int, char **);
Packit Service f629e6
Packit Service f629e6
extern int debug_prog(INSTRUCTION *pc); /* debug.c */
Packit Service f629e6
extern int init_debug();	/* debug.c */
Packit Service f629e6
Packit Service f629e6
/* These nodes store all the special variables AWK uses */
Packit Service f629e6
NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
Packit Service f629e6
NODE *ENVIRON_node, *ERRNO_node, *FIELDWIDTHS_node, *FILENAME_node;
Packit Service f629e6
NODE *FNR_node, *FPAT_node, *FS_node, *IGNORECASE_node, *LINT_node;
Packit Service f629e6
NODE *NF_node, *NR_node, *OFMT_node, *OFS_node, *ORS_node, *PROCINFO_node;
Packit Service f629e6
NODE *RLENGTH_node, *RSTART_node, *RS_node, *RT_node, *SUBSEP_node;
Packit Service f629e6
NODE *PREC_node, *ROUNDMODE_node;
Packit Service f629e6
NODE *TEXTDOMAIN_node;
Packit Service f629e6
Packit Service f629e6
long NF;
Packit Service f629e6
long NR;
Packit Service f629e6
long FNR;
Packit Service f629e6
int BINMODE;
Packit Service f629e6
bool IGNORECASE;
Packit Service f629e6
char *OFS;
Packit Service f629e6
char *ORS;
Packit Service f629e6
char *OFMT;
Packit Service f629e6
char *TEXTDOMAIN;
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * CONVFMT is a convenience pointer for the current number to string format.
Packit Service f629e6
 * We must supply an initial value to avoid recursion problems of
Packit Service f629e6
 *	set_CONVFMT -> fmt_index -> force_string: gets NULL CONVFMT
Packit Service f629e6
 * Fun, fun, fun, fun.
Packit Service f629e6
 */
Packit Service f629e6
char *CONVFMT = "%.6g";
Packit Service f629e6
Packit Service f629e6
NODE *Nnull_string;		/* The global null string */
Packit Service f629e6
Packit Service f629e6
#if defined(HAVE_LOCALE_H)
Packit Service f629e6
struct lconv loc;		/* current locale */
Packit Service f629e6
static void init_locale(struct lconv *l);
Packit Service f629e6
#endif /* defined(HAVE_LOCALE_H) */
Packit Service f629e6
Packit Service f629e6
/* The name the program was invoked under, for error messages */
Packit Service f629e6
const char *myname;
Packit Service f629e6
Packit Service f629e6
/* A block of AWK code to be run */
Packit Service f629e6
INSTRUCTION *code_block = NULL;
Packit Service f629e6
Packit Service f629e6
char **d_argv;			/* saved argv for debugger restarting */
Packit Service f629e6
/*
Packit Service f629e6
 * List of rules and functions with first and last instruction (source_line)
Packit Service f629e6
 * information; used for profiling and debugging.
Packit Service f629e6
 */
Packit Service f629e6
INSTRUCTION *rule_list;
Packit Service f629e6
Packit Service f629e6
int exit_val = EXIT_SUCCESS;		/* exit value */
Packit Service f629e6
Packit Service f629e6
#if defined(YYDEBUG) || defined(GAWKDEBUG)
Packit Service f629e6
extern int yydebug;
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
SRCFILE *srcfiles; /* source files */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * structure to remember variable pre-assignments
Packit Service f629e6
 */
Packit Service f629e6
struct pre_assign {
Packit Service f629e6
	enum assign_type { PRE_ASSIGN = 1, PRE_ASSIGN_FS } type;
Packit Service f629e6
	char *val;
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
static struct pre_assign *preassigns = NULL;	/* requested via -v or -F */
Packit Service f629e6
static long numassigns = -1;			/* how many of them */
Packit Service f629e6
Packit Service f629e6
static bool disallow_var_assigns = false;	/* true for --exec */
Packit Service f629e6
Packit Service f629e6
static void add_preassign(enum assign_type type, char *val);
Packit Service f629e6
Packit Service f629e6
static void parse_args(int argc, char **argv);
Packit Service f629e6
static void set_locale_stuff(void);
Packit Service f629e6
static bool stopped_early = false;
Packit Service f629e6
Packit Service f629e6
int do_flags = false;
Packit Service f629e6
bool do_optimize = true;		/* apply default optimizations */
Packit Service f629e6
static int do_nostalgia = false;	/* provide a blast from the past */
Packit Service f629e6
static int do_binary = false;		/* hands off my data! */
Packit Service f629e6
static int do_version = false;		/* print version info */
Packit Service f629e6
static const char *locale = "";		/* default value to setlocale */
Packit Service f629e6
static char *locale_dir = LOCALEDIR;	/* default locale dir */
Packit Service f629e6
Packit Service f629e6
int use_lc_numeric = false;	/* obey locale for decimal point */
Packit Service f629e6
Packit Service f629e6
int gawk_mb_cur_max;		/* MB_CUR_MAX value, see comment in main() */
Packit Service f629e6
Packit Service f629e6
FILE *output_fp;		/* default gawk output, can be redirected in the debugger */
Packit Service f629e6
bool output_is_tty = false;	/* control flushing of output */
Packit Service f629e6
Packit Service f629e6
/* default format for strftime(), available via PROCINFO */
Packit Service f629e6
const char def_strftime_format[] = "%a %b %e %H:%M:%S %Z %Y";
Packit Service f629e6
Packit Service f629e6
extern const char *version_string;
Packit Service f629e6
Packit Service f629e6
#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
Packit Service f629e6
GETGROUPS_T *groupset;		/* current group set */
Packit Service f629e6
int ngroups;			/* size of said set */
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
void (*lintfunc)(const char *mesg, ...) = r_warning;
Packit Service f629e6
Packit Service f629e6
/* Sorted by long option name! */
Packit Service f629e6
static const struct option optab[] = {
Packit Service f629e6
	{ "assign",		required_argument,	NULL,	'v' },
Packit Service f629e6
	{ "bignum",		no_argument,		NULL,	'M' },
Packit Service f629e6
	{ "characters-as-bytes", no_argument,		& do_binary,	 'b' },
Packit Service f629e6
	{ "copyright",		no_argument,		NULL,	'C' },
Packit Service f629e6
	{ "debug",		optional_argument,	NULL,	'D' },
Packit Service f629e6
	{ "dump-variables",	optional_argument,	NULL,	'd' },
Packit Service f629e6
	{ "exec",		required_argument,	NULL,	'E' },
Packit Service f629e6
	{ "field-separator",	required_argument,	NULL,	'F' },
Packit Service f629e6
	{ "file",		required_argument,	NULL,	'f' },
Packit Service f629e6
	{ "gen-pot",		no_argument,		NULL,	'g' },
Packit Service f629e6
	{ "help",		no_argument,		NULL,	'h' },
Packit Service f629e6
	{ "include",		required_argument,	NULL,	'i' },
Packit Service f629e6
	{ "lint",		optional_argument,	NULL,	'L' },
Packit Service f629e6
	{ "lint-old",		no_argument,		NULL,	't' },
Packit Service f629e6
	{ "load",		required_argument,	NULL,	'l' },
Packit Service f629e6
#if defined(LOCALEDEBUG)
Packit Service f629e6
	{ "locale",		required_argument,	NULL,	'Z' },
Packit Service f629e6
#endif
Packit Service f629e6
	{ "non-decimal-data",	no_argument,		NULL,	'n' },
Packit Service f629e6
	{ "no-optimize",	no_argument,		NULL,	's' },
Packit Service f629e6
	{ "nostalgia",		no_argument,		& do_nostalgia,	1 },
Packit Service f629e6
	{ "optimize",		no_argument,		NULL,	'O' },
Packit Service f629e6
#if defined(YYDEBUG) || defined(GAWKDEBUG)
Packit Service f629e6
	{ "parsedebug",		no_argument,		NULL,	'Y' },
Packit Service f629e6
#endif
Packit Service f629e6
	{ "posix",		no_argument,		NULL,	'P' },
Packit Service f629e6
	{ "pretty-print",	optional_argument,	NULL,	'o' },
Packit Service f629e6
	{ "profile",		optional_argument,	NULL,	'p' },
Packit Service f629e6
	{ "re-interval",	no_argument,		NULL,	'r' },
Packit Service f629e6
	{ "sandbox",		no_argument,		NULL, 	'S' },
Packit Service f629e6
	{ "source",		required_argument,	NULL,	'e' },
Packit Service f629e6
	{ "traditional",	no_argument,		NULL,	'c' },
Packit Service f629e6
	{ "use-lc-numeric",	no_argument,		& use_lc_numeric, 1 },
Packit Service f629e6
	{ "version",		no_argument,		& do_version, 'V' },
Packit Service f629e6
	{ NULL, 0, NULL, '\0' }
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
/* main --- process args, parse program, run it, clean up */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
main(int argc, char **argv)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
	char *extra_stack;
Packit Service f629e6
	int have_srcfile = 0;
Packit Service f629e6
	SRCFILE *s;
Packit Service f629e6
	char *cp;
Packit Service f629e6
#if defined(LOCALEDEBUG)
Packit Service f629e6
	const char *initial_locale;
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	/* do these checks early */
Packit Service f629e6
	if (getenv("TIDYMEM") != NULL)
Packit Service f629e6
		do_flags |= DO_TIDY_MEM;
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_MCHECK_H
Packit Service f629e6
#ifdef HAVE_MTRACE
Packit Service f629e6
	if (do_tidy_mem)
Packit Service f629e6
		mtrace();
Packit Service f629e6
#endif /* HAVE_MTRACE */
Packit Service f629e6
#endif /* HAVE_MCHECK_H */
Packit Service f629e6
Packit Service f629e6
	myname = gawk_name(argv[0]);
Packit Service f629e6
	os_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
Packit Service f629e6
Packit Service f629e6
	if (argc < 2)
Packit Service f629e6
		usage(EXIT_FAILURE, stderr);
Packit Service f629e6
Packit Service f629e6
	if ((cp = getenv("GAWK_LOCALE_DIR")) != NULL)
Packit Service f629e6
		locale_dir = cp;
Packit Service f629e6
Packit Service f629e6
#if defined(F_GETFL) && defined(O_APPEND)
Packit Service f629e6
	// 1/2018: This is needed on modern BSD systems so that the
Packit Service f629e6
	// inplace tests pass. I think it's a bug in those kernels
Packit Service f629e6
	// but let's just work around it anyway.
Packit Service f629e6
	int flags = fcntl(fileno(stderr), F_GETFL, NULL);
Packit Service f629e6
	if (flags >= 0 && (flags & O_APPEND) == 0) {
Packit Service f629e6
		flags |= O_APPEND;
Packit Service f629e6
		(void) fcntl(fileno(stderr), F_SETFL, flags);
Packit Service f629e6
	}
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#if defined(LOCALEDEBUG)
Packit Service f629e6
	initial_locale = locale;
Packit Service f629e6
#endif
Packit Service f629e6
	set_locale_stuff();
Packit Service f629e6
Packit Service f629e6
	(void) signal(SIGFPE, catchsig);
Packit Service f629e6
#ifdef SIGBUS
Packit Service f629e6
	(void) signal(SIGBUS, catchsig);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * Ignore SIGPIPE so that writes to pipes that fail don't
Packit Service f629e6
	 * kill the process but instead return -1 and set errno.
Packit Service f629e6
	 * That lets us print a fatal message instead of dieing suddenly.
Packit Service f629e6
	 *
Packit Service f629e6
	 * Note that this requires ignoring EPIPE when writing and
Packit Service f629e6
	 * flushing stdout/stderr in other parts of the program. E.g.,
Packit Service f629e6
	 *
Packit Service f629e6
	 * 	gawk 'BEGIN { print "hi" }' | exit
Packit Service f629e6
	 *
Packit Service f629e6
	 * should not give us "broken pipe" messages --- mainly because
Packit Service f629e6
	 * it did not do so in the past and people would complain.
Packit Service f629e6
	 */
Packit Service f629e6
	ignore_sigpipe();
Packit Service f629e6
Packit Service f629e6
	(void) sigsegv_install_handler(catchsegv);
Packit Service f629e6
#define STACK_SIZE (16*1024)
Packit Service f629e6
	emalloc(extra_stack, char *, STACK_SIZE, "main");
Packit Service f629e6
	(void) stackoverflow_install_handler(catchstackoverflow, extra_stack, STACK_SIZE);
Packit Service f629e6
#undef STACK_SIZE
Packit Service f629e6
Packit Service f629e6
	/* initialize the null string */
Packit Service f629e6
	Nnull_string = make_string("", 0);
Packit Service f629e6
Packit Service f629e6
	/* Robustness: check that file descriptors 0, 1, 2 are open */
Packit Service f629e6
	init_fds();
Packit Service f629e6
Packit Service f629e6
	/* init array handling. */
Packit Service f629e6
	array_init();
Packit Service f629e6
Packit Service f629e6
	/* init the symbol tables */
Packit Service f629e6
	init_symbol_table();
Packit Service f629e6
Packit Service f629e6
	output_fp = stdout;
Packit Service f629e6
Packit Service f629e6
	/* initialize global (main) execution context */
Packit Service f629e6
	push_context(new_context());
Packit Service f629e6
Packit Service f629e6
	parse_args(argc, argv);
Packit Service f629e6
Packit Service f629e6
#if defined(LOCALEDEBUG)
Packit Service f629e6
	if (locale != initial_locale)
Packit Service f629e6
		set_locale_stuff();
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * In glibc, MB_CUR_MAX is actually a function.  This value is
Packit Service f629e6
	 * tested *a lot* in many speed-critical places in gawk. Caching
Packit Service f629e6
	 * this value once makes a speed difference.
Packit Service f629e6
	 */
Packit Service f629e6
	gawk_mb_cur_max = MB_CUR_MAX;
Packit Service f629e6
Packit Service f629e6
	/* init the cache for checking bytes if they're characters */
Packit Service f629e6
	init_btowc_cache();
Packit Service f629e6
Packit Service f629e6
	if (do_nostalgia)
Packit Service f629e6
		nostalgia();
Packit Service f629e6
Packit Service f629e6
	/* check for POSIXLY_CORRECT environment variable */
Packit Service f629e6
	if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
Packit Service f629e6
		do_flags |= DO_POSIX;
Packit Service f629e6
		if (do_lint)
Packit Service f629e6
			lintwarn(
Packit Service f629e6
	_("environment variable `POSIXLY_CORRECT' set: turning on `--posix'"));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (do_posix) {
Packit Service f629e6
		use_lc_numeric = true;
Packit Service f629e6
		if (do_traditional)	/* both on command line */
Packit Service f629e6
			warning(_("`--posix' overrides `--traditional'"));
Packit Service f629e6
		else
Packit Service f629e6
			do_flags |= DO_TRADITIONAL;
Packit Service f629e6
			/*
Packit Service f629e6
			 * POSIX compliance also implies
Packit Service f629e6
			 * no GNU extensions either.
Packit Service f629e6
			 */
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (do_traditional && do_non_decimal_data) {
Packit Service f629e6
		do_flags &= ~DO_NON_DEC_DATA;
Packit Service f629e6
		warning(_("`--posix'/`--traditional' overrides `--non-decimal-data'"));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (do_lint && os_is_setuid())
Packit Service f629e6
		warning(_("running %s setuid root may be a security problem"), myname);
Packit Service f629e6
Packit Service f629e6
	if (do_binary) {
Packit Service f629e6
		if (do_posix)
Packit Service f629e6
			warning(_("`--posix' overrides `--characters-as-bytes'"));
Packit Service f629e6
		else
Packit Service f629e6
			gawk_mb_cur_max = 1;	/* hands off my data! */
Packit Service f629e6
#if defined(LC_ALL)
Packit Service f629e6
		setlocale(LC_ALL, "C");
Packit Service f629e6
#endif
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (do_debug)	/* Need to register the debugger pre-exec hook before any other */
Packit Service f629e6
		init_debug();
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	/* Set up MPFR defaults, and register pre-exec hook to process arithmetic opcodes */
Packit Service f629e6
	if (do_mpfr)
Packit Service f629e6
		init_mpfr(DEFAULT_PREC, DEFAULT_ROUNDMODE);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	/* load group set */
Packit Service f629e6
	init_groupset();
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	if (do_mpfr) {
Packit Service f629e6
		mpz_init(Nnull_string->mpg_i);
Packit Service f629e6
		Nnull_string->flags = (MALLOC|STRCUR|STRING|MPZN|NUMCUR|NUMBER);
Packit Service f629e6
	} else
Packit Service f629e6
#endif
Packit Service f629e6
	{
Packit Service f629e6
		Nnull_string->numbr = 0.0;
Packit Service f629e6
		Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * Tell the regex routines how they should work.
Packit Service f629e6
	 * Do this before initializing variables, since
Packit Service f629e6
	 * they could want to do a regexp compile.
Packit Service f629e6
	 */
Packit Service f629e6
	resetup();
Packit Service f629e6
Packit Service f629e6
	/* Set up the special variables */
Packit Service f629e6
	init_vars();
Packit Service f629e6
Packit Service f629e6
	/* Set up the field variables */
Packit Service f629e6
	init_fields();
Packit Service f629e6
Packit Service f629e6
	/* Now process the pre-assignments */
Packit Service f629e6
	for (i = 0; i <= numassigns; i++) {
Packit Service f629e6
		if (preassigns[i].type == PRE_ASSIGN)
Packit Service f629e6
			(void) arg_assign(preassigns[i].val, true);
Packit Service f629e6
		else	/* PRE_ASSIGN_FS */
Packit Service f629e6
			cmdline_fs(preassigns[i].val);
Packit Service f629e6
		efree(preassigns[i].val);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (preassigns != NULL)
Packit Service f629e6
		efree(preassigns);
Packit Service f629e6
Packit Service f629e6
	if ((BINMODE & BINMODE_INPUT) != 0)
Packit Service f629e6
		if (os_setbinmode(fileno(stdin), O_BINARY) == -1)
Packit Service f629e6
			fatal(_("can't set binary mode on stdin (%s)"), strerror(errno));
Packit Service f629e6
	if ((BINMODE & BINMODE_OUTPUT) != 0) {
Packit Service f629e6
		if (os_setbinmode(fileno(stdout), O_BINARY) == -1)
Packit Service f629e6
			fatal(_("can't set binary mode on stdout (%s)"), strerror(errno));
Packit Service f629e6
		if (os_setbinmode(fileno(stderr), O_BINARY) == -1)
Packit Service f629e6
			fatal(_("can't set binary mode on stderr (%s)"), strerror(errno));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
#ifdef GAWKDEBUG
Packit Service f629e6
	setbuf(stdout, (char *) NULL);	/* make debugging easier */
Packit Service f629e6
#endif
Packit Service f629e6
	if (os_isatty(fileno(stdout)))
Packit Service f629e6
		output_is_tty = true;
Packit Service f629e6
Packit Service f629e6
	/* initialize API before loading extension libraries */
Packit Service f629e6
	init_ext_api();
Packit Service f629e6
Packit Service f629e6
	/* load extension libs */
Packit Service f629e6
        for (s = srcfiles->next; s != srcfiles; s = s->next) {
Packit Service f629e6
                if (s->stype == SRC_EXTLIB)
Packit Service f629e6
			load_ext(s->fullpath);
Packit Service f629e6
		else if (s->stype != SRC_INC)
Packit Service f629e6
			have_srcfile++;
Packit Service f629e6
        }
Packit Service f629e6
Packit Service f629e6
	/* do version check after extensions are loaded to get extension info */
Packit Service f629e6
	if (do_version)
Packit Service f629e6
		version();
Packit Service f629e6
Packit Service f629e6
	/* No -f or --source options, use next arg */
Packit Service f629e6
	if (! have_srcfile) {
Packit Service f629e6
		if (optind > argc - 1 || stopped_early) /* no args left or no program */
Packit Service f629e6
			usage(EXIT_FAILURE, stderr);
Packit Service f629e6
		(void) add_srcfile(SRC_CMDLINE, argv[optind], srcfiles, NULL, NULL);
Packit Service f629e6
		optind++;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* Select the interpreter routine */
Packit Service f629e6
	init_interpret();
Packit Service f629e6
Packit Service f629e6
	init_args(optind, argc,
Packit Service f629e6
			do_posix ? argv[0] : myname,
Packit Service f629e6
			argv);
Packit Service f629e6
Packit Service f629e6
#if defined(LC_NUMERIC)
Packit Service f629e6
	/*
Packit Service f629e6
	 * FRAGILE!  CAREFUL!
Packit Service f629e6
	 * Pre-initing the variables with arg_assign() can change the
Packit Service f629e6
	 * locale.  Force it to C before parsing the program.
Packit Service f629e6
	 */
Packit Service f629e6
	setlocale(LC_NUMERIC, "C");
Packit Service f629e6
#endif
Packit Service f629e6
	/* Read in the program */
Packit Service f629e6
	if (parse_program(& code_block) != 0)
Packit Service f629e6
		exit(EXIT_FAILURE);
Packit Service f629e6
Packit Service f629e6
	if (do_intl)
Packit Service f629e6
		exit(EXIT_SUCCESS);
Packit Service f629e6
Packit Service f629e6
	install_builtins();
Packit Service f629e6
Packit Service f629e6
	if (do_lint)
Packit Service f629e6
		shadow_funcs();
Packit Service f629e6
Packit Service f629e6
	if (do_lint && code_block->nexti->opcode == Op_atexit)
Packit Service f629e6
		lintwarn(_("no program text at all!"));
Packit Service f629e6
Packit Service f629e6
	load_symbols();
Packit Service f629e6
Packit Service f629e6
	if (do_profile)
Packit Service f629e6
		init_profiling_signals();
Packit Service f629e6
Packit Service f629e6
#if defined(LC_NUMERIC)
Packit Service f629e6
	/*
Packit Service f629e6
	 * See comment above about using locale's decimal point.
Packit Service f629e6
	 *
Packit Service f629e6
	 * 10/2005:
Packit Service f629e6
	 * Bitter experience teaches us that most people the world over
Packit Service f629e6
	 * use period as the decimal point, not whatever their locale
Packit Service f629e6
	 * uses.  Thus, only use the locale's decimal point if being
Packit Service f629e6
	 * posixly anal-retentive.
Packit Service f629e6
	 *
Packit Service f629e6
	 * 7/2007:
Packit Service f629e6
	 * Be a little bit kinder. Allow the --use-lc-numeric option
Packit Service f629e6
	 * to also use the local decimal point. This avoids the draconian
Packit Service f629e6
	 * strictness of POSIX mode if someone just wants to parse their
Packit Service f629e6
	 * data using the local decimal point.
Packit Service f629e6
	 */
Packit Service f629e6
	if (use_lc_numeric)
Packit Service f629e6
		setlocale(LC_NUMERIC, locale);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	init_io();
Packit Service f629e6
	output_fp = stdout;
Packit Service f629e6
Packit Service f629e6
	if (do_debug)
Packit Service f629e6
		debug_prog(code_block);
Packit Service f629e6
	else if (do_pretty_print && ! do_profile)
Packit Service f629e6
		;	/* run pretty printer only. */
Packit Service f629e6
	else
Packit Service f629e6
		interpret(code_block);
Packit Service f629e6
Packit Service f629e6
	if (do_pretty_print) {
Packit Service f629e6
		dump_prog(code_block);
Packit Service f629e6
		dump_funcs();
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (do_dump_vars)
Packit Service f629e6
		dump_vars(varfile);
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	if (do_mpfr)
Packit Service f629e6
		cleanup_mpfr();
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	if (do_tidy_mem)
Packit Service f629e6
		release_all_vars();
Packit Service f629e6
Packit Service f629e6
	/* keep valgrind happier */
Packit Service f629e6
	if (extra_stack)
Packit Service f629e6
		efree(extra_stack);
Packit Service f629e6
Packit Service f629e6
	final_exit(exit_val);
Packit Service f629e6
	return exit_val;	/* to suppress warnings */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* add_preassign --- add one element to preassigns */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
add_preassign(enum assign_type type, char *val)
Packit Service f629e6
{
Packit Service f629e6
	static long alloc_assigns;		/* for how many are allocated */
Packit Service f629e6
Packit Service f629e6
#define INIT_SRC 4
Packit Service f629e6
Packit Service f629e6
	++numassigns;
Packit Service f629e6
Packit Service f629e6
	if (preassigns == NULL) {
Packit Service f629e6
		emalloc(preassigns, struct pre_assign *,
Packit Service f629e6
			INIT_SRC * sizeof(struct pre_assign), "add_preassign");
Packit Service f629e6
		alloc_assigns = INIT_SRC;
Packit Service f629e6
	} else if (numassigns >= alloc_assigns) {
Packit Service f629e6
		alloc_assigns *= 2;
Packit Service f629e6
		erealloc(preassigns, struct pre_assign *,
Packit Service f629e6
			alloc_assigns * sizeof(struct pre_assign), "add_preassigns");
Packit Service f629e6
	}
Packit Service f629e6
	preassigns[numassigns].type = type;
Packit Service f629e6
	preassigns[numassigns].val = estrdup(val, strlen(val));
Packit Service f629e6
Packit Service f629e6
#undef INIT_SRC
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* usage --- print usage information and exit */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
usage(int exitval, FILE *fp)
Packit Service f629e6
{
Packit Service f629e6
	/* Not factoring out common stuff makes it easier to translate. */
Packit Service f629e6
	fprintf(fp, _("Usage: %s [POSIX or GNU style options] -f progfile [--] file ...\n"),
Packit Service f629e6
		myname);
Packit Service f629e6
	fprintf(fp, _("Usage: %s [POSIX or GNU style options] [--] %cprogram%c file ...\n"),
Packit Service f629e6
			myname, quote, quote);
Packit Service f629e6
Packit Service f629e6
	/* GNU long options info. This is too many options. */
Packit Service f629e6
Packit Service f629e6
	fputs(_("POSIX options:\t\tGNU long options: (standard)\n"), fp);
Packit Service f629e6
	fputs(_("\t-f progfile\t\t--file=progfile\n"), fp);
Packit Service f629e6
	fputs(_("\t-F fs\t\t\t--field-separator=fs\n"), fp);
Packit Service f629e6
	fputs(_("\t-v var=val\t\t--assign=var=val\n"), fp);
Packit Service f629e6
	fputs(_("Short options:\t\tGNU long options: (extensions)\n"), fp);
Packit Service f629e6
	fputs(_("\t-b\t\t\t--characters-as-bytes\n"), fp);
Packit Service f629e6
	fputs(_("\t-c\t\t\t--traditional\n"), fp);
Packit Service f629e6
	fputs(_("\t-C\t\t\t--copyright\n"), fp);
Packit Service f629e6
	fputs(_("\t-d[file]\t\t--dump-variables[=file]\n"), fp);
Packit Service f629e6
	fputs(_("\t-D[file]\t\t--debug[=file]\n"), fp);
Packit Service f629e6
	fputs(_("\t-e 'program-text'\t--source='program-text'\n"), fp);
Packit Service f629e6
	fputs(_("\t-E file\t\t\t--exec=file\n"), fp);
Packit Service f629e6
	fputs(_("\t-g\t\t\t--gen-pot\n"), fp);
Packit Service f629e6
	fputs(_("\t-h\t\t\t--help\n"), fp);
Packit Service f629e6
	fputs(_("\t-i includefile\t\t--include=includefile\n"), fp);
Packit Service f629e6
	fputs(_("\t-l library\t\t--load=library\n"), fp);
Packit Service f629e6
	/*
Packit Service f629e6
	 * TRANSLATORS: the "fatal" and "invalid" here are literal
Packit Service f629e6
	 * values, they should not be translated. Thanks.
Packit Service f629e6
	 */
Packit Service f629e6
	fputs(_("\t-L[fatal|invalid]\t--lint[=fatal|invalid]\n"), fp);
Packit Service f629e6
	fputs(_("\t-M\t\t\t--bignum\n"), fp);
Packit Service f629e6
	fputs(_("\t-N\t\t\t--use-lc-numeric\n"), fp);
Packit Service f629e6
	fputs(_("\t-n\t\t\t--non-decimal-data\n"), fp);
Packit Service f629e6
	fputs(_("\t-o[file]\t\t--pretty-print[=file]\n"), fp);
Packit Service f629e6
	fputs(_("\t-O\t\t\t--optimize\n"), fp);
Packit Service f629e6
	fputs(_("\t-p[file]\t\t--profile[=file]\n"), fp);
Packit Service f629e6
	fputs(_("\t-P\t\t\t--posix\n"), fp);
Packit Service f629e6
	fputs(_("\t-r\t\t\t--re-interval\n"), fp);
Packit Service f629e6
	fputs(_("\t-s\t\t\t--no-optimize\n"), fp);
Packit Service f629e6
	fputs(_("\t-S\t\t\t--sandbox\n"), fp);
Packit Service f629e6
	fputs(_("\t-t\t\t\t--lint-old\n"), fp);
Packit Service f629e6
	fputs(_("\t-V\t\t\t--version\n"), fp);
Packit Service f629e6
#ifdef NOSTALGIA
Packit Service f629e6
	fputs(_("\t-W nostalgia\t\t--nostalgia\n"), fp);
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef GAWKDEBUG
Packit Service f629e6
	fputs(_("\t-Y\t\t--parsedebug\n"), fp);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	/* This is one string to make things easier on translators. */
Packit Service f629e6
	/* TRANSLATORS: --help output 5 (end)
Packit Service f629e6
	   TRANSLATORS: the placeholder indicates the bug-reporting address
Packit Service f629e6
	   for this application.  Please add _another line_ with the
Packit Service f629e6
	   address for translation bugs.
Packit Service f629e6
	   no-wrap */
Packit Service f629e6
	fputs(_("\nTo report bugs, see node `Bugs' in `gawk.info'\n\
Packit Service f629e6
which is section `Reporting Problems and Bugs' in the\n\
Packit Service f629e6
printed version.  This same information may be found at\n\
Packit Service f629e6
https://www.gnu.org/software/gawk/manual/html_node/Bugs.html.\n\
Packit Service f629e6
PLEASE do NOT try to report bugs by posting in comp.lang.awk.\n\n"), fp);
Packit Service f629e6
Packit Service f629e6
	/* ditto */
Packit Service f629e6
	fputs(_("gawk is a pattern scanning and processing language.\n\
Packit Service f629e6
By default it reads standard input and writes standard output.\n\n"), fp);
Packit Service f629e6
Packit Service f629e6
	/* ditto */
Packit Service f629e6
	fputs(_("Examples:\n\tgawk '{ sum += $1 }; END { print sum }' file\n\
Packit Service f629e6
\tgawk -F: '{ print $1 }' /etc/passwd\n"), fp);
Packit Service f629e6
Packit Service f629e6
	fflush(fp);
Packit Service f629e6
Packit Service f629e6
	if (ferror(fp)) {
Packit Service f629e6
#ifdef __MINGW32__
Packit Service f629e6
		if (errno == 0 || errno == EINVAL)
Packit Service f629e6
			w32_maybe_set_errno();
Packit Service f629e6
#endif
Packit Service f629e6
		/* don't warn about stdout/stderr if EPIPE, but do error exit */
Packit Service f629e6
		if (errno == EPIPE)
Packit Service f629e6
			die_via_sigpipe();
Packit Service f629e6
Packit Service f629e6
		if (fp == stdout)
Packit Service f629e6
			warning(_("error writing standard output (%s)"), strerror(errno));
Packit Service f629e6
		else if (fp == stderr)
Packit Service f629e6
			warning(_("error writing standard error (%s)"), strerror(errno));
Packit Service f629e6
Packit Service f629e6
		// some other problem than SIGPIPE
Packit Service f629e6
		exit(EXIT_FAILURE);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	exit(exitval);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* copyleft --- print out the short GNU copyright information */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
copyleft()
Packit Service f629e6
{
Packit Service f629e6
	static const char blurb_part1[] =
Packit Service f629e6
	  N_("Copyright (C) 1989, 1991-%d Free Software Foundation.\n\
Packit Service f629e6
\n\
Packit Service f629e6
This program is free software; you can redistribute it and/or modify\n\
Packit Service f629e6
it under the terms of the GNU General Public License as published by\n\
Packit Service f629e6
the Free Software Foundation; either version 3 of the License, or\n\
Packit Service f629e6
(at your option) any later version.\n\
Packit Service f629e6
\n");
Packit Service f629e6
	static const char blurb_part2[] =
Packit Service f629e6
	  N_("This program is distributed in the hope that it will be useful,\n\
Packit Service f629e6
but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
Packit Service f629e6
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
Packit Service f629e6
GNU General Public License for more details.\n\
Packit Service f629e6
\n");
Packit Service f629e6
	static const char blurb_part3[] =
Packit Service f629e6
	  N_("You should have received a copy of the GNU General Public License\n\
Packit Service f629e6
along with this program. If not, see http://www.gnu.org/licenses/.\n");
Packit Service f629e6
Packit Service f629e6
	/* multiple blurbs are needed for some brain dead compilers. */
Packit Service f629e6
	printf(_(blurb_part1), UPDATE_YEAR);	/* Last update year */
Packit Service f629e6
	fputs(_(blurb_part2), stdout);
Packit Service f629e6
	fputs(_(blurb_part3), stdout);
Packit Service f629e6
	fflush(stdout);
Packit Service f629e6
Packit Service f629e6
	if (ferror(stdout)) {
Packit Service f629e6
#ifdef __MINGW32__
Packit Service f629e6
		if (errno == 0 || errno == EINVAL)
Packit Service f629e6
			w32_maybe_set_errno();
Packit Service f629e6
#endif
Packit Service f629e6
		/* don't warn about stdout if EPIPE, but do error exit */
Packit Service f629e6
		if (errno != EPIPE)
Packit Service f629e6
			warning(_("error writing standard output (%s)"), strerror(errno));
Packit Service f629e6
		exit(EXIT_FAILURE);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	exit(EXIT_SUCCESS);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* cmdline_fs --- set FS from the command line */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
cmdline_fs(char *str)
Packit Service f629e6
{
Packit Service f629e6
	NODE **tmp;
Packit Service f629e6
Packit Service f629e6
	tmp = &FS_node->var_value;
Packit Service f629e6
	unref(*tmp);
Packit Service f629e6
	/*
Packit Service f629e6
	 * Only if in full compatibility mode check for the stupid special
Packit Service f629e6
	 * case so -F\t works as documented in awk book even though the shell
Packit Service f629e6
	 * hands us -Ft.  Bleah!
Packit Service f629e6
	 *
Packit Service f629e6
	 * Thankfully, POSIX didn't propagate this "feature".
Packit Service f629e6
	 */
Packit Service f629e6
	if (str[0] == 't' && str[1] == '\0') {
Packit Service f629e6
		if (do_lint)
Packit Service f629e6
			lintwarn(_("-Ft does not set FS to tab in POSIX awk"));
Packit Service f629e6
		if (do_traditional && ! do_posix)
Packit Service f629e6
			str[0] = '\t';
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	*tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
Packit Service f629e6
	set_FS();
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* init_args --- set up ARGV from stuff on the command line */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
init_args(int argc0, int argc, const char *argv0, char **argv)
Packit Service f629e6
{
Packit Service f629e6
	int i, j;
Packit Service f629e6
	NODE **aptr;
Packit Service f629e6
	NODE *tmp;
Packit Service f629e6
Packit Service f629e6
	ARGV_node = install_symbol(estrdup("ARGV", 4), Node_var_array);
Packit Service f629e6
	tmp =  make_number(0.0);
Packit Service f629e6
	aptr = assoc_lookup(ARGV_node, tmp);
Packit Service f629e6
	unref(tmp);
Packit Service f629e6
	unref(*aptr);
Packit Service f629e6
	*aptr = make_string(argv0, strlen(argv0));
Packit Service f629e6
	(*aptr)->flags |= USER_INPUT;
Packit Service f629e6
	for (i = argc0, j = 1; i < argc; i++, j++) {
Packit Service f629e6
		tmp = make_number((AWKNUM) j);
Packit Service f629e6
		aptr = assoc_lookup(ARGV_node, tmp);
Packit Service f629e6
		unref(tmp);
Packit Service f629e6
		unref(*aptr);
Packit Service f629e6
		*aptr = make_string(argv[i], strlen(argv[i]));
Packit Service f629e6
		(*aptr)->flags |= USER_INPUT;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	ARGC_node = install_symbol(estrdup("ARGC", 4), Node_var);
Packit Service f629e6
	ARGC_node->var_value = make_number((AWKNUM) j);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Set all the special variables to their initial values.
Packit Service f629e6
 * Note that some of the variables that have set_FOO routines should
Packit Service f629e6
 * *N*O*T* have those routines called upon initialization, and thus
Packit Service f629e6
 * they have NULL entries in that field. This is notably true of FS
Packit Service f629e6
 * and IGNORECASE.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
struct varinit {
Packit Service f629e6
	NODE **spec;
Packit Service f629e6
	const char *name;
Packit Service f629e6
	const char *strval;
Packit Service f629e6
	AWKNUM numval;
Packit Service f629e6
	Func_ptr update;
Packit Service f629e6
	Func_ptr assign;
Packit Service f629e6
	bool do_assign;
Packit Service f629e6
	int flags;
Packit Service f629e6
#define NO_INSTALL	0x01
Packit Service f629e6
#define NON_STANDARD	0x02
Packit Service f629e6
#define NOT_OFF_LIMITS	0x04	/* may be accessed by extension function */
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
static const struct varinit varinit[] = {
Packit Service f629e6
{NULL,		"ARGC",		NULL,	0,  NULL, NULL,	false, NO_INSTALL },
Packit Service f629e6
{&ARGIND_node,	"ARGIND",	NULL,	0,  NULL, NULL,	false, NON_STANDARD },
Packit Service f629e6
{NULL,		"ARGV",		NULL,	0,  NULL, NULL,	false, NO_INSTALL },
Packit Service f629e6
{&BINMODE_node,	"BINMODE",	NULL,	0,  NULL, set_BINMODE,	false, NON_STANDARD },
Packit Service f629e6
{&CONVFMT_node,	"CONVFMT",	"%.6g",	0,  NULL, set_CONVFMT,true, 	0 },
Packit Service f629e6
{NULL,		"ENVIRON",	NULL,	0,  NULL, NULL,	false, NO_INSTALL },
Packit Service f629e6
{&ERRNO_node,	"ERRNO",	"",	0,  NULL, NULL,	false, NON_STANDARD },
Packit Service f629e6
{&FIELDWIDTHS_node, "FIELDWIDTHS", "",	0,  NULL, set_FIELDWIDTHS,	false, NON_STANDARD },
Packit Service f629e6
{&FILENAME_node, "FILENAME",	"",	0,  NULL, NULL,	false, 0 },
Packit Service f629e6
{&FNR_node,	"FNR",		NULL,	0,  update_FNR, set_FNR,	true, 0 },
Packit Service f629e6
{&FS_node,	"FS",		" ",	0,  NULL, set_FS,	false, 0 },
Packit Service f629e6
{&FPAT_node,	"FPAT",		"[^[:space:]]+", 0,  NULL, set_FPAT,	false, NON_STANDARD },
Packit Service f629e6
{&IGNORECASE_node, "IGNORECASE", NULL,	0,  NULL, set_IGNORECASE,	false, NON_STANDARD },
Packit Service f629e6
{&LINT_node,	"LINT",		NULL,	0,  NULL, set_LINT,	false, NON_STANDARD },
Packit Service f629e6
{&PREC_node,	"PREC",		NULL,	DEFAULT_PREC,	NULL,	set_PREC,	false,	NON_STANDARD},
Packit Service f629e6
{&NF_node,	"NF",		NULL,	-1, update_NF, set_NF,	false, 0 },
Packit Service f629e6
{&NR_node,	"NR",		NULL,	0,  update_NR, set_NR,	true, 0 },
Packit Service f629e6
{&OFMT_node,	"OFMT",		"%.6g",	0,  NULL, set_OFMT,	true, 0 },
Packit Service f629e6
{&OFS_node,	"OFS",		" ",	0,  NULL, set_OFS,	true, 0 },
Packit Service f629e6
{&ORS_node,	"ORS",		"\n",	0,  NULL, set_ORS,	true, 0 },
Packit Service f629e6
{NULL,		"PROCINFO",	NULL,	0,  NULL, NULL,	false, NO_INSTALL | NON_STANDARD | NOT_OFF_LIMITS },
Packit Service f629e6
{&RLENGTH_node, "RLENGTH",	NULL,	0,  NULL, NULL,	false, 0 },
Packit Service f629e6
{&ROUNDMODE_node, "ROUNDMODE",	DEFAULT_ROUNDMODE,	0,  NULL, set_ROUNDMODE,	false, NON_STANDARD },
Packit Service f629e6
{&RS_node,	"RS",		"\n",	0,  NULL, set_RS,	true, 0 },
Packit Service f629e6
{&RSTART_node,	"RSTART",	NULL,	0,  NULL, NULL,	false, 0 },
Packit Service f629e6
{&RT_node,	"RT",		"",	0,  NULL, NULL,	false, NON_STANDARD },
Packit Service f629e6
{&SUBSEP_node,	"SUBSEP",	"\034",	0,  NULL, set_SUBSEP,	true, 0 },
Packit Service f629e6
{&TEXTDOMAIN_node,	"TEXTDOMAIN",	"messages",	0,  NULL, set_TEXTDOMAIN,	true, NON_STANDARD },
Packit Service f629e6
{0,		NULL,		NULL,	0,  NULL, NULL,	false, 0 },
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
/* init_vars --- actually initialize everything in the symbol table */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
init_vars()
Packit Service f629e6
{
Packit Service f629e6
	const struct varinit *vp;
Packit Service f629e6
	NODE *n;
Packit Service f629e6
Packit Service f629e6
	for (vp = varinit; vp->name != NULL; vp++) {
Packit Service f629e6
		if ((vp->flags & NO_INSTALL) != 0)
Packit Service f629e6
			continue;
Packit Service f629e6
		n = *(vp->spec) = install_symbol(estrdup(vp->name, strlen(vp->name)), Node_var);
Packit Service f629e6
		if (vp->strval != NULL)
Packit Service f629e6
			n->var_value = make_string(vp->strval, strlen(vp->strval));
Packit Service f629e6
		else
Packit Service f629e6
			n->var_value = make_number(vp->numval);
Packit Service f629e6
		n->var_assign = (Func_ptr) vp->assign;
Packit Service f629e6
		n->var_update = (Func_ptr) vp->update;
Packit Service f629e6
		if (vp->do_assign)
Packit Service f629e6
			(*(vp->assign))();
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* Load PROCINFO and ENVIRON */
Packit Service f629e6
	if (! do_traditional)
Packit Service f629e6
		load_procinfo();
Packit Service f629e6
	load_environ();
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* path_environ --- put path variable into environment if not already there */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
path_environ(const char *pname, const char *dflt)
Packit Service f629e6
{
Packit Service f629e6
	const char *val;
Packit Service f629e6
	NODE **aptr;
Packit Service f629e6
	NODE *tmp;
Packit Service f629e6
Packit Service f629e6
	tmp = make_string(pname, strlen(pname));
Packit Service f629e6
	/*
Packit Service f629e6
	 * On VMS, environ[] only holds a subset of what getenv() can
Packit Service f629e6
	 * find, so look AWKPATH up before resorting to default path.
Packit Service f629e6
	 */
Packit Service f629e6
	val = getenv(pname);
Packit Service f629e6
	if (val == NULL || *val == '\0')
Packit Service f629e6
		val = dflt;
Packit Service f629e6
	aptr = assoc_lookup(ENVIRON_node, tmp);
Packit Service f629e6
	/*
Packit Service f629e6
	 * If original value was the empty string, set it to
Packit Service f629e6
	 * the default value.
Packit Service f629e6
	 */
Packit Service f629e6
	if ((*aptr)->stlen == 0) {
Packit Service f629e6
		unref(*aptr);
Packit Service f629e6
		*aptr = make_string(val, strlen(val));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	unref(tmp);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* load_environ --- populate the ENVIRON array */
Packit Service f629e6
Packit Service f629e6
static NODE *
Packit Service f629e6
load_environ()
Packit Service f629e6
{
Packit Service f629e6
#if ! (defined(VMS) && defined(__DECC))
Packit Service f629e6
	extern char **environ;
Packit Service f629e6
#endif
Packit Service f629e6
	char *var, *val;
Packit Service f629e6
	NODE **aptr;
Packit Service f629e6
	int i;
Packit Service f629e6
	NODE *tmp;
Packit Service f629e6
	static bool been_here = false;
Packit Service f629e6
Packit Service f629e6
	if (been_here)
Packit Service f629e6
		return ENVIRON_node;
Packit Service f629e6
Packit Service f629e6
	been_here = true;
Packit Service f629e6
Packit Service f629e6
	ENVIRON_node = install_symbol(estrdup("ENVIRON", 7), Node_var_array);
Packit Service f629e6
	for (i = 0; environ[i] != NULL; i++) {
Packit Service f629e6
		static char nullstr[] = "";
Packit Service f629e6
Packit Service f629e6
		var = environ[i];
Packit Service f629e6
		val = strchr(var, '=');
Packit Service f629e6
		if (val != NULL)
Packit Service f629e6
			*val++ = '\0';
Packit Service f629e6
		else
Packit Service f629e6
			val = nullstr;
Packit Service f629e6
		tmp = make_string(var, strlen(var));
Packit Service f629e6
		aptr = assoc_lookup(ENVIRON_node, tmp);
Packit Service f629e6
		unref(tmp);
Packit Service f629e6
		unref(*aptr);
Packit Service f629e6
		*aptr = make_string(val, strlen(val));
Packit Service f629e6
		(*aptr)->flags |= USER_INPUT;
Packit Service f629e6
Packit Service f629e6
		/* restore '=' so that system() gets a valid environment */
Packit Service f629e6
		if (val != nullstr)
Packit Service f629e6
			*--val = '=';
Packit Service f629e6
	}
Packit Service f629e6
	/*
Packit Service f629e6
	 * Put AWKPATH and AWKLIBPATH into ENVIRON if not already there.
Packit Service f629e6
	 * This allows querying it from within awk programs.
Packit Service f629e6
	 *
Packit Service f629e6
	 * October 2014:
Packit Service f629e6
	 * If their values are "", override with the default values;
Packit Service f629e6
	 * since 2.10 AWKPATH used default value if environment's
Packit Service f629e6
	 * value was "".
Packit Service f629e6
	 */
Packit Service f629e6
	path_environ("AWKPATH", defpath);
Packit Service f629e6
	path_environ("AWKLIBPATH", deflibpath);
Packit Service f629e6
Packit Service f629e6
	/* set up array functions */
Packit Service f629e6
	init_env_array(ENVIRON_node);
Packit Service f629e6
Packit Service f629e6
	return ENVIRON_node;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
load_procinfo_argv()
Packit Service f629e6
{
Packit Service f629e6
	NODE *tmp;
Packit Service f629e6
	NODE **aptr;
Packit Service f629e6
	NODE *argv_array;
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	tmp = make_string("argv", 4);
Packit Service f629e6
	aptr = assoc_lookup(PROCINFO_node, tmp);
Packit Service f629e6
	unref(tmp);
Packit Service f629e6
	unref(*aptr);
Packit Service f629e6
	getnode(argv_array);
Packit Service f629e6
 	memset(argv_array, '\0', sizeof(NODE));  /* valgrind wants this */
Packit Service f629e6
	null_array(argv_array);
Packit Service f629e6
	*aptr = argv_array;
Packit Service f629e6
	argv_array->parent_array = PROCINFO_node;
Packit Service f629e6
	argv_array->vname = estrdup("argv", 4);
Packit Service f629e6
	for (i = 0; d_argv[i] != NULL; i++) {
Packit Service f629e6
		tmp = make_number(i);
Packit Service f629e6
		aptr = assoc_lookup(argv_array, tmp);
Packit Service f629e6
		unref(tmp);
Packit Service f629e6
		unref(*aptr);
Packit Service f629e6
		*aptr = make_string(d_argv[i], strlen(d_argv[i]));
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* load_procinfo --- populate the PROCINFO array */
Packit Service f629e6
Packit Service f629e6
static NODE *
Packit Service f629e6
load_procinfo()
Packit Service f629e6
{
Packit Service f629e6
#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
Packit Service f629e6
	int i;
Packit Service f629e6
#endif
Packit Service f629e6
#if (defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0) || defined(HAVE_MPFR)
Packit Service f629e6
	char name[100];
Packit Service f629e6
#endif
Packit Service f629e6
	AWKNUM value;
Packit Service f629e6
	static bool been_here = false;
Packit Service f629e6
Packit Service f629e6
	if (been_here)
Packit Service f629e6
		return PROCINFO_node;
Packit Service f629e6
Packit Service f629e6
	been_here = true;
Packit Service f629e6
Packit Service f629e6
	PROCINFO_node = install_symbol(estrdup("PROCINFO", 8), Node_var_array);
Packit Service f629e6
Packit Service f629e6
	update_PROCINFO_str("version", VERSION);
Packit Service f629e6
	update_PROCINFO_str("strftime", def_strftime_format);
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	sprintf(name, "GNU MPFR %s", mpfr_get_version());
Packit Service f629e6
	update_PROCINFO_str("mpfr_version", name);
Packit Service f629e6
	sprintf(name, "GNU MP %s", gmp_version);
Packit Service f629e6
	update_PROCINFO_str("gmp_version", name);
Packit Service f629e6
	update_PROCINFO_num("prec_max", MPFR_PREC_MAX);
Packit Service f629e6
	update_PROCINFO_num("prec_min", MPFR_PREC_MIN);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#ifdef DYNAMIC
Packit Service f629e6
	update_PROCINFO_num("api_major", GAWK_API_MAJOR_VERSION);
Packit Service f629e6
	update_PROCINFO_num("api_minor", GAWK_API_MINOR_VERSION);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#ifdef GETPGRP_VOID
Packit Service f629e6
#define getpgrp_arg() /* nothing */
Packit Service f629e6
#else
Packit Service f629e6
#define getpgrp_arg() getpid()
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	value = getpgrp(getpgrp_arg());
Packit Service f629e6
	update_PROCINFO_num("pgrpid", value);
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * Could put a lot of this into a table, but then there's
Packit Service f629e6
	 * portability problems declaring all the functions. So just
Packit Service f629e6
	 * do it the slow and stupid way. Sigh.
Packit Service f629e6
	 */
Packit Service f629e6
Packit Service f629e6
	value = getpid();
Packit Service f629e6
	update_PROCINFO_num("pid", value);
Packit Service f629e6
Packit Service f629e6
	value = getppid();
Packit Service f629e6
	update_PROCINFO_num("ppid", value);
Packit Service f629e6
Packit Service f629e6
	value = getuid();
Packit Service f629e6
	update_PROCINFO_num("uid", value);
Packit Service f629e6
Packit Service f629e6
	value = geteuid();
Packit Service f629e6
	update_PROCINFO_num("euid", value);
Packit Service f629e6
Packit Service f629e6
	value = getgid();
Packit Service f629e6
	update_PROCINFO_num("gid", value);
Packit Service f629e6
Packit Service f629e6
	value = getegid();
Packit Service f629e6
	update_PROCINFO_num("egid", value);
Packit Service f629e6
Packit Service f629e6
	update_PROCINFO_str("FS", current_field_sep_str());
Packit Service f629e6
Packit Service f629e6
#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
Packit Service f629e6
	for (i = 0; i < ngroups; i++) {
Packit Service f629e6
		sprintf(name, "group%d", i + 1);
Packit Service f629e6
		value = groupset[i];
Packit Service f629e6
		update_PROCINFO_num(name, value);
Packit Service f629e6
	}
Packit Service f629e6
	if (groupset) {
Packit Service f629e6
		efree(groupset);
Packit Service f629e6
		groupset = NULL;
Packit Service f629e6
	}
Packit Service f629e6
#endif
Packit Service f629e6
	load_procinfo_argv();
Packit Service f629e6
	return PROCINFO_node;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* is_std_var --- return true if a variable is a standard variable */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
is_std_var(const char *var)
Packit Service f629e6
{
Packit Service f629e6
	const struct varinit *vp;
Packit Service f629e6
Packit Service f629e6
	for (vp = varinit; vp->name != NULL; vp++) {
Packit Service f629e6
		if (strcmp(vp->name, var) == 0) {
Packit Service f629e6
			if ((do_traditional || do_posix) && (vp->flags & NON_STANDARD) != 0)
Packit Service f629e6
				return false;
Packit Service f629e6
Packit Service f629e6
			return true;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return false;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * is_off_limits_var --- return true if a variable is off limits
Packit Service f629e6
 * 			to extension functions
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
is_off_limits_var(const char *var)
Packit Service f629e6
{
Packit Service f629e6
	const struct varinit *vp;
Packit Service f629e6
Packit Service f629e6
	for (vp = varinit; vp->name != NULL; vp++) {
Packit Service f629e6
		if (strcmp(vp->name, var) == 0)
Packit Service f629e6
			return ((vp->flags & NOT_OFF_LIMITS) == 0);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return false;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* get_spec_varname --- return the name of a special variable
Packit Service f629e6
	with the given assign or update routine.
Packit Service f629e6
*/
Packit Service f629e6
Packit Service f629e6
const char *
Packit Service f629e6
get_spec_varname(Func_ptr fptr)
Packit Service f629e6
{
Packit Service f629e6
	const struct varinit *vp;
Packit Service f629e6
Packit Service f629e6
	if (! fptr)
Packit Service f629e6
		return NULL;
Packit Service f629e6
	for (vp = varinit; vp->name != NULL; vp++) {
Packit Service f629e6
		if (vp->assign == fptr || vp->update == fptr)
Packit Service f629e6
			return vp->name;
Packit Service f629e6
	}
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* arg_assign --- process a command-line assignment */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
arg_assign(char *arg, bool initing)
Packit Service f629e6
{
Packit Service f629e6
	char *cp, *cp2;
Packit Service f629e6
	bool badvar;
Packit Service f629e6
	NODE *var;
Packit Service f629e6
	NODE *it;
Packit Service f629e6
	NODE **lhs;
Packit Service f629e6
	long save_FNR;
Packit Service f629e6
Packit Service f629e6
	if (! initing && disallow_var_assigns)
Packit Service f629e6
		return false;	/* --exec */
Packit Service f629e6
Packit Service f629e6
	cp = strchr(arg, '=');
Packit Service f629e6
Packit Service f629e6
	if (cp == NULL) {
Packit Service f629e6
		if (! initing)
Packit Service f629e6
			return false;	/* This is file name, not assignment. */
Packit Service f629e6
Packit Service f629e6
		fprintf(stderr,
Packit Service f629e6
			_("%s: `%s' argument to `-v' not in `var=value' form\n\n"),
Packit Service f629e6
			myname, arg);
Packit Service f629e6
		usage(EXIT_FAILURE, stderr);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	*cp++ = '\0';
Packit Service f629e6
Packit Service f629e6
	/* avoid false source indications in a fatal message */
Packit Service f629e6
	source = NULL;
Packit Service f629e6
	sourceline = 0;
Packit Service f629e6
	save_FNR = FNR;
Packit Service f629e6
	FNR = 0;
Packit Service f629e6
Packit Service f629e6
	/* first check that the variable name has valid syntax */
Packit Service f629e6
	badvar = false;
Packit Service f629e6
	if (! is_letter((unsigned char) arg[0]))
Packit Service f629e6
		badvar = true;
Packit Service f629e6
	else
Packit Service f629e6
		for (cp2 = arg+1; *cp2; cp2++)
Packit Service f629e6
			if (! is_identchar((unsigned char) *cp2)) {
Packit Service f629e6
				badvar = true;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
	if (badvar) {
Packit Service f629e6
		if (initing)
Packit Service f629e6
			fatal(_("`%s' is not a legal variable name"), arg);
Packit Service f629e6
Packit Service f629e6
		if (do_lint)
Packit Service f629e6
			lintwarn(_("`%s' is not a variable name, looking for file `%s=%s'"),
Packit Service f629e6
				arg, arg, cp);
Packit Service f629e6
	} else {
Packit Service f629e6
		if (check_special(arg) >= 0)
Packit Service f629e6
			fatal(_("cannot use gawk builtin `%s' as variable name"), arg);
Packit Service f629e6
Packit Service f629e6
		if (! initing) {
Packit Service f629e6
			var = lookup(arg);
Packit Service f629e6
			if (var != NULL && var->type == Node_func)
Packit Service f629e6
				fatal(_("cannot use function `%s' as variable name"), arg);
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		/*
Packit Service f629e6
		 * BWK awk expands escapes inside assignments.
Packit Service f629e6
		 * This makes sense, so we do it too.
Packit Service f629e6
		 */
Packit Service f629e6
		it = make_str_node(cp, strlen(cp), SCAN);
Packit Service f629e6
		it->flags |= USER_INPUT;
Packit Service f629e6
#ifdef LC_NUMERIC
Packit Service f629e6
		/*
Packit Service f629e6
		 * See comment above about locale decimal point.
Packit Service f629e6
		 */
Packit Service f629e6
		if (do_posix)
Packit Service f629e6
			setlocale(LC_NUMERIC, "C");
Packit Service f629e6
#endif /* LC_NUMERIC */
Packit Service f629e6
		(void) force_number(it);
Packit Service f629e6
#ifdef LC_NUMERIC
Packit Service f629e6
		if (do_posix)
Packit Service f629e6
			setlocale(LC_NUMERIC, locale);
Packit Service f629e6
#endif /* LC_NUMERIC */
Packit Service f629e6
Packit Service f629e6
		/*
Packit Service f629e6
		 * since we are restoring the original text of ARGV later,
Packit Service f629e6
		 * need to copy the variable name part if we don't want
Packit Service f629e6
		 * name like v=abc instead of just v in var->vname
Packit Service f629e6
		 */
Packit Service f629e6
Packit Service f629e6
		cp2 = estrdup(arg, cp - arg);	/* var name */
Packit Service f629e6
Packit Service f629e6
		var = variable(0, cp2, Node_var);
Packit Service f629e6
		if (var == NULL)	/* error */
Packit Service f629e6
			final_exit(EXIT_FATAL);
Packit Service f629e6
		if (var->type == Node_var && var->var_update)
Packit Service f629e6
			var->var_update();
Packit Service f629e6
		lhs = get_lhs(var, false);
Packit Service f629e6
		unref(*lhs);
Packit Service f629e6
		*lhs = it;
Packit Service f629e6
		/* check for set_FOO() routine */
Packit Service f629e6
		if (var->type == Node_var && var->var_assign)
Packit Service f629e6
			var->var_assign();
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! initing)
Packit Service f629e6
		*--cp = '=';	/* restore original text of ARGV */
Packit Service f629e6
	FNR = save_FNR;
Packit Service f629e6
	return ! badvar;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* catchsig --- catch signals */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
catchsig(int sig)
Packit Service f629e6
{
Packit Service f629e6
	if (sig == SIGFPE) {
Packit Service f629e6
		fatal(_("floating point exception"));
Packit Service f629e6
	} else if (sig == SIGSEGV
Packit Service f629e6
#ifdef SIGBUS
Packit Service f629e6
	        || sig == SIGBUS
Packit Service f629e6
#endif
Packit Service f629e6
	) {
Packit Service f629e6
		set_loc(__FILE__, __LINE__);
Packit Service f629e6
		msg(_("fatal error: internal error"));
Packit Service f629e6
		/* fatal won't abort() if not compiled for debugging */
Packit Service f629e6
		// GLIBC 2.27 doesn't necessarily flush on abort. Sigh.
Packit Service f629e6
		fflush(NULL);
Packit Service f629e6
		abort();
Packit Service f629e6
	} else
Packit Service f629e6
		cant_happen();
Packit Service f629e6
	/* NOTREACHED */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_LIBSIGSEGV
Packit Service f629e6
/* catchsegv --- for use with libsigsegv */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
catchsegv(void *fault_address, int serious)
Packit Service f629e6
{
Packit Service f629e6
	set_loc(__FILE__, __LINE__);
Packit Service f629e6
	msg(_("fatal error: internal error: segfault"));
Packit Service f629e6
	fflush(NULL);
Packit Service f629e6
	abort();
Packit Service f629e6
	/*NOTREACHED*/
Packit Service f629e6
	return 0;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* catchstackoverflow --- for use with libsigsegv */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
catchstackoverflow(int emergency, stackoverflow_context_t scp)
Packit Service f629e6
{
Packit Service f629e6
	set_loc(__FILE__, __LINE__);
Packit Service f629e6
	msg(_("fatal error: internal error: stack overflow"));
Packit Service f629e6
	fflush(NULL);
Packit Service f629e6
	abort();
Packit Service f629e6
	/*NOTREACHED*/
Packit Service f629e6
	return;
Packit Service f629e6
}
Packit Service f629e6
#endif /* HAVE_LIBSIGSEGV */
Packit Service f629e6
Packit Service f629e6
/* nostalgia --- print the famous error message and die */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
nostalgia()
Packit Service f629e6
{
Packit Service f629e6
	/*
Packit Service f629e6
	 * N.B.: This string is not gettextized, on purpose.
Packit Service f629e6
	 * So there.
Packit Service f629e6
	 */
Packit Service f629e6
	fprintf(stderr, "awk: bailing out near line 1\n");
Packit Service f629e6
	fflush(stderr);
Packit Service f629e6
	abort();
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* version --- print version message */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
version()
Packit Service f629e6
{
Packit Service f629e6
	printf("%s", version_string);
Packit Service f629e6
#ifdef DYNAMIC
Packit Service f629e6
	printf(", API: %d.%d", GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION);
Packit Service f629e6
#endif
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
	printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
Packit Service f629e6
#endif
Packit Service f629e6
	printf("\n");
Packit Service f629e6
	print_ext_versions();
Packit Service f629e6
Packit Service f629e6
	/*
Packit Service f629e6
	 * Per GNU coding standards, print copyright info,
Packit Service f629e6
	 * then exit successfully, do nothing else.
Packit Service f629e6
	 */
Packit Service f629e6
	copyleft();
Packit Service f629e6
	exit(EXIT_SUCCESS);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* init_fds --- check for 0, 1, 2, open on /dev/null if possible */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
init_fds()
Packit Service f629e6
{
Packit Service f629e6
	struct stat sbuf;
Packit Service f629e6
	int fd;
Packit Service f629e6
	int newfd;
Packit Service f629e6
	char const *const opposite_mode[] = {"w", "r", "r"};
Packit Service f629e6
Packit Service f629e6
	/* maybe no stderr, don't bother with error mesg */
Packit Service f629e6
	for (fd = 0; fd <= 2; fd++) {
Packit Service f629e6
		if (fstat(fd, &sbuf) < 0) {
Packit Service f629e6
#if MAKE_A_HEROIC_EFFORT
Packit Service f629e6
			if (do_lint)
Packit Service f629e6
				lintwarn(_("no pre-opened fd %d"), fd);
Packit Service f629e6
#endif
Packit Service f629e6
			newfd = devopen("/dev/null", opposite_mode[fd]);
Packit Service f629e6
			/* turn off some compiler warnings "set but not used" */
Packit Service f629e6
			newfd += 0;
Packit Service f629e6
#ifdef MAKE_A_HEROIC_EFFORT
Packit Service f629e6
			if (do_lint && newfd < 0)
Packit Service f629e6
				lintwarn(_("could not pre-open /dev/null for fd %d"), fd);
Packit Service f629e6
#endif
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* init_groupset --- initialize groupset */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
init_groupset()
Packit Service f629e6
{
Packit Service f629e6
#if defined(HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
Packit Service f629e6
#ifdef GETGROUPS_NOT_STANDARD
Packit Service f629e6
	/* For systems that aren't standards conformant, use old way. */
Packit Service f629e6
	ngroups = NGROUPS_MAX;
Packit Service f629e6
#else
Packit Service f629e6
	/*
Packit Service f629e6
	 * If called with 0 for both args, return value is
Packit Service f629e6
	 * total number of groups.
Packit Service f629e6
	 */
Packit Service f629e6
	ngroups = getgroups(0, NULL);
Packit Service f629e6
#endif
Packit Service f629e6
	/* If an error or no groups, just give up and get on with life. */
Packit Service f629e6
	if (ngroups <= 0)
Packit Service f629e6
		return;
Packit Service f629e6
Packit Service f629e6
	/* fill in groups */
Packit Service f629e6
	emalloc(groupset, GETGROUPS_T *, ngroups * sizeof(GETGROUPS_T), "init_groupset");
Packit Service f629e6
Packit Service f629e6
	ngroups = getgroups(ngroups, groupset);
Packit Service f629e6
	/* same thing here, give up but keep going */
Packit Service f629e6
	if (ngroups == -1) {
Packit Service f629e6
		efree(groupset);
Packit Service f629e6
		ngroups = 0;
Packit Service f629e6
		groupset = NULL;
Packit Service f629e6
	}
Packit Service f629e6
#endif
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* estrdup --- duplicate a string */
Packit Service f629e6
Packit Service f629e6
char *
Packit Service f629e6
estrdup(const char *str, size_t len)
Packit Service f629e6
{
Packit Service f629e6
	char *s;
Packit Service f629e6
	emalloc(s, char *, len + 1, "estrdup");
Packit Service f629e6
	memcpy(s, str, len);
Packit Service f629e6
	s[len] = '\0';
Packit Service f629e6
	return s;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#if defined(HAVE_LOCALE_H)
Packit Service f629e6
Packit Service f629e6
/* init_locale --- initialize locale info. */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * On some operating systems, the pointers in the struct returned
Packit Service f629e6
 * by localeconv() can become dangling pointers after a call to
Packit Service f629e6
 * setlocale().  So we do a deep copy.
Packit Service f629e6
 *
Packit Service f629e6
 * Thanks to KIMURA Koichi <kimura.koichi@canon.co.jp>.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
init_locale(struct lconv *l)
Packit Service f629e6
{
Packit Service f629e6
	struct lconv *t;
Packit Service f629e6
Packit Service f629e6
	t = localeconv();
Packit Service f629e6
	*l = *t;
Packit Service f629e6
	l->thousands_sep = estrdup(t->thousands_sep, strlen(t->thousands_sep));
Packit Service f629e6
	l->decimal_point = estrdup(t->decimal_point, strlen(t->decimal_point));
Packit Service f629e6
	l->grouping = estrdup(t->grouping, strlen(t->grouping));
Packit Service f629e6
	l->int_curr_symbol = estrdup(t->int_curr_symbol, strlen(t->int_curr_symbol));
Packit Service f629e6
	l->currency_symbol = estrdup(t->currency_symbol, strlen(t->currency_symbol));
Packit Service f629e6
	l->mon_decimal_point = estrdup(t->mon_decimal_point, strlen(t->mon_decimal_point));
Packit Service f629e6
	l->mon_thousands_sep = estrdup(t->mon_thousands_sep, strlen(t->mon_thousands_sep));
Packit Service f629e6
	l->mon_grouping = estrdup(t->mon_grouping, strlen(t->mon_grouping));
Packit Service f629e6
	l->positive_sign = estrdup(t->positive_sign, strlen(t->positive_sign));
Packit Service f629e6
	l->negative_sign = estrdup(t->negative_sign, strlen(t->negative_sign));
Packit Service f629e6
}
Packit Service f629e6
#endif /* LOCALE_H */
Packit Service f629e6
Packit Service f629e6
/* save_argv --- save argv array */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
save_argv(int argc, char **argv)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	emalloc(d_argv, char **, (argc + 1) * sizeof(char *), "save_argv");
Packit Service f629e6
	for (i = 0; i < argc; i++)
Packit Service f629e6
		d_argv[i] = estrdup(argv[i], strlen(argv[i]));
Packit Service f629e6
	d_argv[argc] = NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * update_global_values --- make sure the symbol table has correct values.
Packit Service f629e6
 * Called from the grammar before dumping values.
Packit Service f629e6
 *
Packit Service f629e6
 * Also called when accessing through SYMTAB, and from api_sym_lookup().
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
update_global_values()
Packit Service f629e6
{
Packit Service f629e6
	const struct varinit *vp;
Packit Service f629e6
Packit Service f629e6
	for (vp = varinit; vp->name; vp++) {
Packit Service f629e6
		if (vp->update != NULL)
Packit Service f629e6
			vp->update();
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* getenv_long --- read a long value (>= 0) from an environment var. */
Packit Service f629e6
Packit Service f629e6
long
Packit Service f629e6
getenv_long(const char *name)
Packit Service f629e6
{
Packit Service f629e6
	const char *val;
Packit Service f629e6
	long newval;
Packit Service f629e6
	if ((val = getenv(name)) != NULL && isdigit((unsigned char) *val)) {
Packit Service f629e6
		for (newval = 0; *val && isdigit((unsigned char) *val); val++)
Packit Service f629e6
			newval = (newval * 10) + *val - '0';
Packit Service f629e6
		return newval;
Packit Service f629e6
	}
Packit Service f629e6
	return -1;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* parse_args --- do the getopt_long thing */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
parse_args(int argc, char **argv)
Packit Service f629e6
{
Packit Service f629e6
	/*
Packit Service f629e6
	 * The + on the front tells GNU getopt not to rearrange argv.
Packit Service f629e6
	 */
Packit Service f629e6
	const char *optlist = "+F:f:v:W;bcCd::D::e:E:ghi:l:L::nNo::Op::MPrSstVYZ:";
Packit Service f629e6
	int old_optind;
Packit Service f629e6
	int c;
Packit Service f629e6
	char *scan;
Packit Service f629e6
	char *src;
Packit Service f629e6
Packit Service f629e6
	/* we do error messages ourselves on invalid options */
Packit Service f629e6
	opterr = false;
Packit Service f629e6
Packit Service f629e6
	/* copy argv before getopt gets to it; used to restart the debugger */
Packit Service f629e6
	save_argv(argc, argv);
Packit Service f629e6
Packit Service f629e6
	/* option processing. ready, set, go! */
Packit Service f629e6
	for (optopt = 0, old_optind = 1;
Packit Service f629e6
	     (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
Packit Service f629e6
	     optopt = 0, old_optind = optind) {
Packit Service f629e6
		if (do_posix)
Packit Service f629e6
			opterr = true;
Packit Service f629e6
Packit Service f629e6
		switch (c) {
Packit Service f629e6
		case 'F':
Packit Service f629e6
			add_preassign(PRE_ASSIGN_FS, optarg);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'E':
Packit Service f629e6
			disallow_var_assigns = true;
Packit Service f629e6
			/* fall through */
Packit Service f629e6
		case 'f':
Packit Service f629e6
			/*
Packit Service f629e6
			 * Allow multiple -f options.
Packit Service f629e6
			 * This makes function libraries real easy.
Packit Service f629e6
			 * Most of the magic is in the scanner.
Packit Service f629e6
			 *
Packit Service f629e6
			 * The following is to allow for whitespace at the end
Packit Service f629e6
			 * of a #! /bin/gawk line in an executable file
Packit Service f629e6
			 */
Packit Service f629e6
			scan = optarg;
Packit Service f629e6
			if (argv[optind-1] != optarg)
Packit Service f629e6
				while (isspace((unsigned char) *scan))
Packit Service f629e6
					scan++;
Packit Service f629e6
			src = (*scan == '\0' ? argv[optind++] : optarg);
Packit Service f629e6
			(void) add_srcfile((src && src[0] == '-' && src[1] == '\0') ?
Packit Service f629e6
					SRC_STDIN : SRC_FILE,
Packit Service f629e6
					src, srcfiles, NULL, NULL);
Packit Service f629e6
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'v':
Packit Service f629e6
			add_preassign(PRE_ASSIGN, optarg);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'b':
Packit Service f629e6
			do_binary = true;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'c':
Packit Service f629e6
			do_flags |= DO_TRADITIONAL;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'C':
Packit Service f629e6
			copyleft();
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'd':
Packit Service f629e6
			do_flags |= DO_DUMP_VARS;
Packit Service f629e6
			if (optarg != NULL && optarg[0] != '\0')
Packit Service f629e6
				varfile = optarg;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'D':
Packit Service f629e6
			do_flags |= DO_DEBUG;
Packit Service f629e6
			if (optarg != NULL && optarg[0] != '\0')
Packit Service f629e6
				command_file = optarg;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'e':
Packit Service f629e6
			if (optarg[0] == '\0')
Packit Service f629e6
				warning(_("empty argument to `-e/--source' ignored"));
Packit Service f629e6
			else
Packit Service f629e6
				(void) add_srcfile(SRC_CMDLINE, optarg, srcfiles, NULL, NULL);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'g':
Packit Service f629e6
			do_flags |= DO_INTL;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'h':
Packit Service f629e6
			/* write usage to stdout, per GNU coding stds */
Packit Service f629e6
			usage(EXIT_SUCCESS, stdout);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'i':
Packit Service f629e6
			(void) add_srcfile(SRC_INC, optarg, srcfiles, NULL, NULL);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'l':
Packit Service f629e6
			(void) add_srcfile(SRC_EXTLIB, optarg, srcfiles, NULL, NULL);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
#ifndef NO_LINT
Packit Service f629e6
		case 'L':
Packit Service f629e6
			do_flags |= DO_LINT_ALL;
Packit Service f629e6
			if (optarg != NULL) {
Packit Service f629e6
				if (strcmp(optarg, "fatal") == 0)
Packit Service f629e6
					lintfunc = r_fatal;
Packit Service f629e6
				else if (strcmp(optarg, "invalid") == 0) {
Packit Service f629e6
					do_flags &= ~DO_LINT_ALL;
Packit Service f629e6
					do_flags |= DO_LINT_INVALID;
Packit Service f629e6
				}
Packit Service f629e6
			}
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 't':
Packit Service f629e6
			do_flags |= DO_LINT_OLD;
Packit Service f629e6
			break;
Packit Service f629e6
#else
Packit Service f629e6
		case 'L':
Packit Service f629e6
		case 't':
Packit Service f629e6
			break;
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
		case 'n':
Packit Service f629e6
			do_flags |= DO_NON_DEC_DATA;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'N':
Packit Service f629e6
			use_lc_numeric = true;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'O':
Packit Service f629e6
			do_optimize = true;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'p':
Packit Service f629e6
			do_flags |= DO_PROFILE;
Packit Service f629e6
			/* fall through */
Packit Service f629e6
		case 'o':
Packit Service f629e6
			do_flags |= DO_PRETTY_PRINT;
Packit Service f629e6
			if (optarg != NULL)
Packit Service f629e6
				set_prof_file(optarg);
Packit Service f629e6
			else
Packit Service f629e6
				set_prof_file(DEFAULT_PROFILE);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'M':
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
			do_flags |= DO_MPFR;
Packit Service f629e6
#else
Packit Service f629e6
			warning(_("-M ignored: MPFR/GMP support not compiled in"));
Packit Service f629e6
#endif
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'P':
Packit Service f629e6
			do_flags |= DO_POSIX;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'r':
Packit Service f629e6
			do_flags |= DO_INTERVALS;
Packit Service f629e6
 			break;
Packit Service f629e6
Packit Service f629e6
		case 's':
Packit Service f629e6
			do_optimize = false;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'S':
Packit Service f629e6
			do_flags |= DO_SANDBOX;
Packit Service f629e6
  			break;
Packit Service f629e6
Packit Service f629e6
		case 'V':
Packit Service f629e6
			do_version = true;
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'W':       /* gawk specific options - now in getopt_long */
Packit Service f629e6
			fprintf(stderr, _("%s: option `-W %s' unrecognized, ignored\n"),
Packit Service f629e6
				argv[0], optarg);
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 0:
Packit Service f629e6
			/*
Packit Service f629e6
			 * getopt_long found an option that sets a variable
Packit Service f629e6
			 * instead of returning a letter. Do nothing, just
Packit Service f629e6
			 * cycle around for the next one.
Packit Service f629e6
			 */
Packit Service f629e6
			break;
Packit Service f629e6
Packit Service f629e6
		case 'Y':
Packit Service f629e6
		case 'Z':
Packit Service f629e6
#if defined(YYDEBUG) || defined(GAWKDEBUG)
Packit Service f629e6
			if (c == 'Y') {
Packit Service f629e6
				yydebug = 2;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
#endif
Packit Service f629e6
#if defined(LOCALEDEBUG)
Packit Service f629e6
			if (c == 'Z') {
Packit Service f629e6
				locale = optarg;
Packit Service f629e6
				break;
Packit Service f629e6
			}
Packit Service f629e6
#endif
Packit Service f629e6
			/* if not debugging, fall through */
Packit Service f629e6
		case '?':
Packit Service f629e6
		default:
Packit Service f629e6
			/*
Packit Service f629e6
			 * If not posix, an unrecognized option stops argument
Packit Service f629e6
			 * processing so that it can go into ARGV for the awk
Packit Service f629e6
			 * program to see. This makes use of ``#! /bin/gawk -f''
Packit Service f629e6
			 * easier.
Packit Service f629e6
			 *
Packit Service f629e6
			 * However, it's never simple. If optopt is set,
Packit Service f629e6
			 * an option that requires an argument didn't get the
Packit Service f629e6
			 * argument. We care because if opterr is 0, then
Packit Service f629e6
			 * getopt_long won't print the error message for us.
Packit Service f629e6
			 */
Packit Service f629e6
			if (! do_posix
Packit Service f629e6
			    && (optopt == '\0' || strchr(optlist, optopt) == NULL)) {
Packit Service f629e6
				/*
Packit Service f629e6
				 * can't just do optind--. In case of an
Packit Service f629e6
				 * option with >= 2 letters, getopt_long
Packit Service f629e6
				 * won't have incremented optind.
Packit Service f629e6
				 */
Packit Service f629e6
				optind = old_optind;
Packit Service f629e6
				stopped_early = true;
Packit Service f629e6
				goto out;
Packit Service f629e6
			} else if (optopt != '\0') {
Packit Service f629e6
				/* Use POSIX required message format */
Packit Service f629e6
				fprintf(stderr,
Packit Service f629e6
					_("%s: option requires an argument -- %c\n"),
Packit Service f629e6
					myname, optopt);
Packit Service f629e6
				usage(EXIT_FAILURE, stderr);
Packit Service f629e6
			}
Packit Service f629e6
			/* else
Packit Service f629e6
				let getopt print error message for us */
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
		if (c == 'E')	/* --exec ends option processing */
Packit Service f629e6
			break;
Packit Service f629e6
	}
Packit Service f629e6
out:
Packit Service f629e6
	do_optimize = (do_optimize && ! do_pretty_print);
Packit Service f629e6
Packit Service f629e6
	return;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* set_locale_stuff --- setup the locale stuff */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
set_locale_stuff(void)
Packit Service f629e6
{
Packit Service f629e6
#if defined(LC_CTYPE)
Packit Service f629e6
	setlocale(LC_CTYPE, locale);
Packit Service f629e6
#endif
Packit Service f629e6
#if defined(LC_COLLATE)
Packit Service f629e6
	setlocale(LC_COLLATE, locale);
Packit Service f629e6
#endif
Packit Service f629e6
#if defined(LC_MESSAGES)
Packit Service f629e6
	setlocale(LC_MESSAGES, locale);
Packit Service f629e6
#endif
Packit Service f629e6
#if defined(LC_NUMERIC) && defined(HAVE_LOCALE_H)
Packit Service f629e6
	/*
Packit Service f629e6
	 * Force the issue here.  According to POSIX 2001, decimal
Packit Service f629e6
	 * point is used for parsing source code and for command-line
Packit Service f629e6
	 * assignments and the locale value for processing input,
Packit Service f629e6
	 * number to string conversion, and printing output.
Packit Service f629e6
	 *
Packit Service f629e6
	 * 10/2005 --- see below also; we now only use the locale's
Packit Service f629e6
	 * decimal point if do_posix in effect.
Packit Service f629e6
	 *
Packit Service f629e6
	 * 9/2007:
Packit Service f629e6
	 * This is a mess. We need to get the locale's numeric info for
Packit Service f629e6
	 * the thousands separator for the %'d flag.
Packit Service f629e6
	 */
Packit Service f629e6
	setlocale(LC_NUMERIC, locale);
Packit Service f629e6
	init_locale(& loc);
Packit Service f629e6
	setlocale(LC_NUMERIC, "C");
Packit Service f629e6
#endif
Packit Service f629e6
#if defined(LC_TIME)
Packit Service f629e6
	setlocale(LC_TIME, locale);
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	/* These must be done after calling setlocale */
Packit Service f629e6
	(void) bindtextdomain(PACKAGE, locale_dir);
Packit Service f629e6
	(void) textdomain(PACKAGE);
Packit Service f629e6
}