~vcs-imports/gawk/master

« back to all changes in this revision

Viewing changes to main.c

Update README.solaris.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * main.c -- Code generator and main program for gawk.
 
2
 * main.c -- Code generator and main program for gawk. 
3
3
 */
4
4
 
5
 
/*
6
 
 * Copyright (C) 1986, 1988, 1989, 1991-2024,
7
 
 * the Free Software Foundation, Inc.
8
 
 *
 
5
/* 
 
6
 * Copyright (C) 1986, 1988, 1989, 1991-2013 the Free Software Foundation, Inc.
 
7
 * 
9
8
 * This file is part of GAWK, the GNU implementation of the
10
9
 * AWK Programming Language.
11
 
 *
 
10
 * 
12
11
 * GAWK is free software; you can redistribute it and/or modify
13
12
 * it under the terms of the GNU General Public License as published by
14
13
 * the Free Software Foundation; either version 3 of the License, or
15
14
 * (at your option) any later version.
16
 
 *
 
15
 * 
17
16
 * GAWK is distributed in the hope that it will be useful,
18
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
19
 * GNU General Public License for more details.
21
 
 *
 
20
 * 
22
21
 * You should have received a copy of the GNU General Public License
23
22
 * along with this program; if not, write to the Free Software
24
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
25
24
 */
26
25
 
27
26
/* FIX THIS BEFORE EVERY RELEASE: */
28
 
#define UPDATE_YEAR     2024
 
27
#define UPDATE_YEAR     2013
29
28
 
30
29
#include "awk.h"
31
30
#include "getopt.h"
49
48
static void init_vars(void);
50
49
static NODE *load_environ(void);
51
50
static NODE *load_procinfo(void);
52
 
static void catchsig(int sig);
 
51
static RETSIGTYPE catchsig(int sig);
 
52
#ifdef HAVE_LIBSIGSEGV
 
53
static int catchsegv(void *fault_address, int serious);
 
54
static void catchstackoverflow(int emergency, stackoverflow_context_t scp);
 
55
#endif
 
56
static void nostalgia(void) ATTRIBUTE_NORETURN;
53
57
static void version(void) ATTRIBUTE_NORETURN;
54
58
static void init_fds(void);
55
59
static void init_groupset(void);
56
60
static void save_argv(int, char **);
57
 
static const char *platform_name();
58
 
static void check_pma_security(const char *pma_file);
 
61
 
 
62
extern int debug_prog(INSTRUCTION *pc); /* debug.c */
 
63
extern int init_debug();        /* debug.c */
59
64
 
60
65
/* These nodes store all the special variables AWK uses */
61
66
NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
62
 
static NODE *ENVIRON_node;
63
 
NODE *ERRNO_node, *FIELDWIDTHS_node, *FILENAME_node;
 
67
NODE *ENVIRON_node, *ERRNO_node, *FIELDWIDTHS_node, *FILENAME_node;
64
68
NODE *FNR_node, *FPAT_node, *FS_node, *IGNORECASE_node, *LINT_node;
65
69
NODE *NF_node, *NR_node, *OFMT_node, *OFS_node, *ORS_node, *PROCINFO_node;
66
70
NODE *RLENGTH_node, *RSTART_node, *RS_node, *RT_node, *SUBSEP_node;
71
75
long NR;
72
76
long FNR;
73
77
int BINMODE;
74
 
bool IGNORECASE;
 
78
int IGNORECASE;
75
79
char *OFS;
76
80
char *ORS;
77
81
char *OFMT;
83
87
 *      set_CONVFMT -> fmt_index -> force_string: gets NULL CONVFMT
84
88
 * Fun, fun, fun, fun.
85
89
 */
86
 
const char *CONVFMT = "%.6g";
 
90
char *CONVFMT = "%.6g";
87
91
 
88
92
NODE *Nnull_string;             /* The global null string */
89
93
 
128
132
 
129
133
static void add_preassign(enum assign_type type, char *val);
130
134
 
131
 
static void parse_args(int argc, char **argv);
132
 
static void set_locale_stuff(void);
133
 
static bool stopped_early = false;
134
 
 
135
 
bool using_persistent_malloc = false;
136
 
enum do_flag_values do_flags = DO_FLAG_NONE;
137
 
bool do_itrace = false;                 /* provide simple instruction trace */
138
 
bool do_optimize = true;                /* apply default optimizations */
 
135
int do_flags = false;
 
136
bool do_optimize = false;               /* apply default optimizations */
 
137
static int do_nostalgia = false;        /* provide a blast from the past */
139
138
static int do_binary = false;           /* hands off my data! */
140
139
static int do_version = false;          /* print version info */
141
 
static const char *locale = "";         /* default value to setlocale */
142
 
static const char *locale_dir = LOCALEDIR;      /* default locale dir */
143
 
#ifdef USE_PERSISTENT_MALLOC
144
 
const char *get_pma_version(void);
145
 
#endif
146
140
 
147
141
int use_lc_numeric = false;     /* obey locale for decimal point */
148
142
 
 
143
#if MBS_SUPPORT
149
144
int gawk_mb_cur_max;            /* MB_CUR_MAX value, see comment in main() */
 
145
#endif
150
146
 
151
147
FILE *output_fp;                /* default gawk output, can be redirected in the debugger */
152
148
bool output_is_tty = false;     /* control flushing of output */
169
165
        { "bignum",             no_argument,            NULL,   'M' },
170
166
        { "characters-as-bytes", no_argument,           & do_binary,     'b' },
171
167
        { "copyright",          no_argument,            NULL,   'C' },
172
 
        { "csv",                no_argument,            NULL,   'k' },
173
168
        { "debug",              optional_argument,      NULL,   'D' },
174
169
        { "dump-variables",     optional_argument,      NULL,   'd' },
175
170
        { "exec",               required_argument,      NULL,   'E' },
181
176
        { "lint",               optional_argument,      NULL,   'L' },
182
177
        { "lint-old",           no_argument,            NULL,   't' },
183
178
        { "load",               required_argument,      NULL,   'l' },
184
 
#if defined(LOCALEDEBUG)
185
 
        { "locale",             required_argument,      NULL,   'Z' },
186
 
#endif
187
179
        { "non-decimal-data",   no_argument,            NULL,   'n' },
188
 
        { "no-optimize",        no_argument,            NULL,   's' },
 
180
        { "nostalgia",          no_argument,            & do_nostalgia, 1 },
189
181
        { "optimize",           no_argument,            NULL,   'O' },
190
182
#if defined(YYDEBUG) || defined(GAWKDEBUG)
191
183
        { "parsedebug",         no_argument,            NULL,   'Y' },
192
184
#endif
193
 
        { "persist",            optional_argument,      NULL,   'T' },
194
185
        { "posix",              no_argument,            NULL,   'P' },
195
186
        { "pretty-print",       optional_argument,      NULL,   'o' },
196
187
        { "profile",            optional_argument,      NULL,   'p' },
197
188
        { "re-interval",        no_argument,            NULL,   'r' },
198
189
        { "sandbox",            no_argument,            NULL,   'S' },
199
190
        { "source",             required_argument,      NULL,   'e' },
200
 
        { "trace",              no_argument,            NULL,   'I' },
201
191
        { "traditional",        no_argument,            NULL,   'c' },
202
192
        { "use-lc-numeric",     no_argument,            & use_lc_numeric, 1 },
203
193
        { "version",            no_argument,            & do_version, 'V' },
