diff options
author | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 06:41:07 +0000 |
---|---|---|
committer | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 06:41:07 +0000 |
commit | 4ee9c6840ad3fc92a9034343278a1e476ad6872a (patch) | |
tree | a2568888a519c077427b133de9ece5879a8484a5 /libgfortran/runtime/environ.c | |
parent | ebb338380ab170c91e64d38038e6b5ce930d69a1 (diff) | |
download | gcc-4ee9c6840ad3fc92a9034343278a1e476ad6872a.tar.gz |
Merge tree-ssa-20020619-branch into mainline.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@81764 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgfortran/runtime/environ.c')
-rw-r--r-- | libgfortran/runtime/environ.c | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/libgfortran/runtime/environ.c b/libgfortran/runtime/environ.c new file mode 100644 index 00000000000..71419616920 --- /dev/null +++ b/libgfortran/runtime/environ.c @@ -0,0 +1,678 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with libgfor; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include <string.h> +#include <stdlib.h> +#include <ctype.h> + +#include "libgfortran.h" +#include "../io/io.h" + + +/* Environment scanner. Examine the environment for controlling minor + * aspects of the program's execution. Our philosophy here that the + * environment should not prevent the program from running, so an + * environment variable with a messed-up value will be interpreted in + * the default way. + * + * Most of the environment is checked early in the startup sequence, + * but other variables are checked during execution of the user's + * program. */ + +options_t options; + +extern char **environ; + +typedef struct variable +{ + const char *name; + int value, *var; + void (*init) (struct variable *); + void (*show) (struct variable *); + const char *desc; + int bad; +} +variable; + + +/* print_spaces()-- Print a particular number of spaces */ + +static void +print_spaces (int n) +{ + char buffer[80]; + int i; + + if (n <= 0) + return; + + for (i = 0; i < n; i++) + buffer[i] = ' '; + + buffer[i] = '\0'; + + st_printf (buffer); +} + + +/* var_source()-- Return a string that describes where the value of a + * variable comes from */ + +static const char * +var_source (variable * v) +{ + + if (getenv (v->name) == NULL) + return "Default"; + + if (v->bad) + return "Bad "; + + return "Set "; +} + + +/* init_integer()-- Initialize an integer environment variable */ + +static void +init_integer (variable * v) +{ + char *p, *q; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + for (q = p; *q; q++) + if (!isdigit (*q)) + { + v->bad = 1; + goto set_default; + } + + *v->var = atoi (p); + return; + +set_default: + *v->var = v->value; + return; +} + + +/* show_integer()-- Show an integer environment variable */ + +static void +show_integer (variable * v) +{ + + st_printf ("%s %d\n", var_source (v), *v->var); +} + + +/* init_boolean()-- Initialize a boolean environment variable. We + * only look at the first letter of the variable. */ + +static void +init_boolean (variable * v) +{ + char *p; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + if (*p == '1' || *p == 'Y' || *p == 'y') + { + *v->var = 1; + return; + } + + if (*p == '0' || *p == 'N' || *p == 'n') + { + *v->var = 0; + return; + } + + v->bad = 1; + +set_default: + *v->var = v->value; + return; +} + + +/* show_boolean()-- Show a boolean environment variable */ + +static void +show_boolean (variable * v) +{ + + st_printf ("%s %s\n", var_source (v), *v->var ? "Yes" : "No"); +} + + +/* init_mem()-- Initialize environment variables that have to do with + * how memory from an ALLOCATE statement is filled. A single flag + * enables filling and a second variable gives the value that is used + * to initialize the memory. */ + +static void +init_mem (variable * v) +{ + int offset, n; + char *p; + + p = getenv (v->name); + + options.allocate_init_flag = 0; /* The default */ + + if (p == NULL) + return; + + if (strcasecmp (p, "NONE") == 0) + return; + + /* IEEE-754 Quiet Not-a-Number that will work for single and double + * precision. Look for the 'f95' mantissa in debug dumps. */ + + if (strcasecmp (p, "NaN") == 0) + { + options.allocate_init_flag = 1; + options.allocate_init_value = 0xfff80f95; + return; + } + + /* Interpret the string as a hexadecimal constant */ + + n = 0; + while (*p) + { + if (!isxdigit (*p)) + { + v->bad = 1; + return; + } + + offset = '0'; + if (islower (*p)) + offset = 'a'; + if (isupper (*p)) + offset = 'A'; + + n = (n << 4) | (*p++ - offset); + } + + options.allocate_init_flag = 1; + options.allocate_init_value = n; +} + + +static void +show_mem (variable * v) +{ + char *p; + + p = getenv (v->name); + + st_printf ("%s ", var_source (v)); + + if (options.allocate_init_flag) + st_printf ("0x%x", options.allocate_init_value); + + st_printf ("\n"); +} + + +static void +init_sep (variable * v) +{ + int seen_comma; + char *p; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + v->bad = 1; + options.separator = p; + options.separator_len = strlen (p); + + /* Make sure the separator is valid */ + + if (options.separator_len == 0) + goto set_default; + seen_comma = 0; + + while (*p) + { + if (*p == ',') + { + if (seen_comma) + goto set_default; + seen_comma = 1; + p++; + continue; + } + + if (*p++ != ' ') + goto set_default; + } + + v->bad = 0; + return; + +set_default: + options.separator = " "; + options.separator_len = 1; +} + + +static void +show_sep (variable * v) +{ + + st_printf ("%s \"%s\"\n", var_source (v), options.separator); +} + + +static void +init_string (variable * v) +{ +} + +static void +show_string (variable * v) +{ + const char *p; + + p = getenv (v->name); + if (p == NULL) + p = ""; + + st_printf ("%s \"%s\"\n", var_source (v), p); +} + + +/* Structure for associating names and values. */ + +typedef struct +{ + const char *name; + int value; +} +choice; + + +enum +{ FP_ROUND_NEAREST, FP_ROUND_UP, FP_ROUND_DOWN, FP_ROUND_ZERO }; + +static choice rounding[] = { + {"NEAREST", FP_ROUND_NEAREST}, + {"UP", FP_ROUND_UP}, + {"DOWN", FP_ROUND_DOWN}, + {"ZERO", FP_ROUND_ZERO}, + {NULL} +}, precision[] = +{ + { + "24", 1} + , + { + "53", 2} + , + { + "64", 0} + , + { + NULL} +} + +, signal_choices[] = +{ + { + "IGNORE", 1} + , + { + "ABORT", 0} + , + { + NULL} +}; + + +static void +init_choice (variable * v, choice * c) +{ + char *p; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + for (; c->name; c++) + if (strcasecmp (c->name, p) == 0) + break; + + if (c->name == NULL) + { + v->bad = 1; + goto set_default; + } + + *v->var = c->value; + return; + +set_default: + *v->var = v->value; +} + + +static void +show_choice (variable * v, choice * c) +{ + + st_printf ("%s ", var_source (v)); + + for (; c->name; c++) + if (c->value == *v->var) + break; + + if (c->name) + st_printf ("%s\n", c->name); + else + st_printf ("(Unknown)\n"); + +} + + +static void +init_round (variable * v) +{ + init_choice (v, rounding); +} +static void +show_round (variable * v) +{ + show_choice (v, rounding); +} + +static void +init_precision (variable * v) +{ + init_choice (v, precision); +} +static void +show_precision (variable * v) +{ + show_choice (v, precision); +} + +static void +init_signal (variable * v) +{ + init_choice (v, signal_choices); +} +static void +show_signal (variable * v) +{ + show_choice (v, signal_choices); +} + + +static variable variable_table[] = { + {"GFORTRAN_STDIN_UNIT", 5, &options.stdin_unit, init_integer, show_integer, + "Unit number that will be preconnected to standard input\n" + "(No preconnection if negative)"}, + + {"GFORTRAN_STDOUT_UNIT", 6, &options.stdout_unit, init_integer, + show_integer, + "Unit number that will be preconnected to standard output\n" + "(No preconnection if negative)"}, + + {"GFORTRAN_USE_STDERR", 1, &options.use_stderr, init_boolean, + show_boolean, + "Sends library output to standard error instead of standard output."}, + + {"GFORTRAN_TMPDIR", 0, NULL, init_string, show_string, + "Directory for scratch files. Overrides the TMP environment variable\n" + "If TMP is not set " DEFAULT_TEMPDIR " is used."}, + + {"GFORTRAN_UNBUFFERED_ALL", 0, &options.all_unbuffered, init_boolean, + show_boolean, + "If TRUE, all output is unbuffered. This will slow down large writes " + "but can be\nuseful for forcing data to be displayed immediately."}, + + {"GFORTRAN_SHOW_LOCUS", 1, &options.locus, init_boolean, show_boolean, + "If TRUE, print filename and line number where runtime errors happen."}, + +/* GFORTRAN_NAME_xx (where xx is a unit number) gives the names of files + * preconnected to those units. */ + +/* GFORTRAN_UNBUFFERED_xx (where xx is a unit number) gives a boolean that is used + * to turn off buffering for that unit. */ + + {"GFORTRAN_OPTIONAL_PLUS", 0, &options.optional_plus, init_boolean, show_boolean, + "Print optional plus signs in numbers where permitted. Default FALSE."}, + + {"GFORTRAN_DEFAULT_RECL", DEFAULT_RECL, &options.default_recl, + init_integer, show_integer, + "Default maximum record length for sequential files. Most useful for\n" + "adjusting line length of preconnected units. Default " + stringize (DEFAULT_RECL)}, + + {"GFORTRAN_LIST_SEPARATOR", 0, NULL, init_sep, show_sep, + "Separatator to use when writing list output. May contain any number of " + "spaces\nand at most one comma. Default is a single space."}, + + /* Memory related controls */ + + {"GFORTRAN_MEM_INIT", 0, NULL, init_mem, show_mem, + "How to initialize allocated memory. Default value is NONE for no " + "initialization\n(faster), NAN for a Not-a-Number with the mantissa " + "0x40f95 or a custom\nhexadecimal value"}, + + {"GFORTRAN_MEM_CHECK", 0, &options.mem_check, init_boolean, show_boolean, + "Whether memory still allocated will be reported when the program ends."}, + + /* Signal handling (Unix). */ + + {"GFORTRAN_SIGHUP", 0, &options.sighup, init_signal, show_signal, + "Whether the program will IGNORE or ABORT on SIGHUP."}, + + {"GFORTRAN_SIGINT", 0, &options.sigint, init_signal, show_signal, + "Whether the program will IGNORE or ABORT on SIGINT."}, + + /* Floating point control */ + + {"GFORTRAN_FPU_ROUND", 0, &options.fpu_round, init_round, show_round, + "Set floating point rounding. Values are NEAREST, UP, DOWN, ZERO."}, + + {"GFORTRAN_FPU_PRECISION", 0, &options.fpu_precision, init_precision, + show_precision, + "Precision of intermediate results. Values are 24, 53 and 64."}, + + {"GFORTRAN_FPU_INVALID", 1, &options.fpu_invalid, init_boolean, + show_boolean, + "Raise a floating point exception on invalid FP operation."}, + + {"GFORTRAN_FPU_DENORMAL", 1, &options.fpu_denormal, init_boolean, + show_boolean, + "Raise a floating point exception when denormal numbers are encountered."}, + + {"GFORTRAN_FPU_ZERO", 0, &options.fpu_zerodiv, init_boolean, show_boolean, + "Raise a floating point exception when dividing by zero."}, + + {"GFORTRAN_FPU_OVERFLOW", 0, &options.fpu_overflow, init_boolean, + show_boolean, + "Raise a floating point exception on overflow."}, + + {"GFORTRAN_FPU_UNDERFLOW", 0, &options.fpu_underflow, init_boolean, + show_boolean, + "Raise a floating point exception on underflow."}, + + {"GFORTRAN_FPU_PRECISION", 0, &options.fpu_precision_loss, init_boolean, + show_boolean, + "Raise a floating point exception on precision loss."}, + + {NULL} +}; + + +/* init_variables()-- Initialize most runtime variables from + * environment variables. */ + +void +init_variables (void) +{ + variable *v; + + for (v = variable_table; v->name; v++) + v->init (v); +} + + +/* check_buffered()-- Given an unit number n, determine if an override + * for the stream exists. Returns zero for unbuffered, one for + * buffered or two for not set. */ + +int +check_buffered (int n) +{ + char name[40]; + variable v; + int rv; + + if (options.all_unbuffered) + return 0; + + strcpy (name, "GFORTRAN_UNBUFFERED_"); + strcat (name, itoa (n)); + + v.name = name; + v.value = 2; + v.var = &rv; + + init_boolean (&v); + + return rv; +} + + +/* pattern_scan()-- Given an environment string, check that the name + * has the same name as the pattern followed by an integer. On a + * match, a pointer to the value is returned and the integer pointed + * to by n is updated. Returns NULL on no match. */ + +static char * +pattern_scan (char *env, const char *pattern, int *n) +{ + char *p; + size_t len; + + len = strlen (pattern); + if (strncasecmp (env, pattern, len) != 0) + return NULL; + p = env + len; + + if (!isdigit (*p)) + return NULL; + + while (isdigit (*p)) + p++; + + if (*p != '=') + return NULL; + + *p = '\0'; + *n = atoi (env + len); + *p++ = '='; + + return p; +} + + +void +show_variables (void) +{ + char *p, **e; + variable *v; + int n; +/* TODO: print version number. */ + st_printf ("GNU Fortran 95 runtime library version " + "UNKNOWN" "\n\n"); + + st_printf ("Environment variables:\n"); + st_printf ("----------------------\n"); + + for (v = variable_table; v->name; v++) + { + n = st_printf ("%s", v->name); + print_spaces (25 - n); + + if (v->show == show_integer) + st_printf ("Integer "); + else if (v->show == show_boolean) + st_printf ("Boolean "); + else + st_printf ("String "); + + v->show (v); + st_printf ("%s\n\n", v->desc); + } + + st_printf ("\nDefault unit names (GFORTRAN_NAME_x):\n"); + + for (e = environ; *e; e++) + { + p = pattern_scan (*e, "GFORTRAN_NAME_", &n); + if (p == NULL) + continue; + st_printf ("GFORTRAN_NAME_%d %s\n", n, p); + } + + st_printf ("\nUnit buffering overrides (GFORTRAN_UNBUFFERED_x):\n"); + for (e = environ; *e; e++) + { + p = pattern_scan (*e, "GFORTRAN_UNBUFFERED_", &n); + if (p == NULL) + continue; + + st_printf ("GFORTRAN_UNBUFFERED_%d = %s\n", n, p); + } + + /* System error codes */ + + st_printf ("\nRuntime error codes:"); + st_printf ("\n--------------------\n"); + + for (n = ERROR_FIRST + 1; n < ERROR_LAST; n++) + if (n < 0 || n > 9) + st_printf ("%d %s\n", n, translate_error (n)); + else + st_printf (" %d %s\n", n, translate_error (n)); + + st_printf ("\nCommand line arguments:\n"); + st_printf (" --help Print this list\n"); + + /* st_printf(" --resume <dropfile> Resume program execution from dropfile\n"); */ + + sys_exit (0); +} |