OSDN Git Service

2005-02-26 Peter O'Gorman <peter@pogman.com>
[pf3gnuchains/gcc-fork.git] / libgfortran / runtime / environ.c
1 /* Copyright (C) 2002-2003 Free Software Foundation, Inc.
2    Contributed by Andy Vaught
3
4 This file is part of the GNU Fortran 95 runtime library (libgfortran).
5
6 Libgfortran is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file.  (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
18 executable.)
19
20 Libgfortran is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with libgfortran; see the file COPYING.  If not, write to
27 the Free Software Foundation, 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA.  */
29
30 #include "config.h"
31 #include <string.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34
35 #include "libgfortran.h"
36 #include "../io/io.h"
37
38
39 /* Environment scanner.  Examine the environment for controlling minor
40  * aspects of the program's execution.  Our philosophy here that the
41  * environment should not prevent the program from running, so an
42  * environment variable with a messed-up value will be interpreted in
43  * the default way.
44  *
45  * Most of the environment is checked early in the startup sequence,
46  * but other variables are checked during execution of the user's
47  * program. */
48
49 options_t options = { };
50
51
52 typedef struct variable
53 {
54   const char *name;
55   int value, *var;
56   void (*init) (struct variable *);
57   void (*show) (struct variable *);
58   const char *desc;
59   int bad;
60 }
61 variable;
62
63
64 /* print_spaces()-- Print a particular number of spaces */
65
66 static void
67 print_spaces (int n)
68 {
69   char buffer[80];
70   int i;
71
72   if (n <= 0)
73     return;
74
75   for (i = 0; i < n; i++)
76     buffer[i] = ' ';
77
78   buffer[i] = '\0';
79
80   st_printf (buffer);
81 }
82
83
84 /* var_source()-- Return a string that describes where the value of a
85  * variable comes from */
86
87 static const char *
88 var_source (variable * v)
89 {
90   if (getenv (v->name) == NULL)
91     return "Default";
92
93   if (v->bad)
94     return "Bad    ";
95
96   return "Set    ";
97 }
98
99
100 /* init_integer()-- Initialize an integer environment variable */
101
102 static void
103 init_integer (variable * v)
104 {
105   char *p, *q;
106
107   p = getenv (v->name);
108   if (p == NULL)
109     goto set_default;
110
111   for (q = p; *q; q++)
112     if (!isdigit (*q))
113       {
114         v->bad = 1;
115         goto set_default;
116       }
117
118   *v->var = atoi (p);
119   return;
120
121  set_default:
122   *v->var = v->value;
123   return;
124 }
125
126
127 /* show_integer()-- Show an integer environment variable */
128
129 static void
130 show_integer (variable * v)
131 {
132   st_printf ("%s  %d\n", var_source (v), *v->var);
133 }
134
135
136 /* init_boolean()-- Initialize a boolean environment variable.  We
137  * only look at the first letter of the variable. */
138
139 static void
140 init_boolean (variable * v)
141 {
142   char *p;
143
144   p = getenv (v->name);
145   if (p == NULL)
146     goto set_default;
147
148   if (*p == '1' || *p == 'Y' || *p == 'y')
149     {
150       *v->var = 1;
151       return;
152     }
153
154   if (*p == '0' || *p == 'N' || *p == 'n')
155     {
156       *v->var = 0;
157       return;
158     }
159
160   v->bad = 1;
161
162 set_default:
163   *v->var = v->value;
164   return;
165 }
166
167
168 /* show_boolean()-- Show a boolean environment variable */
169
170 static void
171 show_boolean (variable * v)
172 {
173   st_printf ("%s  %s\n", var_source (v), *v->var ? "Yes" : "No");
174 }
175
176
177 /* init_mem()-- Initialize environment variables that have to do with
178  * how memory from an ALLOCATE statement is filled.  A single flag
179  * enables filling and a second variable gives the value that is used
180  * to initialize the memory. */
181
182 static void
183 init_mem (variable * v)
184 {
185   int offset, n;
186   char *p;
187
188   p = getenv (v->name);
189
190   options.allocate_init_flag = 0;       /* The default */
191
192   if (p == NULL)
193     return;
194
195   if (strcasecmp (p, "NONE") == 0)
196     return;
197
198   /* IEEE-754 Quiet Not-a-Number that will work for single and double
199    * precision.  Look for the 'f95' mantissa in debug dumps. */
200
201   if (strcasecmp (p, "NaN") == 0)
202     {
203       options.allocate_init_flag = 1;
204       options.allocate_init_value = 0xfff80f95;
205       return;
206     }
207
208   /* Interpret the string as a hexadecimal constant */
209
210   n = 0;
211   while (*p)
212     {
213       if (!isxdigit (*p))
214         {
215           v->bad = 1;
216           return;
217         }
218
219       offset = '0';
220       if (islower (*p))
221         offset = 'a';
222       if (isupper (*p))
223         offset = 'A';
224
225       n = (n << 4) | (*p++ - offset);
226     }
227
228   options.allocate_init_flag = 1;
229   options.allocate_init_value = n;
230 }
231
232
233 static void
234 show_mem (variable * v)
235 {
236   char *p;
237
238   p = getenv (v->name);
239
240   st_printf ("%s  ", var_source (v));
241
242   if (options.allocate_init_flag)
243     st_printf ("0x%x", options.allocate_init_value);
244
245   st_printf ("\n");
246 }
247
248
249 static void
250 init_sep (variable * v)
251 {
252   int seen_comma;
253   char *p;
254
255   p = getenv (v->name);
256   if (p == NULL)
257     goto set_default;
258
259   v->bad = 1;
260   options.separator = p;
261   options.separator_len = strlen (p);
262
263   /* Make sure the separator is valid */
264
265   if (options.separator_len == 0)
266     goto set_default;
267   seen_comma = 0;
268
269   while (*p)
270     {
271       if (*p == ',')
272         {
273           if (seen_comma)
274             goto set_default;
275           seen_comma = 1;
276           p++;
277           continue;
278         }
279
280       if (*p++ != ' ')
281         goto set_default;
282     }
283
284   v->bad = 0;
285   return;
286
287 set_default:
288   options.separator = " ";
289   options.separator_len = 1;
290 }
291
292
293 static void
294 show_sep (variable * v)
295 {
296   st_printf ("%s  \"%s\"\n", var_source (v), options.separator);
297 }
298
299
300 static void
301 init_string (variable * v)
302 {
303 }
304
305 static void
306 show_string (variable * v)
307 {
308   const char *p;
309
310   p = getenv (v->name);
311   if (p == NULL)
312     p = "";
313
314   st_printf ("%s  \"%s\"\n", var_source (v), p);
315 }
316
317
318 /* Structure for associating names and values.  */
319
320 typedef struct
321 {
322   const char *name;
323   int value;
324 }
325 choice;
326
327
328 enum
329 { FP_ROUND_NEAREST, FP_ROUND_UP, FP_ROUND_DOWN, FP_ROUND_ZERO };
330
331 static choice rounding[] = {
332   {"NEAREST", FP_ROUND_NEAREST},
333   {"UP", FP_ROUND_UP},
334   {"DOWN", FP_ROUND_DOWN},
335   {"ZERO", FP_ROUND_ZERO},
336   {NULL}
337 };
338
339 static choice precision[] =
340 {
341   { "24", 1},
342   { "53", 2},
343   { "64", 0},
344   { NULL}
345 };
346
347 static choice signal_choices[] =
348 {
349   { "IGNORE", 1},
350   { "ABORT", 0},
351   { NULL}
352 };
353
354
355 static void
356 init_choice (variable * v, choice * c)
357 {
358   char *p;
359
360   p = getenv (v->name);
361   if (p == NULL)
362     goto set_default;
363
364   for (; c->name; c++)
365     if (strcasecmp (c->name, p) == 0)
366       break;
367
368   if (c->name == NULL)
369     {
370       v->bad = 1;
371       goto set_default;
372     }
373
374   *v->var = c->value;
375   return;
376
377  set_default:
378   *v->var = v->value;
379 }
380
381
382 static void
383 show_choice (variable * v, choice * c)
384 {
385   st_printf ("%s  ", var_source (v));
386
387   for (; c->name; c++)
388     if (c->value == *v->var)
389       break;
390
391   if (c->name)
392     st_printf ("%s\n", c->name);
393   else
394     st_printf ("(Unknown)\n");
395 }
396
397
398 static void
399 init_round (variable * v)
400 {
401   init_choice (v, rounding);
402 }
403
404 static void
405 show_round (variable * v)
406 {
407   show_choice (v, rounding);
408 }
409
410 static void
411 init_precision (variable * v)
412 {
413   init_choice (v, precision);
414 }
415
416 static void
417 show_precision (variable * v)
418 {
419   show_choice (v, precision);
420 }
421
422 static void
423 init_signal (variable * v)
424 {
425   init_choice (v, signal_choices);
426 }
427
428 static void
429 show_signal (variable * v)
430 {
431   show_choice (v, signal_choices);
432 }
433
434
435 static variable variable_table[] = {
436   {"GFORTRAN_STDIN_UNIT", 5, &options.stdin_unit, init_integer, show_integer,
437    "Unit number that will be preconnected to standard input\n"
438    "(No preconnection if negative)"},
439
440   {"GFORTRAN_STDOUT_UNIT", 6, &options.stdout_unit, init_integer,
441    show_integer,
442    "Unit number that will be preconnected to standard output\n"
443    "(No preconnection if negative)"},
444
445   {"GFORTRAN_STDERR_UNIT", 0, &options.stderr_unit, init_integer,
446    show_integer,
447    "Unit number that will be preconnected to standard error\n"
448    "(No preconnection if negative)"},
449
450   {"GFORTRAN_USE_STDERR", 1, &options.use_stderr, init_boolean,
451    show_boolean,
452    "Sends library output to standard error instead of standard output."},
453
454   {"GFORTRAN_TMPDIR", 0, NULL, init_string, show_string,
455    "Directory for scratch files.  Overrides the TMP environment variable\n"
456    "If TMP is not set " DEFAULT_TEMPDIR " is used."},
457
458   {"GFORTRAN_UNBUFFERED_ALL", 0, &options.all_unbuffered, init_boolean,
459    show_boolean,
460    "If TRUE, all output is unbuffered.  This will slow down large writes "
461    "but can be\nuseful for forcing data to be displayed immediately."},
462
463   {"GFORTRAN_SHOW_LOCUS", 1, &options.locus, init_boolean, show_boolean,
464    "If TRUE, print filename and line number where runtime errors happen."},
465
466   {"GFORTRAN_OPTIONAL_PLUS", 0, &options.optional_plus, init_boolean, show_boolean,
467    "Print optional plus signs in numbers where permitted.  Default FALSE."},
468
469   {"GFORTRAN_DEFAULT_RECL", DEFAULT_RECL, &options.default_recl,
470    init_integer, show_integer,
471    "Default maximum record length for sequential files.  Most useful for\n"
472    "adjusting line length of preconnected units.  Default "
473    stringize (DEFAULT_RECL)},
474
475   {"GFORTRAN_LIST_SEPARATOR", 0, NULL, init_sep, show_sep,
476    "Separatator to use when writing list output.  May contain any number of "
477    "spaces\nand at most one comma.  Default is a single space."},
478
479   /* Memory related controls */
480
481   {"GFORTRAN_MEM_INIT", 0, NULL, init_mem, show_mem,
482    "How to initialize allocated memory.  Default value is NONE for no "
483    "initialization\n(faster), NAN for a Not-a-Number with the mantissa "
484    "0x40f95 or a custom\nhexadecimal value"},
485
486   {"GFORTRAN_MEM_CHECK", 0, &options.mem_check, init_boolean, show_boolean,
487    "Whether memory still allocated will be reported when the program ends."},
488
489   /* Signal handling (Unix).  */
490
491   {"GFORTRAN_SIGHUP", 0, &options.sighup, init_signal, show_signal,
492    "Whether the program will IGNORE or ABORT on SIGHUP."},
493
494   {"GFORTRAN_SIGINT", 0, &options.sigint, init_signal, show_signal,
495    "Whether the program will IGNORE or ABORT on SIGINT."},
496
497   /* Floating point control */
498
499   {"GFORTRAN_FPU_ROUND", 0, &options.fpu_round, init_round, show_round,
500    "Set floating point rounding.  Values are NEAREST, UP, DOWN, ZERO."},
501
502   {"GFORTRAN_FPU_PRECISION", 0, &options.fpu_precision, init_precision,
503    show_precision,
504    "Precision of intermediate results.  Values are 24, 53 and 64."},
505
506   {"GFORTRAN_FPU_INVALID", 1, &options.fpu_invalid, init_boolean,
507    show_boolean,
508    "Raise a floating point exception on invalid FP operation."},
509
510   {"GFORTRAN_FPU_DENORMAL", 1, &options.fpu_denormal, init_boolean,
511    show_boolean,
512    "Raise a floating point exception when denormal numbers are encountered."},
513
514   {"GFORTRAN_FPU_ZERO", 0, &options.fpu_zerodiv, init_boolean, show_boolean,
515    "Raise a floating point exception when dividing by zero."},
516
517   {"GFORTRAN_FPU_OVERFLOW", 0, &options.fpu_overflow, init_boolean,
518    show_boolean,
519    "Raise a floating point exception on overflow."},
520
521   {"GFORTRAN_FPU_UNDERFLOW", 0, &options.fpu_underflow, init_boolean,
522    show_boolean,
523    "Raise a floating point exception on underflow."},
524
525   {"GFORTRAN_FPU_PRECISION", 0, &options.fpu_precision_loss, init_boolean,
526    show_boolean,
527    "Raise a floating point exception on precision loss."},
528
529   {NULL}
530 };
531
532
533 /* init_variables()-- Initialize most runtime variables from
534  * environment variables. */
535
536 void
537 init_variables (void)
538 {
539   variable *v;
540
541   for (v = variable_table; v->name; v++)
542     v->init (v);
543 }
544
545
546 /* check_buffered()-- Given an unit number n, determine if an override
547  * for the stream exists.  Returns zero for unbuffered, one for
548  * buffered or two for not set. */
549
550 int
551 check_buffered (int n)
552 {
553   char name[40];
554   variable v;
555   int rv;
556
557   if (options.all_unbuffered)
558     return 0;
559
560   strcpy (name, "GFORTRAN_UNBUFFERED_");
561   strcat (name, gfc_itoa (n));
562
563   v.name = name;
564   v.value = 2;
565   v.var = &rv;
566
567   init_boolean (&v);
568
569   return rv;
570 }
571
572
573 void
574 show_variables (void)
575 {
576   variable *v;
577   int n;
578
579   /* TODO: print version number.  */
580   st_printf ("GNU Fortran 95 runtime library version "
581              "UNKNOWN" "\n\n");
582
583   st_printf ("Environment variables:\n");
584   st_printf ("----------------------\n");
585
586   for (v = variable_table; v->name; v++)
587     {
588       n = st_printf ("%s", v->name);
589       print_spaces (25 - n);
590
591       if (v->show == show_integer)
592         st_printf ("Integer ");
593       else if (v->show == show_boolean)
594         st_printf ("Boolean ");
595       else
596         st_printf ("String  ");
597
598       v->show (v);
599       st_printf ("%s\n\n", v->desc);
600     }
601
602   /* System error codes */
603
604   st_printf ("\nRuntime error codes:");
605   st_printf ("\n--------------------\n");
606
607   for (n = ERROR_FIRST + 1; n < ERROR_LAST; n++)
608     if (n < 0 || n > 9)
609       st_printf ("%d  %s\n", n, translate_error (n));
610     else
611       st_printf (" %d  %s\n", n, translate_error (n));
612
613   st_printf ("\nCommand line arguments:\n");
614   st_printf ("  --help               Print this list\n");
615
616   /* st_printf("  --resume <dropfile>  Resume program execution from dropfile\n"); */
617
618   sys_exit (0);
619 }