209
199
int
210
200
main(int argc, char **argv)
211
201
{
 
202
        /*
 
203
         * The + on the front tells GNU getopt not to rearrange argv.
 
204
         */
 
205
        const char *optlist = "+F:f:v:W;bcCd::D::e:E:gh:i:l:L:nNo::Op::MPrStVY";
 
206
        bool stopped_early = false;
 
207
        int old_optind;
212
208
        int i;
213
 
        bool have_srcfile = false;
 
209
        int c;
 
210
        char *scan, *src;
 
211
        char *extra_stack;
 
212
        int have_srcfile = 0;
214
213
        SRCFILE *s;
215
 
        char *cp;
216
 
        const char *persist_file = getenv("GAWK_PERSIST_FILE"); /* backing file for PMA */
217
 
#if defined(LOCALEDEBUG)
218
 
        const char *initial_locale;
219
 
#endif
220
 
 
221
 
        myname = gawk_name(argv[0]);
222
 
 
223
 
        check_pma_security(persist_file);
224
 
 
225
 
        int pma_result = pma_init(1, persist_file);
226
 
        if (pma_result != 0) {
227
 
                // don't use 'fatal' routine, memory can't be allocated
228
 
                fprintf(stderr, _("%s: fatal: persistent memory allocator failed to initialize: return value %d, pma.c line: %d.\n"),
229
 
                                myname, pma_result, pma_errno);
230
 
                exit(EXIT_FATAL);
231
 
        }
232
 
 
233
 
        using_persistent_malloc = (persist_file != NULL);
234
 
#ifndef USE_PERSISTENT_MALLOC
235
 
        if (using_persistent_malloc)
236
 
                warning(_("persistent memory is not supported"));
237
 
#endif
238
 
#ifdef HAVE_MPFR
239
 
        mp_set_memory_functions(mpfr_mem_alloc, mpfr_mem_realloc, mpfr_mem_free);
240
 
#endif
241
214
 
242
215
        /* do these checks early */
243
216
        if (getenv("TIDYMEM") != NULL)
245
218
 
246
219
#ifdef HAVE_MCHECK_H
247
220
#ifdef HAVE_MTRACE
248
 
        if (! using_persistent_malloc && do_tidy_mem)
 
221
        if (do_tidy_mem)
249
222
                mtrace();
250
223
#endif /* HAVE_MTRACE */
251
224
#endif /* HAVE_MCHECK_H */
252
225
 
253
 
        os_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
254
 
 
255
 
        if (argc < 2)
256
 
                usage(EXIT_FAILURE, stderr);
257
 
 
258
 
        if ((cp = getenv("GAWK_LOCALE_DIR")) != NULL)
259
 
                locale_dir = cp;
260
 
 
261
 
#if defined(F_GETFL) && defined(O_APPEND)
262
 
        // 1/2018: This is needed on modern BSD systems so that the
263
 
        // inplace tests pass. I think it's a bug in those kernels
264
 
        // but let's just work around it anyway.
265
 
        int flags = fcntl(fileno(stderr), F_GETFL, NULL);
266
 
        if (flags >= 0 && (flags & O_APPEND) == 0) {
267
 
                flags |= O_APPEND;
268
 
                (void) fcntl(fileno(stderr), F_SETFL, flags);
269
 
        }
270
 
#endif
271
 
 
272
 
#if defined(LOCALEDEBUG)
273
 
        initial_locale = locale;
274
 
#endif
275
 
        set_locale_stuff();
276
 
 
277
 
        (void) signal(SIGSEGV, catchsig);
 
226
#if defined(LC_CTYPE)
 
227
        setlocale(LC_CTYPE, "");
 
228
#endif
 
229
#if defined(LC_COLLATE)
 
230
        setlocale(LC_COLLATE, "");
 
231
#endif
 
232
#if defined(LC_MESSAGES)
 
233
        setlocale(LC_MESSAGES, "");
 
234
#endif
 
235
#if defined(LC_NUMERIC) && defined(HAVE_LOCALE_H)
 
236
        /*
 
237
         * Force the issue here.  According to POSIX 2001, decimal
 
238
         * point is used for parsing source code and for command-line
 
239
         * assignments and the locale value for processing input,
 
240
         * number to string conversion, and printing output.
 
241
         *
 
242
         * 10/2005 --- see below also; we now only use the locale's
 
243
         * decimal point if do_posix in effect.
 
244
         *
 
245
         * 9/2007:
 
246
         * This is a mess. We need to get the locale's numeric info for
 
247
         * the thousands separator for the %'d flag.
 
248
         */
 
249
        setlocale(LC_NUMERIC, "");
 
250
        init_locale(& loc);
 
251
        setlocale(LC_NUMERIC, "C");
 
252
#endif
 
253
#if defined(LC_TIME)
 
254
        setlocale(LC_TIME, "");
 
255
#endif
 
256
 
 
257
#if MBS_SUPPORT
 
258
        /*
 
259
         * In glibc, MB_CUR_MAX is actually a function.  This value is
 
260
         * tested *a lot* in many speed-critical places in gawk. Caching
 
261
         * this value once makes a speed difference.
 
262
         */
 
263
        gawk_mb_cur_max = MB_CUR_MAX;
 
264
        /* Without MBS_SUPPORT, gawk_mb_cur_max is 1. */
 
265
#ifdef LIBC_IS_BORKED
 
266
{
 
267
        const char *env_lc;
 
268
 
 
269
        env_lc = getenv("LC_ALL");
 
270
        if (env_lc == NULL)
 
271
                env_lc = getenv("LANG");
 
272
        if (env_lc != NULL && env_lc[1] == '\0' && tolower(env_lc[0]) == 'c')
 
273
                gawk_mb_cur_max = 1;
 
274
}
 
275
#endif
 
276
 
 
277
        /* init the cache for checking bytes if they're characters */
 
278
        init_btowc_cache();
 
279
#endif
 
280
 
 
281
        (void) bindtextdomain(PACKAGE, LOCALEDIR);
 
282
        (void) textdomain(PACKAGE);
 
283
 
278
284
        (void) signal(SIGFPE, catchsig);
279
285
#ifdef SIGBUS
280
286
        (void) signal(SIGBUS, catchsig);
281
287
#endif
282
 
 
 
288
#ifdef SIGPIPE
283
289
        /*
284
290
         * Ignore SIGPIPE so that writes to pipes that fail don't
285
291
         * kill the process but instead return -1 and set errno.
293
299
         * should not give us "broken pipe" messages --- mainly because
294
300
         * it did not do so in the past and people would complain.
295
301
         */
296
 
        ignore_sigpipe();
 
302
        signal(SIGPIPE, SIG_IGN);
 
303
#endif
 
304
 
 
305
        (void) sigsegv_install_handler(catchsegv);
 
306
#define STACK_SIZE (16*1024)
 
307
        emalloc(extra_stack, char *, STACK_SIZE, "main");
 
308
        (void) stackoverflow_install_handler(catchstackoverflow, extra_stack, STACK_SIZE);
 
309
#undef STACK_SIZE
 
310
 
 
311
        myname = gawk_name(argv[0]);
 
312
        os_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
 
313
 
 
314
        if (argc < 2)
 
315
                usage(EXIT_FAILURE, stderr);
297
316
 
298
317
        /* initialize the null string */
299
318
        Nnull_string = make_string("", 0);
309
328
 
310
329
        output_fp = stdout;
311
330
 
 
331
        /* we do error messages ourselves on invalid options */
 
332
        opterr = false;
 
333
 
 
334
        /* copy argv before getopt gets to it; used to restart the debugger */  
 
335
        save_argv(argc, argv);
 
336
 
312
337
        /* initialize global (main) execution context */
313
338
        push_context(new_context());
314
339
 
315
 
        parse_args(argc, argv);
316
 
 
317
 
#if defined(LOCALEDEBUG)
318
 
        if (locale != initial_locale)
319
 
                set_locale_stuff();
320
 
#endif
321
 
 
322
 
        /*
323
 
         * In glibc, MB_CUR_MAX is actually a function.  This value is
324
 
         * tested *a lot* in many speed-critical places in gawk. Caching
325
 
         * this value once makes a speed difference.
326
 
         */
327
 
        gawk_mb_cur_max = MB_CUR_MAX;
328
 
 
329
 
        /* init the cache for checking bytes if they're characters */
330
 
        init_btowc_cache();
331
 
 
332
 
        /* set up the single byte case table */
333
 
        if (gawk_mb_cur_max == 1)
334
 
                load_casetable();
 
340
        /* option processing. ready, set, go! */
 
341
        for (optopt = 0, old_optind = 1;
 
342
             (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
 
343
             optopt = 0, old_optind = optind) {
 
344
                if (do_posix)
 
345
                        opterr = true;
 
346
 
 
347
                switch (c) {
 
348
                case 'F':
 
349
                        add_preassign(PRE_ASSIGN_FS, optarg);
 
350
                        break;
 
351
 
 
352
                case 'E':
 
353
                        disallow_var_assigns = true;
 
354
                        /* fall through */
 
355
                case 'f':
 
356
                        /*
 
357
                         * Allow multiple -f options.
 
358
                         * This makes function libraries real easy.
 
359
                         * Most of the magic is in the scanner.
 
360
                         *
 
361
                         * The following is to allow for whitespace at the end
 
362
                         * of a #! /bin/gawk line in an executable file
 
363
                         */
 
364
                        scan = optarg;
 
365
                        if (argv[optind-1] != optarg)
 
366
                                while (isspace((unsigned char) *scan))
 
367
                                        scan++;
 
368
                        src = (*scan == '\0' ? argv[optind++] : optarg);
 
369
                        (void) add_srcfile((src && src[0] == '-' && src[1] == '\0') ?
 
370
                                        SRC_STDIN : SRC_FILE,
 
371
                                        src, srcfiles, NULL, NULL);
 
372
 
 
373
                        break;
 
374
 
 
375
                case 'v':
 
376
                        add_preassign(PRE_ASSIGN, optarg);
 
377
                        break;
 
378
 
 
379
                case 'b':
 
380
                        do_binary = true;
 
381
                        break;
 
382
 
 
383
                case 'c':
 
384
                        do_flags |= DO_TRADITIONAL;
 
385
                        break;
 
386
 
 
387
                case 'C':
 
388
                        copyleft();
 
389
                        break;
 
390
 
 
391
                case 'd':
 
392
                        do_flags |= DO_DUMP_VARS;
 
393
                        if (optarg != NULL && optarg[0] != '\0')
 
394
                                varfile = optarg;
 
395
                        break;
 
396
 
 
397
                case 'D':
 
398
                        do_flags |= DO_DEBUG;
 
399
                        if (optarg != NULL && optarg[0] != '\0')
 
400
                                command_file = optarg;
 
401
                        break;
 
402
 
 
403
                case 'e':
 
404
                        if (optarg[0] == '\0')
 
405
                                warning(_("empty argument to `-e/--source' ignored"));
 
406
                        else
 
407
                                (void) add_srcfile(SRC_CMDLINE, optarg, srcfiles, NULL, NULL);
 
408
                        break;
 
409
 
 
410
                case 'g':
 
411
                        do_flags |= DO_INTL;
 
412
                        break;
 
413
 
 
414
                case 'h':
 
415
                        /* write usage to stdout, per GNU coding stds */
 
416
                        usage(EXIT_SUCCESS, stdout);
 
417
                        break;
 
418
 
 
419
                case 'i':
 
420
                        (void) add_srcfile(SRC_INC, optarg, srcfiles, NULL, NULL);
 
421
                        break;
 
422
 
 
423
                case 'l':
 
424
                        (void) add_srcfile(SRC_EXTLIB, optarg, srcfiles, NULL, NULL);
 
425
                        break;
 
426
 
 
427
#ifndef NO_LINT
 
428
                case 'L':
 
429
                        do_flags |= DO_LINT_ALL;
 
430
                        if (optarg != NULL) {
 
431
                                if (strcmp(optarg, "fatal") == 0)
 
432
                                        lintfunc = r_fatal;
 
433
                                else if (strcmp(optarg, "invalid") == 0) {
 
434
                                        do_flags &= ~DO_LINT_ALL;
 
435
                                        do_flags |= DO_LINT_INVALID;
 
436
                                }
 
437
                        }
 
438
                        break;
 
439
 
 
440
                case 't':
 
441
                        do_flags |= DO_LINT_OLD;
 
442
                        break;
 
443
#else
 
444
                case 'L':
 
445
                case 't':
 
446
                        break;
 
447
#endif
 
448
 
 
449
                case 'n':
 
450
                        do_flags |= DO_NON_DEC_DATA;
 
451
                        break;
 
452
 
 
453
                case 'N':
 
454
                        use_lc_numeric = true;
 
455
                        break;
 
456
 
 
457
                case 'O':
 
458
                        do_optimize = true;
 
459
                        break;
 
460
 
 
461
                case 'p':
 
462
                        do_flags |= DO_PROFILE;
 
463
                        /* fall through */
 
464
                case 'o':
 
465
                        do_flags |= DO_PRETTY_PRINT;
 
466
                        if (optarg != NULL)
 
467
                                set_prof_file(optarg);
 
468
                        else
 
469
                                set_prof_file(DEFAULT_PROFILE);
 
470
                        break;
 
471
 
 
472
                case 'M':
 
473
#ifdef HAVE_MPFR
 
474
                        do_flags |= DO_MPFR;
 
475
#endif
 
476
                        break;
 
477
 
 
478
                case 'P':
 
479
                        do_flags |= DO_POSIX;
 
480
                        break;
 
481
 
 
482
                case 'r':
 
483
                        do_flags |= DO_INTERVALS;
 
484
                        break;
 
485
 
 
486
                case 'S':
 
487
                        do_flags |= DO_SANDBOX;
 
488
                        break;
 
489
 
 
490
                case 'V':
 
491
                        do_version = true;
 
492
                        break;
 
493
 
 
494
                case 'W':       /* gawk specific options - now in getopt_long */
 
495
                        fprintf(stderr, _("%s: option `-W %s' unrecognized, ignored\n"),
 
496
                                argv[0], optarg);
 
497
                        break;
 
498
 
 
499
                case 0:
 
500
                        /*
 
501
                         * getopt_long found an option that sets a variable
 
502
                         * instead of returning a letter. Do nothing, just
 
503
                         * cycle around for the next one.
 
504
                         */
 
505
                        break;
 
506
 
 
507
                case 'Y':
 
508
#if defined(YYDEBUG) || defined(GAWKDEBUG)
 
509
                        if (c == 'Y') {
 
510
                                yydebug = 2;
 
511
                                break;
 
512
                        }
 
513
#endif
 
514
                        /* if not debugging, fall through */
 
515
                case '?':
 
516
                default:
 
517
                        /*
 
518
                         * If not posix, an unrecognized option stops argument
 
519
                         * processing so that it can go into ARGV for the awk
 
520
                         * program to see. This makes use of ``#! /bin/gawk -f''
 
521
                         * easier.
 
522
                         *
 
523
                         * However, it's never simple. If optopt is set,
 
524
                         * an option that requires an argument didn't get the
 
525
                         * argument. We care because if opterr is 0, then
 
526
                         * getopt_long won't print the error message for us.
 
527
                         */
 
528
                        if (! do_posix
 
529
                            && (optopt == '\0' || strchr(optlist, optopt) == NULL)) {
 
530
                                /*
 
531
                                 * can't just do optind--. In case of an
 
532
                                 * option with >= 2 letters, getopt_long
 
533
                                 * won't have incremented optind.
 
534
                                 */
 
535
                                optind = old_optind;
 
536
                                stopped_early = true;
 
537
                                goto out;
 
538
                        } else if (optopt != '\0') {
 
539
                                /* Use POSIX required message format */
 
540
                                fprintf(stderr,
 
541
                                        _("%s: option requires an argument -- %c\n"),
 
542
                                        myname, optopt);
 
543
                                usage(EXIT_FAILURE, stderr);
 
544
                        }
 
545
                        /* else
 
546
                                let getopt print error message for us */
 
547
                        break;
 
548
                }
 
549
                if (c == 'E')   /* --exec ends option processing */
 
550
                        break;
 
551
        }
 
552
out:
 
553
 
 
554
        if (do_nostalgia)
 
555
                nostalgia();
335
556
 
336
557
        /* check for POSIXLY_CORRECT environment variable */
337
558
        if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
341
562
        _("environment variable `POSIXLY_CORRECT' set: turning on `--posix'"));
342
563
        }
