aboutsummaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2010-07-15 23:12:49 +0300
committerArnold D. Robbins <arnold@skeeve.com>2010-07-15 23:12:49 +0300
commit3697ec5ca140f686643d204a54181a5ddbf9a799 (patch)
tree592873e8614475012ddd5f4e6d0482acadbfc9e2 /main.c
parentf3d9dd233ac07f764a554528c85be3768a1d1ddb (diff)
downloadegawk-3697ec5ca140f686643d204a54181a5ddbf9a799.tar.gz
egawk-3697ec5ca140f686643d204a54181a5ddbf9a799.tar.bz2
egawk-3697ec5ca140f686643d204a54181a5ddbf9a799.zip
Moved to gawk 2.11.
Diffstat (limited to 'main.c')
-rw-r--r--main.c548
1 files changed, 548 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 00000000..dbafe917
--- /dev/null
+++ b/main.c
@@ -0,0 +1,548 @@
+/*
+ * main.c -- Expression tree constructors and main program for gawk.
+ */
+
+/*
+ * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Progamming 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 1, 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 GAWK; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "awk.h"
+#include "patchlevel.h"
+#include <signal.h>
+
+extern int yyparse();
+extern void do_input();
+extern int close_io();
+extern void init_fields();
+extern int getopt();
+extern int re_set_syntax();
+extern NODE *node();
+
+static void usage();
+static void set_fs();
+static void init_vars();
+static void init_args();
+static NODE *spc_var();
+static void pre_assign();
+static void copyleft();
+
+/* These nodes store all the special variables AWK uses */
+NODE *FS_node, *NF_node, *RS_node, *NR_node;
+NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
+NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
+NODE *ENVIRON_node, *IGNORECASE_node;
+NODE *ARGC_node, *ARGV_node;
+
+/*
+ * The parse tree and field nodes are stored here. Parse_end is a dummy item
+ * used to free up unneeded fields without freeing the program being run
+ */
+int errcount = 0; /* error counter, used by yyerror() */
+
+/* The global null string */
+NODE *Nnull_string;
+
+/* The name the program was invoked under, for error messages */
+char *myname;
+
+/* A block of AWK code to be run before running the program */
+NODE *begin_block = 0;
+
+/* A block of AWK code to be run after the last input file */
+NODE *end_block = 0;
+
+int exiting = 0; /* Was an "exit" statement executed? */
+int exit_val = 0; /* optional exit value */
+
+#ifdef DEBUG
+/* non-zero means in debugging is enabled. Probably not very useful */
+int debugging = 0;
+extern int yydebug;
+#endif
+
+int tempsource = 0; /* source is in a temp file */
+char **sourcefile = NULL; /* source file name(s) */
+int numfiles = -1; /* how many source files */
+
+int strict = 0; /* turn off gnu extensions */
+
+int output_is_tty = 0; /* control flushing of output */
+
+NODE *expression_value;
+
+/*
+ * for strict to work, legal options must be first
+ *
+ * Unfortunately, -a and -e are orthogonal to -c.
+ */
+#define EXTENSIONS 8 /* where to clear */
+#ifdef DEBUG
+char awk_opts[] = "F:f:v:caeCVdD";
+#else
+char awk_opts[] = "F:f:v:caeCV";
+#endif
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+#ifdef DEBUG
+ /* Print out the parse tree. For debugging */
+ register int dotree = 0;
+#endif
+ extern char *version_string;
+ FILE *fp;
+ int c;
+ extern int opterr, optind;
+ extern char *optarg;
+ extern char *strrchr();
+ extern char *tmpnam();
+ extern int catchsig();
+ int i;
+ int nostalgia;
+#ifdef somtime_in_the_future
+ int regex_mode = RE_SYNTAX_POSIX_EGREP;
+#else
+ int regex_mode = RE_SYNTAX_AWK;
+#endif
+
+ (void) signal(SIGFPE, catchsig);
+ (void) signal(SIGSEGV, catchsig);
+
+ myname = strrchr(argv[0], '/');
+ if (myname == NULL)
+ myname = argv[0];
+ else
+ myname++;
+ if (argc < 2)
+ usage();
+
+ /* initialize the null string */
+ Nnull_string = make_string("", 0);
+ Nnull_string->numbr = 0.0;
+ Nnull_string->type = Node_val;
+ Nnull_string->flags = (PERM|STR|NUM|NUMERIC);
+
+ /* Set up the special variables */
+
+ /*
+ * Note that this must be done BEFORE arg parsing else -F
+ * breaks horribly
+ */
+ init_vars();
+
+ /* worst case */
+ emalloc(sourcefile, char **, argc * sizeof(char *), "main");
+
+
+#ifdef STRICT /* strict new awk compatibility */
+ strict = 1;
+ awk_opts[EXTENSIONS] = '\0';
+#endif
+
+#ifndef STRICT
+ /* undocumented feature, inspired by nostalgia, and a T-shirt */
+ nostalgia = 0;
+ for (i = 1; i < argc && argv[i][0] == '-'; i++) {
+ if (argv[i][1] == '-') /* -- */
+ break;
+ else if (argv[i][1] == 'c') { /* compatibility mode */
+ nostalgia = 0;
+ break;
+ } else if (STREQ(&argv[i][1], "nostalgia"))
+ nostalgia = 1;
+ /* keep looping, in case -c after -nostalgia */
+ }
+ if (nostalgia) {
+ fprintf (stderr, "awk: bailing out near line 1\n");
+ abort();
+ }
+#endif
+
+ while ((c = getopt (argc, argv, awk_opts)) != EOF) {
+ switch (c) {
+#ifdef DEBUG
+ case 'd':
+ debugging++;
+ dotree++;
+ break;
+
+ case 'D':
+ debugging++;
+ yydebug = 2;
+ break;
+#endif
+
+#ifndef STRICT
+ case 'c':
+ strict = 1;
+ break;
+#endif
+
+ case 'F':
+ set_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.
+ */
+ sourcefile[++numfiles] = optarg;
+ break;
+
+ case 'v':
+ pre_assign(optarg);
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s, patchlevel %d\n",
+ version_string, PATCHLEVEL);
+ break;
+
+ case 'C':
+ copyleft();
+ break;
+
+ case 'a': /* use old fashioned awk regexps */
+ regex_mode = RE_SYNTAX_AWK;
+ break;
+
+ case 'e': /* use egrep style regexps, per Posix */
+ regex_mode = RE_SYNTAX_POSIX_EGREP;
+ break;
+
+ case '?':
+ default:
+ /* getopt will print a message for us */
+ /* S5R4 awk ignores bad options and keeps going */
+ break;
+ }
+ }
+
+ /* Tell the regex routines how they should work. . . */
+ (void) re_set_syntax(regex_mode);
+
+#ifdef DEBUG
+ setbuf(stdout, (char *) NULL); /* make debugging easier */
+#endif
+ if (isatty(fileno(stdout)))
+ output_is_tty = 1;
+ /* No -f option, use next arg */
+ /* write to temp file and save sourcefile name */
+ if (numfiles == -1) {
+ int i;
+
+ if (optind > argc - 1) /* no args left */
+ usage();
+ numfiles++;
+ i = strlen (argv[optind]);
+ if (i == 0) { /* sanity check */
+ fprintf(stderr, "%s: empty program text\n", myname);
+ usage();
+ /* NOTREACHED */
+ }
+ sourcefile[0] = tmpnam((char *) NULL);
+ if ((fp = fopen (sourcefile[0], "w")) == NULL)
+ fatal("could not save source prog in temp file (%s)",
+ strerror(errno));
+ if (fwrite (argv[optind], 1, i, fp) == 0)
+ fatal(
+ "could not write source program to temp file (%s)",
+ strerror(errno));
+ if (argv[optind][i-1] != '\n')
+ putc ('\n', fp);
+ (void) fclose (fp);
+ tempsource++;
+ optind++;
+ }
+ init_args(optind, argc, myname, argv);
+
+ /* Read in the program */
+ if (yyparse() || errcount)
+ exit(1);
+
+#ifdef DEBUG
+ if (dotree)
+ print_parse_tree(expression_value);
+#endif
+ /* Set up the field variables */
+ init_fields();
+
+ if (begin_block)
+ (void) interpret(begin_block);
+ if (!exiting && (expression_value || end_block))
+ do_input();
+ if (end_block)
+ (void) interpret(end_block);
+ if (close_io() != 0 && exit_val == 0)
+ exit_val = 1;
+ exit(exit_val);
+}
+
+static void
+usage()
+{
+ char *opt1 = " -f progfile [--]";
+ char *opt2 = " [--] 'program'";
+#ifdef STRICT
+ char *regops = " [-ae] [-F fs] [-v var=val]"
+#else
+ char *regops = " [-aecCV] [-F fs] [-v var=val]";
+#endif
+
+ fprintf(stderr, "usage: %s%s%s file ...\n %s%s%s file ...\n",
+ myname, regops, opt1, myname, regops, opt2);
+ exit(11);
+}
+
+/* Generate compiled regular expressions */
+struct re_pattern_buffer *
+make_regexp(s, ignorecase)
+NODE *s;
+int ignorecase;
+{
+ struct re_pattern_buffer *rp;
+ char *err;
+
+ emalloc(rp, struct re_pattern_buffer *, sizeof(*rp), "make_regexp");
+ memset((char *) rp, 0, sizeof(*rp));
+ emalloc(rp->buffer, char *, 16, "make_regexp");
+ rp->allocated = 16;
+ emalloc(rp->fastmap, char *, 256, "make_regexp");
+
+ if (! strict && ignorecase)
+ rp->translate = casetable;
+ else
+ rp->translate = NULL;
+ if ((err = re_compile_pattern(s->stptr, s->stlen, rp)) != NULL)
+ fatal("%s: /%s/", err, s->stptr);
+ free_temp(s);
+ return rp;
+}
+
+struct re_pattern_buffer *
+mk_re_parse(s, ignorecase)
+char *s;
+int ignorecase;
+{
+ char *src;
+ register char *dest;
+ register int c;
+ int in_brack = 0;
+
+ for (dest = src = s; *src != '\0';) {
+ if (*src == '\\') {
+ c = *++src;
+ switch (c) {
+ case '/':
+ case 'a':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'v':
+ case 'x':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ c = parse_escape(&src);
+ if (c < 0)
+ cant_happen();
+ *dest++ = c;
+ break;
+ default:
+ *dest++ = '\\';
+ *dest++ = c;
+ src++;
+ break;
+ }
+ } else if (*src == '/' && ! in_brack)
+ break;
+ else {
+ if (*src == '[')
+ in_brack = 1;
+ else if (*src == ']')
+ in_brack = 0;
+
+ *dest++ = *src++;
+ }
+ }
+ return make_regexp(tmp_string(s, dest-s), ignorecase);
+}
+
+static void
+copyleft ()
+{
+ extern char *version_string;
+ char *cp;
+ static char blurb[] =
+"Copyright (C) 1989, Free Software Foundation.\n\
+GNU Awk comes with ABSOLUTELY NO WARRANTY. This is free software, and\n\
+you are welcome to distribute it under the terms of the GNU General\n\
+Public License, which covers both the warranty information and the\n\
+terms for redistribution.\n\n\
+You should have received a copy of the GNU General Public License along\n\
+with this program; if not, write to the Free Software Foundation, Inc.,\n\
+675 Mass Ave, Cambridge, MA 02139, USA.\n";
+
+ fprintf (stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
+ fputs(blurb, stderr);
+ fflush(stderr);
+}
+
+static void
+set_fs(str)
+char *str;
+{
+ register NODE **tmp;
+
+ tmp = get_lhs(FS_node, 0);
+ /*
+ * Only if in full compatibility mode check for the stupid special
+ * case so -F\t works as documented in awk even though the shell
+ * hands us -Ft. Bleah!
+ */
+ if (strict && str[0] == 't' && str[1] == '\0')
+ str[0] = '\t';
+ *tmp = make_string(str, 1);
+ do_deref();
+}
+
+static void
+init_args(argc0, argc, argv0, argv)
+int argc0, argc;
+char *argv0;
+char **argv;
+{
+ int i, j;
+ NODE **aptr;
+
+ ARGV_node = spc_var("ARGV", Nnull_string);
+ aptr = assoc_lookup(ARGV_node, tmp_number(0.0));
+ *aptr = make_string(argv0, strlen(argv0));
+ for (i = argc0, j = 1; i < argc; i++) {
+ aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j));
+ *aptr = make_string(argv[i], strlen(argv[i]));
+ j++;
+ }
+ ARGC_node = spc_var("ARGC", make_number((AWKNUM) j));
+}
+
+/*
+ * Set all the special variables to their initial values.
+ */
+static void
+init_vars()
+{
+ extern char **environ;
+ char *var, *val;
+ NODE **aptr;
+ int i;
+
+ FS_node = spc_var("FS", make_string(" ", 1));
+ NF_node = spc_var("NF", make_number(-1.0));
+ RS_node = spc_var("RS", make_string("\n", 1));
+ NR_node = spc_var("NR", make_number(0.0));
+ FNR_node = spc_var("FNR", make_number(0.0));
+ FILENAME_node = spc_var("FILENAME", make_string("-", 1));
+ OFS_node = spc_var("OFS", make_string(" ", 1));
+ ORS_node = spc_var("ORS", make_string("\n", 1));
+ OFMT_node = spc_var("OFMT", make_string("%.6g", 4));
+ RLENGTH_node = spc_var("RLENGTH", make_number(0.0));
+ RSTART_node = spc_var("RSTART", make_number(0.0));
+ SUBSEP_node = spc_var("SUBSEP", make_string("\034", 1));
+ IGNORECASE_node = spc_var("IGNORECASE", make_number(0.0));
+
+ ENVIRON_node = spc_var("ENVIRON", Nnull_string);
+ for (i = 0; environ[i]; i++) {
+ static char nullstr[] = "";
+
+ var = environ[i];
+ val = strchr(var, '=');
+ if (val)
+ *val++ = '\0';
+ else
+ val = nullstr;
+ aptr = assoc_lookup(ENVIRON_node, tmp_string(var, strlen (var)));
+ *aptr = make_string(val, strlen (val));
+
+ /* restore '=' so that system() gets a valid environment */
+ if (val != nullstr)
+ *--val = '=';
+ }
+}
+
+/* Create a special variable */
+static NODE *
+spc_var(name, value)
+char *name;
+NODE *value;
+{
+ register NODE *r;
+
+ if ((r = lookup(variables, name)) == NULL)
+ r = install(variables, name, node(value, Node_var, (NODE *) NULL));
+ return r;
+}
+
+static void
+pre_assign(v)
+char *v;
+{
+ char *cp;
+
+ cp = strchr(v, '=');
+ if (cp != NULL) {
+ *cp++ = '\0';
+ variable(v)->var_value = make_string(cp, strlen(cp));
+ } else {
+ fprintf (stderr,
+ "%s: '%s' argument to -v not in 'var=value' form\n",
+ myname, v);
+ usage();
+ }
+}
+
+int
+catchsig(sig, code)
+int sig, code;
+{
+#ifdef lint
+ code = 0; sig = code; code = sig;
+#endif
+ if (sig == SIGFPE) {
+ fatal("floating point exception");
+ } else if (sig == SIGSEGV) {
+ msg("fatal error: segmentation fault");
+ /* fatal won't abort() if not compiled for debugging */
+ abort();
+ } else
+ cant_happen();
+ /* NOTREACHED */
+}