aboutsummaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c496
1 files changed, 310 insertions, 186 deletions
diff --git a/main.c b/main.c
index 4292874a..d054ec1a 100644
--- a/main.c
+++ b/main.c
@@ -35,6 +35,8 @@
#define DEFAULT_PROFILE "awkprof.out" /* where to put profile */
#define DEFAULT_VARFILE "awkvars.out" /* where to put vars */
+#define DEFAULT_PREC 53
+#define DEFAULT_ROUNDMODE "N" /* round to nearest */
static const char *varfile = DEFAULT_VARFILE;
const char *command_file = NULL; /* debugger commands */
@@ -55,19 +57,20 @@ static void nostalgia(void) ATTRIBUTE_NORETURN;
static void version(void) ATTRIBUTE_NORETURN;
static void init_fds(void);
static void init_groupset(void);
-
static void save_argv(int, char **);
+extern int debug_prog(INSTRUCTION *pc); /* debug.c */
+extern int init_debug(); /* debug.c */
+
/* These nodes store all the special variables AWK uses */
NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
NODE *ENVIRON_node, *ERRNO_node, *FIELDWIDTHS_node, *FILENAME_node;
NODE *FNR_node, *FPAT_node, *FS_node, *IGNORECASE_node, *LINT_node;
NODE *NF_node, *NR_node, *OFMT_node, *OFS_node, *ORS_node, *PROCINFO_node;
NODE *RLENGTH_node, *RSTART_node, *RS_node, *RT_node, *SUBSEP_node;
+NODE *PREC_node, *ROUNDMODE_node;
NODE *TEXTDOMAIN_node;
-NODE *_r; /* used as temporary in stack macros */
-
long NF;
long NR;
long FNR;
@@ -81,7 +84,7 @@ char *TEXTDOMAIN;
/*
* CONVFMT is a convenience pointer for the current number to string format.
* We must supply an initial value to avoid recursion problems of
- * set_CONVFMT -> fmt_index -> r_force_string: gets NULL CONVFMT
+ * set_CONVFMT -> fmt_index -> force_string: gets NULL CONVFMT
* Fun, fun, fun, fun.
*/
char *CONVFMT = "%.6g";
@@ -125,35 +128,24 @@ struct pre_assign {
static struct pre_assign *preassigns = NULL; /* requested via -v or -F */
static long numassigns = -1; /* how many of them */
-static int disallow_var_assigns = FALSE; /* true for --exec */
+static bool disallow_var_assigns = false; /* true for --exec */
static void add_preassign(enum assign_type type, char *val);
-#undef do_lint
-#undef do_lint_old
-
-int do_traditional = FALSE; /* no gnu extensions, add traditional weirdnesses */
-int do_posix = FALSE; /* turn off gnu and unix extensions */
-int do_lint = FALSE; /* provide warnings about questionable stuff */
-int do_lint_old = FALSE; /* warn about stuff not in V7 awk */
-int do_intl = FALSE; /* dump locale-izable strings to stdout */
-int do_non_decimal_data = FALSE; /* allow octal/hex C style DATA. Use with caution! */
-int do_nostalgia = FALSE; /* provide a blast from the past */
-int do_intervals = FALSE; /* allow {...,...} in regexps, see resetup() */
-int do_profiling = FALSE; /* profile and pretty print the program */
-int do_dump_vars = FALSE; /* dump all global variables at end */
-int do_tidy_mem = FALSE; /* release vars when done */
-int do_optimize = TRUE; /* apply default optimizations */
-int do_binary = FALSE; /* hands off my data! */
-int do_sandbox = FALSE; /* sandbox mode - disable 'system' function & redirections */
-int use_lc_numeric = FALSE; /* obey locale for decimal point */
+int do_flags = false;
+bool do_optimize = true; /* apply default optimizations */
+static int do_nostalgia = false; /* provide a blast from the past */
+static int do_binary = false; /* hands off my data! */
+static int do_version = false; /* print version info */
+
+int use_lc_numeric = false; /* obey locale for decimal point */
#if MBS_SUPPORT
int gawk_mb_cur_max; /* MB_CUR_MAX value, see comment in main() */
#endif
-FILE *output_fp; /* default output for debugger */
-int output_is_tty = FALSE; /* control flushing of output */
+FILE *output_fp; /* default gawk output, can be redirected in the debugger */
+bool output_is_tty = false; /* control flushing of output */
/* default format for strftime(), available via PROCINFO */
const char def_strftime_format[] = "%a %b %e %H:%M:%S %Z %Y";
@@ -167,44 +159,39 @@ int ngroups; /* size of said set */
void (*lintfunc)(const char *mesg, ...) = warning;
-/*
- * Note: reserve -D for future use, to merge dgawk into gawk.
- * Note: reserve -l for future use, for xgawk's -l option.
- */
static const struct option optab[] = {
- { "traditional", no_argument, & do_traditional, 1 },
- { "lint", optional_argument, NULL, 'L' },
- { "lint-old", no_argument, & do_lint_old, 1 },
- { "optimize", no_argument, & do_optimize, 'O' },
- { "posix", no_argument, & do_posix, 1 },
- { "command", required_argument, NULL, 'R' },
+ { "traditional", no_argument, NULL, 'c' },
+ { "lint", optional_argument, NULL, 'L' },
+ { "lint-old", no_argument, NULL, 't' },
+ { "optimize", no_argument, NULL, 'O' },
+ { "posix", no_argument, NULL, 'P' },
{ "nostalgia", no_argument, & do_nostalgia, 1 },
- { "gen-pot", no_argument, & do_intl, 1 },
- { "non-decimal-data", no_argument, & do_non_decimal_data, 1 },
- { "profile", optional_argument, NULL, 'p' },
- { "copyright", no_argument, NULL, 'C' },
- { "field-separator", required_argument, NULL, 'F' },
- { "file", required_argument, NULL, 'f' },
- { "re-interval", no_argument, & do_intervals, 1 },
- { "source", required_argument, NULL, 'e' },
- { "dump-variables", optional_argument, NULL, 'd' },
- { "assign", required_argument, NULL, 'v' },
- { "version", no_argument, NULL, 'V' },
- { "help", no_argument, NULL, 'h' },
- { "exec", required_argument, NULL, 'E' },
+ { "gen-pot", no_argument, NULL, 'g' },
+ { "non-decimal-data", no_argument, NULL, 'n' },
+ { "pretty-print", optional_argument, NULL, 'o' },
+ { "profile", optional_argument, NULL, 'p' },
+ { "debug", optional_argument, NULL, 'D' },
+ { "copyright", no_argument, NULL, 'C' },
+ { "field-separator", required_argument, NULL, 'F' },
+ { "file", required_argument, NULL, 'f' },
+ { "re-interval", no_argument, NULL, 'r' },
+ { "source", required_argument, NULL, 'e' },
+ { "load", required_argument, NULL, 'l' },
+ { "dump-variables", optional_argument, NULL, 'd' },
+ { "assign", required_argument, NULL, 'v' },
+ { "version", no_argument, & do_version, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ { "exec", required_argument, NULL, 'E' },
{ "use-lc-numeric", no_argument, & use_lc_numeric, 1 },
{ "characters-as-bytes", no_argument, & do_binary, 'b' },
- { "sandbox", no_argument, & do_sandbox, 1 },
+ { "sandbox", no_argument, NULL, 'S' },
+ { "bignum", no_argument, NULL, 'M' },
#if defined(YYDEBUG) || defined(GAWKDEBUG)
{ "parsedebug", no_argument, NULL, 'Y' },
#endif
{ NULL, 0, NULL, '\0' }
};
-#ifdef NO_LINT
-#define do_lint 0
-#define do_lint_old 0
-#endif
/* main --- process args, parse program, run it, clean up */
@@ -213,19 +200,20 @@ main(int argc, char **argv)
{
/*
* The + on the front tells GNU getopt not to rearrange argv.
- * Note: reserve -D for future use, to merge dgawk into gawk.
- * Note: reserve -l for future use, for xgawk's -l option.
*/
- const char *optlist = "+F:f:v:W;m:bcCd::e:E:gh:L:nNOp::PrR:StVY";
- int stopped_early = FALSE;
+ const char *optlist = "+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::MPrStVY";
+ bool stopped_early = false;
int old_optind;
int i;
int c;
char *scan, *src;
char *extra_stack;
+ int have_srcfile = 0;
+ SRCFILE *s;
/* do these checks early */
- do_tidy_mem = (getenv("TIDYMEM") != NULL);
+ if (getenv("TIDYMEM") != NULL)
+ do_flags |= DO_TIDY_MEM;
#ifdef HAVE_MCHECK_H
#ifdef HAVE_MTRACE
@@ -298,16 +286,22 @@ main(int argc, char **argv)
if (argc < 2)
usage(EXIT_FAILURE, stderr);
+ /* initialize the null string */
+ Nnull_string = make_string("", 0);
+
/* Robustness: check that file descriptors 0, 1, 2 are open */
init_fds();
/* init array handling. */
array_init();
+ /* init the symbol tables */
+ init_symbol_table();
+
output_fp = stdout;
/* we do error messages ourselves on invalid options */
- opterr = FALSE;
+ opterr = false;
/* copy argv before getopt gets to it; used to restart the debugger */
save_argv(argc, argv);
@@ -320,7 +314,7 @@ main(int argc, char **argv)
(c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
optopt = 0, old_optind = optind) {
if (do_posix)
- opterr = TRUE;
+ opterr = true;
switch (c) {
case 'F':
@@ -328,7 +322,7 @@ main(int argc, char **argv)
break;
case 'E':
- disallow_var_assigns = TRUE;
+ disallow_var_assigns = true;
/* fall through */
case 'f':
/*
@@ -369,11 +363,11 @@ main(int argc, char **argv)
break;
case 'b':
- do_binary = TRUE;
+ do_binary = true;
break;
case 'c':
- do_traditional = TRUE;
+ do_flags |= DO_TRADITIONAL;
break;
case 'C':
@@ -381,11 +375,17 @@ main(int argc, char **argv)
break;
case 'd':
- do_dump_vars = TRUE;
+ do_flags |= DO_DUMP_VARS;
if (optarg != NULL && optarg[0] != '\0')
varfile = optarg;
break;
+ case 'D':
+ do_flags |= DO_DEBUG;
+ if (optarg != NULL && optarg[0] != '\0')
+ command_file = optarg;
+ break;
+
case 'e':
if (optarg[0] == '\0')
warning(_("empty argument to `-e/--source' ignored"));
@@ -394,7 +394,7 @@ main(int argc, char **argv)
break;
case 'g':
- do_intl = TRUE;
+ do_flags |= DO_INTL;
break;
case 'h':
@@ -402,19 +402,29 @@ main(int argc, char **argv)
usage(EXIT_SUCCESS, stdout);
break;
-#ifndef NO_LINT
+ case 'i':
+ (void) add_srcfile(SRC_INC, optarg, srcfiles, NULL, NULL);
+ break;
+
+ case 'l':
+ (void) add_srcfile(SRC_EXTLIB, optarg, srcfiles, NULL, NULL);
+ break;
+
case 'L':
- do_lint = LINT_ALL;
+#ifndef NO_LINT
+ do_flags |= DO_LINT_ALL;
if (optarg != NULL) {
if (strcmp(optarg, "fatal") == 0)
lintfunc = r_fatal;
- else if (strcmp(optarg, "invalid") == 0)
- do_lint = LINT_INVALID;
+ else if (strcmp(optarg, "invalid") == 0) {
+ do_flags &= ~DO_LINT_ALL;
+ do_flags |= DO_LINT_INVALID;
+ }
}
break;
case 't':
- do_lint_old = TRUE;
+ do_flags |= DO_LINT_OLD;
break;
#else
case 'L':
@@ -423,11 +433,11 @@ main(int argc, char **argv)
#endif
case 'n':
- do_non_decimal_data = TRUE;
+ do_flags |= DO_NON_DEC_DATA;
break;
case 'N':
- use_lc_numeric = TRUE;
+ use_lc_numeric = true;
break;
case 'O':
@@ -435,27 +445,36 @@ main(int argc, char **argv)
break;
case 'p':
- do_profiling = TRUE;
+ do_flags |= DO_PROFILE;
+ /* fall through */
+ case 'o':
+ do_flags |= DO_PRETTY_PRINT;
if (optarg != NULL)
set_prof_file(optarg);
else
set_prof_file(DEFAULT_PROFILE);
break;
+ case 'M':
+#ifdef HAVE_MPFR
+ do_flags |= DO_MPFR;
+#endif
+ break;
+
case 'P':
- do_posix = TRUE;
+ do_flags |= DO_POSIX;
break;
case 'r':
- do_intervals = TRUE;
+ do_flags |= DO_INTERVALS;
break;
case 'S':
- do_sandbox = TRUE;
+ do_flags |= DO_SANDBOX;
break;
case 'V':
- version();
+ do_version = true;
break;
case 'W': /* gawk specific options - now in getopt_long */
@@ -472,20 +491,13 @@ main(int argc, char **argv)
break;
case 'Y':
- case 'R':
#if defined(YYDEBUG) || defined(GAWKDEBUG)
if (c == 'Y') {
yydebug = 2;
break;
}
#endif
- if (c == 'R' && which_gawk == exe_debugging) {
- if (optarg[0] != '\0')
- command_file = optarg;
- break;
- }
- /* if not debugging or dgawk, fall through */
-
+ /* if not debugging, fall through */
case '?':
default:
/*
@@ -507,7 +519,7 @@ main(int argc, char **argv)
* won't have incremented optind.
*/
optind = old_optind;
- stopped_early = TRUE;
+ stopped_early = true;
goto out;
} else if (optopt != '\0') {
/* Use POSIX required message format */
@@ -530,18 +542,18 @@ out:
/* check for POSIXLY_CORRECT environment variable */
if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
- do_posix = TRUE;
+ do_flags |= DO_POSIX;
if (do_lint)
lintwarn(
_("environment variable `POSIXLY_CORRECT' set: turning on `--posix'"));
}
if (do_posix) {
- use_lc_numeric = TRUE;
+ use_lc_numeric = true;
if (do_traditional) /* both on command line */
warning(_("`--posix' overrides `--traditional'"));
else
- do_traditional = TRUE;
+ do_flags |= DO_TRADITIONAL;
/*
* POSIX compliance also implies
* no GNU extensions either.
@@ -549,7 +561,7 @@ out:
}
if (do_traditional && do_non_decimal_data) {
- do_non_decimal_data = FALSE;
+ do_flags &= ~DO_NON_DEC_DATA;
warning(_("`--posix'/`--traditional' overrides `--non-decimal-data'"));
}
@@ -568,21 +580,28 @@ out:
}
#endif
- /*
- * Force profiling if this is pgawk.
- * Don't bother if the command line already set profiling up.
- */
- if (! do_profiling)
- init_profiling(& do_profiling, DEFAULT_PROFILE);
+ if (do_debug) /* Need to register the debugger pre-exec hook before any other */
+ init_debug();
+
+#ifdef HAVE_MPFR
+ /* Set up MPFR defaults, and register pre-exec hook to process arithmetic opcodes */
+ if (do_mpfr)
+ init_mpfr(DEFAULT_PREC, DEFAULT_ROUNDMODE);
+#endif
/* load group set */
init_groupset();
- /* initialize the null string */
- Nnull_string = make_string("", 0);
- Nnull_string->numbr = 0.0;
- Nnull_string->type = Node_val;
- Nnull_string->flags = (PERM|STRCUR|STRING|NUMCUR|NUMBER);
+#ifdef HAVE_MPFR
+ if (do_mpfr) {
+ mpz_init(Nnull_string->mpg_i);
+ Nnull_string->flags = (MALLOC|STRCUR|STRING|MPZN|NUMCUR|NUMBER);
+ } else
+#endif
+ {
+ Nnull_string->numbr = 0.0;
+ Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER);
+ }
/*
* Tell the regex routines how they should work.
@@ -591,8 +610,6 @@ out:
*/
resetup();
- (void) grow_stack();
-
/* Set up the special variables */
init_vars();
@@ -602,7 +619,7 @@ out:
/* Now process the pre-assignments */
for (i = 0; i <= numassigns; i++) {
if (preassigns[i].type == PRE_ASSIGN)
- (void) arg_assign(preassigns[i].val, TRUE);
+ (void) arg_assign(preassigns[i].val, true);
else /* PRE_ASSIGN_FS */
cmdline_fs(preassigns[i].val);
efree(preassigns[i].val);
@@ -625,15 +642,34 @@ out:
setbuf(stdout, (char *) NULL); /* make debugging easier */
#endif
if (os_isatty(fileno(stdout)))
- output_is_tty = TRUE;
+ output_is_tty = true;
+
+ /* initialize API before loading extension libraries */
+ init_ext_api();
+
+ /* load extension libs */
+ for (s = srcfiles->next; s != srcfiles; s = s->next) {
+ if (s->stype == SRC_EXTLIB)
+ load_ext(s->fullpath);
+ else if (s->stype != SRC_INC)
+ have_srcfile++;
+ }
+
+ /* do version check after extensions are loaded to get extension info */
+ if (do_version)
+ version();
+
/* No -f or --source options, use next arg */
- if (srcfiles->next == srcfiles) {
+ if (! have_srcfile) {
if (optind > argc - 1 || stopped_early) /* no args left or no program */
usage(EXIT_FAILURE, stderr);
(void) add_srcfile(SRC_CMDLINE, argv[optind], srcfiles, NULL, NULL);
optind++;
}
+ /* Select the interpreter routine */
+ init_interpret();
+
init_args(optind, argc,
do_posix ? argv[0] : myname,
argv);
@@ -647,7 +683,7 @@ out:
setlocale(LC_NUMERIC, "C");
#endif
/* Read in the program */
- if (parse_program(&code_block) != 0)
+ if (parse_program(& code_block) != 0)
exit(EXIT_FAILURE);
if (do_intl)
@@ -659,7 +695,10 @@ out:
if (do_lint && code_block->nexti->opcode == Op_atexit)
lintwarn(_("no program text at all!"));
- init_profiling_signals();
+ load_symbols();
+
+ if (do_profile)
+ init_profiling_signals();
#if defined(LC_NUMERIC)
/*
@@ -680,10 +719,16 @@ out:
if (use_lc_numeric)
setlocale(LC_NUMERIC, "");
#endif
+
+ init_io();
+ output_fp = stdout;
- interpret(code_block);
+ if (do_debug)
+ debug_prog(code_block);
+ else
+ interpret(code_block);
- if (do_profiling) {
+ if (do_pretty_print) {
dump_prog(code_block);
dump_funcs();
}
@@ -698,7 +743,7 @@ out:
if (extra_stack)
efree(extra_stack);
- exit(exit_val); /* more portable */
+ final_exit(exit_val);
return exit_val; /* to suppress warnings */
}
@@ -737,7 +782,7 @@ usage(int exitval, FILE *fp)
fprintf(fp, _("Usage: %s [POSIX or GNU style options] -f progfile [--] file ...\n"),
myname);
fprintf(fp, _("Usage: %s [POSIX or GNU style options] [--] %cprogram%c file ...\n"),
- myname, quote, quote);
+ myname, quote, quote);
/* GNU long options info. This is too many options. */
@@ -750,19 +795,22 @@ usage(int exitval, FILE *fp)
fputs(_("\t-c\t\t\t--traditional\n"), fp);
fputs(_("\t-C\t\t\t--copyright\n"), fp);
fputs(_("\t-d[file]\t\t--dump-variables[=file]\n"), fp);
+ fputs(_("\t-D[file]\t\t--debug[=file]\n"), fp);
fputs(_("\t-e 'program-text'\t--source='program-text'\n"), fp);
fputs(_("\t-E file\t\t\t--exec=file\n"), fp);
fputs(_("\t-g\t\t\t--gen-pot\n"), fp);
fputs(_("\t-h\t\t\t--help\n"), fp);
+ fputs(_("\t-i includefile\t\t--include=includefile\n"), fp);
+ fputs(_("\t-l library\t\t--load=library\n"), fp);
fputs(_("\t-L [fatal]\t\t--lint[=fatal]\n"), fp);
fputs(_("\t-n\t\t\t--non-decimal-data\n"), fp);
+ fputs(_("\t-M\t\t\t--bignum\n"), fp);
fputs(_("\t-N\t\t\t--use-lc-numeric\n"), fp);
+ fputs(_("\t-o[file]\t\t--pretty-print[=file]\n"), fp);
fputs(_("\t-O\t\t\t--optimize\n"), fp);
fputs(_("\t-p[file]\t\t--profile[=file]\n"), fp);
fputs(_("\t-P\t\t\t--posix\n"), fp);
fputs(_("\t-r\t\t\t--re-interval\n"), fp);
- if (which_gawk == exe_debugging)
- fputs(_("\t-R file\t\t\t--command=file\n"), fp);
fputs(_("\t-S\t\t\t--sandbox\n"), fp);
fputs(_("\t-t\t\t\t--lint-old\n"), fp);
fputs(_("\t-V\t\t\t--version\n"), fp);
@@ -860,6 +908,7 @@ cmdline_fs(char *str)
if (do_traditional && ! do_posix)
str[0] = '\t';
}
+
*tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
set_FS();
}
@@ -873,26 +922,27 @@ init_args(int argc0, int argc, const char *argv0, char **argv)
NODE **aptr;
NODE *tmp;
- ARGV_node = install_symbol(estrdup("ARGV", 4), mk_symbol(Node_var_array, (NODE *) NULL));
+ ARGV_node = install_symbol(estrdup("ARGV", 4), Node_var_array);
tmp = make_number(0.0);
- aptr = assoc_lookup(ARGV_node, tmp, FALSE);
+ aptr = assoc_lookup(ARGV_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(argv0, strlen(argv0));
(*aptr)->flags |= MAYBE_NUM;
for (i = argc0, j = 1; i < argc; i++, j++) {
tmp = make_number((AWKNUM) j);
- aptr = assoc_lookup(ARGV_node, tmp, FALSE);
+ aptr = assoc_lookup(ARGV_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(argv[i], strlen(argv[i]));
(*aptr)->flags |= MAYBE_NUM;
}
- ARGC_node = install_symbol(estrdup("ARGC", 4),
- mk_symbol(Node_var, make_number((AWKNUM) j)));
+ ARGC_node = install_symbol(estrdup("ARGC", 4), Node_var);
+ ARGC_node->var_value = make_number((AWKNUM) j);
}
+
/*
* Set all the special variables to their initial values.
* Note that some of the variables that have set_FOO routines should
@@ -908,40 +958,43 @@ struct varinit {
AWKNUM numval;
Func_ptr update;
Func_ptr assign;
- int do_assign;
+ bool do_assign;
int flags;
#define NO_INSTALL 0x01
#define NON_STANDARD 0x02
+#define NOT_OFF_LIMITS 0x04 /* may be accessed by extension function */
};
static const struct varinit varinit[] = {
-{NULL, "ARGC", NULL, 0, NULL, NULL, FALSE, NO_INSTALL },
-{&ARGIND_node, "ARGIND", NULL, 0, NULL, NULL, FALSE, NON_STANDARD },
-{NULL, "ARGV", NULL, 0, NULL, NULL, FALSE, NO_INSTALL },
-{&BINMODE_node, "BINMODE", NULL, 0, NULL, set_BINMODE, FALSE, NON_STANDARD },
-{&CONVFMT_node, "CONVFMT", "%.6g", 0, NULL, set_CONVFMT,TRUE, 0 },
-{NULL, "ENVIRON", NULL, 0, NULL, NULL, FALSE, NO_INSTALL },
-{&ERRNO_node, "ERRNO", "", 0, NULL, NULL, FALSE, NON_STANDARD },
-{&FIELDWIDTHS_node, "FIELDWIDTHS", "", 0, NULL, set_FIELDWIDTHS, FALSE, NON_STANDARD },
-{&FILENAME_node, "FILENAME", "", 0, NULL, NULL, FALSE, 0 },
-{&FNR_node, "FNR", NULL, 0, update_FNR, set_FNR, TRUE, 0 },
-{&FS_node, "FS", " ", 0, NULL, set_FS, FALSE, 0 },
-{&FPAT_node, "FPAT", "[^[:space:]]+", 0, NULL, set_FPAT, FALSE, NON_STANDARD },
-{&IGNORECASE_node, "IGNORECASE", NULL, 0, NULL, set_IGNORECASE, FALSE, NON_STANDARD },
-{&LINT_node, "LINT", NULL, 0, NULL, set_LINT, FALSE, NON_STANDARD },
-{&NF_node, "NF", NULL, -1, update_NF, set_NF, FALSE, 0 },
-{&NR_node, "NR", NULL, 0, update_NR, set_NR, TRUE, 0 },
-{&OFMT_node, "OFMT", "%.6g", 0, NULL, set_OFMT, TRUE, 0 },
-{&OFS_node, "OFS", " ", 0, NULL, set_OFS, TRUE, 0 },
-{&ORS_node, "ORS", "\n", 0, NULL, set_ORS, TRUE, 0 },
-{NULL, "PROCINFO", NULL, 0, NULL, NULL, FALSE, NO_INSTALL | NON_STANDARD },
-{&RLENGTH_node, "RLENGTH", NULL, 0, NULL, NULL, FALSE, 0 },
-{&RS_node, "RS", "\n", 0, NULL, set_RS, TRUE, 0 },
-{&RSTART_node, "RSTART", NULL, 0, NULL, NULL, FALSE, 0 },
-{&RT_node, "RT", "", 0, NULL, NULL, FALSE, NON_STANDARD },
-{&SUBSEP_node, "SUBSEP", "\034", 0, NULL, set_SUBSEP, TRUE, 0 },
-{&TEXTDOMAIN_node, "TEXTDOMAIN", "messages", 0, NULL, set_TEXTDOMAIN, TRUE, NON_STANDARD },
-{0, NULL, NULL, 0, NULL, NULL, FALSE, 0 },
+{NULL, "ARGC", NULL, 0, NULL, NULL, false, NO_INSTALL },
+{&ARGIND_node, "ARGIND", NULL, 0, NULL, NULL, false, NON_STANDARD },
+{NULL, "ARGV", NULL, 0, NULL, NULL, false, NO_INSTALL },
+{&BINMODE_node, "BINMODE", NULL, 0, NULL, set_BINMODE, false, NON_STANDARD },
+{&CONVFMT_node, "CONVFMT", "%.6g", 0, NULL, set_CONVFMT,true, 0 },
+{NULL, "ENVIRON", NULL, 0, NULL, NULL, false, NO_INSTALL },
+{&ERRNO_node, "ERRNO", "", 0, NULL, NULL, false, NON_STANDARD },
+{&FIELDWIDTHS_node, "FIELDWIDTHS", "", 0, NULL, set_FIELDWIDTHS, false, NON_STANDARD },
+{&FILENAME_node, "FILENAME", "", 0, NULL, NULL, false, 0 },
+{&FNR_node, "FNR", NULL, 0, update_FNR, set_FNR, true, 0 },
+{&FS_node, "FS", " ", 0, NULL, set_FS, false, 0 },
+{&FPAT_node, "FPAT", "[^[:space:]]+", 0, NULL, set_FPAT, false, NON_STANDARD },
+{&IGNORECASE_node, "IGNORECASE", NULL, 0, NULL, set_IGNORECASE, false, NON_STANDARD },
+{&LINT_node, "LINT", NULL, 0, NULL, set_LINT, false, NON_STANDARD },
+{&PREC_node, "PREC", NULL, DEFAULT_PREC, NULL, set_PREC, false, NON_STANDARD},
+{&NF_node, "NF", NULL, -1, update_NF, set_NF, false, 0 },
+{&NR_node, "NR", NULL, 0, update_NR, set_NR, true, 0 },
+{&OFMT_node, "OFMT", "%.6g", 0, NULL, set_OFMT, true, 0 },
+{&OFS_node, "OFS", " ", 0, NULL, set_OFS, true, 0 },
+{&ORS_node, "ORS", "\n", 0, NULL, set_ORS, true, 0 },
+{NULL, "PROCINFO", NULL, 0, NULL, NULL, false, NO_INSTALL | NON_STANDARD | NOT_OFF_LIMITS },
+{&RLENGTH_node, "RLENGTH", NULL, 0, NULL, NULL, false, 0 },
+{&ROUNDMODE_node, "ROUNDMODE", DEFAULT_ROUNDMODE, 0, NULL, set_ROUNDMODE, false, NON_STANDARD },
+{&RS_node, "RS", "\n", 0, NULL, set_RS, true, 0 },
+{&RSTART_node, "RSTART", NULL, 0, NULL, NULL, false, 0 },
+{&RT_node, "RT", "", 0, NULL, NULL, false, NON_STANDARD },
+{&SUBSEP_node, "SUBSEP", "\034", 0, NULL, set_SUBSEP, true, 0 },
+{&TEXTDOMAIN_node, "TEXTDOMAIN", "messages", 0, NULL, set_TEXTDOMAIN, true, NON_STANDARD },
+{0, NULL, NULL, 0, NULL, NULL, false, 0 },
};
/* init_vars --- actually initialize everything in the symbol table */
@@ -955,13 +1008,13 @@ init_vars()
for (vp = varinit; vp->name != NULL; vp++) {
if ((vp->flags & NO_INSTALL) != 0)
continue;
- n = mk_symbol(Node_var, vp->strval == NULL
- ? make_number(vp->numval)
- : make_string(vp->strval, strlen(vp->strval)));
+ n = *(vp->spec) = install_symbol(estrdup(vp->name, strlen(vp->name)), Node_var);
+ if (vp->strval != NULL)
+ n->var_value = make_string(vp->strval, strlen(vp->strval));
+ else
+ n->var_value = make_number(vp->numval);
n->var_assign = (Func_ptr) vp->assign;
n->var_update = (Func_ptr) vp->update;
-
- *(vp->spec) = install_symbol(estrdup(vp->name, strlen(vp->name)), n);
if (vp->do_assign)
(*(vp->assign))();
}
@@ -972,6 +1025,31 @@ init_vars()
register_deferred_variable("ENVIRON", load_environ);
}
+/* path_environ --- put path variable into environment if not already there */
+
+static void
+path_environ(const char *pname, const char *dflt)
+{
+ const char *val;
+ NODE **aptr;
+ NODE *tmp;
+
+ tmp = make_string(pname, strlen(pname));
+ if (! in_array(ENVIRON_node, tmp)) {
+ /*
+ * On VMS, environ[] only holds a subset of what getenv() can
+ * find, so look AWKPATH up before resorting to default path.
+ */
+ val = getenv(pname);
+ if (val == NULL)
+ val = dflt;
+ aptr = assoc_lookup(ENVIRON_node, tmp);
+ unref(*aptr);
+ *aptr = make_string(val, strlen(val));
+ }
+ unref(tmp);
+}
+
/* load_environ --- populate the ENVIRON array */
static NODE *
@@ -984,10 +1062,14 @@ load_environ()
NODE **aptr;
int i;
NODE *tmp;
+ static bool been_here = false;
- ENVIRON_node = install_symbol(estrdup("ENVIRON", 7),
- mk_symbol(Node_var_array, (NODE *) NULL));
+ if (been_here)
+ return ENVIRON_node;
+ been_here = true;
+
+ ENVIRON_node = install_symbol(estrdup("ENVIRON", 7), Node_var_array);
for (i = 0; environ[i] != NULL; i++) {
static char nullstr[] = "";
@@ -998,7 +1080,7 @@ load_environ()
else
val = nullstr;
tmp = make_string(var, strlen(var));
- aptr = assoc_lookup(ENVIRON_node, tmp, FALSE);
+ aptr = assoc_lookup(ENVIRON_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(val, strlen(val));
@@ -1009,23 +1091,11 @@ load_environ()
*--val = '=';
}
/*
- * Put AWKPATH into ENVIRON if it's not there.
+ * Put AWKPATH and AWKLIBPATH into ENVIRON if not already there.
* This allows querying it from within awk programs.
*/
- tmp = make_string("AWKPATH", 7);
- if (! in_array(ENVIRON_node, tmp)) {
- /*
- * On VMS, environ[] only holds a subset of what getenv() can
- * find, so look AWKPATH up before resorting to default path.
- */
- val = getenv("AWKPATH");
- if (val == NULL)
- val = defpath;
- aptr = assoc_lookup(ENVIRON_node, tmp, FALSE);
- unref(*aptr);
- *aptr = make_string(val, strlen(val));
- }
- unref(tmp);
+ path_environ("AWKPATH", defpath);
+ path_environ("AWKLIBPATH", deflibpath);
return ENVIRON_node;
}
@@ -1036,16 +1106,32 @@ load_procinfo()
{
#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
int i;
+#endif
+#if (defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0) || defined(HAVE_MPFR)
char name[100];
#endif
AWKNUM value;
+ static bool been_here = false;
+
+ if (been_here)
+ return PROCINFO_node;
- PROCINFO_node = install_symbol(estrdup("PROCINFO", 8),
- mk_symbol(Node_var_array, (NODE *) NULL));
+ been_here = true;
+
+ PROCINFO_node = install_symbol(estrdup("PROCINFO", 8), Node_var_array);
update_PROCINFO_str("version", VERSION);
update_PROCINFO_str("strftime", def_strftime_format);
+#ifdef HAVE_MPFR
+ sprintf(name, "GNU MPFR %s", mpfr_get_version());
+ update_PROCINFO_str("mpfr_version", name);
+ sprintf(name, "GNU MP %s", gmp_version);
+ update_PROCINFO_str("gmp_version", name);
+ update_PROCINFO_num("prec_max", MPFR_PREC_MAX);
+ update_PROCINFO_num("prec_min", MPFR_PREC_MIN);
+#endif
+
#ifdef GETPGRP_VOID
#define getpgrp_arg() /* nothing */
#else
@@ -1120,15 +1206,32 @@ is_std_var(const char *var)
for (vp = varinit; vp->name != NULL; vp++) {
if (strcmp(vp->name, var) == 0) {
if ((do_traditional || do_posix) && (vp->flags & NON_STANDARD) != 0)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
+/*
+ * is_off_limits_var --- return true if a variable is off limits
+ * to extension functions
+ */
+
+int
+is_off_limits_var(const char *var)
+{
+ const struct varinit *vp;
+
+ for (vp = varinit; vp->name != NULL; vp++) {
+ if (strcmp(vp->name, var) == 0)
+ return ((vp->flags & NOT_OFF_LIMITS) == 0);
+ }
+
+ return false;
+}
/* get_spec_varname --- return the name of a special variable
with the given assign or update routine.
@@ -1152,23 +1255,23 @@ get_spec_varname(Func_ptr fptr)
/* arg_assign --- process a command-line assignment */
int
-arg_assign(char *arg, int initing)
+arg_assign(char *arg, bool initing)
{
char *cp, *cp2;
- int badvar;
+ bool badvar;
NODE *var;
NODE *it;
NODE **lhs;
long save_FNR;
if (! initing && disallow_var_assigns)
- return FALSE; /* --exec */
+ return false; /* --exec */
cp = strchr(arg, '=');
if (cp == NULL) {
if (! initing)
- return FALSE; /* This is file name, not assignment. */
+ return false; /* This is file name, not assignment. */
fprintf(stderr,
_("%s: `%s' argument to `-v' not in `var=value' form\n\n"),
@@ -1185,13 +1288,13 @@ arg_assign(char *arg, int initing)
FNR = 0;
/* first check that the variable name has valid syntax */
- badvar = FALSE;
+ badvar = false;
if (! isalpha((unsigned char) arg[0]) && arg[0] != '_')
- badvar = TRUE;
+ badvar = true;
else
for (cp2 = arg+1; *cp2; cp2++)
if (! isalnum((unsigned char) *cp2) && *cp2 != '_') {
- badvar = TRUE;
+ badvar = true;
break;
}
@@ -1237,12 +1340,12 @@ arg_assign(char *arg, int initing)
cp2 = estrdup(arg, cp - arg); /* var name */
- var = variable(cp2, Node_var);
+ var = variable(0, cp2, Node_var);
if (var == NULL) /* error */
- exit(EXIT_FATAL);
+ final_exit(EXIT_FATAL);
if (var->type == Node_var && var->var_update)
var->var_update();
- lhs = get_lhs(var, FALSE);
+ lhs = get_lhs(var, false);
unref(*lhs);
*lhs = it;
/* check for set_FOO() routine */
@@ -1322,7 +1425,13 @@ nostalgia()
static void
version()
{
- printf("%s\n", version_string);
+ printf("%s", version_string);
+#ifdef HAVE_MPFR
+ printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
+#endif
+ printf("\n");
+ print_ext_versions();
+
/*
* Per GNU coding standards, print copyright info,
* then exit successfully, do nothing else.
@@ -1464,3 +1573,18 @@ update_global_values()
vp->update();
}
}
+
+/* getenv_long --- read a long value (>= 0) from an environment var. */
+
+long
+getenv_long(const char *name)
+{
+ const char *val;
+ long newval;
+ if ((val = getenv(name)) != NULL && isdigit((unsigned char) *val)) {
+ for (newval = 0; *val && isdigit((unsigned char) *val); val++)
+ newval = (newval * 10) + *val - '0';
+ return newval;
+ }
+ return -1;
+}