diff options
Diffstat (limited to 'contrib/awk/main.c')
-rw-r--r-- | contrib/awk/main.c | 1006 |
1 files changed, 0 insertions, 1006 deletions
diff --git a/contrib/awk/main.c b/contrib/awk/main.c deleted file mode 100644 index 1b9b415..0000000 --- a/contrib/awk/main.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * main.c -- Expression tree constructors and main program for gawk. - */ - -/* - * Copyright (C) 1986, 1988, 1989, 1991-2001 the Free Software Foundation, Inc. - * - * This file is part of GAWK, the GNU implementation of the - * AWK Programming Language. - * - * GAWK is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GAWK is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $FreeBSD$ - */ - -#include "awk.h" -#include "getopt.h" -#ifdef TANDEM -#include "ptchlvl.h" /* blech */ -#else -#include "patchlev.h" -#endif - -#ifndef O_BINARY -#include <fcntl.h> -#endif - -#ifdef HAVE_MCHECK_H -#include <mcheck.h> -#endif - -#define DEFAULT_PROFILE "awkprof.out" /* where to put profile */ -#define DEFAULT_VARFILE "awkvars.out" /* where to put vars */ - -static char *varfile = DEFAULT_VARFILE; - -static void usage P((int exitval, FILE *fp)); -static void copyleft P((void)); -static void cmdline_fs P((char *str)); -static void init_args P((int argc0, int argc, char *argv0, char **argv)); -static void init_vars P((void)); -static void pre_assign P((char *v)); -RETSIGTYPE catchsig P((int sig, int code)); -static void nostalgia P((void)); -static void version P((void)); -static void init_fds P((void)); - -/* 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, *FNR_node; -NODE *FS_node, *IGNORECASE_node, *NF_node, *NR_node, *OFMT_node, *OFS_node; -NODE *ORS_node, *PROCINFO_node, *RLENGTH_node, *RSTART_node, *RS_node; -NODE *RT_node, *SUBSEP_node, *LINT_node, *TEXTDOMAIN_node; - -long NF; -long NR; -long FNR; -int BINMODE; -int IGNORECASE; -char *OFS; -char *ORS; -char *OFMT; -char *TEXTDOMAIN; -int MRL; /* See -mr option for use of this variable */ - -/* - * 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 - * Fun, fun, fun, fun. - */ -char *CONVFMT = "%.6g"; - - -int errcount = 0; /* error counter, used by yyerror() */ - -NODE *Nnull_string; /* The global null string */ - -/* The name the program was invoked under, for error messages */ -const char *myname; - -/* A block of AWK code to be run before running the program */ -NODE *begin_block = NULL; - -/* A block of AWK code to be run after the last input file */ -NODE *end_block = NULL; - -int exiting = FALSE; /* Was an "exit" statement executed? */ -int exit_val = 0; /* optional exit value */ - -#if defined(YYDEBUG) || defined(GAWKDEBUG) -extern int yydebug; -#endif - -struct src *srcfiles = NULL; /* source file name(s) */ -long numfiles = -1; /* how many source files */ - -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 */ -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 in_begin_rule = FALSE; /* we're in a BEGIN rule */ -int in_end_rule = FALSE; /* we're in a END rule */ - -int output_is_tty = FALSE; /* control flushing of output */ - -extern char *version_string; /* current version, for printing */ - -/* The parse tree is stored here. */ -NODE *expression_value; - -#if _MSC_VER == 510 -void (*lintfunc) P((va_list va_alist, ...)) = warning; -#else -void (*lintfunc) P((char *mesg, ...)) = warning; -#endif - -static struct option optab[] = { - { "compat", no_argument, & do_traditional, 1 }, - { "traditional", no_argument, & do_traditional, 1 }, - { "lint", optional_argument, NULL, 'l' }, - { "lint-old", no_argument, & do_lint_old, 1 }, - { "posix", no_argument, & do_posix, 1 }, - { "nostalgia", no_argument, & do_nostalgia, 1 }, - { "gen-po", no_argument, & do_intl, 1 }, - { "non-decimal-data", no_argument, & do_non_decimal_data, 1 }, - { "profile", optional_argument, NULL, 'p' }, - { "copyleft", no_argument, NULL, 'C' }, - { "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, 's' }, - { "dump-variables", optional_argument, NULL, 'd' }, - { "assign", required_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { "usage", no_argument, NULL, 'u' }, - { "help", no_argument, NULL, 'u' }, -#ifdef GAWKDEBUG - { "parsedebug", no_argument, NULL, 'D' }, -#endif - { NULL, 0, NULL, '\0' } -}; - -/* main --- process args, parse program, run it, clean up */ - -int -main(int argc, char **argv) -{ - int c; - char *scan; - /* the + on the front tells GNU getopt not to rearrange argv */ - const char *optlist = "+F:f:v:W;m:"; - int stopped_early = FALSE; - int old_optind; - extern int optind; - extern int opterr; - extern char *optarg; - - /* do these checks early */ - if (getenv("TIDYMEM") != NULL) - do_tidy_mem = TRUE; - -#ifdef HAVE_MCHECK_H - if (do_tidy_mem) - mtrace(); -#endif /* HAVE_MCHECK_H */ - - - setlocale(LC_CTYPE, ""); - setlocale(LC_COLLATE, ""); - /* setlocale (LC_ALL, ""); */ - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - - (void) signal(SIGFPE, (RETSIGTYPE (*) P((int))) catchsig); - (void) signal(SIGSEGV, (RETSIGTYPE (*) P((int))) catchsig); -#ifdef SIGBUS - (void) signal(SIGBUS, (RETSIGTYPE (*) P((int))) catchsig); -#endif - - myname = gawk_name(argv[0]); - argv[0] = (char *) myname; - os_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */ - - /* remove sccs gunk */ - if (strncmp(version_string, "@(#)", 4) == 0) - version_string += 4; - - if (argc < 2) - usage(1, stderr); - - /* initialize the null string */ - Nnull_string = make_string("", 0); - Nnull_string->numbr = 0.0; - Nnull_string->type = Node_val; - Nnull_string->flags = (PERM|STR|STRING|NUM|NUMBER); - - /* - * Tell the regex routines how they should work. - * Do this before initializing variables, since - * they could want to do a regexp compile. - */ - resetup(); - - /* Set up the special variables */ - /* - * Note that this must be done BEFORE arg parsing else -F - * breaks horribly. - */ - init_vars(); - - /* Set up the field variables */ - /* - * Do this before arg parsing so that `-v NF=blah' won't - * break anything. - */ - init_fields(); - - /* Robustness: check that 0, 1, 2, exist */ - init_fds(); - - /* worst case */ - emalloc(srcfiles, struct src *, argc * sizeof(struct src), "main"); - memset(srcfiles, '\0', argc * sizeof(struct src)); - - /* we do error messages ourselves on invalid options */ - opterr = FALSE; - - /* option processing. ready, set, go! */ - for (optopt = 0, old_optind = 1; - (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF; - optopt = 0, old_optind = optind) { - if (do_posix) - opterr = TRUE; - - switch (c) { - case 'F': - cmdline_fs(optarg); - break; - - case 'f': - /* - * a la MKS awk, allow multiple -f options. - * this makes function libraries real easy. - * most of the magic is in the scanner. - * - * The following is to allow for whitespace at the end - * of a #! /bin/gawk line in an executable file - */ - scan = optarg; - while (ISSPACE(*scan)) - scan++; - - ++numfiles; - srcfiles[numfiles].stype = SOURCEFILE; - if (*scan == '\0') - srcfiles[numfiles].val = argv[optind++]; - else - srcfiles[numfiles].val = optarg; - break; - - case 'v': - pre_assign(optarg); - break; - - case 'm': - /* - * Research awk extension. - * -mf nnn set # fields, gawk ignores - * -mr nnn set record length, ditto - */ - if (do_lint) - lintwarn(_("`-m[fr]' option irrelevant in gawk")); - if (optarg[0] != 'r' && optarg[0] != 'f') - warning(_("-m option usage: `-m[fr] nnn'")); - /* - * Set fixed length records for Tandem, - * ignored on other platforms (see io.c:get_a_record). - */ - if (optarg[0] == 'r') { - if (ISDIGIT(optarg[1])) - MRL = atoi(optarg+1); - else { - MRL = atoi(argv[optind]); - optind++; - } - } else if (optarg[1] == '\0') - optind++; - break; - - case 'W': /* gawk specific options - now in getopt_long */ - fprintf(stderr, _("%s: option `-W %s' unrecognized, ignored\n"), - argv[0], optarg); - break; - - /* These can only come from long form options */ - case 'C': - copyleft(); - break; - - case 'd': - do_dump_vars = TRUE; - if (optarg != NULL && optarg[0] != '\0') - varfile = optarg; - break; - - case 'l': - do_lint = TRUE; - if (optarg != NULL && strcmp(optarg, "fatal") == 0) - lintfunc = r_fatal; - break; - - case 'p': - do_profiling = TRUE; - if (optarg != NULL) - set_prof_file(optarg); - else - set_prof_file(DEFAULT_PROFILE); - break; - - case 's': - if (optarg[0] == '\0') - warning(_("empty argument to `--source' ignored")); - else { - srcfiles[++numfiles].stype = CMDLINE; - srcfiles[numfiles].val = optarg; - } - break; - - case 'u': - usage(0, stdout); /* per coding stds */ - break; - - case 'V': - version(); - break; - -#ifdef GAWKDEBUG - case 'D': - yydebug = 2; - break; -#endif - - case 0: - /* - * getopt_long found an option that sets a variable - * instead of returning a letter. Do nothing, just - * cycle around for the next one. - */ - break; - - case '?': - default: - /* - * New behavior. If not posix, an unrecognized - * option stops argument processing so that it can - * go into ARGV for the awk program to see. This - * makes use of ``#! /bin/gawk -f'' easier. - * - * However, it's never simple. If optopt is set, - * an option that requires an argument didn't get the - * argument. We care because if opterr is 0, then - * getopt_long won't print the error message for us. - */ - if (! do_posix - && (optopt == '\0' || strchr(optlist, optopt) == NULL)) { - /* - * can't just do optind--. In case of an - * option with >= 2 letters, getopt_long - * won't have incremented optind. - */ - optind = old_optind; - stopped_early = TRUE; - goto out; - } else if (optopt != '\0') - /* Use 1003.2 required message format */ - fprintf(stderr, - _("%s: option requires an argument -- %c\n"), - myname, optopt); - /* else - let getopt print error message for us */ - break; - } - } -out: - - if (do_nostalgia) - nostalgia(); - - /* check for POSIXLY_CORRECT environment variable */ - if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) { - do_posix = TRUE; - if (do_lint) - lintwarn( - _("environment variable `POSIXLY_CORRECT' set: turning on `--posix'")); - } - - if (do_posix) { - if (do_traditional) /* both on command line */ - warning(_("`--posix' overrides `--traditional'")); - else - do_traditional = TRUE; - /* - * POSIX compliance also implies - * no GNU extensions either. - */ - } - - if (do_traditional && do_non_decimal_data) { - do_non_decimal_data = FALSE; - warning(_("`--posix'/`--traditional' overrides `--non-decimal-data'")); - } - - if (do_lint && os_is_setuid()) - warning(_("runing %s setuid root may be a security problem"), myname); - - /* - * Tell the regex routines how they should work. - * Do this again, after argument processing, since do_posix - * and do_traditional are now paid attention to by resetup(). - */ - if (do_traditional || do_posix || do_intervals) { - resetup(); - - /* now handle RS and FS. have to be careful with FS */ - set_RS(); - if (using_fieldwidths()) { - set_FS(); - set_FIELDWIDTHS(); - } else - set_FS(); - } - - /* - * Initialize profiling info, do after parsing args, - * in case this is pgawk. Don't bother if the command - * line already set profling up. - */ - if (! do_profiling) - init_profiling(& do_profiling, DEFAULT_PROFILE); - - if ((BINMODE & 1) != 0) - if (os_setbinmode(fileno(stdin), O_BINARY) == -1) - fatal(_("can't set mode on stdin (%s)"), strerror(errno)); - if ((BINMODE & 2) != 0) { - if (os_setbinmode(fileno(stdout), O_BINARY) == -1) - fatal(_("can't set mode on stdout (%s)"), strerror(errno)); - if (os_setbinmode(fileno(stderr), O_BINARY) == -1) - fatal(_("can't set mode on stderr (%s)"), strerror(errno)); - } - -#ifdef GAWKDEBUG - setbuf(stdout, (char *) NULL); /* make debugging easier */ -#endif - if (isatty(fileno(stdout))) - output_is_tty = TRUE; - /* No -f or --source options, use next arg */ - if (numfiles == -1) { - if (optind > argc - 1 || stopped_early) /* no args left or no program */ - usage(1, stderr); - srcfiles[++numfiles].stype = CMDLINE; - srcfiles[numfiles].val = argv[optind]; - optind++; - } - - init_args(optind, argc, (char *) myname, argv); - (void) tokexpand(); - - /* Read in the program */ - if (yyparse() != 0 || errcount != 0) - exit(1); - - if (do_intl) - exit(0); - - if (do_lint && begin_block == NULL && expression_value == NULL - && end_block == NULL) - lintwarn(_("no program text at all!")); - - if (do_lint) - shadow_funcs(); - - init_profiling_signals(); - - if (begin_block != NULL) { - in_begin_rule = TRUE; - (void) interpret(begin_block); - } - in_begin_rule = FALSE; - if (! exiting && (expression_value != NULL || end_block != NULL)) - do_input(); - if (end_block != NULL) { - in_end_rule = TRUE; - (void) interpret(end_block); - } - in_end_rule = FALSE; - if (close_io() != 0 && exit_val == 0) - exit_val = 1; - - if (do_profiling) { - dump_prog(begin_block, expression_value, end_block); - dump_funcs(); - } - - if (do_dump_vars) - dump_vars(varfile); - - if (do_tidy_mem) - release_all_vars(); - - exit(exit_val); /* more portable */ - return exit_val; /* to suppress warnings */ -} - -/* usage --- print usage information and exit */ - -static void -usage(int exitval, FILE *fp) -{ - /* Not factoring out common stuff makes it easier to translate. */ - - 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); - - /* GNU long options info. This is too many options. */ - - fputs(_("POSIX options:\t\tGNU long options:\n"), fp); - fputs(_("\t-f progfile\t\t--file=progfile\n"), fp); - fputs(_("\t-F fs\t\t\t--field-separator=fs\n"), fp); - fputs(_("\t-v var=val\t\t--assign=var=val\n"), fp); - fputs(_("\t-m[fr] val\n"), fp); - fputs(_("\t-W compat\t\t--compat\n"), fp); - fputs(_("\t-W copyleft\t\t--copyleft\n"), fp); - fputs(_("\t-W copyright\t\t--copyright\n"), fp); - fputs(_("\t-W dump-variables[=file]\t--dump-variables[=file]\n"), fp); - fputs(_("\t-W gen-po\t\t--gen-po\n"), fp); - fputs(_("\t-W help\t\t\t--help\n"), fp); - fputs(_("\t-W lint[=fatal]\t\t--lint[=fatal]\n"), fp); - fputs(_("\t-W lint-old\t\t--lint-old\n"), fp); - fputs(_("\t-W non-decimal-data\t--non-decimal-data\n"), fp); -#ifdef NOSTALGIA - fputs(_("\t-W nostalgia\t\t--nostalgia\n"), fp); -#endif -#ifdef GAWKDEBUG - fputs(_("\t-W parsedebug\t\t--parsedebug\n"), fp); -#endif - fputs(_("\t-W profile[=file]\t--profile[=file]\n"), fp); - fputs(_("\t-W posix\t\t--posix\n"), fp); - fputs(_("\t-W re-interval\t\t--re-interval\n"), fp); - fputs(_("\t-W source=program-text\t--source=program-text\n"), fp); - fputs(_("\t-W traditional\t\t--traditional\n"), fp); - fputs(_("\t-W usage\t\t--usage\n"), fp); - fputs(_("\t-W version\t\t--version\n"), fp); - fputs(_("\nTo report bugs, see node `Bugs' in `gawk.info', which is\n"), fp); - fputs(_("section `Reporting Problems and Bugs' in the printed version.\n"), fp); - exit(exitval); -} - -/* copyleft --- print out the short GNU copyright information */ - -static void -copyleft() -{ - static char blurb_part1[] = - N_("Copyright (C) 1989, 1991-2001 Free Software Foundation.\n\ -\n\ -This program is free software; you can redistribute it and/or modify\n\ -it under the terms of the GNU General Public License as published by\n\ -the Free Software Foundation; either version 2 of the License, or\n\ -(at your option) any later version.\n\ -\n"); - static char blurb_part2[] = - N_("This program is distributed in the hope that it will be useful,\n\ -but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ -GNU General Public License for more details.\n\ -\n"); - static char blurb_part3[] = - N_("You should have received a copy of the GNU General Public License\n\ -along with this program; if not, write to the Free Software\n\ -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"); - - /* multiple blurbs are needed for some brain dead compilers. */ - fputs(_(blurb_part1), stdout); - fputs(_(blurb_part2), stdout); - fputs(_(blurb_part3), stdout); - fflush(stdout); - exit(0); -} - -/* cmdline_fs --- set FS from the command line */ - -static void -cmdline_fs(char *str) -{ - register NODE **tmp; - - tmp = get_lhs(FS_node, (Func_ptr *) 0, FALSE); - unref(*tmp); - /* - * Only if in full compatibility mode check for the stupid special - * case so -F\t works as documented in awk book even though the shell - * hands us -Ft. Bleah! - * - * Thankfully, Posix didn't propogate this "feature". - */ - if (str[0] == 't' && str[1] == '\0') { - if (do_lint) - lintwarn(_("-Ft does not set FS to tab in POSIX awk")); - if (do_traditional && ! do_posix) - str[0] = '\t'; - } - *tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */ - set_FS(); -} - -/* init_args --- set up ARGV from stuff on the command line */ - -static void -init_args(int argc0, int argc, char *argv0, char **argv) -{ - int i, j; - NODE **aptr; - - ARGV_node = install("ARGV", node(Nnull_string, Node_var_array, (NODE *) NULL)); - aptr = assoc_lookup(ARGV_node, tmp_number(0.0), FALSE); - *aptr = make_string(argv0, strlen(argv0)); - (*aptr)->flags |= MAYBE_NUM; - for (i = argc0, j = 1; i < argc; i++) { - aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j), FALSE); - *aptr = make_string(argv[i], strlen(argv[i])); - (*aptr)->flags |= MAYBE_NUM; - (*aptr)->flags &= ~UNINITIALIZED; - j++; - } - ARGC_node = install("ARGC", - node(make_number((AWKNUM) j), Node_var, (NODE *) NULL)); - ARGC_node->flags &= ~UNINITIALIZED; -} - -/* - * Set all the special variables to their initial values. - * Note that some of the variables that have set_FOO routines should - * *N*O*T* have those routines called upon initialization, and thus - * they have NULL entries in that field. This is notably true of FS - * and IGNORECASE. - */ -struct varinit { - NODE **spec; - const char *name; - NODETYPE type; - const char *strval; - AWKNUM numval; - Func_ptr assign; -}; -static struct varinit varinit[] = { -{&CONVFMT_node, "CONVFMT", Node_CONVFMT, "%.6g", 0, set_CONVFMT }, -{&NF_node, "NF", Node_NF, NULL, -1, set_NF }, -{&FIELDWIDTHS_node, "FIELDWIDTHS", Node_FIELDWIDTHS, "", 0, NULL }, -{&NR_node, "NR", Node_NR, NULL, 0, set_NR }, -{&FNR_node, "FNR", Node_FNR, NULL, 0, set_FNR }, -{&FS_node, "FS", Node_FS, " ", 0, NULL }, -{&RS_node, "RS", Node_RS, "\n", 0, set_RS }, -{&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE, NULL, 0, NULL }, -{&FILENAME_node, "FILENAME", Node_var, "", 0, NULL }, -{&OFS_node, "OFS", Node_OFS, " ", 0, set_OFS }, -{&ORS_node, "ORS", Node_ORS, "\n", 0, set_ORS }, -{&OFMT_node, "OFMT", Node_OFMT, "%.6g", 0, set_OFMT }, -{&RLENGTH_node, "RLENGTH", Node_var, NULL, 0, NULL }, -{&RSTART_node, "RSTART", Node_var, NULL, 0, NULL }, -{&SUBSEP_node, "SUBSEP", Node_var, "\034", 0, NULL }, -{&ARGIND_node, "ARGIND", Node_var, NULL, 0, NULL }, -{&ERRNO_node, "ERRNO", Node_var, NULL, 0, NULL }, -{&RT_node, "RT", Node_var, "", 0, NULL }, -{&BINMODE_node, "BINMODE", Node_BINMODE, NULL, 0, NULL }, -{&LINT_node, "LINT", Node_LINT, NULL, 0, NULL }, -{&TEXTDOMAIN_node, "TEXTDOMAIN", Node_TEXTDOMAIN, "messages", 0, set_TEXTDOMAIN }, -{0, NULL, Node_illegal, NULL, 0, NULL }, -}; - -/* init_vars --- actually initialize everything in the symbol table */ - -static void -init_vars() -{ - register struct varinit *vp; - - for (vp = varinit; vp->name; vp++) { - *(vp->spec) = install((char *) vp->name, - node(vp->strval == NULL ? make_number(vp->numval) - : make_string((char *) vp->strval, - strlen(vp->strval)), - vp->type, (NODE *) NULL)); - (*(vp->spec))->flags |= SCALAR; - (*(vp->spec))->flags &= ~UNINITIALIZED; - if (vp->assign) - (*(vp->assign))(); - } -} - -/* load_environ --- populate the ENVIRON array */ - -void -load_environ() -{ -#if ! defined(TANDEM) -#if ! (defined(MSDOS) && !defined(DJGPP)) && ! defined(OS2) && ! (defined(VMS) && defined(__DECC)) - extern char **environ; -#endif - register char *var, *val; - NODE **aptr; - register int i; - - ENVIRON_node = install("ENVIRON", - node(Nnull_string, Node_var, (NODE *) NULL)); - for (i = 0; environ[i] != NULL; i++) { - static char nullstr[] = ""; - - var = environ[i]; - val = strchr(var, '='); - if (val != NULL) - *val++ = '\0'; - else - val = nullstr; - aptr = assoc_lookup(ENVIRON_node,tmp_string(var, strlen(var)), - FALSE); - *aptr = make_string(val, strlen(val)); - (*aptr)->flags |= (MAYBE_NUM|SCALAR); - - /* restore '=' so that system() gets a valid environment */ - if (val != nullstr) - *--val = '='; - } - /* - * Put AWKPATH into ENVIRON if it's not there. - * This allows querying it from within awk programs. - */ - if (getenv("AWKPATH") == NULL) { - aptr = assoc_lookup(ENVIRON_node, tmp_string("AWKPATH", 7), FALSE); - *aptr = make_string(defpath, strlen(defpath)); - (*aptr)->flags |= SCALAR; - } -#endif /* TANDEM */ -} - -/* load_procinfo --- populate the PROCINFO array */ - -void -load_procinfo() -{ - int i; - NODE **aptr; - char name[100]; - AWKNUM value; -#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 - GETGROUPS_T groupset[NGROUPS_MAX]; - int ngroups; -#endif - - PROCINFO_node = install("PROCINFO", - node(Nnull_string, Node_var, (NODE *) NULL)); - -#ifdef GETPGRP_VOID -#define getpgrp_arg() /* nothing */ -#else -#define getpgrp_arg() getpid() -#endif - - value = getpgrp(getpgrp_arg()); - aptr = assoc_lookup(PROCINFO_node, tmp_string("pgrpid", 6), FALSE); - *aptr = make_number(value); - - /* - * could put a lot of this into a table, but then there's - * portability problems declaring all the functions. so just - * do it the slow and stupid way. sigh. - */ - - value = getpid(); - aptr = assoc_lookup(PROCINFO_node, tmp_string("pid", 3), FALSE); - *aptr = make_number(value); - - value = getppid(); - aptr = assoc_lookup(PROCINFO_node, tmp_string("ppid", 4), FALSE); - *aptr = make_number(value); - - value = getuid(); - aptr = assoc_lookup(PROCINFO_node, tmp_string("uid", 3), FALSE); - *aptr = make_number(value); - - value = geteuid(); - aptr = assoc_lookup(PROCINFO_node, tmp_string("euid", 4), FALSE); - *aptr = make_number(value); - - value = getgid(); - aptr = assoc_lookup(PROCINFO_node, tmp_string("gid", 3), FALSE); - *aptr = make_number(value); - - value = getegid(); - aptr = assoc_lookup(PROCINFO_node, tmp_string("egid", 4), FALSE); - *aptr = make_number(value); - - aptr = assoc_lookup(PROCINFO_node, tmp_string("FS", 2), FALSE); - *aptr = make_string("FS", 2); - -#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 - ngroups = getgroups(NGROUPS_MAX, groupset); - if (ngroups == -1) - fatal(_("could not find groups: %s"), strerror(errno)); - - for (i = 0; i < ngroups; i++) { - sprintf(name, "group%d", i + 1); - value = groupset[i]; - aptr = assoc_lookup(PROCINFO_node, tmp_string(name, strlen(name)), FALSE); - *aptr = make_number(value); - } -#endif -} - -/* arg_assign --- process a command-line assignment */ - -char * -arg_assign(char *arg) -{ - char *cp, *cp2; - int badvar; - Func_ptr after_assign = NULL; - NODE *var; - NODE *it; - NODE **lhs; - - cp = strchr(arg, '='); - if (cp != NULL) { - *cp++ = '\0'; - /* first check that the variable name has valid syntax */ - badvar = FALSE; - if (! ISALPHA(arg[0]) && arg[0] != '_') - badvar = TRUE; - else - for (cp2 = arg+1; *cp2; cp2++) - if (! ISALNUM(*cp2) && *cp2 != '_') { - badvar = TRUE; - break; - } - - if (badvar) { - if (do_lint) - lintwarn(_("invalid syntax in name `%s' for variable assignment"), arg); - *--cp = '='; /* restore original text of ARGV */ - return NULL; - } - - /* - * Recent versions of nawk expand escapes inside assignments. - * This makes sense, so we do it too. - */ - it = make_str_node(cp, strlen(cp), SCAN); - it->flags |= (MAYBE_NUM|SCALAR); - var = variable(arg, FALSE, Node_var); - lhs = get_lhs(var, &after_assign, FALSE); - unref(*lhs); - *lhs = it; - if (after_assign != NULL) - (*after_assign)(); - *--cp = '='; /* restore original text of ARGV */ - } - return cp; -} - -/* pre_assign --- handle -v, print a message and die if a problem */ - -static void -pre_assign(char *v) -{ - char *cp; - /* - * There is a problem when doing profiling. For -v x=y, - * the variable x gets installed into the symbol table pointing - * at the value in argv. This is what gets dumped. The string - * ends up containing the full x=y, leading to stuff in the profile - * of the form: - * - * if (x=y) ... - * - * Needless to say, this is gross, ugly and wrong. To fix, we - * malloc a private copy of the storage that we can tweak to - * our heart's content. - * - * This can't depend upon do_profiling; that variable isn't set up yet. - * Sigh. - */ - - emalloc(cp, char *, strlen(v) + 1, "pre_assign"); - strcpy(cp, v); - - if (arg_assign(cp) == NULL) { - fprintf(stderr, - "%s: `%s' argument to `-v' not in `var=value' form\n", - myname, v); - usage(1, stderr); - } - - cp = strchr(cp, '='); - assert(cp); - *cp = '\0'; -} - -/* catchsig --- catch signals */ - -RETSIGTYPE -catchsig(int sig, int code) -{ -#ifdef lint - code = 0; sig = code; code = sig; -#endif - if (sig == SIGFPE) { - fatal(_("floating point exception")); - } else if (sig == SIGSEGV -#ifdef SIGBUS - || sig == SIGBUS -#endif - ) { - set_loc(__FILE__, __LINE__); - msg(_("fatal error: internal error")); - /* fatal won't abort() if not compiled for debugging */ - abort(); - } else - cant_happen(); - /* NOTREACHED */ -} - -/* nostalgia --- print the famous error message and die */ - -static void -nostalgia() -{ - /* - * N.B.: This string is not gettextized, on purpose. - * So there. - */ - fprintf(stderr, "awk: bailing out near line 1\n"); - fflush(stderr); - abort(); -} - -/* version --- print version message */ - -static void -version() -{ - printf("%s.%d\n", version_string, PATCHLEVEL); - /* - * Per GNU coding standards, print copyright info, - * then exit successfully, do nothing else. - */ - copyleft(); - exit(0); -} - -/* init_fds --- check for 0, 1, 2, open on /dev/null if possible */ - -static void -init_fds() -{ - struct stat sbuf; - int fd; - int newfd; - - /* maybe no stderr, don't bother with error mesg */ - for (fd = 0; fd <= 2; fd++) { - if (fstat(fd, &sbuf) < 0) { -#if MAKE_A_HEROIC_EFFORT - if (do_lint) - lintwarn(_("no pre-opened fd %d"), fd); -#endif - newfd = devopen("/dev/null", "r+"); -#ifdef MAKE_A_HEROIC_EFFORT - if (do_lint && newfd < 0) - lintwarn(_("could not pre-open /dev/null for fd %d"), fd); -#endif - } - } -} |