1 /* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
4 This file is part of the GNU Fortran 95 runtime library (libgfortran).
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 3, or (at your option)
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 #include "libgfortran.h"
32 /* Environment scanner. Examine the environment for controlling minor
33 * aspects of the program's execution. Our philosophy here that the
34 * environment should not prevent the program from running, so an
35 * environment variable with a messed-up value will be interpreted in
38 * Most of the environment is checked early in the startup sequence,
39 * but other variables are checked during execution of the user's
45 typedef struct variable
49 void (*init
) (struct variable
*);
50 void (*show
) (struct variable
*);
56 static void init_unformatted (variable
*);
58 /* print_spaces()-- Print a particular number of spaces. */
69 for (i
= 0; i
< n
; i
++)
78 /* var_source()-- Return a string that describes where the value of a
79 * variable comes from */
82 var_source (variable
* v
)
84 if (getenv (v
->name
) == NULL
)
94 /* init_integer()-- Initialize an integer environment variable. */
97 init_integer (variable
* v
)
101 p
= getenv (v
->name
);
106 if (!isdigit (*q
) && (p
!= q
|| *q
!= '-'))
121 /* init_unsigned_integer()-- Initialize an integer environment variable
122 which has to be positive. */
125 init_unsigned_integer (variable
* v
)
129 p
= getenv (v
->name
);
149 /* show_integer()-- Show an integer environment variable */
152 show_integer (variable
* v
)
154 st_printf ("%s %d\n", var_source (v
), *v
->var
);
158 /* init_boolean()-- Initialize a boolean environment variable. We
159 * only look at the first letter of the variable. */
162 init_boolean (variable
* v
)
166 p
= getenv (v
->name
);
170 if (*p
== '1' || *p
== 'Y' || *p
== 'y')
176 if (*p
== '0' || *p
== 'N' || *p
== 'n')
190 /* show_boolean()-- Show a boolean environment variable */
193 show_boolean (variable
* v
)
195 st_printf ("%s %s\n", var_source (v
), *v
->var
? "Yes" : "No");
200 init_sep (variable
* v
)
205 p
= getenv (v
->name
);
210 options
.separator
= p
;
211 options
.separator_len
= strlen (p
);
213 /* Make sure the separator is valid */
215 if (options
.separator_len
== 0)
238 options
.separator
= " ";
239 options
.separator_len
= 1;
244 show_sep (variable
* v
)
246 st_printf ("%s \"%s\"\n", var_source (v
), options
.separator
);
251 init_string (variable
* v
__attribute__ ((unused
)))
256 show_string (variable
* v
)
260 p
= getenv (v
->name
);
264 estr_write (var_source (v
));
271 static variable variable_table
[] = {
272 {"GFORTRAN_STDIN_UNIT", GFC_STDIN_UNIT_NUMBER
, &options
.stdin_unit
,
273 init_integer
, show_integer
,
274 "Unit number that will be preconnected to standard input\n"
275 "(No preconnection if negative)", 0},
277 {"GFORTRAN_STDOUT_UNIT", GFC_STDOUT_UNIT_NUMBER
, &options
.stdout_unit
,
278 init_integer
, show_integer
,
279 "Unit number that will be preconnected to standard output\n"
280 "(No preconnection if negative)", 0},
282 {"GFORTRAN_STDERR_UNIT", GFC_STDERR_UNIT_NUMBER
, &options
.stderr_unit
,
283 init_integer
, show_integer
,
284 "Unit number that will be preconnected to standard error\n"
285 "(No preconnection if negative)", 0},
287 {"GFORTRAN_TMPDIR", 0, NULL
, init_string
, show_string
,
288 "Directory for scratch files. Overrides the TMP environment variable\n"
289 "If TMP is not set " DEFAULT_TEMPDIR
" is used.", 0},
291 {"GFORTRAN_UNBUFFERED_ALL", 0, &options
.all_unbuffered
, init_boolean
,
293 "If TRUE, all output is unbuffered. This will slow down large writes "
294 "but can be\nuseful for forcing data to be displayed immediately.", 0},
296 {"GFORTRAN_UNBUFFERED_PRECONNECTED", 0, &options
.unbuffered_preconnected
,
297 init_boolean
, show_boolean
,
298 "If TRUE, output to preconnected units is unbuffered.", 0},
300 {"GFORTRAN_SHOW_LOCUS", 1, &options
.locus
, init_boolean
, show_boolean
,
301 "If TRUE, print filename and line number where runtime errors happen.", 0},
303 {"GFORTRAN_OPTIONAL_PLUS", 0, &options
.optional_plus
, init_boolean
, show_boolean
,
304 "Print optional plus signs in numbers where permitted. Default FALSE.", 0},
306 {"GFORTRAN_DEFAULT_RECL", DEFAULT_RECL
, &options
.default_recl
,
307 init_unsigned_integer
, show_integer
,
308 "Default maximum record length for sequential files. Most useful for\n"
309 "adjusting line length of preconnected units. Default "
310 stringize (DEFAULT_RECL
), 0},
312 {"GFORTRAN_LIST_SEPARATOR", 0, NULL
, init_sep
, show_sep
,
313 "Separator to use when writing list output. May contain any number of "
314 "spaces\nand at most one comma. Default is a single space.", 0},
316 /* GFORTRAN_CONVERT_UNIT - Set the default data conversion for
318 {"GFORTRAN_CONVERT_UNIT", 0, 0, init_unformatted
, show_string
,
319 "Set format for unformatted files", 0},
321 {"GFORTRAN_ERROR_BACKTRACE", -1, &options
.backtrace
,
322 init_boolean
, show_boolean
,
323 "Print out a backtrace (if possible) on runtime error", -1},
325 {NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0}
329 /* init_variables()-- Initialize most runtime variables from
330 * environment variables. */
333 init_variables (void)
337 for (v
= variable_table
; v
->name
; v
++)
343 show_variables (void)
348 /* TODO: print version number. */
349 estr_write ("GNU Fortran runtime library version "
352 estr_write ("Environment variables:\n");
353 estr_write ("----------------------\n");
355 for (v
= variable_table
; v
->name
; v
++)
357 n
= estr_write (v
->name
);
358 print_spaces (25 - n
);
360 if (v
->show
== show_integer
)
361 estr_write ("Integer ");
362 else if (v
->show
== show_boolean
)
363 estr_write ("Boolean ");
365 estr_write ("String ");
368 estr_write (v
->desc
);
372 /* System error codes */
374 estr_write ("\nRuntime error codes:");
375 estr_write ("\n--------------------\n");
377 for (n
= LIBERROR_FIRST
+ 1; n
< LIBERROR_LAST
; n
++)
379 st_printf ("%d %s\n", n
, translate_error (n
));
381 st_printf (" %d %s\n", n
, translate_error (n
));
383 estr_write ("\nCommand line arguments:\n");
384 estr_write (" --help Print this list\n");
389 /* This is the handling of the GFORTRAN_CONVERT_UNITS environment variable.
390 It is called from environ.c to parse this variable, and from
391 open.c to determine if the user specified a default for an
393 The syntax of the environment variable is, in bison grammar:
395 GFORTRAN_CONVERT_UNITS: mode | mode ';' exception ;
396 mode: 'native' | 'swap' | 'big_endian' | 'little_endian' ;
397 exception: mode ':' unit_list | unit_list ;
398 unit_list: unit_spec | unit_list unit_spec ;
399 unit_spec: INTEGER | INTEGER '-' INTEGER ;
402 /* Defines for the tokens. Other valid tokens are ',', ':', '-'. */
409 /* Some space for additional tokens later. */
421 static char *p
; /* Main character pointer for parsing. */
422 static char *lastpos
; /* Auxiliary pointer, for backing up. */
423 static int unit_num
; /* The last unit number read. */
424 static int unit_count
; /* The number of units found. */
425 static int do_count
; /* Parsing is done twice - first to count the number
426 of units, then to fill in the table. This
427 variable controls what to do. */
428 static exception_t
*elist
; /* The list of exceptions to the default. This is
429 sorted according to unit number. */
430 static int n_elist
; /* Number of exceptions to the default. */
432 static unit_convert endian
; /* Current endianness. */
434 static unit_convert def
; /* Default as specified (if any). */
436 /* Search for a unit number, using a binary search. The
437 first argument is the unit number to search for. The second argument
438 is a pointer to an index.
439 If the unit number is found, the function returns 1, and the index
440 is that of the element.
441 If the unit number is not found, the function returns 0, and the
442 index is the one where the element would be inserted. */
445 search_unit (int unit
, int *ip
)
451 while (high
- low
> 1)
453 mid
= (low
+ high
) / 2;
454 if (unit
<= elist
[mid
].unit
)
460 if (elist
[high
].unit
== unit
)
466 /* This matches a keyword. If it is found, return the token supplied,
467 otherwise return ILLEGAL. */
470 match_word (const char *word
, int tok
)
474 if (strncasecmp (p
, word
, strlen (word
)) == 0)
485 /* Match an integer and store its value in unit_num. This only works
486 if p actually points to the start of an integer. The caller has
494 unit_num
= unit_num
* 10 + (*p
++ - '0');
499 /* This reads the next token from the GFORTRAN_CONVERT_UNITS variable.
500 Returned values are the different tokens. */
524 result
= match_word ("big_endian", BIG
);
529 result
= match_word ("little_endian", LITTLE
);
534 result
= match_word ("native", NATIVE
);
539 result
= match_word ("swap", SWAP
);
542 case '1': case '2': case '3': case '4': case '5':
543 case '6': case '7': case '8': case '9':
544 result
= match_integer ();
554 /* Back up the last token by setting back the character pointer. */
562 /* This is called when a unit is identified. If do_count is nonzero,
563 increment the number of units by one. If do_count is zero,
564 put the unit into the table. */
567 mark_single (int unit
)
576 if (search_unit (unit
, &i
))
578 elist
[unit
].conv
= endian
;
582 for (j
=n_elist
; j
>=i
; j
--)
583 elist
[j
+1] = elist
[j
];
586 elist
[i
].unit
= unit
;
587 elist
[i
].conv
= endian
;
591 /* This is called when a unit range is identified. If do_count is
592 nonzero, increase the number of units. If do_count is zero,
593 put the unit into the table. */
596 mark_range (int unit1
, int unit2
)
600 unit_count
+= abs (unit2
- unit1
) + 1;
604 for (i
=unit2
; i
<=unit1
; i
++)
607 for (i
=unit1
; i
<=unit2
; i
++)
612 /* Parse the GFORTRAN_CONVERT_UNITS variable. This is called
613 twice, once to count the units and once to actually mark them in
614 the table. When counting, we don't check for double occurrences
629 /* Parse the string. First, let's look for a default. */
634 endian
= GFC_CONVERT_NATIVE
;
638 endian
= GFC_CONVERT_SWAP
;
642 endian
= GFC_CONVERT_BIG
;
646 endian
= GFC_CONVERT_LITTLE
;
650 /* A leading digit means that we are looking at an exception.
651 Reset the position to the beginning, and continue processing
652 at the exception list. */
674 /* This isn't a default after all. Reset the position to the
675 beginning, and continue processing at the exception list. */
692 /* Loop over all exceptions. */
699 if (next_token () != ':')
701 endian
= GFC_CONVERT_NATIVE
;
705 if (next_token () != ':')
707 endian
= GFC_CONVERT_SWAP
;
711 if (next_token () != ':')
713 endian
= GFC_CONVERT_LITTLE
;
717 if (next_token () != ':')
719 endian
= GFC_CONVERT_BIG
;
734 /* We arrive here when we want to parse a list of
745 /* The number can be followed by a - and another number,
746 which means that this is a unit range, a comma
750 if (next_token () != INTEGER
)
753 mark_range (unit1
, unit_num
);
782 } while (continue_ulist
);
787 def
= GFC_CONVERT_NONE
;
791 void init_unformatted (variable
* v
)
794 val
= getenv (v
->name
);
795 def
= GFC_CONVERT_NONE
;
810 elist
= get_mem (unit_count
* sizeof (exception_t
));
817 /* Get the default conversion for for an unformatted unit. */
820 get_unformatted_convert (int unit
)
826 else if (search_unit (unit
, &i
))
827 return elist
[i
].conv
;