aboutsummaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2010-07-16 12:18:27 +0300
committerArnold D. Robbins <arnold@skeeve.com>2010-07-16 12:18:27 +0300
commite1ef22d366abd1f9ec95eb495c727d55181c8584 (patch)
treecc0fee624202820eb928e60b6a096362c85ff807 /main.c
parentcae8bc6ced84c12590e3554a06a952283735363a (diff)
downloadegawk-e1ef22d366abd1f9ec95eb495c727d55181c8584.tar.gz
egawk-e1ef22d366abd1f9ec95eb495c727d55181c8584.tar.bz2
egawk-e1ef22d366abd1f9ec95eb495c727d55181c8584.zip
Move to 2.15.
Diffstat (limited to 'main.c')
-rw-r--r--main.c320
1 files changed, 168 insertions, 152 deletions
diff --git a/main.c b/main.c
index 04cb1e9d..77d0bf74 100644
--- a/main.c
+++ b/main.c
@@ -23,10 +23,11 @@
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "getopt.h"
#include "awk.h"
#include "patchlevel.h"
-static void usage P((void));
+static void usage P((int exitval));
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));
@@ -35,27 +36,29 @@ static void pre_assign P((char *v));
SIGTYPE catchsig P((int sig, int code));
static void gawk_option P((char *optstr));
static void nostalgia P((void));
-static char *gawk_name P((char *filespec));
+static void version P((void));
+char *gawk_name P((char *filespec));
#ifdef MSDOS
-extern int getopt P((int argc, char **argv, char *optstring));
extern int isatty P((int));
#endif
+extern void resetup P((void));
+
/* 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 *CONVFMT_node;
+NODE *ERRNO_node;
NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
NODE *ENVIRON_node, *IGNORECASE_node;
-NODE *ARGC_node, *ARGV_node;
+NODE *ARGC_node, *ARGV_node, *ARGIND_node;
NODE *FIELDWIDTHS_node;
int NF;
int NR;
int FNR;
int IGNORECASE;
-char *FS;
char *RS;
char *OFS;
char *ORS;
@@ -87,13 +90,14 @@ int exit_val = 0; /* optional exit value */
extern int yydebug;
#endif
-char **srcfiles = NULL; /* source file name(s) */
+struct src *srcfiles = NULL; /* source file name(s) */
int numfiles = -1; /* how many source files */
-char *cmdline_src = NULL; /* if prog is on command line */
-int strict = 0; /* turn off gnu extensions */
-int do_posix = 0; /* turn off gnu extensions and \x */
+int do_unix = 0; /* turn off gnu extensions */
+int do_posix = 0; /* turn off gnu and unix extensions */
int do_lint = 0; /* provide warnings about questionable stuff */
+int do_nostalgia = 0; /* provide a blast from the past */
+
int in_begin_rule = 0; /* we're in a BEGIN rule */
int in_end_rule = 0; /* we're in a END rule */
@@ -103,21 +107,25 @@ extern char *version_string; /* current version, for printing */
NODE *expression_value;
-/*
- * for strict to work, legal options must be first
- *
- * Unfortunately, -a and -e are orthogonal to -c.
- *
- * Note that after 2.13, c,a,e,C,D, and V go away.
- */
-/* the + on the front is for GNU getopt */
+static struct option optab[] = {
+ { "compat", no_argument, & do_unix, 1 },
+ { "lint", no_argument, & do_lint, 1 },
+ { "posix", no_argument, & do_posix, 1 },
+ { "nostalgia", no_argument, & do_nostalgia, 1 },
+ { "copyleft", no_argument, NULL, 'C' },
+ { "copyright", no_argument, NULL, 'C' },
+ { "field-separator", required_argument, NULL, 'F' },
+ { "file", required_argument, NULL, 'f' },
+ { "assign", required_argument, NULL, 'v' },
+ { "version", no_argument, NULL, 'V' },
+ { "usage", no_argument, NULL, 'u' },
+ { "help", no_argument, NULL, 'u' },
+ { "source", required_argument, NULL, 's' },
#ifdef DEBUG
-char awk_opts[] = "+F:f:v:W:caeCVD";
-#else
-char awk_opts[] = "+F:f:v:W:caeCV";
+ { "parsedebug", no_argument, NULL, 'D' },
#endif
-
-extern void resetup P((void));
+ { 0, 0, 0, 0 }
+};
int
main(argc, argv)
@@ -127,13 +135,13 @@ char **argv;
int c;
char *scan;
extern int optind;
+ extern int opterr;
extern char *optarg;
int i;
- int do_nostalgia;
(void) signal(SIGFPE, (SIGTYPE (*) P((int))) catchsig);
(void) signal(SIGSEGV, (SIGTYPE (*) P((int))) catchsig);
-#ifndef MSDOS
+#ifdef SIGBUS
(void) signal(SIGBUS, (SIGTYPE (*) P((int))) catchsig);
#endif
@@ -142,13 +150,14 @@ char **argv;
#ifdef VMS
vms_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
#endif
- if (argc < 2)
- usage();
/* remove sccs gunk */
if (strncmp(version_string, "@(#)", 4) == 0)
version_string += 4;
+ if (argc < 2)
+ usage(1);
+
/* initialize the null string */
Nnull_string = make_string("", 0);
Nnull_string->numbr = 0.0;
@@ -164,47 +173,20 @@ char **argv;
init_vars();
/* worst case */
- emalloc(srcfiles, char **, argc * sizeof(char *), "main");
- srcfiles[0] = NULL;
+ emalloc(srcfiles, struct src *, argc * sizeof(struct src), "main");
+ memset(srcfiles, '\0', argc * sizeof(struct src));
- /* undocumented feature, inspired by nostalgia, and a T-shirt */
- do_nostalgia = 0;
- for (i = 1; i < argc && argv[i][0] == '-'; i++) {
- if (argv[i][1] == '-') /* -- */
- break;
- else if (argv[i][1] == 'c') { /* compat not in next release */
- do_nostalgia = 0;
- break;
- } else if (STREQ(&argv[i][1], "nostalgia"))
- do_nostalgia = 1;
- /* keep looping, in case -c after -nostalgia */
- }
- if (do_nostalgia) {
- fprintf(stderr, "%s, %s\n",
- "warning: option -nostalgia will go away in a future release",
- "use -W nostalgia");
- nostalgia();
- /* NOTREACHED */
- }
/* Tell the regex routines how they should work. . . */
resetup();
- while ((c = getopt (argc, argv, awk_opts)) != EOF) {
- switch (c) {
-#ifdef DEBUG
- case 'D':
- fprintf(stderr,
-"warning: option -D will go away in a future release, use -W parsedebug\n");
- gawk_option("parsedebug");
- break;
-#endif
-
- case 'c':
- fprintf(stderr,
- "warning: option -c will go away in a future release, use -W compat\n");
- gawk_option("compat");
- break;
+ /* we do error messages ourselves on invalid options */
+ opterr = 0;
+ /* the + on the front tells GNU getopt not to rearrange argv */
+ while ((c = getopt_long(argc, argv, "+F:f:v:W:", optab, NULL)) != EOF) {
+ if (do_posix)
+ opterr = 1;
+ switch (c) {
case 'F':
cmdline_fs(optarg);
break;
@@ -221,62 +203,87 @@ char **argv;
scan = optarg;
while (isspace(*scan))
scan++;
+ ++numfiles;
+ srcfiles[numfiles].stype = SOURCEFILE;
if (*scan == '\0')
- srcfiles[++numfiles] = argv[optind++];
+ srcfiles[numfiles].val = argv[optind++];
else
- srcfiles[++numfiles] = optarg;
+ srcfiles[numfiles].val = optarg;
break;
case 'v':
pre_assign(optarg);
break;
+ case 'W': /* gawk specific options */
+ gawk_option(optarg);
+ break;
+
+ /* These can only come from long form options */
case 'V':
- warning(
- "option -V will go away in a future release, use -W version");
- gawk_option("version");
+ version();
break;
case 'C':
- warning(
- "option -C will go away in a future release, use -W copyright");
- gawk_option("copyright");
+ copyleft();
break;
- case 'a': /* use old fashioned awk regexps */
- warning("option -a will go away in a future release");
+ case 'u':
+ usage(0);
break;
- case 'e': /* use Posix style regexps */
- warning("option -e will go away in a future release");
+ case 's':
+ if (strlen(optarg) == 0)
+ warning("empty argument to --source ignored");
+ else {
+ srcfiles[++numfiles].stype = CMDLINE;
+ srcfiles[numfiles].val = optarg;
+ }
break;
- case 'W': /* gawk specific options */
- gawk_option(optarg);
+#ifdef DEBUG
+ case 'D':
+ yydebug = 2;
break;
+#endif
case '?':
default:
- /* getopt will print a message for us */
- /* S5R4 awk ignores bad options and keeps going */
+ /*
+ * 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.
+ */
+ if (! do_posix)
+ goto out;
+ /* else
+ let getopt print error message for us */
break;
}
}
+out:
+
+ if (do_nostalgia)
+ nostalgia();
+
+ /* POSIX compliance also implies no Unix extensions either */
+ if (do_posix)
+ do_unix = 1;
#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 */
+ /* No -f or --source options, use next arg */
if (numfiles == -1) {
if (optind > argc - 1) /* no args left */
- usage();
- cmdline_src = argv[optind];
+ usage(1);
+ srcfiles[++numfiles].stype = CMDLINE;
+ srcfiles[numfiles].val = argv[optind];
optind++;
}
- srcfiles[++numfiles] = NULL;
init_args(optind, argc, (char *) myname, argv);
(void) tokexpand();
@@ -305,72 +312,41 @@ char **argv;
return exit_val; /* to suppress warnings */
}
+/* usage --- print usage information and exit */
+
static void
-usage()
+usage(exitval)
+int exitval;
{
char *opt1 = " -f progfile [--]";
char *opt2 = " [--] 'program'";
- char *regops = " [-F fs] [-v var=val] [-W gawk-opts]";
+ char *regops = " [POSIX or GNU style options]";
+ version();
fprintf(stderr, "usage: %s%s%s file ...\n %s%s%s file ...\n",
myname, regops, opt1, myname, regops, opt2);
- exit(11);
-}
-
-Regexp *
-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++ = (char)c;
- break;
- default:
- *dest++ = '\\';
- *dest++ = (char)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, 1);
+ /* GNU long options info. Gack. */
+ fputs("\nPOSIX options:\t\tGNU long options:\n", stderr);
+ fputs("\t-f progfile\t\t--file=progfile\n", stderr);
+ fputs("\t-F fs\t\t\t--field-separator=fs\n", stderr);
+ fputs("\t-v var=val\t\t--assign=var=val\n", stderr);
+ fputs("\t-W compat\t\t--compat\n", stderr);
+ fputs("\t-W copyleft\t\t--copyleft\n", stderr);
+ fputs("\t-W copyright\t\t--copyright\n", stderr);
+ fputs("\t-W help\t\t\t--help\n", stderr);
+ fputs("\t-W lint\t\t\t--lint\n", stderr);
+#if 0
+ fputs("\t-W nostalgia\t\t--nostalgia\n", stderr);
+#endif
+#ifdef DEBUG
+ fputs("\t-W parsedebug\t\t--parsedebug\n", stderr);
+#endif
+ fputs("\t-W posix\t\t--posix\n", stderr);
+ fputs("\t-W source=program-text\t--source=program-text\n", stderr);
+ fputs("\t-W usage\t\t--usage\n", stderr);
+ fputs("\t-W version\t\t--version\n", stderr);
+ exit(exitval);
}
static void
@@ -395,7 +371,7 @@ GNU General Public License for more details.\n\
along with this program; if not, write to the Free Software\n\
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
- fprintf(stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
+ version();
fputs(blurb_part1, stderr);
fputs(blurb_part2, stderr);
fputs(blurb_part3, stderr);
@@ -421,7 +397,7 @@ char *str;
if (str[0] == 't' && str[1] == '\0') {
if (do_lint)
warning("-Ft does not set FS to tab in POSIX awk");
- if (strict && ! do_posix)
+ if (do_unix && ! do_posix)
str[0] = '\t';
}
*tmp = make_str_node(str, len, SCAN); /* do process escapes */
@@ -478,6 +454,8 @@ static struct varinit varinit[] = {
{&RLENGTH_node, "RLENGTH", Node_var, 0, 0, 0 },
{&RSTART_node, "RSTART", Node_var, 0, 0, 0 },
{&SUBSEP_node, "SUBSEP", Node_var, "\034", 0, 0 },
+{&ARGIND_node, "ARGIND", Node_var, 0, 0, 0 },
+{&ERRNO_node, "ERRNO", Node_var, 0, 0, 0 },
{0, 0, Node_illegal, 0, 0, 0 },
};
@@ -566,7 +544,7 @@ char *v;
fprintf (stderr,
"%s: '%s' argument to -v not in 'var=value' form\n",
myname, v);
- usage();
+ usage(1);
}
}
@@ -580,7 +558,7 @@ int sig, code;
if (sig == SIGFPE) {
fatal("floating point exception");
} else if (sig == SIGSEGV
-#ifndef MSDOS
+#ifdef SIGBUS
|| sig == SIGBUS
#endif
) {
@@ -613,8 +591,7 @@ char *optstr;
goto unknown;
else
cp += 6;
- fprintf(stderr, "%s, patchlevel %d\n",
- version_string, PATCHLEVEL);
+ version();
break;
case 'c':
case 'C':
@@ -626,12 +603,16 @@ char *optstr;
copyleft();
} else if (strncasecmp(cp, "compat", 6) == 0) {
cp += 5;
- strict = 1;
+ do_unix = 1;
} else
goto unknown;
break;
case 'n':
case 'N':
+ /*
+ * Undocumented feature,
+ * inspired by nostalgia, and a T-shirt
+ */
if (strncasecmp(cp, "nostalgia", 9) != 0)
goto unknown;
nostalgia();
@@ -640,7 +621,7 @@ char *optstr;
case 'P':
#ifdef DEBUG
if (strncasecmp(cp, "parsedebug", 10) == 0) {
- cp += 10;
+ cp += 9;
yydebug = 2;
break;
}
@@ -648,8 +629,7 @@ char *optstr;
if (strncasecmp(cp, "posix", 5) != 0)
goto unknown;
cp += 4;
- do_posix = 1;
- strict = 1;
+ do_posix = do_unix = 1;
break;
case 'l':
case 'L':
@@ -658,6 +638,33 @@ char *optstr;
cp += 3;
do_lint = 1;
break;
+ case 'H':
+ case 'h':
+ if (strncasecmp(cp, "help", 4) != 0)
+ goto unknown;
+ cp += 3;
+ usage(0);
+ break;
+ case 'U':
+ case 'u':
+ if (strncasecmp(cp, "usage", 5) != 0)
+ goto unknown;
+ cp += 4;
+ usage(0);
+ break;
+ case 's':
+ case 'S':
+ if (strncasecmp(cp, "source=", 7) != 0)
+ goto unknown;
+ cp += 7;
+ if (strlen(cp) == 0)
+ warning("empty argument to -Wsource ignored");
+ else {
+ srcfiles[++numfiles].stype = CMDLINE;
+ srcfiles[numfiles].val = cp;
+ return;
+ }
+ break;
default:
unknown:
fprintf(stderr, "'%c' -- unknown option, ignored\n",
@@ -676,7 +683,16 @@ nostalgia()
abort();
}
-static char *
+/* version --- print version message */
+
+static void
+version()
+{
+ fprintf(stderr, "%s, patchlevel %d\n", version_string, PATCHLEVEL);
+}
+
+/* static */
+char *
gawk_name(filespec)
char *filespec;
{