summaryrefslogtreecommitdiff
path: root/libgfortran/runtime/environ.c
diff options
context:
space:
mode:
authordnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2004-05-13 06:41:07 +0000
committerdnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2004-05-13 06:41:07 +0000
commit4ee9c6840ad3fc92a9034343278a1e476ad6872a (patch)
treea2568888a519c077427b133de9ece5879a8484a5 /libgfortran/runtime/environ.c
parentebb338380ab170c91e64d38038e6b5ce930d69a1 (diff)
downloadgcc-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.c678
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);
+}