source: vendor/gawk/3.1.5/main.c@ 3508

Last change on this file since 3508 was 3076, checked in by bird, 18 years ago

gawk 3.1.5

File size: 31.3 KB
Line 
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
43static const char *varfile = DEFAULT_VARFILE;
44
45static void usage P((int exitval, FILE *fp)) ATTRIBUTE_NORETURN;
46static void copyleft P((void)) ATTRIBUTE_NORETURN;
47static void cmdline_fs P((char *str));
48static void init_args P((int argc0, int argc, char *argv0, char **argv));
49static void init_vars P((void));
50static NODE *load_environ P((void));
51static NODE *load_procinfo P((void));
52static void add_src P((struct src **data, long *num, long *alloc, enum srctype stype, char *val));
53static RETSIGTYPE catchsig P((int sig)) ATTRIBUTE_NORETURN;
54static void nostalgia P((void)) ATTRIBUTE_NORETURN;
55static void version P((void)) ATTRIBUTE_NORETURN;
56static void init_fds P((void));
57static void init_groupset P((void));
58
59/* These nodes store all the special variables AWK uses */
60NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
61NODE *ENVIRON_node, *ERRNO_node, *FIELDWIDTHS_node, *FILENAME_node, *FNR_node;
62NODE *FS_node, *IGNORECASE_node, *NF_node, *NR_node, *OFMT_node, *OFS_node;
63NODE *ORS_node, *PROCINFO_node, *RLENGTH_node, *RSTART_node, *RS_node;
64NODE *RT_node, *SUBSEP_node, *LINT_node, *TEXTDOMAIN_node;
65
66long NF;
67long NR;
68long FNR;
69int BINMODE;
70int IGNORECASE;
71char *OFS;
72char *ORS;
73char *OFMT;
74char *TEXTDOMAIN;
75int 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 */
83char *CONVFMT = "%.6g";
84
85
86int errcount = 0; /* error counter, used by yyerror() */
87
88NODE *Nnull_string; /* The global null string */
89
90#if defined(HAVE_LOCALE_H)
91struct lconv loc; /* current locale */
92#endif /* defined(HAVE_LOCALE_H) */
93
94/* The name the program was invoked under, for error messages */
95const char *myname;
96
97/* A block of AWK code to be run before running the program */
98NODE *begin_block = NULL;
99
100/* A block of AWK code to be run after the last input file */
101NODE *end_block = NULL;
102
103int exiting = FALSE; /* Was an "exit" statement executed? */
104int exit_val = 0; /* optional exit value */
105
106#if defined(YYDEBUG) || defined(GAWKDEBUG)
107extern int yydebug;
108#endif
109
110struct src *srcfiles = NULL; /* source file name(s) */
111long numfiles = -1; /* how many source files */
112static long allocfiles; /* for how many is *srcfiles allocated */
113
114#define srcfiles_add(stype, val) \
115 add_src(&srcfiles, &numfiles, &allocfiles, stype, val)
116
117static struct src *preassigns = NULL; /* requested via -v or -F */
118static long numassigns = -1; /* how many of them */
119static long allocassigns; /* for how many is allocated */
120
121static 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
129int do_traditional = FALSE; /* no gnu extensions, add traditional weirdnesses */
130int do_posix = FALSE; /* turn off gnu and unix extensions */
131int do_lint = FALSE; /* provide warnings about questionable stuff */
132int do_lint_old = FALSE; /* warn about stuff not in V7 awk */
133int do_intl = FALSE; /* dump locale-izable strings to stdout */
134int do_non_decimal_data = FALSE; /* allow octal/hex C style DATA. Use with caution! */
135int do_nostalgia = FALSE; /* provide a blast from the past */
136int do_intervals = FALSE; /* allow {...,...} in regexps */
137int do_profiling = FALSE; /* profile and pretty print the program */
138int do_dump_vars = FALSE; /* dump all global variables at end */
139int do_tidy_mem = FALSE; /* release vars when done */
140
141int in_begin_rule = FALSE; /* we're in a BEGIN rule */
142int in_end_rule = FALSE; /* we're in a END rule */
143int whiny_users = FALSE; /* do things that whiny users want */
144#ifdef MBS_SUPPORT
145int gawk_mb_cur_max; /* MB_CUR_MAX value, see comment in main() */
146#else
147const int gawk_mb_cur_max = 1;
148#endif
149
150int output_is_tty = FALSE; /* control flushing of output */
151
152extern const char *version_string;
153
154#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
155GETGROUPS_T *groupset; /* current group set */
156int ngroups; /* size of said set */
157#endif
158
159/* The parse tree is stored here. */
160NODE *expression_value;
161
162#if _MSC_VER == 510
163void (*lintfunc) P((va_list va_alist, ...)) = warning;
164#else
165#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
166void (*lintfunc) P((const char *mesg, ...)) = warning;
167#else
168void (*lintfunc) () = warning;
169#endif
170#endif
171
172static 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
207int
208main(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 }
457out:
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
637static void
638add_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
660static void
661usage(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\
704section `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\
708By 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
727static void
728copyleft()
729{
730 static const char blurb_part1[] =
731 N_("Copyright (C) 1989, 1991-%d Free Software Foundation.\n\
732\n\
733This program is free software; you can redistribute it and/or modify\n\
734it under the terms of the GNU General Public License as published by\n\
735the 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\
740but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
741MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
742GNU 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\
746along with this program; if not, write to the Free Software\n\
747Foundation, 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
765static void
766cmdline_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
791static void
792init_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 */
818struct varinit {
819 NODE **spec;
820 const char *name;
821 NODETYPE type;
822 const char *strval;
823 AWKNUM numval;
824 Func_ptr assign;
825};
826static 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
853static void
854init_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
876static NODE *
877load_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
923static NODE *
924load_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
998int
999arg_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
1070static RETSIGTYPE
1071catchsig(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
1091static void
1092nostalgia()
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
1105static void
1106version()
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
1119static void
1120init_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
1147static void
1148init_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}
Note: See TracBrowser for help on using the repository browser.