1 | /*
|
---|
2 | * main.c -- Expression tree constructors and main program for gawk.
|
---|
3 | */
|
---|
4 |
|
---|
5 | /*
|
---|
6 | * Copyright (C) 1986, 1988, 1989, 1991-2005 the Free Software Foundation, Inc.
|
---|
7 | *
|
---|
8 | * This file is part of GAWK, the GNU implementation of the
|
---|
9 | * AWK Programming Language.
|
---|
10 | *
|
---|
11 | * GAWK is free software; you can redistribute it and/or modify
|
---|
12 | * it under the terms of the GNU General Public License as published by
|
---|
13 | * the Free Software Foundation; either version 2 of the License, or
|
---|
14 | * (at your option) any later version.
|
---|
15 | *
|
---|
16 | * GAWK is distributed in the hope that it will be useful,
|
---|
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
19 | * GNU General Public License for more details.
|
---|
20 | *
|
---|
21 | * You should have received a copy of the GNU General Public License
|
---|
22 | * along with this program; if not, write to the Free Software
|
---|
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
---|
24 | */
|
---|
25 |
|
---|
26 | /* FIX THIS BEFORE EVERY RELEASE: */
|
---|
27 | #define UPDATE_YEAR 2005
|
---|
28 |
|
---|
29 | #include "awk.h"
|
---|
30 | #include "getopt.h"
|
---|
31 |
|
---|
32 | #ifndef O_BINARY
|
---|
33 | #include <fcntl.h>
|
---|
34 | #endif
|
---|
35 |
|
---|
36 | #ifdef HAVE_MCHECK_H
|
---|
37 | #include <mcheck.h>
|
---|
38 | #endif
|
---|
39 |
|
---|
40 | #define DEFAULT_PROFILE "awkprof.out" /* where to put profile */
|
---|
41 | #define DEFAULT_VARFILE "awkvars.out" /* where to put vars */
|
---|
42 |
|
---|
43 | static const char *varfile = DEFAULT_VARFILE;
|
---|
44 |
|
---|
45 | static void usage P((int exitval, FILE *fp)) ATTRIBUTE_NORETURN;
|
---|
46 | static void copyleft P((void)) ATTRIBUTE_NORETURN;
|
---|
47 | static void cmdline_fs P((char *str));
|
---|
48 | static void init_args P((int argc0, int argc, char *argv0, char **argv));
|
---|
49 | static void init_vars P((void));
|
---|
50 | static NODE *load_environ P((void));
|
---|
51 | static NODE *load_procinfo P((void));
|
---|
52 | static void add_src P((struct src **data, long *num, long *alloc, enum srctype stype, char *val));
|
---|
53 | static RETSIGTYPE catchsig P((int sig)) ATTRIBUTE_NORETURN;
|
---|
54 | static void nostalgia P((void)) ATTRIBUTE_NORETURN;
|
---|
55 | static void version P((void)) ATTRIBUTE_NORETURN;
|
---|
56 | static void init_fds P((void));
|
---|
57 | static void init_groupset P((void));
|
---|
58 |
|
---|
59 | /* These nodes store all the special variables AWK uses */
|
---|
60 | NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
|
---|
61 | NODE *ENVIRON_node, *ERRNO_node, *FIELDWIDTHS_node, *FILENAME_node, *FNR_node;
|
---|
62 | NODE *FS_node, *IGNORECASE_node, *NF_node, *NR_node, *OFMT_node, *OFS_node;
|
---|
63 | NODE *ORS_node, *PROCINFO_node, *RLENGTH_node, *RSTART_node, *RS_node;
|
---|
64 | NODE *RT_node, *SUBSEP_node, *LINT_node, *TEXTDOMAIN_node;
|
---|
65 |
|
---|
66 | long NF;
|
---|
67 | long NR;
|
---|
68 | long FNR;
|
---|
69 | int BINMODE;
|
---|
70 | int IGNORECASE;
|
---|
71 | char *OFS;
|
---|
72 | char *ORS;
|
---|
73 | char *OFMT;
|
---|
74 | char *TEXTDOMAIN;
|
---|
75 | int MRL; /* See -mr option for use of this variable */
|
---|
76 |
|
---|
77 | /*
|
---|
78 | * CONVFMT is a convenience pointer for the current number to string format.
|
---|
79 | * We must supply an initial value to avoid recursion problems of
|
---|
80 | * set_CONVFMT -> fmt_index -> r_force_string: gets NULL CONVFMT
|
---|
81 | * Fun, fun, fun, fun.
|
---|
82 | */
|
---|
83 | char *CONVFMT = "%.6g";
|
---|
84 |
|
---|
85 |
|
---|
86 | int errcount = 0; /* error counter, used by yyerror() */
|
---|
87 |
|
---|
88 | NODE *Nnull_string; /* The global null string */
|
---|
89 |
|
---|
90 | #if defined(HAVE_LOCALE_H)
|
---|
91 | struct lconv loc; /* current locale */
|
---|
92 | #endif /* defined(HAVE_LOCALE_H) */
|
---|
93 |
|
---|
94 | /* The name the program was invoked under, for error messages */
|
---|
95 | const char *myname;
|
---|
96 |
|
---|
97 | /* A block of AWK code to be run before running the program */
|
---|
98 | NODE *begin_block = NULL;
|
---|
99 |
|
---|
100 | /* A block of AWK code to be run after the last input file */
|
---|
101 | NODE *end_block = NULL;
|
---|
102 |
|
---|
103 | int exiting = FALSE; /* Was an "exit" statement executed? */
|
---|
104 | int exit_val = 0; /* optional exit value */
|
---|
105 |
|
---|
106 | #if defined(YYDEBUG) || defined(GAWKDEBUG)
|
---|
107 | extern int yydebug;
|
---|
108 | #endif
|
---|
109 |
|
---|
110 | struct src *srcfiles = NULL; /* source file name(s) */
|
---|
111 | long numfiles = -1; /* how many source files */
|
---|
112 | static long allocfiles; /* for how many is *srcfiles allocated */
|
---|
113 |
|
---|
114 | #define srcfiles_add(stype, val) \
|
---|
115 | add_src(&srcfiles, &numfiles, &allocfiles, stype, val)
|
---|
116 |
|
---|
117 | static struct src *preassigns = NULL; /* requested via -v or -F */
|
---|
118 | static long numassigns = -1; /* how many of them */
|
---|
119 | static long allocassigns; /* for how many is allocated */
|
---|
120 |
|
---|
121 | static int disallow_var_assigns = FALSE; /* true for --exec */
|
---|
122 |
|
---|
123 | #define preassigns_add(stype, val) \
|
---|
124 | add_src(&preassigns, &numassigns, &allocassigns, stype, val)
|
---|
125 |
|
---|
126 | #undef do_lint
|
---|
127 | #undef do_lint_old
|
---|
128 |
|
---|
129 | int do_traditional = FALSE; /* no gnu extensions, add traditional weirdnesses */
|
---|
130 | int do_posix = FALSE; /* turn off gnu and unix extensions */
|
---|
131 | int do_lint = FALSE; /* provide warnings about questionable stuff */
|
---|
132 | int do_lint_old = FALSE; /* warn about stuff not in V7 awk */
|
---|
133 | int do_intl = FALSE; /* dump locale-izable strings to stdout */
|
---|
134 | int do_non_decimal_data = FALSE; /* allow octal/hex C style DATA. Use with caution! */
|
---|
135 | int do_nostalgia = FALSE; /* provide a blast from the past */
|
---|
136 | int do_intervals = FALSE; /* allow {...,...} in regexps */
|
---|
137 | int do_profiling = FALSE; /* profile and pretty print the program */
|
---|
138 | int do_dump_vars = FALSE; /* dump all global variables at end */
|
---|
139 | int do_tidy_mem = FALSE; /* release vars when done */
|
---|
140 |
|
---|
141 | int in_begin_rule = FALSE; /* we're in a BEGIN rule */
|
---|
142 | int in_end_rule = FALSE; /* we're in a END rule */
|
---|
143 | int whiny_users = FALSE; /* do things that whiny users want */
|
---|
144 | #ifdef MBS_SUPPORT
|
---|
145 | int gawk_mb_cur_max; /* MB_CUR_MAX value, see comment in main() */
|
---|
146 | #else
|
---|
147 | const int gawk_mb_cur_max = 1;
|
---|
148 | #endif
|
---|
149 |
|
---|
150 | int output_is_tty = FALSE; /* control flushing of output */
|
---|
151 |
|
---|
152 | extern const char *version_string;
|
---|
153 |
|
---|
154 | #if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
|
---|
155 | GETGROUPS_T *groupset; /* current group set */
|
---|
156 | int ngroups; /* size of said set */
|
---|
157 | #endif
|
---|
158 |
|
---|
159 | /* The parse tree is stored here. */
|
---|
160 | NODE *expression_value;
|
---|
161 |
|
---|
162 | #if _MSC_VER == 510
|
---|
163 | void (*lintfunc) P((va_list va_alist, ...)) = warning;
|
---|
164 | #else
|
---|
165 | #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
|
---|
166 | void (*lintfunc) P((const char *mesg, ...)) = warning;
|
---|
167 | #else
|
---|
168 | void (*lintfunc) () = warning;
|
---|
169 | #endif
|
---|
170 | #endif
|
---|
171 |
|
---|
172 | static const struct option optab[] = {
|
---|
173 | { "compat", no_argument, & do_traditional, 1 },
|
---|
174 | { "traditional", no_argument, & do_traditional, 1 },
|
---|
175 | { "lint", optional_argument, NULL, 'l' },
|
---|
176 | { "lint-old", no_argument, & do_lint_old, 1 },
|
---|
177 | { "posix", no_argument, & do_posix, 1 },
|
---|
178 | { "nostalgia", no_argument, & do_nostalgia, 1 },
|
---|
179 | { "gen-po", no_argument, & do_intl, 1 },
|
---|
180 | { "non-decimal-data", no_argument, & do_non_decimal_data, 1 },
|
---|
181 | { "profile", optional_argument, NULL, 'p' },
|
---|
182 | { "copyleft", no_argument, NULL, 'C' },
|
---|
183 | { "copyright", no_argument, NULL, 'C' },
|
---|
184 | { "field-separator", required_argument, NULL, 'F' },
|
---|
185 | { "file", required_argument, NULL, 'f' },
|
---|
186 | { "re-interval", no_argument, & do_intervals, 1 },
|
---|
187 | { "source", required_argument, NULL, 's' },
|
---|
188 | { "dump-variables", optional_argument, NULL, 'd' },
|
---|
189 | { "assign", required_argument, NULL, 'v' },
|
---|
190 | { "version", no_argument, NULL, 'V' },
|
---|
191 | { "usage", no_argument, NULL, 'u' },
|
---|
192 | { "help", no_argument, NULL, 'u' },
|
---|
193 | { "exec", required_argument, NULL, 'S' },
|
---|
194 | #ifdef GAWKDEBUG
|
---|
195 | { "parsedebug", no_argument, NULL, 'D' },
|
---|
196 | #endif
|
---|
197 | { NULL, 0, NULL, '\0' }
|
---|
198 | };
|
---|
199 |
|
---|
200 | #ifdef NO_LINT
|
---|
201 | #define do_lint 0
|
---|
202 | #define do_lint_old 0
|
---|
203 | #endif
|
---|
204 |
|
---|
205 | /* main --- process args, parse program, run it, clean up */
|
---|
206 |
|
---|
207 | int
|
---|
208 | main(int argc, char **argv)
|
---|
209 | {
|
---|
210 | int c;
|
---|
211 | char *scan;
|
---|
212 | /* the + on the front tells GNU getopt not to rearrange argv */
|
---|
213 | const char *optlist = "+F:f:v:W;m:D";
|
---|
214 | int stopped_early = FALSE;
|
---|
215 | int old_optind;
|
---|
216 | extern int optind;
|
---|
217 | extern int opterr;
|
---|
218 | extern char *optarg;
|
---|
219 | int i;
|
---|
220 | int stdio_problem = FALSE;
|
---|
221 |
|
---|
222 | /* do these checks early */
|
---|
223 | if (getenv("TIDYMEM") != NULL)
|
---|
224 | do_tidy_mem = TRUE;
|
---|
225 |
|
---|
226 | if (getenv("WHINY_USERS") != NULL)
|
---|
227 | whiny_users = TRUE;
|
---|
228 |
|
---|
229 | #ifdef HAVE_MCHECK_H
|
---|
230 | if (do_tidy_mem)
|
---|
231 | mtrace();
|
---|
232 | #endif /* HAVE_MCHECK_H */
|
---|
233 |
|
---|
234 | #if defined(LC_CTYPE)
|
---|
235 | setlocale(LC_CTYPE, "");
|
---|
236 | #endif
|
---|
237 | #if defined(LC_COLLATE)
|
---|
238 | setlocale(LC_COLLATE, "");
|
---|
239 | #endif
|
---|
240 | #if defined(LC_MESSAGES)
|
---|
241 | setlocale(LC_MESSAGES, "");
|
---|
242 | #endif
|
---|
243 | #if defined(LC_NUMERIC)
|
---|
244 | /*
|
---|
245 | * Force the issue here. According to POSIX 2001, decimal
|
---|
246 | * point is used for parsing source code and for command-line
|
---|
247 | * assignments and the locale value for processing input,
|
---|
248 | * number to string conversion, and printing output.
|
---|
249 | */
|
---|
250 | setlocale(LC_NUMERIC, "C");
|
---|
251 | #endif
|
---|
252 | #if defined(LC_TIME)
|
---|
253 | setlocale(LC_TIME, "");
|
---|
254 | #endif
|
---|
255 |
|
---|
256 | #ifdef MBS_SUPPORT
|
---|
257 | /*
|
---|
258 | * In glibc, MB_CUR_MAX is actually a function. This value is
|
---|
259 | * tested *a lot* in many speed-critical places in gawk. Caching
|
---|
260 | * this value once makes a speed difference.
|
---|
261 | */
|
---|
262 | gawk_mb_cur_max = MB_CUR_MAX;
|
---|
263 | /* Without MBS_SUPPORT, gawk_mb_cur_max is 1. */
|
---|
264 | #endif
|
---|
265 |
|
---|
266 | (void) bindtextdomain(PACKAGE, LOCALEDIR);
|
---|
267 | (void) textdomain(PACKAGE);
|
---|
268 |
|
---|
269 | (void) signal(SIGFPE, catchsig);
|
---|
270 | (void) signal(SIGSEGV, catchsig);
|
---|
271 | #ifdef SIGBUS
|
---|
272 | (void) signal(SIGBUS, catchsig);
|
---|
273 | #endif
|
---|
274 |
|
---|
275 | myname = gawk_name(argv[0]);
|
---|
276 | argv[0] = (char *) myname;
|
---|
277 | os_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
|
---|
278 |
|
---|
279 | /* remove sccs gunk */
|
---|
280 | if (strncmp(version_string, "@(#)", 4) == 0)
|
---|
281 | version_string += 4;
|
---|
282 |
|
---|
283 | if (argc < 2)
|
---|
284 | usage(1, stderr);
|
---|
285 |
|
---|
286 | /* Robustness: check that file descriptors 0, 1, 2 are open */
|
---|
287 | init_fds();
|
---|
288 |
|
---|
289 | /* init array handling. */
|
---|
290 | array_init();
|
---|
291 |
|
---|
292 | /* we do error messages ourselves on invalid options */
|
---|
293 | opterr = FALSE;
|
---|
294 |
|
---|
295 | /* option processing. ready, set, go! */
|
---|
296 | for (optopt = 0, old_optind = 1;
|
---|
297 | (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
|
---|
298 | optopt = 0, old_optind = optind) {
|
---|
299 | if (do_posix)
|
---|
300 | opterr = TRUE;
|
---|
301 |
|
---|
302 | switch (c) {
|
---|
303 | case 'F':
|
---|
304 | preassigns_add(PRE_ASSIGN_FS, optarg);
|
---|
305 | break;
|
---|
306 |
|
---|
307 | case 'S':
|
---|
308 | disallow_var_assigns = TRUE;
|
---|
309 | /* fall through */
|
---|
310 | case 'f':
|
---|
311 | /*
|
---|
312 | * a la MKS awk, allow multiple -f options.
|
---|
313 | * this makes function libraries real easy.
|
---|
314 | * most of the magic is in the scanner.
|
---|
315 | *
|
---|
316 | * The following is to allow for whitespace at the end
|
---|
317 | * of a #! /bin/gawk line in an executable file
|
---|
318 | */
|
---|
319 | scan = optarg;
|
---|
320 | if (argv[optind-1] != optarg)
|
---|
321 | while (ISSPACE(*scan))
|
---|
322 | scan++;
|
---|
323 | srcfiles_add(SOURCEFILE,
|
---|
324 | (*scan == '\0' ? argv[optind++] : optarg));
|
---|
325 | break;
|
---|
326 |
|
---|
327 | case 'v':
|
---|
328 | preassigns_add(PRE_ASSIGN, optarg);
|
---|
329 | break;
|
---|
330 |
|
---|
331 | case 'm':
|
---|
332 | /*
|
---|
333 | * Research awk extension.
|
---|
334 | * -mf nnn set # fields, gawk ignores
|
---|
335 | * -mr nnn set record length, ditto
|
---|
336 | */
|
---|
337 | if (do_lint)
|
---|
338 | lintwarn(_("`-m[fr]' option irrelevant in gawk"));
|
---|
339 | if (optarg[0] != 'r' && optarg[0] != 'f')
|
---|
340 | warning(_("-m option usage: `-m[fr] nnn'"));
|
---|
341 | /*
|
---|
342 | * Set fixed length records for Tandem,
|
---|
343 | * ignored on other platforms (see io.c:get_a_record).
|
---|
344 | */
|
---|
345 | if (optarg[0] == 'r') {
|
---|
346 | if (ISDIGIT(optarg[1]))
|
---|
347 | MRL = atoi(optarg+1);
|
---|
348 | else {
|
---|
349 | MRL = atoi(argv[optind]);
|
---|
350 | optind++;
|
---|
351 | }
|
---|
352 | } else if (optarg[1] == '\0')
|
---|
353 | optind++;
|
---|
354 | break;
|
---|
355 |
|
---|
356 | case 'W': /* gawk specific options - now in getopt_long */
|
---|
357 | fprintf(stderr, _("%s: option `-W %s' unrecognized, ignored\n"),
|
---|
358 | argv[0], optarg);
|
---|
359 | break;
|
---|
360 |
|
---|
361 | /* These can only come from long form options */
|
---|
362 | case 'C':
|
---|
363 | copyleft();
|
---|
364 | break;
|
---|
365 |
|
---|
366 | case 'd':
|
---|
367 | do_dump_vars = TRUE;
|
---|
368 | if (optarg != NULL && optarg[0] != '\0')
|
---|
369 | varfile = optarg;
|
---|
370 | break;
|
---|
371 |
|
---|
372 | case 'l':
|
---|
373 | #ifndef NO_LINT
|
---|
374 | do_lint = LINT_ALL;
|
---|
375 | if (optarg != NULL) {
|
---|
376 | if (strcmp(optarg, "fatal") == 0)
|
---|
377 | lintfunc = r_fatal;
|
---|
378 | else if (strcmp(optarg, "invalid") == 0)
|
---|
379 | do_lint = LINT_INVALID;
|
---|
380 | }
|
---|
381 | #endif
|
---|
382 | break;
|
---|
383 |
|
---|
384 | case 'p':
|
---|
385 | do_profiling = TRUE;
|
---|
386 | if (optarg != NULL)
|
---|
387 | set_prof_file(optarg);
|
---|
388 | else
|
---|
389 | set_prof_file(DEFAULT_PROFILE);
|
---|
390 | break;
|
---|
391 |
|
---|
392 | case 's':
|
---|
393 | if (optarg[0] == '\0')
|
---|
394 | warning(_("empty argument to `--source' ignored"));
|
---|
395 | else
|
---|
396 | srcfiles_add(CMDLINE, optarg);
|
---|
397 | break;
|
---|
398 |
|
---|
399 | case 'u':
|
---|
400 | usage(0, stdout); /* per coding stds */
|
---|
401 | break;
|
---|
402 |
|
---|
403 | case 'V':
|
---|
404 | version();
|
---|
405 | break;
|
---|
406 |
|
---|
407 | case 0:
|
---|
408 | /*
|
---|
409 | * getopt_long found an option that sets a variable
|
---|
410 | * instead of returning a letter. Do nothing, just
|
---|
411 | * cycle around for the next one.
|
---|
412 | */
|
---|
413 | break;
|
---|
414 |
|
---|
415 | case 'D':
|
---|
416 | #ifdef GAWKDEBUG
|
---|
417 | yydebug = 2;
|
---|
418 | break;
|
---|
419 | #endif
|
---|
420 | /* if not debugging, fall through */
|
---|
421 |
|
---|
422 | case '?':
|
---|
423 | default:
|
---|
424 | /*
|
---|
425 | * New behavior. If not posix, an unrecognized
|
---|
426 | * option stops argument processing so that it can
|
---|
427 | * go into ARGV for the awk program to see. This
|
---|
428 | * makes use of ``#! /bin/gawk -f'' easier.
|
---|
429 | *
|
---|
430 | * However, it's never simple. If optopt is set,
|
---|
431 | * an option that requires an argument didn't get the
|
---|
432 | * argument. We care because if opterr is 0, then
|
---|
433 | * getopt_long won't print the error message for us.
|
---|
434 | */
|
---|
435 | if (! do_posix
|
---|
436 | && (optopt == '\0' || strchr(optlist, optopt) == NULL)) {
|
---|
437 | /*
|
---|
438 | * can't just do optind--. In case of an
|
---|
439 | * option with >= 2 letters, getopt_long
|
---|
440 | * won't have incremented optind.
|
---|
441 | */
|
---|
442 | optind = old_optind;
|
---|
443 | stopped_early = TRUE;
|
---|
444 | goto out;
|
---|
445 | } else if (optopt != '\0')
|
---|
446 | /* Use 1003.2 required message format */
|
---|
447 | fprintf(stderr,
|
---|
448 | _("%s: option requires an argument -- %c\n"),
|
---|
449 | myname, optopt);
|
---|
450 | /* else
|
---|
451 | let getopt print error message for us */
|
---|
452 | break;
|
---|
453 | }
|
---|
454 | if (c == 'S') /* --exec ends option processing */
|
---|
455 | break;
|
---|
456 | }
|
---|
457 | out:
|
---|
458 |
|
---|
459 | if (do_nostalgia)
|
---|
460 | nostalgia();
|
---|
461 |
|
---|
462 | /* check for POSIXLY_CORRECT environment variable */
|
---|
463 | if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
|
---|
464 | do_posix = TRUE;
|
---|
465 | if (do_lint)
|
---|
466 | lintwarn(
|
---|
467 | _("environment variable `POSIXLY_CORRECT' set: turning on `--posix'"));
|
---|
468 | }
|
---|
469 |
|
---|
470 | if (do_posix) {
|
---|
471 | if (do_traditional) /* both on command line */
|
---|
472 | warning(_("`--posix' overrides `--traditional'"));
|
---|
473 | else
|
---|
474 | do_traditional = TRUE;
|
---|
475 | /*
|
---|
476 | * POSIX compliance also implies
|
---|
477 | * no GNU extensions either.
|
---|
478 | */
|
---|
479 | }
|
---|
480 |
|
---|
481 | if (do_traditional && do_non_decimal_data) {
|
---|
482 | do_non_decimal_data = FALSE;
|
---|
483 | warning(_("`--posix'/`--traditional' overrides `--non-decimal-data'"));
|
---|
484 | }
|
---|
485 |
|
---|
486 | if (do_lint && os_is_setuid())
|
---|
487 | warning(_("running %s setuid root may be a security problem"), myname);
|
---|
488 |
|
---|
489 | /*
|
---|
490 | * Force profiling if this is pgawk.
|
---|
491 | * Don't bother if the command line already set profiling up.
|
---|
492 | */
|
---|
493 | if (! do_profiling)
|
---|
494 | init_profiling(& do_profiling, DEFAULT_PROFILE);
|
---|
495 |
|
---|
496 | /* load group set */
|
---|
497 | init_groupset();
|
---|
498 |
|
---|
499 | /* initialize the null string */
|
---|
500 | Nnull_string = make_string("", 0);
|
---|
501 | Nnull_string->numbr = 0.0;
|
---|
502 | Nnull_string->type = Node_val;
|
---|
503 | Nnull_string->flags = (PERM|STRCUR|STRING|NUMCUR|NUMBER);
|
---|
504 |
|
---|
505 | /*
|
---|
506 | * Tell the regex routines how they should work.
|
---|
507 | * Do this before initializing variables, since
|
---|
508 | * they could want to do a regexp compile.
|
---|
509 | */
|
---|
510 | resetup();
|
---|
511 |
|
---|
512 | /* Set up the special variables */
|
---|
513 | init_vars();
|
---|
514 |
|
---|
515 | /* Set up the field variables */
|
---|
516 | init_fields();
|
---|
517 |
|
---|
518 | /* Now process the pre-assignments */
|
---|
519 | for (i = 0; i <= numassigns; i++)
|
---|
520 | if (preassigns[i].stype == PRE_ASSIGN)
|
---|
521 | (void) arg_assign(preassigns[i].val, TRUE);
|
---|
522 | else /* PRE_ASSIGN_FS */
|
---|
523 | cmdline_fs(preassigns[i].val);
|
---|
524 | free(preassigns);
|
---|
525 |
|
---|
526 | if ((BINMODE & 1) != 0)
|
---|
527 | if (os_setbinmode(fileno(stdin), O_BINARY) == -1)
|
---|
528 | fatal(_("can't set binary mode on stdin (%s)"), strerror(errno));
|
---|
529 | if ((BINMODE & 2) != 0) {
|
---|
530 | if (os_setbinmode(fileno(stdout), O_BINARY) == -1)
|
---|
531 | fatal(_("can't set binary mode on stdout (%s)"), strerror(errno));
|
---|
532 | if (os_setbinmode(fileno(stderr), O_BINARY) == -1)
|
---|
533 | fatal(_("can't set binary mode on stderr (%s)"), strerror(errno));
|
---|
534 | }
|
---|
535 |
|
---|
536 | #ifdef GAWKDEBUG
|
---|
537 | setbuf(stdout, (char *) NULL); /* make debugging easier */
|
---|
538 | #endif
|
---|
539 | if (isatty(fileno(stdout)))
|
---|
540 | output_is_tty = TRUE;
|
---|
541 | /* No -f or --source options, use next arg */
|
---|
542 | if (numfiles == -1) {
|
---|
543 | if (optind > argc - 1 || stopped_early) /* no args left or no program */
|
---|
544 | usage(1, stderr);
|
---|
545 | srcfiles_add(CMDLINE, argv[optind]);
|
---|
546 | optind++;
|
---|
547 | }
|
---|
548 |
|
---|
549 | init_args(optind, argc, (char *) myname, argv);
|
---|
550 | (void) tokexpand();
|
---|
551 |
|
---|
552 | #if defined(LC_NUMERIC)
|
---|
553 | /*
|
---|
554 | * FRAGILE! CAREFUL!
|
---|
555 | * Pre-initing the variables with arg_assign() can change the
|
---|
556 | * locale. Force it to C before parsing the program.
|
---|
557 | */
|
---|
558 | setlocale(LC_NUMERIC, "C");
|
---|
559 | #endif
|
---|
560 |
|
---|
561 | /* Read in the program */
|
---|
562 | if (yyparse() != 0 || errcount != 0)
|
---|
563 | exit(1);
|
---|
564 |
|
---|
565 | free(srcfiles);
|
---|
566 |
|
---|
567 | if (do_intl)
|
---|
568 | exit(0);
|
---|
569 |
|
---|
570 | if (do_lint && begin_block == NULL && expression_value == NULL
|
---|
571 | && end_block == NULL)
|
---|
572 | lintwarn(_("no program text at all!"));
|
---|
573 |
|
---|
574 | if (do_lint)
|
---|
575 | shadow_funcs();
|
---|
576 |
|
---|
577 | init_profiling_signals();
|
---|
578 |
|
---|
579 | #if defined(LC_NUMERIC)
|
---|
580 | /* See comment above. */
|
---|
581 | setlocale(LC_NUMERIC, "");
|
---|
582 | #endif
|
---|
583 |
|
---|
584 | #if defined(HAVE_LOCALE_H)
|
---|
585 | loc = *localeconv(); /* Make a local copy of locale numeric info */
|
---|
586 | #endif
|
---|
587 |
|
---|
588 | /* Whew. Finally, run the program. */
|
---|
589 | if (begin_block != NULL) {
|
---|
590 | in_begin_rule = TRUE;
|
---|
591 | (void) interpret(begin_block);
|
---|
592 | }
|
---|
593 | in_begin_rule = FALSE;
|
---|
594 | if (! exiting && (expression_value != NULL || end_block != NULL))
|
---|
595 | do_input();
|
---|
596 | if (end_block != NULL) {
|
---|
597 | in_end_rule = TRUE;
|
---|
598 | (void) interpret(end_block);
|
---|
599 | }
|
---|
600 | in_end_rule = FALSE;
|
---|
601 | /*
|
---|
602 | * This used to be:
|
---|
603 | *
|
---|
604 | * if (close_io() != 0 && ! exiting && exit_val == 0)
|
---|
605 | * exit_val = 1;
|
---|
606 | *
|
---|
607 | * Other awks don't care about problems closing open files
|
---|
608 | * and pipes, in that it doesn't affect their exit status.
|
---|
609 | * So we no longer do either.
|
---|
610 | */
|
---|
611 | (void) close_io(& stdio_problem);
|
---|
612 | /*
|
---|
613 | * However, we do want to exit non-zero if there was a problem
|
---|
614 | * with stdout/stderr, so we reinstate a slightly different
|
---|
615 | * version of the above:
|
---|
616 | */
|
---|
617 | if (stdio_problem && ! exiting && exit_val == 0)
|
---|
618 | exit_val = 1;
|
---|
619 |
|
---|
620 | if (do_profiling) {
|
---|
621 | dump_prog(begin_block, expression_value, end_block);
|
---|
622 | dump_funcs();
|
---|
623 | }
|
---|
624 |
|
---|
625 | if (do_dump_vars)
|
---|
626 | dump_vars(varfile);
|
---|
627 |
|
---|
628 | if (do_tidy_mem)
|
---|
629 | release_all_vars();
|
---|
630 |
|
---|
631 | exit(exit_val); /* more portable */
|
---|
632 | return exit_val; /* to suppress warnings */
|
---|
633 | }
|
---|
634 |
|
---|
635 | /* add_src --- add one element to *srcfiles or *preassigns */
|
---|
636 |
|
---|
637 | static void
|
---|
638 | add_src(struct src **data, long *num, long *alloc, enum srctype stype, char *val)
|
---|
639 | {
|
---|
640 | #define INIT_SRC 4
|
---|
641 |
|
---|
642 | ++*num;
|
---|
643 |
|
---|
644 | if (*data == NULL) {
|
---|
645 | emalloc(*data, struct src *, INIT_SRC * sizeof(struct src), "add_src");
|
---|
646 | *alloc = INIT_SRC;
|
---|
647 | } else if (*num >= *alloc) {
|
---|
648 | (*alloc) *= 2;
|
---|
649 | erealloc(*data, struct src *, (*alloc) * sizeof(struct src), "add_src");
|
---|
650 | }
|
---|
651 |
|
---|
652 | (*data)[*num].stype = stype;
|
---|
653 | (*data)[*num].val = val;
|
---|
654 |
|
---|
655 | #undef INIT_SRC
|
---|
656 | }
|
---|
657 |
|
---|
658 | /* usage --- print usage information and exit */
|
---|
659 |
|
---|
660 | static void
|
---|
661 | usage(int exitval, FILE *fp)
|
---|
662 | {
|
---|
663 |
|
---|
664 | /* Not factoring out common stuff makes it easier to translate. */
|
---|
665 | fprintf(fp, _("Usage: %s [POSIX or GNU style options] -f progfile [--] file ...\n"),
|
---|
666 | myname);
|
---|
667 | fprintf(fp, _("Usage: %s [POSIX or GNU style options] [--] %cprogram%c file ...\n"),
|
---|
668 | myname, quote, quote);
|
---|
669 |
|
---|
670 | /* GNU long options info. This is too many options. */
|
---|
671 |
|
---|
672 | fputs(_("POSIX options:\t\tGNU long options:\n"), fp);
|
---|
673 | fputs(_("\t-f progfile\t\t--file=progfile\n"), fp);
|
---|
674 | fputs(_("\t-F fs\t\t\t--field-separator=fs\n"), fp);
|
---|
675 | fputs(_("\t-v var=val\t\t--assign=var=val\n"), fp);
|
---|
676 | fputs(_("\t-m[fr] val\n"), fp);
|
---|
677 | fputs(_("\t-W compat\t\t--compat\n"), fp);
|
---|
678 | fputs(_("\t-W copyleft\t\t--copyleft\n"), fp);
|
---|
679 | fputs(_("\t-W copyright\t\t--copyright\n"), fp);
|
---|
680 | fputs(_("\t-W dump-variables[=file]\t--dump-variables[=file]\n"), fp);
|
---|
681 | fputs(_("\t-W exec=file\t\t--exec=file\n"), fp);
|
---|
682 | fputs(_("\t-W gen-po\t\t--gen-po\n"), fp);
|
---|
683 | fputs(_("\t-W help\t\t\t--help\n"), fp);
|
---|
684 | fputs(_("\t-W lint[=fatal]\t\t--lint[=fatal]\n"), fp);
|
---|
685 | fputs(_("\t-W lint-old\t\t--lint-old\n"), fp);
|
---|
686 | fputs(_("\t-W non-decimal-data\t--non-decimal-data\n"), fp);
|
---|
687 | #ifdef NOSTALGIA
|
---|
688 | fputs(_("\t-W nostalgia\t\t--nostalgia\n"), fp);
|
---|
689 | #endif
|
---|
690 | #ifdef GAWKDEBUG
|
---|
691 | fputs(_("\t-W parsedebug\t\t--parsedebug\n"), fp);
|
---|
692 | #endif
|
---|
693 | fputs(_("\t-W profile[=file]\t--profile[=file]\n"), fp);
|
---|
694 | fputs(_("\t-W posix\t\t--posix\n"), fp);
|
---|
695 | fputs(_("\t-W re-interval\t\t--re-interval\n"), fp);
|
---|
696 | fputs(_("\t-W source=program-text\t--source=program-text\n"), fp);
|
---|
697 | fputs(_("\t-W traditional\t\t--traditional\n"), fp);
|
---|
698 | fputs(_("\t-W usage\t\t--usage\n"), fp);
|
---|
699 | fputs(_("\t-W version\t\t--version\n"), fp);
|
---|
700 |
|
---|
701 |
|
---|
702 | /* This is one string to make things easier on translators. */
|
---|
703 | fputs(_("\nTo report bugs, see node `Bugs' in `gawk.info', which is\n\
|
---|
704 | section `Reporting Problems and Bugs' in the printed version.\n\n"), fp);
|
---|
705 |
|
---|
706 | /* ditto */
|
---|
707 | fputs(_("gawk is a pattern scanning and processing language.\n\
|
---|
708 | By default it reads standard input and writes standard output.\n\n"), fp);
|
---|
709 |
|
---|
710 | /* ditto */
|
---|
711 | fputs(_("Examples:\n\tgawk '{ sum += $1 }; END { print sum }' file\n\
|
---|
712 | \tgawk -F: '{ print $1 }' /etc/passwd\n"), fp);
|
---|
713 |
|
---|
714 | fflush(fp);
|
---|
715 |
|
---|
716 | if (ferror(fp)) {
|
---|
717 | if (fp == stdout)
|
---|
718 | warning(_("error writing standard output (%s)"), strerror(errno));
|
---|
719 | exit(1);
|
---|
720 | }
|
---|
721 |
|
---|
722 | exit(exitval);
|
---|
723 | }
|
---|
724 |
|
---|
725 | /* copyleft --- print out the short GNU copyright information */
|
---|
726 |
|
---|
727 | static void
|
---|
728 | copyleft()
|
---|
729 | {
|
---|
730 | static const char blurb_part1[] =
|
---|
731 | N_("Copyright (C) 1989, 1991-%d Free Software Foundation.\n\
|
---|
732 | \n\
|
---|
733 | This program is free software; you can redistribute it and/or modify\n\
|
---|
734 | it under the terms of the GNU General Public License as published by\n\
|
---|
735 | the Free Software Foundation; either version 2 of the License, or\n\
|
---|
736 | (at your option) any later version.\n\
|
---|
737 | \n");
|
---|
738 | static const char blurb_part2[] =
|
---|
739 | N_("This program is distributed in the hope that it will be useful,\n\
|
---|
740 | but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
|
---|
741 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
|
---|
742 | GNU General Public License for more details.\n\
|
---|
743 | \n");
|
---|
744 | static const char blurb_part3[] =
|
---|
745 | N_("You should have received a copy of the GNU General Public License\n\
|
---|
746 | along with this program; if not, write to the Free Software\n\
|
---|
747 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n");
|
---|
748 |
|
---|
749 | /* multiple blurbs are needed for some brain dead compilers. */
|
---|
750 | printf(_(blurb_part1), UPDATE_YEAR); /* Last update year */
|
---|
751 | fputs(_(blurb_part2), stdout);
|
---|
752 | fputs(_(blurb_part3), stdout);
|
---|
753 | fflush(stdout);
|
---|
754 |
|
---|
755 | if (ferror(stdout)) {
|
---|
756 | warning(_("error writing standard output (%s)"), strerror(errno));
|
---|
757 | exit(1);
|
---|
758 | }
|
---|
759 |
|
---|
760 | exit(0);
|
---|
761 | }
|
---|
762 |
|
---|
763 | /* cmdline_fs --- set FS from the command line */
|
---|
764 |
|
---|
765 | static void
|
---|
766 | cmdline_fs(char *str)
|
---|
767 | {
|
---|
768 | register NODE **tmp;
|
---|
769 |
|
---|
770 | tmp = get_lhs(FS_node, (Func_ptr *) 0, FALSE);
|
---|
771 | unref(*tmp);
|
---|
772 | /*
|
---|
773 | * Only if in full compatibility mode check for the stupid special
|
---|
774 | * case so -F\t works as documented in awk book even though the shell
|
---|
775 | * hands us -Ft. Bleah!
|
---|
776 | *
|
---|
777 | * Thankfully, Posix didn't propagate this "feature".
|
---|
778 | */
|
---|
779 | if (str[0] == 't' && str[1] == '\0') {
|
---|
780 | if (do_lint)
|
---|
781 | lintwarn(_("-Ft does not set FS to tab in POSIX awk"));
|
---|
782 | if (do_traditional && ! do_posix)
|
---|
783 | str[0] = '\t';
|
---|
784 | }
|
---|
785 | *tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
|
---|
786 | set_FS();
|
---|
787 | }
|
---|
788 |
|
---|
789 | /* init_args --- set up ARGV from stuff on the command line */
|
---|
790 |
|
---|
791 | static void
|
---|
792 | init_args(int argc0, int argc, char *argv0, char **argv)
|
---|
793 | {
|
---|
794 | int i, j;
|
---|
795 | NODE **aptr;
|
---|
796 |
|
---|
797 | ARGV_node = install("ARGV", node((NODE *) NULL, Node_var_array, (NODE *) NULL));
|
---|
798 | aptr = assoc_lookup(ARGV_node, tmp_number(0.0), FALSE);
|
---|
799 | *aptr = make_string(argv0, strlen(argv0));
|
---|
800 | (*aptr)->flags |= MAYBE_NUM;
|
---|
801 | for (i = argc0, j = 1; i < argc; i++) {
|
---|
802 | aptr = assoc_lookup(ARGV_node, tmp_number((AWKNUM) j), FALSE);
|
---|
803 | *aptr = make_string(argv[i], strlen(argv[i]));
|
---|
804 | (*aptr)->flags |= MAYBE_NUM;
|
---|
805 | j++;
|
---|
806 | }
|
---|
807 | ARGC_node = install("ARGC",
|
---|
808 | node(make_number((AWKNUM) j), Node_var, (NODE *) NULL));
|
---|
809 | }
|
---|
810 |
|
---|
811 | /*
|
---|
812 | * Set all the special variables to their initial values.
|
---|
813 | * Note that some of the variables that have set_FOO routines should
|
---|
814 | * *N*O*T* have those routines called upon initialization, and thus
|
---|
815 | * they have NULL entries in that field. This is notably true of FS
|
---|
816 | * and IGNORECASE.
|
---|
817 | */
|
---|
818 | struct varinit {
|
---|
819 | NODE **spec;
|
---|
820 | const char *name;
|
---|
821 | NODETYPE type;
|
---|
822 | const char *strval;
|
---|
823 | AWKNUM numval;
|
---|
824 | Func_ptr assign;
|
---|
825 | };
|
---|
826 | static const struct varinit varinit[] = {
|
---|
827 | {&CONVFMT_node, "CONVFMT", Node_CONVFMT, "%.6g", 0, set_CONVFMT },
|
---|
828 | {&NF_node, "NF", Node_NF, NULL, -1, NULL },
|
---|
829 | {&FIELDWIDTHS_node, "FIELDWIDTHS", Node_FIELDWIDTHS, "", 0, NULL },
|
---|
830 | {&NR_node, "NR", Node_NR, NULL, 0, set_NR },
|
---|
831 | {&FNR_node, "FNR", Node_FNR, NULL, 0, set_FNR },
|
---|
832 | {&FS_node, "FS", Node_FS, " ", 0, NULL },
|
---|
833 | {&RS_node, "RS", Node_RS, "\n", 0, set_RS },
|
---|
834 | {&IGNORECASE_node, "IGNORECASE", Node_IGNORECASE, NULL, 0, NULL },
|
---|
835 | {&FILENAME_node, "FILENAME", Node_var, "", 0, NULL },
|
---|
836 | {&OFS_node, "OFS", Node_OFS, " ", 0, set_OFS },
|
---|
837 | {&ORS_node, "ORS", Node_ORS, "\n", 0, set_ORS },
|
---|
838 | {&OFMT_node, "OFMT", Node_OFMT, "%.6g", 0, set_OFMT },
|
---|
839 | {&RLENGTH_node, "RLENGTH", Node_var, NULL, 0, NULL },
|
---|
840 | {&RSTART_node, "RSTART", Node_var, NULL, 0, NULL },
|
---|
841 | {&SUBSEP_node, "SUBSEP", Node_SUBSEP, "\034", 0, NULL },
|
---|
842 | {&ARGIND_node, "ARGIND", Node_var, NULL, 0, NULL },
|
---|
843 | {&ERRNO_node, "ERRNO", Node_var, NULL, 0, NULL },
|
---|
844 | {&RT_node, "RT", Node_var, "", 0, NULL },
|
---|
845 | {&BINMODE_node, "BINMODE", Node_BINMODE, NULL, 0, NULL },
|
---|
846 | {&LINT_node, "LINT", Node_LINT, NULL, 0, NULL },
|
---|
847 | {&TEXTDOMAIN_node, "TEXTDOMAIN", Node_TEXTDOMAIN, "messages", 0, set_TEXTDOMAIN },
|
---|
848 | {0, NULL, Node_illegal, NULL, 0, NULL },
|
---|
849 | };
|
---|
850 |
|
---|
851 | /* init_vars --- actually initialize everything in the symbol table */
|
---|
852 |
|
---|
853 | static void
|
---|
854 | init_vars()
|
---|
855 | {
|
---|
856 | register const struct varinit *vp;
|
---|
857 |
|
---|
858 | for (vp = varinit; vp->name; vp++) {
|
---|
859 | *(vp->spec) = install((char *) vp->name,
|
---|
860 | node(vp->strval == NULL ? make_number(vp->numval)
|
---|
861 | : make_string((char *) vp->strval,
|
---|
862 | strlen(vp->strval)),
|
---|
863 | vp->type, (NODE *) NULL));
|
---|
864 | if (vp->assign)
|
---|
865 | (*(vp->assign))();
|
---|
866 | }
|
---|
867 |
|
---|
868 | /* Set up deferred variables (loaded only when accessed). */
|
---|
869 | if (! do_traditional)
|
---|
870 | register_deferred_variable("PROCINFO", load_procinfo);
|
---|
871 | register_deferred_variable("ENVIRON", load_environ);
|
---|
872 | }
|
---|
873 |
|
---|
874 | /* load_environ --- populate the ENVIRON array */
|
---|
875 |
|
---|
876 | static NODE *
|
---|
877 | load_environ()
|
---|
878 | {
|
---|
879 | #if ! defined(TANDEM)
|
---|
880 | #if ! (defined(MSDOS) && !defined(DJGPP)) && ! defined(OS2) && ! (defined(VMS) && defined(__DECC))
|
---|
881 | extern char **environ;
|
---|
882 | #endif
|
---|
883 | register char *var, *val;
|
---|
884 | NODE **aptr;
|
---|
885 | register int i;
|
---|
886 | #endif /* TANDEM */
|
---|
887 |
|
---|
888 | ENVIRON_node = install("ENVIRON",
|
---|
889 | node((NODE *) NULL, Node_var_array, (NODE *) NULL));
|
---|
890 | #if ! defined(TANDEM)
|
---|
891 | for (i = 0; environ[i] != NULL; i++) {
|
---|
892 | static char nullstr[] = "";
|
---|
893 |
|
---|
894 | var = environ[i];
|
---|
895 | val = strchr(var, '=');
|
---|
896 | if (val != NULL)
|
---|
897 | *val++ = '\0';
|
---|
898 | else
|
---|
899 | val = nullstr;
|
---|
900 | aptr = assoc_lookup(ENVIRON_node, tmp_string(var, strlen(var)),
|
---|
901 | FALSE);
|
---|
902 | *aptr = make_string(val, strlen(val));
|
---|
903 | (*aptr)->flags |= MAYBE_NUM;
|
---|
904 |
|
---|
905 | /* restore '=' so that system() gets a valid environment */
|
---|
906 | if (val != nullstr)
|
---|
907 | *--val = '=';
|
---|
908 | }
|
---|
909 | /*
|
---|
910 | * Put AWKPATH into ENVIRON if it's not there.
|
---|
911 | * This allows querying it from within awk programs.
|
---|
912 | */
|
---|
913 | if (getenv("AWKPATH") == NULL) {
|
---|
914 | aptr = assoc_lookup(ENVIRON_node, tmp_string("AWKPATH", 7), FALSE);
|
---|
915 | *aptr = make_string(defpath, strlen(defpath));
|
---|
916 | }
|
---|
917 | #endif /* TANDEM */
|
---|
918 | return ENVIRON_node;
|
---|
919 | }
|
---|
920 |
|
---|
921 | /* load_procinfo --- populate the PROCINFO array */
|
---|
922 |
|
---|
923 | static NODE *
|
---|
924 | load_procinfo()
|
---|
925 | {
|
---|
926 | int i;
|
---|
927 | NODE **aptr;
|
---|
928 | char name[100];
|
---|
929 | AWKNUM value;
|
---|
930 |
|
---|
931 | PROCINFO_node = install("PROCINFO",
|
---|
932 | node((NODE *) NULL, Node_var_array, (NODE *) NULL));
|
---|
933 |
|
---|
934 | #ifdef GETPGRP_VOID
|
---|
935 | #define getpgrp_arg() /* nothing */
|
---|
936 | #else
|
---|
937 | #define getpgrp_arg() getpid()
|
---|
938 | #endif
|
---|
939 |
|
---|
940 | value = getpgrp(getpgrp_arg());
|
---|
941 | aptr = assoc_lookup(PROCINFO_node, tmp_string("pgrpid", 6), FALSE);
|
---|
942 | *aptr = make_number(value);
|
---|
943 |
|
---|
944 | /*
|
---|
945 | * could put a lot of this into a table, but then there's
|
---|
946 | * portability problems declaring all the functions. so just
|
---|
947 | * do it the slow and stupid way. sigh.
|
---|
948 | */
|
---|
949 |
|
---|
950 | aptr = assoc_lookup(PROCINFO_node, tmp_string("version", 7), FALSE);
|
---|
951 | *aptr = make_string(VERSION, strlen(VERSION));
|
---|
952 |
|
---|
953 | value = getpid();
|
---|
954 | aptr = assoc_lookup(PROCINFO_node, tmp_string("pid", 3), FALSE);
|
---|
955 | *aptr = make_number(value);
|
---|
956 |
|
---|
957 | value = getppid();
|
---|
958 | aptr = assoc_lookup(PROCINFO_node, tmp_string("ppid", 4), FALSE);
|
---|
959 | *aptr = make_number(value);
|
---|
960 |
|
---|
961 | value = getuid();
|
---|
962 | aptr = assoc_lookup(PROCINFO_node, tmp_string("uid", 3), FALSE);
|
---|
963 | *aptr = make_number(value);
|
---|
964 |
|
---|
965 | value = geteuid();
|
---|
966 | aptr = assoc_lookup(PROCINFO_node, tmp_string("euid", 4), FALSE);
|
---|
967 | *aptr = make_number(value);
|
---|
968 |
|
---|
969 | value = getgid();
|
---|
970 | aptr = assoc_lookup(PROCINFO_node, tmp_string("gid", 3), FALSE);
|
---|
971 | *aptr = make_number(value);
|
---|
972 |
|
---|
973 | value = getegid();
|
---|
974 | aptr = assoc_lookup(PROCINFO_node, tmp_string("egid", 4), FALSE);
|
---|
975 | *aptr = make_number(value);
|
---|
976 |
|
---|
977 | aptr = assoc_lookup(PROCINFO_node, tmp_string("FS", 2), FALSE);
|
---|
978 | *aptr = (using_fieldwidths() ? make_string("FIELDWIDTHS", 11) :
|
---|
979 | make_string("FS", 2) );
|
---|
980 |
|
---|
981 | #if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
|
---|
982 | for (i = 0; i < ngroups; i++) {
|
---|
983 | sprintf(name, "group%d", i + 1);
|
---|
984 | value = groupset[i];
|
---|
985 | aptr = assoc_lookup(PROCINFO_node, tmp_string(name, strlen(name)), FALSE);
|
---|
986 | *aptr = make_number(value);
|
---|
987 | }
|
---|
988 | if (groupset) {
|
---|
989 | free(groupset);
|
---|
990 | groupset = NULL;
|
---|
991 | }
|
---|
992 | #endif
|
---|
993 | return PROCINFO_node;
|
---|
994 | }
|
---|
995 |
|
---|
996 | /* arg_assign --- process a command-line assignment */
|
---|
997 |
|
---|
998 | int
|
---|
999 | arg_assign(char *arg, int initing)
|
---|
1000 | {
|
---|
1001 | char *cp, *cp2;
|
---|
1002 | int badvar;
|
---|
1003 | Func_ptr after_assign = NULL;
|
---|
1004 | NODE *var;
|
---|
1005 | NODE *it;
|
---|
1006 | NODE **lhs;
|
---|
1007 |
|
---|
1008 | if (! initing && disallow_var_assigns)
|
---|
1009 | return FALSE; /* --exec */
|
---|
1010 |
|
---|
1011 | cp = strchr(arg, '=');
|
---|
1012 |
|
---|
1013 | if (cp == NULL) {
|
---|
1014 | if (! initing)
|
---|
1015 | return FALSE; /* This is file name, not assignment. */
|
---|
1016 |
|
---|
1017 | fprintf(stderr,
|
---|
1018 | _("%s: `%s' argument to `-v' not in `var=value' form\n\n"),
|
---|
1019 | myname, arg);
|
---|
1020 | usage(1, stderr);
|
---|
1021 | }
|
---|
1022 |
|
---|
1023 | *cp++ = '\0';
|
---|
1024 |
|
---|
1025 | /* first check that the variable name has valid syntax */
|
---|
1026 | badvar = FALSE;
|
---|
1027 | if (! ISALPHA(arg[0]) && arg[0] != '_')
|
---|
1028 | badvar = TRUE;
|
---|
1029 | else
|
---|
1030 | for (cp2 = arg+1; *cp2; cp2++)
|
---|
1031 | if (! ISALNUM(*cp2) && *cp2 != '_') {
|
---|
1032 | badvar = TRUE;
|
---|
1033 | break;
|
---|
1034 | }
|
---|
1035 |
|
---|
1036 | if (badvar) {
|
---|
1037 | if (initing)
|
---|
1038 | fatal(_("`%s' is not a legal variable name"), arg);
|
---|
1039 |
|
---|
1040 | if (do_lint)
|
---|
1041 | lintwarn(_("`%s' is not a variable name, looking for file `%s=%s'"),
|
---|
1042 | arg, arg, cp);
|
---|
1043 | } else {
|
---|
1044 | /*
|
---|
1045 | * Recent versions of nawk expand escapes inside assignments.
|
---|
1046 | * This makes sense, so we do it too.
|
---|
1047 | */
|
---|
1048 | it = make_str_node(cp, strlen(cp), SCAN);
|
---|
1049 | it->flags |= MAYBE_NUM;
|
---|
1050 | #ifdef LC_NUMERIC
|
---|
1051 | setlocale(LC_NUMERIC, "C");
|
---|
1052 | (void) force_number(it);
|
---|
1053 | setlocale(LC_NUMERIC, "");
|
---|
1054 | #endif /* LC_NUMERIC */
|
---|
1055 | var = variable(arg, FALSE, Node_var);
|
---|
1056 | lhs = get_lhs(var, &after_assign, FALSE);
|
---|
1057 | unref(*lhs);
|
---|
1058 | *lhs = it;
|
---|
1059 | if (after_assign != NULL)
|
---|
1060 | (*after_assign)();
|
---|
1061 | }
|
---|
1062 |
|
---|
1063 | *--cp = '='; /* restore original text of ARGV */
|
---|
1064 |
|
---|
1065 | return ! badvar;
|
---|
1066 | }
|
---|
1067 |
|
---|
1068 | /* catchsig --- catch signals */
|
---|
1069 |
|
---|
1070 | static RETSIGTYPE
|
---|
1071 | catchsig(int sig)
|
---|
1072 | {
|
---|
1073 | if (sig == SIGFPE) {
|
---|
1074 | fatal(_("floating point exception"));
|
---|
1075 | } else if (sig == SIGSEGV
|
---|
1076 | #ifdef SIGBUS
|
---|
1077 | || sig == SIGBUS
|
---|
1078 | #endif
|
---|
1079 | ) {
|
---|
1080 | set_loc(__FILE__, __LINE__);
|
---|
1081 | msg(_("fatal error: internal error"));
|
---|
1082 | /* fatal won't abort() if not compiled for debugging */
|
---|
1083 | abort();
|
---|
1084 | } else
|
---|
1085 | cant_happen();
|
---|
1086 | /* NOTREACHED */
|
---|
1087 | }
|
---|
1088 |
|
---|
1089 | /* nostalgia --- print the famous error message and die */
|
---|
1090 |
|
---|
1091 | static void
|
---|
1092 | nostalgia()
|
---|
1093 | {
|
---|
1094 | /*
|
---|
1095 | * N.B.: This string is not gettextized, on purpose.
|
---|
1096 | * So there.
|
---|
1097 | */
|
---|
1098 | fprintf(stderr, "awk: bailing out near line 1\n");
|
---|
1099 | fflush(stderr);
|
---|
1100 | abort();
|
---|
1101 | }
|
---|
1102 |
|
---|
1103 | /* version --- print version message */
|
---|
1104 |
|
---|
1105 | static void
|
---|
1106 | version()
|
---|
1107 | {
|
---|
1108 | printf("%s\n", version_string);
|
---|
1109 | /*
|
---|
1110 | * Per GNU coding standards, print copyright info,
|
---|
1111 | * then exit successfully, do nothing else.
|
---|
1112 | */
|
---|
1113 | copyleft();
|
---|
1114 | exit(0);
|
---|
1115 | }
|
---|
1116 |
|
---|
1117 | /* init_fds --- check for 0, 1, 2, open on /dev/null if possible */
|
---|
1118 |
|
---|
1119 | static void
|
---|
1120 | init_fds()
|
---|
1121 | {
|
---|
1122 | struct stat sbuf;
|
---|
1123 | int fd;
|
---|
1124 | int newfd;
|
---|
1125 | char const *const opposite_mode[] = {"w", "r", "r"};
|
---|
1126 |
|
---|
1127 | /* maybe no stderr, don't bother with error mesg */
|
---|
1128 | for (fd = 0; fd <= 2; fd++) {
|
---|
1129 | if (fstat(fd, &sbuf) < 0) {
|
---|
1130 | #if MAKE_A_HEROIC_EFFORT
|
---|
1131 | if (do_lint)
|
---|
1132 | lintwarn(_("no pre-opened fd %d"), fd);
|
---|
1133 | #endif
|
---|
1134 | newfd = devopen("/dev/null", opposite_mode[fd]);
|
---|
1135 | /* turn off some compiler warnings "set but not used" */
|
---|
1136 | newfd += 0;
|
---|
1137 | #ifdef MAKE_A_HEROIC_EFFORT
|
---|
1138 | if (do_lint && newfd < 0)
|
---|
1139 | lintwarn(_("could not pre-open /dev/null for fd %d"), fd);
|
---|
1140 | #endif
|
---|
1141 | }
|
---|
1142 | }
|
---|
1143 | }
|
---|
1144 |
|
---|
1145 | /* init_groupset --- initialize groupset */
|
---|
1146 |
|
---|
1147 | static void
|
---|
1148 | init_groupset()
|
---|
1149 | {
|
---|
1150 | #if defined(HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
|
---|
1151 | #ifdef GETGROUPS_NOT_STANDARD
|
---|
1152 | /* For systems that aren't standards conformant, use old way. */
|
---|
1153 | ngroups = NGROUPS_MAX;
|
---|
1154 | #else
|
---|
1155 | /*
|
---|
1156 | * If called with 0 for both args, return value is
|
---|
1157 | * total number of groups.
|
---|
1158 | */
|
---|
1159 | ngroups = getgroups(0, NULL);
|
---|
1160 | #endif
|
---|
1161 | if (ngroups == -1)
|
---|
1162 | fatal(_("could not find groups: %s"), strerror(errno));
|
---|
1163 | else if (ngroups == 0)
|
---|
1164 | return;
|
---|
1165 |
|
---|
1166 | /* fill in groups */
|
---|
1167 | emalloc(groupset, GETGROUPS_T *, ngroups * sizeof(GETGROUPS_T), "init_groupset");
|
---|
1168 |
|
---|
1169 | ngroups = getgroups(ngroups, groupset);
|
---|
1170 | if (ngroups == -1)
|
---|
1171 | fatal(_("could not find groups: %s"), strerror(errno));
|
---|
1172 | #endif
|
---|
1173 | }
|
---|