343
564
 
344
 
        // Checks for conflicting command-line arguments.
345
565
        if (do_posix) {
346
566
                use_lc_numeric = true;
347
567
                if (do_traditional)     /* both on command line */
359
579
                warning(_("`--posix'/`--traditional' overrides `--non-decimal-data'"));
360
580
        }
361
581
 
 
582
        if (do_lint && os_is_setuid())
 
583
                warning(_("running %s setuid root may be a security problem"), myname);
 
584
 
 
585
#if MBS_SUPPORT
362
586
        if (do_binary) {
363
587
                if (do_posix)
364
588
                        warning(_("`--posix' overrides `--characters-as-bytes'"));
365
 
                else {
 
589
                else
366
590
                        gawk_mb_cur_max = 1;    /* hands off my data! */
367
591
#if defined(LC_ALL)
368
 
                        setlocale(LC_ALL, "C");
369
 
#endif
370
 
                }
371
 
        }
372
 
 
373
 
        if (do_csv && do_posix)
374
 
                fatal(_("`--posix' and `--csv' conflict"));
375
 
 
376
 
        if (do_lint) {
377
 
                if (os_is_setuid())
378
 
                        lintwarn(_("running %s setuid root may be a security problem"), myname);
379
 
                if (do_intervals)
380
 
                        lintwarn(_("The -r/--re-interval options no longer have any effect"));
381
 
        }
 
592
                setlocale(LC_ALL, "C");
 
593
#endif
 
594
        }
 
595
#endif
382
596
 
383
597
        if (do_debug)   /* Need to register the debugger pre-exec hook before any other */
384
598
                init_debug();
385
599
 
386
600
#ifdef HAVE_MPFR
387
 
        /* Set up MPFR defaults, and register pre-exec hook to process arithmetic opcodes */
 
601
        /* Set up MPFR defaults, and register pre-exec hook to process arithmetic opcodes */ 
388
602
        if (do_mpfr)
389
603
                init_mpfr(DEFAULT_PREC, DEFAULT_ROUNDMODE);
390
604
#endif
413
627
        /* Set up the special variables */
414
628
        init_vars();
415
629
 
416
 
        /* set up CSV */
417
 
        init_csv_records();
418
 
        init_csv_fields();
419
 
 
420
630
        /* Set up the field variables */
421
631
        init_fields();
422
632
 
423
633
        /* Now process the pre-assignments */
424
 
        int dash_v_errs = 0;    // bad stuff for -v
