This patch contains these changes: 1) Changes the way of option processing: pre-assignments processing (-v and -F options) is deffered after other options has been processed; ("awk -Ft --traditional" changes behaviour) 2) free(srcfiles) when no longer needed; 3) changes arg_assign prototype and the function itself--better error/warning messages; 4) removes the pre_assign function, I guess it's obsolete; 5) typo: "profling". diff -ur gawk-3.1.1.orig/awk.h gawk-3.1.1/awk.h --- gawk-3.1.1.orig/awk.h Tue Apr 16 13:40:18 2002 +++ gawk-3.1.1/awk.h Mon May 20 14:15:28 2002 @@ -572,9 +572,12 @@ char *mode; }; -/* structure for our source, either a command line string or a source file */ +/* + * structure for our source, either a command line string or a source file + * the same structure is used to remember variable pre-assignments + */ struct src { - enum srctype { CMDLINE = 1, SOURCEFILE } stype; + enum srctype { CMDLINE = 1, SOURCEFILE, PRE_ASSIGN, PRE_ASSIGN_FS } stype; char *val; }; @@ -942,7 +945,7 @@ extern int main P((int argc, char **argv)); extern void load_environ P((void)); extern void load_procinfo P((void)); -extern char *arg_assign P((char *arg)); +extern int arg_assign P((char *arg, int initing)); extern RETSIGTYPE catchsig P((int sig, int code)); /* msg.c */ extern void err P((const char *s, const char *emsg, va_list argp)); diff -ur gawk-3.1.1.orig/io.c gawk-3.1.1/io.c --- gawk-3.1.1.orig/io.c Tue Apr 16 13:57:44 2002 +++ gawk-3.1.1/io.c Mon May 20 13:01:37 2002 @@ -208,7 +208,7 @@ unref(ARGIND_node->var_value); ARGIND_node->var_value = make_number((AWKNUM) i); } - if (! arg_assign(arg->stptr)) { + if (! arg_assign(arg->stptr, FALSE)) { files++; fname = arg->stptr; curfile = iop_open(fname, binmode("r"), &mybuf); diff -ur gawk-3.1.1.orig/main.c gawk-3.1.1/main.c --- gawk-3.1.1.orig/main.c Wed May 1 16:12:45 2002 +++ gawk-3.1.1/main.c Mon May 20 14:14:58 2002 @@ -49,7 +49,6 @@ 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)); @@ -105,6 +104,17 @@ struct src *srcfiles = NULL; /* source file name(s) */ long numfiles = -1; /* how many source files */ +static long allocfiles; /* for how many is *srcfiles allocated */ + +#define srcfiles_add(stype, val) \ + add_src(&srcfiles, &numfiles, &allocfiles, stype, val) + +static struct src *preassigns = NULL; /* requested via -v or -F */ +static long numassigns = -1; /* how many of them */ +static long allocassigns; /* for how many is allocated */ + +#define preassigns_add(stype, val) \ + add_src(&preassigns, &numassigns, &allocassigns, stype, val) int do_traditional = FALSE; /* no gnu extensions, add traditional weirdnesses */ int do_posix = FALSE; /* turn off gnu and unix extensions */ @@ -181,6 +191,7 @@ extern int optind; extern int opterr; extern char *optarg; + int i; /* do these checks early */ if (getenv("TIDYMEM") != NULL) @@ -220,30 +231,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(); @@ -251,12 +236,4 @@ init_fds(); - - /* load group set */ - init_groupset(); - - /* 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; @@ -269,7 +246,7 @@ switch (c) { case 'F': - cmdline_fs(optarg); + preassigns_add(PRE_ASSIGN_FS, optarg); break; case 'f': @@ -284,17 +261,12 @@ scan = optarg; while (ISSPACE(*scan)) scan++; - - ++numfiles; - srcfiles[numfiles].stype = SOURCEFILE; - if (*scan == '\0') - srcfiles[numfiles].val = argv[optind++]; - else - srcfiles[numfiles].val = optarg; + srcfiles_add(SOURCEFILE, + (*scan == '\0' ? argv[optind++] : optarg)); break; case 'v': - pre_assign(optarg); + preassigns_add(PRE_ASSIGN, optarg); break; case 'm': @@ -355,10 +327,8 @@ case 's': if (optarg[0] == '\0') warning(_("empty argument to `--source' ignored")); - else { - srcfiles[++numfiles].stype = CMDLINE; - srcfiles[numfiles].val = optarg; - } + else + srcfiles_add(CMDLINE, optarg); break; case 'u': @@ -449,29 +419,41 @@ warning(_("running %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(). + * Force profiling if this is pgawk. + * Don't bother if the command line already set profiling up. */ - if (do_traditional || do_posix || do_intervals) { - resetup(); + if (! do_profiling) + init_profiling(& do_profiling, DEFAULT_PROFILE); - /* now handle RS and FS. have to be careful with FS */ - set_RS(); - if (using_fieldwidths()) { - set_FS(); - set_FIELDWIDTHS(); - } else - set_FS(); - } + /* 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|STR|STRING|NUM|NUMBER); /* - * Initialize profiling info, do after parsing args, - * in case this is pgawk. Don't bother if the command - * line already set profling up. + * Tell the regex routines how they should work. + * Do this before initializing variables, since + * they could want to do a regexp compile. */ - if (! do_profiling) - init_profiling(& do_profiling, DEFAULT_PROFILE); + resetup(); + + /* Set up the special variables */ + init_vars(); + + /* Set up the field variables */ + init_fields(); + + /* Now process the pre-assignments */ + for (i = 0; i <= numassigns; i++) + if (preassigns[i].stype == PRE_ASSIGN) + (void) arg_assign(preassigns[i].val, TRUE); + else /* PRE_ASSIGN_FS */ + cmdline_fs(preassigns[i].val); + free(preassigns); if ((BINMODE & 1) != 0) if (os_setbinmode(fileno(stdin), O_BINARY) == -1) @@ -492,8 +474,7 @@ 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]; + srcfiles_add(CMDLINE, argv[optind]); optind++; } @@ -504,6 +485,8 @@ if (yyparse() != 0 || errcount != 0) exit(1); + free(srcfiles); + if (do_intl) exit(0); @@ -546,6 +529,29 @@ return exit_val; /* to suppress warnings */ } +/* add_src --- add one element to *srcfiles or *preassigns */ + +static void +add_src(struct src **data, int *num, int *alloc, enum srctype stype, char *val) +{ +#define INIT_SRC 4 + + ++*num; + + if (*data == NULL ) { + emalloc(*data, struct src *, INIT_SRC * sizeof(struct src), "add_src"); + *alloc = INIT_SRC; + } else if (*num >= *alloc) { + (*alloc) *= 2; + erealloc(*data, struct src *, (*alloc) * sizeof(struct src), "add_src"); + } + + (*data)[*num].stype = stype; + (*data)[*num].val = val; + +#undef INIT_SRC +} + /* usage --- print usage information and exit */ static void @@ -859,8 +865,8 @@ /* arg_assign --- process a command-line assignment */ -char * -arg_assign(char *arg) +int +arg_assign(char *arg, int initing) { char *cp, *cp2; int badvar; @@ -870,26 +876,38 @@ 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; - } + if (cp == NULL) { + if (! initing) + return FALSE; /* This is file name, not assignment. */ + + fprintf(stderr, + _("%s: `%s' argument to `-v' not in `var=value' form\n\n"), + myname, arg); + usage(1, stderr); + } + + *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 (initing) + fatal(_("`%s' is not legal variable name"), arg); + if (do_lint) + lintwarn(_("`%s' is not variable name, looking for file `%s=%s'"), + arg, arg, cp); + } else { /* * Recent versions of nawk expand escapes inside assignments. * This makes sense, so we do it too. @@ -902,47 +920,11 @@ *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 = '='; /* restore original text of ARGV */ - cp = strchr(cp, '='); - assert(cp); - *cp = '\0'; + return ! badvar; } /* catchsig --- catch signals */