425
634
        for (i = 0; i <= numassigns; i++) {
426
635
                if (preassigns[i].type == PRE_ASSIGN)
427
 
                        dash_v_errs += (arg_assign(preassigns[i].val, true) == false);
 
636
                        (void) arg_assign(preassigns[i].val, true);
428
637
                else    /* PRE_ASSIGN_FS */
429
638
                        cmdline_fs(preassigns[i].val);
430
639
                efree(preassigns[i].val);
435
644
 
436
645
        if ((BINMODE & BINMODE_INPUT) != 0)
437
646
                if (os_setbinmode(fileno(stdin), O_BINARY) == -1)
438
 
                        fatal(_("cannot set binary mode on stdin: %s"), strerror(errno));
 
647
                        fatal(_("can't set binary mode on stdin (%s)"), strerror(errno));
439
648
        if ((BINMODE & BINMODE_OUTPUT) != 0) {
440
649
                if (os_setbinmode(fileno(stdout), O_BINARY) == -1)
441
 
                        fatal(_("cannot set binary mode on stdout: %s"), strerror(errno));
 
650
                        fatal(_("can't set binary mode on stdout (%s)"), strerror(errno));
442
651
                if (os_setbinmode(fileno(stderr), O_BINARY) == -1)
443
 
                        fatal(_("cannot set binary mode on stderr: %s"), strerror(errno));
 
652
                        fatal(_("can't set binary mode on stderr (%s)"), strerror(errno));
444
653
        }
445
654
 
446
655
#ifdef GAWKDEBUG
449
658
        if (os_isatty(fileno(stdout)))
450
659
                output_is_tty = true;
451
660
 
452
 
        /* arrange to save free lists if using PMA */
453
 
        atexit(pma_save_free_lists);
454
 
 
455
661
        /* initialize API before loading extension libraries */
456
662
        init_ext_api();
457
663
 
458
664
        /* load extension libs */
459
 
        for (s = srcfiles->next; s != srcfiles; s = s->next) {
460
 
                if (s->stype == SRC_EXTLIB)
 
665
        for (s = srcfiles->next; s != srcfiles; s = s->next) {
 
666
                if (s->stype == SRC_EXTLIB)
461
667
                        load_ext(s->fullpath);
462
668
                else if (s->stype != SRC_INC)
463
 
                        have_srcfile = true;
464
 
        }
 
669
                        have_srcfile++;
 
670
        }
465
671
 
466
672
        /* do version check after extensions are loaded to get extension info */
467
673
        if (do_version)
491
697
        setlocale(LC_NUMERIC, "C");
492
698
#endif
493
699
        /* Read in the program */
494
 
        if (parse_program(& code_block, false) != 0 || dash_v_errs > 0)
 
700
        if (parse_program(& code_block) != 0)
495
701
                exit(EXIT_FAILURE);
496
 
 
 
702
        
497
703
        if (do_intl)
498
704
                exit(EXIT_SUCCESS);
499
705
 
500
 
        set_current_namespace(awk_namespace);
501
 
 
502
 
        install_builtins();
503
 
 
504
706
        if (do_lint)
505
707
                shadow_funcs();
506
708
 
529
731
         * data using the local decimal point.
530
732
         */
531
733
        if (use_lc_numeric)
532
 
                setlocale(LC_NUMERIC, locale);
 
734
                setlocale(LC_NUMERIC, "");
533
735
#endif
534
 
 
 
736
        
535
737
        init_io();
536
738
        output_fp = stdout;
537
739
 
538
740
        if (do_debug)
539
741
                debug_prog(code_block);
540
 
        else if (do_pretty_print && ! do_profile)
541
 
                ;       /* run pretty printer only. */
 
742
        else if (do_pretty_print && ! do_debug && getenv("GAWK_NO_PP_RUN") != NULL)
 
743
                /* hack to run pretty printer only. need a better solution */
 
744
                ;
542
745
        else
543
746
                interpret(code_block);
544
747
 
545
748
        if (do_pretty_print) {
546
 
                set_current_namespace(awk_namespace);
547
749
                dump_prog(code_block);
548
750
                dump_funcs();
549
751
        }
551
753
        if (do_dump_vars)
552
754
                dump_vars(varfile);
553
755
 
554
 
#ifdef HAVE_MPFR
555
 
        if (do_mpfr)
556
 
                cleanup_mpfr();
557
 
#endif
558
 
 
559
756
        if (do_tidy_mem)
560
757
                release_all_vars();
 
758
        
 
759
        /* keep valgrind happier */
 
760
        if (extra_stack)
 
761
                efree(extra_stack);
561
762
 
562
763
        final_exit(exit_val);
563
764
        return exit_val;        /* to suppress warnings */
594
795
static void
595
796
usage(int exitval, FILE *fp)
596
797
{
597
 
        static const char gnu_url[] = "https://ftp.gnu.org/gnu/gawk";
598
 
        static const char beta_url[] = "https://www.skeeve.com/gawk";
599
 
        const char *url;
600
 
        int major_version, minor_version, patchlevel;
601
 
 
602
 
        major_version = minor_version = patchlevel = 0;
603
 
        sscanf(PACKAGE_VERSION, "%d.%d.%d", & major_version, & minor_version, & patchlevel);
604
 
 
605
798
        /* Not factoring out common stuff makes it easier to translate. */
606
799
        fprintf(fp, _("Usage: %s [POSIX or GNU style options] -f progfile [--] file ...\n"),
607
800
                myname);
625
818
        fputs(_("\t-g\t\t\t--gen-pot\n"), fp);
626
819
        fputs(_("\t-h\t\t\t--help\n"), fp);
627
820
        fputs(_("\t-i includefile\t\t--include=includefile\n"), fp);
628
 
        fputs(_("\t-I\t\t\t--trace\n"), fp);
629
 
        fputs(_("\t-k\t\t\t--csv\n"), fp);
630
821
        fputs(_("\t-l library\t\t--load=library\n"), fp);
631
 
        /*
632
 
         * TRANSLATORS: the "fatal", "invalid" and "no-ext" here are literal
633
 
         * values, they should not be translated. Thanks.
634
 
         */
635
 
        fputs(_("\t-L[fatal|invalid|no-ext]\t--lint[=fatal|invalid|no-ext]\n"), fp);
 
822
        fputs(_("\t-L [fatal]\t\t--lint[=fatal]\n"), fp);
 
823
        fputs(_("\t-n\t\t\t--non-decimal-data\n"), fp);
636
824
        fputs(_("\t-M\t\t\t--bignum\n"), fp);
637
825
        fputs(_("\t-N\t\t\t--use-lc-numeric\n"), fp);
638
 
        fputs(_("\t-n\t\t\t--non-decimal-data\n"), fp);
639
826
        fputs(_("\t-o[file]\t\t--pretty-print[=file]\n"), fp);
640
827
        fputs(_("\t-O\t\t\t--optimize\n"), fp);
641
828
        fputs(_("\t-p[file]\t\t--profile[=file]\n"), fp);
642
829
        fputs(_("\t-P\t\t\t--posix\n"), fp);
643
830
        fputs(_("\t-r\t\t\t--re-interval\n"), fp);
644
 
        fputs(_("\t-s\t\t\t--no-optimize\n"), fp);
645
831
        fputs(_("\t-S\t\t\t--sandbox\n"), fp);
646
832
        fputs(_("\t-t\t\t\t--lint-old\n"), fp);
647
833
        fputs(_("\t-V\t\t\t--version\n"), fp);
648
 
#ifdef GAWKDEBUG
649
 
        fputs(_("\t-Y\t\t\t--parsedebug\n"), fp);
 
834
#ifdef NOSTALGIA
 
835
        fputs(_("\t-W nostalgia\t\t--nostalgia\n"), fp);
650
836
#endif
651
837
#ifdef GAWKDEBUG
652
 
        fputs(_("\t-Z locale-name\t\t--locale=locale-name\n"), fp);
 
838
        fputs(_("\t-Y\t\t--parsedebug\n"), fp);
653
839
#endif
654
840
 
655
841
        /* This is one string to make things easier on translators. */
656
 
        /* TRANSLATORS: --help output (end)
 
842
        /* TRANSLATORS: --help output 5 (end)
 
843
           TRANSLATORS: the placeholder indicates the bug-reporting address
 
844
           for this application.  Please add _another line_ with the
 
845
           address for translation bugs.
657
846
           no-wrap */
658
 
        fputs(_("\nTo report bugs, use the `gawkbug' program.\n\
659
 
For full instructions, see the node `Bugs' in `gawk.info'\n\
660
 
which is section `Reporting Problems and Bugs' in the\n\
661
 
printed version.  This same information may be found at\n\
662
 
https://www.gnu.org/software/gawk/manual/html_node/Bugs.html.\n\
663
 
PLEASE do NOT try to report bugs by posting in comp.lang.awk,\n\
664
 
or by using a web forum such as Stack Overflow.\n\n"), fp);
665
 
 
666
 
        // 5.2.60 is beta release on master, will become 5.3.0.
667
 
        // 5.2.2a is beta release on stable, will become 5.2.3.
668
 
        if (patchlevel >= 60 || isalpha((int) PACKAGE_VERSION[strlen(PACKAGE_VERSION)-1]))
669
 
                url = beta_url;
670
 
        else
671
 
                url = gnu_url;
672
 
 
673
 
        /* ditto */
674
 
        fprintf(fp, _("Source code for gawk may be obtained from\n%s/gawk-%s.tar.gz\n\n"),
675
 
                url, PACKAGE_VERSION);
 
847
        fputs(_("\nTo report bugs, see node `Bugs' in `gawk.info', which is\n\
 
848
section `Reporting Problems and Bugs' in the printed version.\n\n"), fp);
676
849
 
677
850
        /* ditto */
678
851
        fputs(_("gawk is a pattern scanning and processing language.\n\
679
852
By default it reads standard input and writes standard output.\n\n"), fp);
680
853
 
681
854
        /* ditto */
682
 
        fprintf(fp, _("Examples:\n\t%s '{ sum += $1 }; END { print sum }' file\n\
683
 
\t%s -F: '{ print $1 }' /etc/passwd\n"), myname, myname);
 
855
        fputs(_("Examples:\n\tgawk '{ sum += $1 }; END { print sum }' file\n\
 
856
\tgawk -F: '{ print $1 }' /etc/passwd\n"), fp);
684
857
 
685
858
        fflush(fp);
686
859
 
687
860
        if (ferror(fp)) {
688
 
                os_maybe_set_errno();
689
 
 
690
861
                /* don't warn about stdout/stderr if EPIPE, but do error exit */
691
 
                if (errno == EPIPE)
692
 
                        die_via_sigpipe();
693
 
 
694
 
                if (fp == stdout)
695
 
                        warning(_("error writing standard output: %s"), strerror(errno));
696
 
                else if (fp == stderr)
697
 
                        warning(_("error writing standard error: %s"), strerror(errno));
698
 
 
699
 
                // some other problem than SIGPIPE
 
862
                if (errno != EPIPE) {
 
863
                        if (fp == stdout)
 
864
                                warning(_("error writing standard output (%s)"), strerror(errno));
 
865
                        else if (fp == stderr)
 
866
                                warning(_("error writing standard error (%s)"), strerror(errno));
 
867
                }
700
868
                exit(EXIT_FAILURE);
701
869
        }
702
870
 
725
893
        static const char blurb_part3[] =
726
894
          N_("You should have received a copy of the GNU General Public License\n\
727
895
along with this program. If not, see http://www.gnu.org/licenses/.\n");
728
 
 
 
896
 
729
897
        /* multiple blurbs are needed for some brain dead compilers. */
730
898
        printf(_(blurb_part1), UPDATE_YEAR);    /* Last update year */
731
899
        fputs(_(blurb_part2), stdout);
733
901
        fflush(stdout);
734
902
 
735
903
        if (ferror(stdout)) {
736
 
                os_maybe_set_errno();
737
 
 
738
904
                /* don't warn about stdout if EPIPE, but do error exit */
739
905
                if (errno != EPIPE)
740
 
                        warning(_("error writing standard output: %s"), strerror(errno));
 
906
                        warning(_("error writing standard output (%s)"), strerror(errno));
741
907
                exit(EXIT_FAILURE);
742
908
        }
743
909
 
777
943
init_args(int argc0, int argc, const char *argv0, char **argv)
778
944
{
779
945
        int i, j;
780
 
        NODE *sub, *val;
781
 
        NODE *shadow_node = NULL;
 
946
        NODE **aptr;
 
947
        NODE *tmp;
782
948
 
783
949
        ARGV_node = install_symbol(estrdup("ARGV", 4), Node_var_array);
784
 
        sub = make_number(0.0);
785
 
        val = make_string(argv0, strlen(argv0));
786
 
        val->flags |= USER_INPUT;
787
 
        assoc_set(ARGV_node, sub, val);
788
 
 
789
 
        if (do_sandbox) {
790
 
                shadow_node = make_array();
791
 
                sub = make_string(argv0, strlen(argv0));
792
 
                val = make_number(0.0);
793
 
                assoc_set(shadow_node, sub, val);
794
 
        }
795
 
 
796
 
 
 
950
        tmp =  make_number(0.0);
 
951
        aptr = assoc_lookup(ARGV_node, tmp);
 
952
        unref(tmp);
 
953
        unref(*aptr);
 
954
        *aptr = make_string(argv0, strlen(argv0));
 
955
        (*aptr)->flags |= MAYBE_NUM;
797
956
        for (i = argc0, j = 1; i < argc; i++, j++) {
798
 
                sub = make_number((AWKNUM) j);
799
 
                val = make_string(argv[i], strlen(argv[i]));
800
 
                val->flags |= USER_INPUT;
801
 
                assoc_set(ARGV_node, sub, val);
802
 
 
803
 
                if (do_sandbox) {
804
 
                        sub = make_string(argv[i], strlen(argv[i]));
805
 
                        val = make_number(0.0);
806
 
                        assoc_set(shadow_node, sub, val);
807
 
                }
 
957
                tmp = make_number((AWKNUM) j);
 
958
                aptr = assoc_lookup(ARGV_node, tmp);
 
959
                unref(tmp);
 
960
                unref(*aptr);
 
961
                *aptr = make_string(argv[i], strlen(argv[i]));
 
962
                (*aptr)->flags |= MAYBE_NUM;
808
963
        }
809
964
 
810
965
        ARGC_node = install_symbol(estrdup("ARGC", 4), Node_var);
811
966
        ARGC_node->var_value = make_number((AWKNUM) j);
812
 
 
813
 
        if (do_sandbox)
814
 
                init_argv_array(ARGV_node, shadow_node);
815
967
}
816
968
 
817
969
 
852
1004
{&FPAT_node,    "FPAT",         "[^[:space:]]+", 0,  NULL, set_FPAT,    false, NON_STANDARD },
853
1005
{&IGNORECASE_node, "IGNORECASE", NULL,  0,  NULL, set_IGNORECASE,       false, NON_STANDARD },
854
1006
{&LINT_node,    "LINT",         NULL,   0,  NULL, set_LINT,     false, NON_STANDARD },
855
 
{&PREC_node,    "PREC",         NULL,   DEFAULT_PREC,   NULL,   set_PREC,       false,  NON_STANDARD},
 
1007
{&PREC_node,    "PREC",         NULL,   DEFAULT_PREC,   NULL,   set_PREC,       false,  NON_STANDARD},  
856
1008
{&NF_node,      "NF",           NULL,   -1, update_NF, set_NF,  false, 0 },
857
1009
{&NR_node,      "NR",           NULL,   0,  update_NR, set_NR,  true, 0 },
858
1010
{&OFMT_node,    "OFMT",         "%.6g", 0,  NULL, set_OFMT,     true, 0 },
891
1043
                        (*(vp->assign))();
892
1044
        }
893
1045
 
894
 
        /* Load PROCINFO and ENVIRON */
 
1046
        /* Set up deferred variables (loaded only when accessed). */
895
1047
        if (! do_traditional)
896
 
                load_procinfo();
897
 
        load_environ();
 
1048
                register_deferred_variable("PROCINFO", load_procinfo);
 
1049
        register_deferred_variable("ENVIRON", load_environ);
898
1050
}
899
1051
 
900
1052
/* path_environ --- put path variable into environment if not already there */
907
1059
        NODE *tmp;
908
1060
 
909
1061
        tmp = make_string(pname, strlen(pname));
910
 
        /*
911
 
         * On VMS, environ[] only holds a subset of what getenv() can
912
 
         * find, so look AWKPATH up before resorting to default path.
913
 
         */
914
 
        val = getenv(pname);
915
 
        if (val == NULL || *val == '\0')
916
 
                val = dflt;
917
 
        aptr = assoc_lookup(ENVIRON_node, tmp);
918
 
        /*
919
 
         * If original value was the empty string, set it to
920
 
         * the default value.
921
 
         */
922
 
        if ((*aptr)->stlen == 0) {
 
1062
        if (! in_array(ENVIRON_node, tmp)) {
 
1063
                /*
 
1064
                 * On VMS, environ[] only holds a subset of what getenv() can
 
1065
                 * find, so look AWKPATH up before resorting to default path.
 
1066
                 */
 
1067
                val = getenv(pname);
 
1068
                if (val == NULL)
 
1069
                        val = dflt;
 
1070
                aptr = assoc_lookup(ENVIRON_node, tmp);
923
1071
                unref(*aptr);
924
1072
                *aptr = make_string(val, strlen(val));
925
1073
        }
926
 
 
927
1074
        unref(tmp);
928
1075
}
929
1076
 
936
1083
        extern char **environ;
937
1084
#endif
938
1085
        char *var, *val;
 
1086
        NODE **aptr;
939
1087
        int i;
940
 
        NODE *sub, *newval;
 
1088
        NODE *tmp;
941
1089
        static bool been_here = false;
942
1090
 
943
1091
        if (been_here)
946
1094
        been_here = true;
947
1095
 
948
1096
        ENVIRON_node = install_symbol(estrdup("ENVIRON", 7), Node_var_array);
949
 
 
950
 
        // Force string functions; if the first element in environ[]
951
 
        // looks like "0=foo" we end up with the cint_funcs and that's
952
 
        // not what we want, we just get core dumps.
953
 
        ENVIRON_node->array_funcs = & str_array_func;
954
 
 
955
1097
        for (i = 0; environ[i] != NULL; i++) {
956
1098
                static char nullstr[] = "";
957
1099
 
961
1103
                        *val++ = '\0';
962
1104
                else
963
1105
                        val = nullstr;
964
 
                sub = make_string(var, strlen(var));
965
 
                newval = make_string(val, strlen(val));
966
 
                newval->flags |= USER_INPUT;
967
 
                assoc_set(ENVIRON_node, sub, newval);
 
1106
                tmp = make_string(var, strlen(var));
 
1107
                aptr = assoc_lookup(ENVIRON_node, tmp);
 
1108
                unref(tmp);
 
1109
                unref(*aptr);
 
1110
                *aptr = make_string(val, strlen(val));
 
1111
                (*aptr)->flags |= MAYBE_NUM;
968
1112
 
969
1113
                /* restore '=' so that system() gets a valid environment */
970
1114
                if (val != nullstr)
973
1117
        /*
974
1118
         * Put AWKPATH and AWKLIBPATH into ENVIRON if not already there.
975
1119
         * This allows querying it from within awk programs.
976
 
         *
977
 
         * October 2014:
978
 
         * If their values are "", override with the default values;
979
 
         * since 2.10 AWKPATH used default value if environment's
980
 
         * value was "".
981
1120
         */
982
1121
        path_environ("AWKPATH", defpath);
983
1122
        path_environ("AWKLIBPATH", deflibpath);
984
 
 
985
 
        /* set up array functions */
986
 
        init_env_array(ENVIRON_node);
987
 
 
988
1123
        return ENVIRON_node;
989
1124
}
990
1125
 
991
 
/* load_procinfo_argv --- populate PROCINFO["argv"] */
992
 
 
993
 
static void
994
 
load_procinfo_argv()
995
 
{
996
 
        NODE *sub;
997
 
        NODE *val;
998
 
        NODE *argv_array;
999
 
        int i;
1000
 
 
1001
 
        // build the sub-array first
1002
 
        getnode(argv_array);
1003
 
        memset(argv_array, '\0', sizeof(NODE));  /* valgrind wants this */
1004
 
        null_array(argv_array);
1005
 
        argv_array->parent_array = PROCINFO_node;
1006
 
        argv_array->vname = estrdup("argv", 4);
1007
 
        for (i = 0; d_argv[i] != NULL; i++) {
1008
 
                sub = make_number(i);
1009
 
                val = make_string(d_argv[i], strlen(d_argv[i]));
1010
 
                assoc_set(argv_array, sub, val);
1011
 
        }
1012
 
 
1013
 
        // hook it into PROCINFO
1014
 
        sub = make_string("argv", 4);
1015
 
        assoc_set(PROCINFO_node, sub, argv_array);
1016
 
}
1017
 
 
1018
1126
/* load_procinfo --- populate the PROCINFO array */
1019
1127
 
1020
1128
static NODE *
1038
1146
 
1039
1147
        update_PROCINFO_str("version", VERSION);
1040
1148
        update_PROCINFO_str("strftime", def_strftime_format);
1041
 
        update_PROCINFO_str("platform", platform_name());
1042
1149
 
1043
1150
#ifdef HAVE_MPFR
1044
1151
        sprintf(name, "GNU MPFR %s", mpfr_get_version());
1087
1194
        value = getegid();
1088
1195
        update_PROCINFO_num("egid", value);
1089
1196
 
1090
 
        update_PROCINFO_str("FS", current_field_sep_str());
 
1197
        switch (current_field_sep()) {
 
1198
        case Using_FIELDWIDTHS:
 
1199
                update_PROCINFO_str("FS", "FIELDWIDTHS");
 
1200
                break;
 
1201
        case Using_FPAT:
 
1202
                update_PROCINFO_str("FS", "FPAT");
 
1203
                break;
 
1204
        case Using_FS:
 
1205
                update_PROCINFO_str("FS", "FS");
 
1206
                break;
 
1207
        default:
 
1208
                fatal(_("unknown value for field spec: %d\n"),
 
1209
                                current_field_sep());
 
1210
                break;
 
1211
        }
 
1212
 
1091
1213
 
1092
1214
#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
1093
1215
        for (i = 0; i < ngroups; i++) {
1100
1222
                groupset = NULL;
1101
1223
        }
1102
1224
#endif
1103
 
 
1104
 
#ifdef USE_PERSISTENT_MALLOC
1105
 
        update_PROCINFO_str("pma", get_pma_version());
1106
 
#endif /* USE_PERSISTENT_MALLOC */
1107
 
 
1108
 
        if (do_csv)
1109
 
                update_PROCINFO_num("CSV", 1);
1110
 
 
1111
 
        load_procinfo_argv();
1112
1225
        return PROCINFO_node;
1113
1226
}
1114
1227
 
1205
1318
 
1206
1319
        /* first check that the variable name has valid syntax */
1207
1320
        badvar = false;
1208
 
        if (! is_letter((unsigned char) arg[0]))
 
1321
        if (! isalpha((unsigned char) arg[0]) && arg[0] != '_')
1209
1322
                badvar = true;
1210
1323
        else
1211
1324
                for (cp2 = arg+1; *cp2; cp2++)
1212
 
                        if (! is_identchar((unsigned char) *cp2) && *cp2 != ':') {
 
1325
                        if (! isalnum((unsigned char) *cp2) && *cp2 != '_') {
1213
1326
                                badvar = true;
1214
1327
                                break;
1215
1328
                        }
1221
1334
                if (do_lint)
1222
1335
                        lintwarn(_("`%s' is not a variable name, looking for file `%s=%s'"),
1223
1336
                                arg, arg, cp);
1224
 
 
1225
 
                goto done;
1226
 
        }
1227
 
 
1228
 
        // Assigning a string or typed regex
1229
 
 
1230
 
        if (! validate_qualified_name(arg)) {
1231
 
                badvar = true;
1232
 
                goto done;
1233
 
        }
1234
 
 
1235
 
        if (check_special(arg) >= 0)
1236
 
                fatal(_("cannot use gawk builtin `%s' as variable name"), arg);
1237
 
 
1238
 
        if (! initing) {
1239
 
                var = lookup(arg);
1240
 
                if (var != NULL && var->type == Node_func)
1241
 
                        fatal(_("cannot use function `%s' as variable name"), arg);
1242
 
        }
1243
 
 
1244
 
        cp2 = cp + strlen(cp) - 1;      // end char
1245
 
        if (! do_traditional
1246
 
            && strlen(cp) >= 3          // '@/' doesn't do it.
1247
 
            && cp[0] == '@' && cp[1] == '/' && *cp2 == '/') {
1248
 
                // typed regex
1249
 
                size_t len = strlen(cp) - 3;
1250
 
 
1251
 
                ezalloc(cp2, char *, len + 1, "arg_assign");
1252
 
                memcpy(cp2, cp + 2, len);
1253
 
 
1254
 
                it = make_typed_regex(cp2, len);
1255
 
                // fall through to variable setup
1256
1337
        } else {
1257
 
                // string assignment
 
1338
                if (check_special(arg) >= 0)
 
1339
                        fatal(_("cannot use gawk builtin `%s' as variable name"), arg);
1258
1340
 
1259
 
                // POSIX disallows any newlines inside strings
1260
 
                // The scanner handles that for program files.
1261
 
                // We have to check here for strings passed to -v.
1262
 
                if (do_posix && strchr(cp, '\n') != NULL)
1263
 
                        fatal(_("POSIX does not allow physical newlines in string values"));
 
1341
                if (! initing) {
 
1342
                        var = lookup(arg);
 
1343
                        if (var != NULL && var->type == Node_func)
 
1344
                                fatal(_("cannot use function `%s' as variable name"), arg); 
 
1345
                }
1264
1346
 
1265
1347
                /*
1266
1348
                 * BWK awk expands escapes inside assignments.
1267
1349
                 * This makes sense, so we do it too.
1268
 
                 * In addition, remove \-<newline> as in scanning.
1269
1350
                 */
1270
1351
                it = make_str_node(cp, strlen(cp), SCAN);
1271
 
                it->flags |= USER_INPUT;
 
1352
                it->flags |= MAYBE_NUM;
1272
1353
#ifdef LC_NUMERIC
1273
1354
                /*
1274
1355
                 * See comment above about locale decimal point.
1275
1356
                 */
1276
1357
                if (do_posix)
1277
1358
                        setlocale(LC_NUMERIC, "C");
1278
 
#endif /* LC_NUMERIC */
1279
1359
                (void) force_number(it);
1280
 
#ifdef LC_NUMERIC
1281
1360
                if (do_posix)
1282
 
                        setlocale(LC_NUMERIC, locale);
 
1361
                        setlocale(LC_NUMERIC, "");
1283
1362
#endif /* LC_NUMERIC */
 
1363
 
 
1364
                /*
 
1365
                 * since we are restoring the original text of ARGV later,
 
1366
                 * need to copy the variable name part if we don't want
 
1367
                 * name like v=abc instead of just v in var->vname
 
1368
                 */
 
1369
 
 
1370
                cp2 = estrdup(arg, cp - arg);   /* var name */
 
1371
 
 
1372
                var = variable(0, cp2, Node_var);
 
1373
                if (var == NULL)        /* error */
 
1374
                        final_exit(EXIT_FATAL);
 
1375
                if (var->type == Node_var && var->var_update)
 
1376
                        var->var_update();
 
1377
                lhs = get_lhs(var, false);
 
1378
                unref(*lhs);
 
1379
                *lhs = it;
 
1380
                /* check for set_FOO() routine */
 
1381
                if (var->type == Node_var && var->var_assign)
 
1382
                        var->var_assign();
1284
1383
        }
1285
1384
 
1286
 
        /*
1287
 
         * since we are restoring the original text of ARGV later,
1288
 
         * need to copy the variable name part if we don't want
1289
 
         * name like v=abc instead of just v in var->vname
1290
 
         */
1291
 
 
1292
 
        cp2 = estrdup(arg, cp - arg);   /* var name */
1293
 
 
1294
 
        var = variable(0, cp2, Node_var);
1295
 
        if (var == NULL)        /* error */
1296
 
                final_exit(EXIT_FATAL);
1297
 
 
1298
 
        if (var->type == Node_var && var->var_update)
1299
 
                var->var_update();
1300
 
        lhs = get_lhs(var, false);
1301
 
        unref(*lhs);
1302
 
        *lhs = it;
1303
 
        /* check for set_FOO() routine */
1304
 
        if (var->type == Node_var && var->var_assign)
1305
 
                var->var_assign();
1306
 
 
1307
 
done:
1308
1385
        if (! initing)
1309
1386
                *--cp = '=';    /* restore original text of ARGV */
1310
1387
        FNR = save_FNR;
1313
1390
 
1314
1391
/* catchsig --- catch signals */
1315
1392
 
1316
 
static void
 
1393
static RETSIGTYPE
1317
1394
catchsig(int sig)
1318
1395
{
1319
1396
        if (sig == SIGFPE) {
1323
1400
                || sig == SIGBUS
1324
1401
#endif
1325
1402
        ) {
1326
 
                if (errcount > 0)       // assume a syntax error corrupted our data structures
1327
 
                        exit(EXIT_FATAL);
1328
 
 
1329
1403
                set_loc(__FILE__, __LINE__);
1330
1404
                msg(_("fatal error: internal error"));
1331
1405
                /* fatal won't abort() if not compiled for debugging */
1332
 
                // GLIBC 2.27 doesn't necessarily flush on abort. Sigh.
1333
 
                fflush(NULL);
1334
1406
                abort();
1335
1407
        } else
1336
 
                cant_happen("unexpected signal, number %d (%s)", sig, strsignal(sig));
 
1408
                cant_happen();
1337
1409
        /* NOTREACHED */
1338
1410
}
1339
1411
 
1340
 
#ifdef USE_PERSISTENT_MALLOC
1341
 
/* get_pma_version --- get a usable version string out of PMA */
1342
 
 
1343
 
const char *
1344
 
get_pma_version(void)
1345
 
{
1346
 
        static char buf[200];
1347
 
        const char *open, *close;
1348
 
        char *out;
1349
 
        const char *in;
1350
 
 
 
1412
#ifdef HAVE_LIBSIGSEGV
 
1413
/* catchsegv --- for use with libsigsegv */
 
1414
 
 
1415
static int
 
1416
catchsegv(void *fault_address, int serious)
 
1417
{
 
1418
        set_loc(__FILE__, __LINE__);
 
1419
        msg(_("fatal error: internal error: segfault"));
 
1420
        abort();
 
1421
        /*NOTREACHED*/
 
1422
        return 0;
 
1423
}
 
1424
 
 
1425
/* catchstackoverflow --- for use with libsigsegv */
 
1426
 
 
1427
static void
 
1428
catchstackoverflow(int emergency, stackoverflow_context_t scp)
 
1429
{
 
1430
        set_loc(__FILE__, __LINE__);
 
1431
        msg(_("fatal error: internal error: stack overflow"));
 
1432
        abort();
 
1433
        /*NOTREACHED*/
 
1434
        return;
 
1435
}
 
1436
#endif /* HAVE_LIBSIGSEGV */
 
1437
 
 
1438
/* nostalgia --- print the famous error message and die */
 
1439
 
 
1440
static void
 
1441
nostalgia()
 
1442
{
1351
1443
        /*
1352
 
         * The default version string looks like this:
1353
 
         * 2022.08Aug.03.1659520468 (Avon 7)
1354
 
         * Yucko. Just pull out the bits between the parens.
 
1444
         * N.B.: This string is not gettextized, on purpose.
 
1445
         * So there.
1355
1446
         */
1356
 
 
1357
 
        open = strchr(pma_version, '(');
1358
 
        if (open == NULL)
1359
 
                return pma_version;     // sigh.
1360
 
 
1361
 
        open++;
1362
 
        close = strchr(open, ')');
1363
 
        if (close == NULL)
1364
 
                return pma_version;     // sigh, again.
1365
 
 
1366
 
        // copy over the short name
1367
 
        for (out = buf, in = open; in < close;)
1368
 
                *out++ = *in++;
1369
 
 
1370
 
        *out++ = '\0';
1371
 
 
1372
 
        return buf;
 
1447
        fprintf(stderr, "awk: bailing out near line 1\n");
 
1448
        fflush(stderr);
 
1449
        abort();
1373
1450
}
1374
 
#endif
1375
1451
 
1376
1452
/* version --- print version message */
1377
1453
 
1380
1456
{
1381
1457
        printf("%s", version_string);
1382
1458
#ifdef DYNAMIC
1383
 
        printf(", API %d.%d", GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION);
1384
 
#endif
1385
 
#ifdef USE_PERSISTENT_MALLOC
1386
 
        printf(", PMA %s", get_pma_version());
 
1459
        printf(", API: %d.%d", GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION);
1387
1460
#endif
1388
1461
#ifdef HAVE_MPFR
1389
 
        printf(", (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
 
1462
        printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
1390
1463
#endif
1391
 
        printf("\n");
 
1464
        printf("\n"); 
1392
1465
        print_ext_versions();
1393
1466
 
1394
1467
        /*
1471
1544
        s[len] = '\0';
1472
1545
        return s;
1473
1546
}
1474
 
 
 
1547
             
1475
1548
#if defined(HAVE_LOCALE_H)
1476
1549
 
1477
1550
/* init_locale --- initialize locale info. */
1541
1614
getenv_long(const char *name)
1542
1615
{
1543
1616
        const char *val;
1544
 
        long newval;
 
1617
        long newval;    
1545
1618
        if ((val = getenv(name)) != NULL && isdigit((unsigned char) *val)) {
1546
1619
                for (newval = 0; *val && isdigit((unsigned char) *val); val++)
1547
1620
                        newval = (newval * 10) + *val - '0';
1549
1622
        }
1550
1623
        return -1;
1551
1624
}
1552
 
 
1553
 
/* parse_args --- do the getopt_long thing */
1554
 
 
1555
 
static void
1556
 
parse_args(int argc, char **argv)
1557
 
{
1558
 
        /*
1559
 
         * The + on the front tells GNU getopt not to rearrange argv.
1560
 
         */
1561
 
        const char *optlist = "+F:f:v:W;bcCd::D::e:E:ghi:kIl:L::nNo::Op::MPrSstVYZ:";
1562
 
        int old_optind;
1563
 
        int c;
1564
 
        char *scan;
1565
 
        char *src;
1566
 
 
1567
 
        /* we do error messages ourselves on invalid options */
1568
 
        opterr = false;
1569
 
 
1570
 
        /* copy argv before getopt gets to it; used to restart the debugger */
1571
 
        save_argv(argc, argv);
1572
 
 
1573
 
        /* option processing. ready, set, go! */
1574
 
        for (optopt = 0, old_optind = 1;
1575
 
             (c = getopt_long(argc, argv, optlist, optab, NULL)) != EOF;
1576
 
             optopt = 0, old_optind = optind) {
1577
 
                if (do_posix)
1578
 
                        opterr = true;
1579
 
 
1580
 
                switch (c) {
1581
 
                case 'F':
1582
 
                        add_preassign(PRE_ASSIGN_FS, optarg);
1583
 
                        break;
1584
 
 
1585
 
                case 'E':
1586
 
                        disallow_var_assigns = true;
1587
 
                        /* fall through */
1588
 
                case 'f':
1589
 
                        /*
1590
 
                         * Allow multiple -f options.
1591
 
                         * This makes function libraries real easy.
1592
 
                         * Most of the magic is in the scanner.
1593
 
                         *
1594
 
                         * The following is to allow for whitespace at the end
1595
 
                         * of a #! /bin/gawk line in an executable file
1596
 
                         */
1597
 
                        scan = optarg;
1598
 
                        if (argv[optind-1] != optarg)
1599
 
                                while (isspace((unsigned char) *scan))
1600
 
                                        scan++;
1601
 
                        src = (*scan == '\0' ? argv[optind++] : optarg);
1602
 
                        (void) add_srcfile((src && src[0] == '-' && src[1] == '\0') ?
1603
 
                                        SRC_STDIN : SRC_FILE,
1604
 
                                        src, srcfiles, NULL, NULL);
1605
 
 
1606
 
                        break;
1607
 
 
1608
 
                case 'v':
1609
 
                        add_preassign(PRE_ASSIGN, optarg);
1610
 
                        break;
1611
 
 
1612
 
                case 'b':
1613
 
                        do_binary = true;
1614
 
                        break;
1615
 
 
1616
 
                case 'c':
1617
 
                        do_flags |= DO_TRADITIONAL;
1618
 
                        break;
1619
 
 
1620
 
                case 'C':
1621
 
                        copyleft();
1622
 
                        break;
1623
 
 
1624
 
                case 'd':
1625
 
                        do_flags |= DO_DUMP_VARS;
1626
 
                        if (optarg != NULL && optarg[0] != '\0')
1627
 
                                varfile = optarg;
1628
 
                        break;
1629
 
 
1630
 
                case 'D':
1631
 
                        do_flags |= DO_DEBUG;
1632
 
                        if (optarg != NULL && optarg[0] != '\0')
1633
 
                                command_file = optarg;
1634
 
                        break;
1635
 
 
1636
 
                case 'e':
1637
 
                        if (optarg[0] == '\0')
1638
 
                                warning(_("empty argument to `-e/--source' ignored"));
1639
 
                        else
1640
 
                                (void) add_srcfile(SRC_CMDLINE, optarg, srcfiles, NULL, NULL);
1641
 
                        break;
1642
 
 
1643
 
                case 'g':
1644
 
                        do_flags |= DO_INTL;
1645
 
                        break;
1646
 
 
1647
 
                case 'h':
1648
 
                        /* write usage to stdout, per GNU coding stds */
1649
 
                        usage(EXIT_SUCCESS, stdout);
1650
 
                        break;
1651
 
 
1652
 
                case 'i':
1653
 
                        (void) add_srcfile(SRC_INC, optarg, srcfiles, NULL, NULL);
1654
 
                        break;
1655
 
 
1656
 
                case 'I':
1657
 
                        do_itrace = true;
1658
 
                        break;
1659
 
 
1660
 
                case 'k':       // k is for "comma". it's a stretch, I know
1661
 
                        do_flags |= DO_CSV;
1662
 
                        break;
1663
 
 
1664
 
                case 'l':
1665
 
                        (void) add_srcfile(SRC_EXTLIB, optarg, srcfiles, NULL, NULL);
1666
 
                        break;
1667
 
 
1668
 
#ifndef NO_LINT
1669
 
                case 'L':
1670
 
                        do_flags |= (DO_LINT_ALL|DO_LINT_EXTENSIONS);
1671
 
                        if (optarg != NULL) {
1672
 
                                if (strcmp(optarg, "fatal") == 0)
1673
 
                                        lintfunc = r_fatal;
1674
 
                                else if (strcmp(optarg, "invalid") == 0) {
1675
 
                                        do_flags &= ~DO_LINT_ALL;
1676
 
                                        do_flags |= DO_LINT_INVALID;
1677
 
                                }
1678
 
                                else if (strcmp(optarg, "no-ext") == 0) {
1679
 
                                        do_flags &= ~DO_LINT_EXTENSIONS;
1680
 
                                }
1681
 
                        }
1682
 
                        break;
1683
 
 
1684
 
                case 't':
1685
 
                        do_flags |= DO_LINT_OLD;
1686
 
                        break;
1687
 
#else
1688
 
                case 'L':
1689
 
                case 't':
1690
 
                        break;
1691
 
#endif
1692
 
 
1693
 
                case 'n':
1694
 
                        do_flags |= DO_NON_DEC_DATA;
1695
 
                        break;
1696
 
 
1697
 
                case 'N':
1698
 
                        use_lc_numeric = true;
1699
 
                        break;
1700
 
 
1701
 
                case 'O':
1702
 
                        do_optimize = true;
1703
 
                        break;
1704
 
 
1705
 
                case 'p':
1706
 
                        if (do_pretty_print && ! do_profile)
1707
 
                                warning(_("`--profile' overrides `--pretty-print'"));
1708
 
                        do_flags |= DO_PROFILE;
1709
 
                        /* fall through */
1710
 
                case 'o':
1711
 
                        if (c == 'o' && do_profile)
1712
 
                                warning(_("`--profile' overrides `--pretty-print'"));
1713
 
                        do_flags |= DO_PRETTY_PRINT;
1714
 
                        if (optarg != NULL)
1715
 
                                set_prof_file(optarg);
1716
 
                        else
1717
 
                                set_prof_file(DEFAULT_PROFILE);
1718
 
                        break;
1719
 
 
1720
 
                case 'M':
1721
 
#ifdef HAVE_MPFR
1722
 
                        do_flags |= DO_MPFR;
1723
 
#else
1724
 
                        warning(_("-M ignored: MPFR/GMP support not compiled in"));
1725
 
#endif
1726
 
                        break;
1727
 
 
1728
 
                case 'P':
1729
 
                        do_flags |= DO_POSIX;
1730
 
                        break;
1731
 
 
1732
 
                case 'r':
1733
 
                        // This no longer has any effect. It remains for the
1734
 
                        // lint check in main().
1735
 
                        do_flags |= DO_INTERVALS;
1736
 
                        break;
1737
 
 
1738
 
                case 's':
1739
 
                        do_optimize = false;
1740
 
                        break;
1741
 
 
1742
 
                case 'S':
1743
 
                        do_flags |= DO_SANDBOX;
1744
 
                        break;
1745
 
 
1746
 
                case 'T':       // --persist[=file]
1747
 
#ifdef USE_PERSISTENT_MALLOC
1748
 
                        if (optarg == NULL)
1749
 
                                optarg = "/some/file";
1750
 
                        fatal(_("Use `GAWK_PERSIST_FILE=%s gawk ...' instead of --persist."), optarg);
1751
 
#else
1752
 
                        warning(_("Persistent memory is not supported."));
1753
 
#endif /* USE_PERSISTENT_MALLOC */
1754
 
                        break;
1755
 
 
1756
 
                case 'V':
1757
 
                        do_version = true;
1758
 
                        break;
1759
 
 
1760
 
                case 'W':       /* gawk specific options - now in getopt_long */
1761
 
                        fprintf(stderr, _("%s: option `-W %s' unrecognized, ignored\n"),
1762
 
                                argv[0], optarg);
1763
 
                        break;
1764
 
 
1765
 
                case 0:
1766
 
                        /*
1767
 
                         * getopt_long found an option that sets a variable
1768
 
                         * instead of returning a letter. Do nothing, just
1769
 
                         * cycle around for the next one.
1770
 
                         */
1771
 
                        break;
1772
 
 
1773
 
                case 'Y':
1774
 
                case 'Z':
1775
 
#if defined(YYDEBUG) || defined(GAWKDEBUG)
1776
 
                        if (c == 'Y') {
1777
 
                                yydebug = 2;
1778
 
                                break;
1779
 
                        }
1780
 
#endif
1781
 
#if defined(LOCALEDEBUG)
1782
 
                        if (c == 'Z') {
1783
 
                                locale = optarg;
1784
 
                                break;
1785
 
                        }
1786
 
#endif
1787
 
                        /* if not debugging, fall through */
1788
 
                case '?':
1789
 
                default:
1790
 
                        /*
1791
 
                         * If not posix, an unrecognized option stops argument
1792
 
                         * processing so that it can go into ARGV for the awk
1793
 
                         * program to see. This makes use of ``#! /bin/gawk -f''
1794
 
                         * easier.
1795
 
                         *
1796
 
                         * However, it's never simple. If optopt is set,
1797
 
                         * an option that requires an argument didn't get the
1798
 
                         * argument. We care because if opterr is 0, then
1799
 
                         * getopt_long won't print the error message for us.
1800
 
                         */
1801
 
                        if (! do_posix
1802
 
                            && (optopt == '\0' || strchr(optlist, optopt) == NULL)) {
1803
 
                                /*
1804
 
                                 * can't just do optind--. In case of an
1805
 
                                 * option with >= 2 letters, getopt_long
1806
 
                                 * won't have incremented optind.
1807
 
                                 */
1808
 
                                optind = old_optind;
1809
 
                                stopped_early = true;
1810
 
                                goto out;
1811
 
                        } else if (optopt != '\0') {
1812
 
                                /* Use POSIX required message format */
1813
 
                                fprintf(stderr,
1814
 
                                        _("%s: option requires an argument -- %c\n"),
1815
 
                                        myname, optopt);
1816
 
                                usage(EXIT_FAILURE, stderr);
1817
 
                        }
1818
 
                        /* else
1819
 
                                let getopt print error message for us */
1820
 
                        break;
1821
 
                }
1822
 
                if (c == 'E')   /* --exec ends option processing */
1823
 
                        break;
1824
 
        }
1825
 
out:
1826
 
        do_optimize = (do_optimize && ! do_pretty_print);
1827
 
 
1828
 
        pma_mpfr_check();
1829
 
 
1830
 
        return;
1831
 
}
1832
 
 
1833
 
/* set_locale_stuff --- setup the locale stuff */
1834
 
 
1835
 
static void
1836
 
set_locale_stuff(void)
1837
 
{
1838
 
#if defined(LC_CTYPE)
1839
 
        setlocale(LC_CTYPE, locale);
1840
 
#endif
1841
 
#if defined(LC_COLLATE)
1842
 
        setlocale(LC_COLLATE, locale);
1843
 
#endif
1844
 
#if defined(LC_MESSAGES)
1845
 
        setlocale(LC_MESSAGES, locale);
1846
 
#endif
1847
 
#if defined(LC_NUMERIC) && defined(HAVE_LOCALE_H)
1848
 
        /*
1849
 
         * Force the issue here.  According to POSIX 2001, decimal
1850
 
         * point is used for parsing source code and for command-line
1851
 
         * assignments and the locale value for processing input,
1852
 
         * number to string conversion, and printing output.
1853
 
         *
1854
 
         * 10/2005 --- see below also; we now only use the locale's
1855
 
         * decimal point if do_posix in effect.
1856
 
         *
1857
 
         * 9/2007:
1858
 
         * This is a mess. We need to get the locale's numeric info for
1859
 
         * the thousands separator for the %'d flag.
1860
 
         */
1861
 
        setlocale(LC_NUMERIC, locale);
1862
 
        init_locale(& loc);
1863
 
        setlocale(LC_NUMERIC, "C");
1864
 
#endif
1865
 
#if defined(LC_TIME)
1866
 
        setlocale(LC_TIME, locale);
1867
 
#endif
1868
 
 
1869
 
        /* These must be done after calling setlocale */
1870
 
        (void) bindtextdomain(PACKAGE, locale_dir);
1871
 
        (void) textdomain(PACKAGE);
1872
 
}
1873
 
 
1874
 
/* platform_name --- return the platform name */
1875
 
 
1876
 
static const char *
1877
 
platform_name()
1878
 
{
1879
 
        // Cygwin and Mac OS X count as POSIX
1880
 
#if defined(__VMS)
1881
 
        return "vms";
1882
 
#elif defined(__MINGW32__)
1883
 
        return "mingw";
1884
 
#elif defined(USE_EBCDIC)
1885
 
        return "os390";
1886
 
#else
1887
 
        return "posix";
1888
 
#endif
1889
 
}
1890
 
 
1891
 
/* set_current_namespace --- set current_namespace and handle memory management */
1892
 
 
1893
 
void
1894
 
set_current_namespace(const char *new_namespace)
1895
 
{
1896
 
        if (current_namespace != awk_namespace)
1897
 
                efree((void *) current_namespace);
1898
 
 
1899
 
        current_namespace = new_namespace;
1900
 
}
1901
 
 
1902
 
/* check_pma_security --- make some minimal security checks */
1903
 
 
1904
 
static void
1905
 
check_pma_security(const char *pma_file)
1906
 
{
1907
 
#ifdef USE_PERSISTENT_MALLOC
1908
 
        struct stat sbuf;
1909
 
        int euid = geteuid();
1910
 
 
1911
 
        // don't use 'fatal' routine, it seems to need to allocate memory
1912
 
        // and we haven't initialized PMA yet.
1913
 
 
1914
 
        if (pma_file == NULL)
1915
 
                return;
1916
 
        else if (stat(pma_file, & sbuf) < 0) {
1917
 
                fprintf(stderr, _("%s: fatal: cannot stat %s: %s\n"),
1918
 
                                myname, pma_file, strerror(errno));
1919
 
                exit(EXIT_FATAL);
1920
 
        } else if (euid == 0) {
1921
 
                fprintf(stderr, _("%s: fatal: using persistent memory is not allowed when running as root.\n"), myname);
1922
 
                exit(EXIT_FATAL);
1923
 
        } else if (sbuf.st_uid != euid) {
1924
 
                fprintf(stderr, _("%s: warning: %s is not owned by euid %d.\n"),
1925
 
                                myname, pma_file, euid);
1926
 
        }
1927
 
#endif /* USE_PERSISTENT_MALLOC */
1928
 
}