2011-08-19 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libgfortran / runtime / environ.c
blob6bd88865d89b47d320aeecd7b0d1ef62275009f6
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)
9 any later version.
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"
27 #include <string.h>
28 #include <stdlib.h>
29 #include <ctype.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
36 * the default way.
38 * Most of the environment is checked early in the startup sequence,
39 * but other variables are checked during execution of the user's
40 * program. */
42 options_t options;
45 typedef struct variable
47 const char *name;
48 int value, *var;
49 void (*init) (struct variable *);
50 void (*show) (struct variable *);
51 const char *desc;
52 int bad;
54 variable;
56 static void init_unformatted (variable *);
58 /* print_spaces()-- Print a particular number of spaces. */
60 static void
61 print_spaces (int n)
63 char buffer[80];
64 int i;
66 if (n <= 0)
67 return;
69 for (i = 0; i < n; i++)
70 buffer[i] = ' ';
72 buffer[i] = '\0';
74 estr_write (buffer);
78 /* var_source()-- Return a string that describes where the value of a
79 * variable comes from */
81 static const char *
82 var_source (variable * v)
84 if (getenv (v->name) == NULL)
85 return "Default";
87 if (v->bad)
88 return "Bad ";
90 return "Set ";
94 /* init_integer()-- Initialize an integer environment variable. */
96 static void
97 init_integer (variable * v)
99 char *p, *q;
101 p = getenv (v->name);
102 if (p == NULL)
103 goto set_default;
105 for (q = p; *q; q++)
106 if (!isdigit (*q) && (p != q || *q != '-'))
108 v->bad = 1;
109 goto set_default;
112 *v->var = atoi (p);
113 return;
115 set_default:
116 *v->var = v->value;
117 return;
121 /* init_unsigned_integer()-- Initialize an integer environment variable
122 which has to be positive. */
124 static void
125 init_unsigned_integer (variable * v)
127 char *p, *q;
129 p = getenv (v->name);
130 if (p == NULL)
131 goto set_default;
133 for (q = p; *q; q++)
134 if (!isdigit (*q))
136 v->bad = 1;
137 goto set_default;
140 *v->var = atoi (p);
141 return;
143 set_default:
144 *v->var = v->value;
145 return;
149 /* show_integer()-- Show an integer environment variable */
151 static void
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. */
161 static void
162 init_boolean (variable * v)
164 char *p;
166 p = getenv (v->name);
167 if (p == NULL)
168 goto set_default;
170 if (*p == '1' || *p == 'Y' || *p == 'y')
172 *v->var = 1;
173 return;
176 if (*p == '0' || *p == 'N' || *p == 'n')
178 *v->var = 0;
179 return;
182 v->bad = 1;
184 set_default:
185 *v->var = v->value;
186 return;
190 /* show_boolean()-- Show a boolean environment variable */
192 static void
193 show_boolean (variable * v)
195 st_printf ("%s %s\n", var_source (v), *v->var ? "Yes" : "No");
199 static void
200 init_sep (variable * v)
202 int seen_comma;
203 char *p;
205 p = getenv (v->name);
206 if (p == NULL)
207 goto set_default;
209 v->bad = 1;
210 options.separator = p;
211 options.separator_len = strlen (p);
213 /* Make sure the separator is valid */
215 if (options.separator_len == 0)
216 goto set_default;
217 seen_comma = 0;
219 while (*p)
221 if (*p == ',')
223 if (seen_comma)
224 goto set_default;
225 seen_comma = 1;
226 p++;
227 continue;
230 if (*p++ != ' ')
231 goto set_default;
234 v->bad = 0;
235 return;
237 set_default:
238 options.separator = " ";
239 options.separator_len = 1;
243 static void
244 show_sep (variable * v)
246 st_printf ("%s \"%s\"\n", var_source (v), options.separator);
250 static void
251 init_string (variable * v __attribute__ ((unused)))
255 static void
256 show_string (variable * v)
258 const char *p;
260 p = getenv (v->name);
261 if (p == NULL)
262 p = "";
264 estr_write (var_source (v));
265 estr_write (" \"");
266 estr_write (p);
267 estr_write ("\"\n");
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,
292 show_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
317 unformatted I/O. */
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. */
332 void
333 init_variables (void)
335 variable *v;
337 for (v = variable_table; v->name; v++)
338 v->init (v);
342 void
343 show_variables (void)
345 variable *v;
346 int n;
348 /* TODO: print version number. */
349 estr_write ("GNU Fortran runtime library version "
350 "UNKNOWN" "\n\n");
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 ");
364 else
365 estr_write ("String ");
367 v->show (v);
368 estr_write (v->desc);
369 estr_write ("\n\n");
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++)
378 if (n < 0 || n > 9)
379 st_printf ("%d %s\n", n, translate_error (n));
380 else
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");
386 exit (0);
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
392 unformatted file.
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 ',', ':', '-'. */
405 #define NATIVE 257
406 #define SWAP 258
407 #define BIG 259
408 #define LITTLE 260
409 /* Some space for additional tokens later. */
410 #define INTEGER 273
411 #define END (-1)
412 #define ILLEGAL (-2)
414 typedef struct
416 int unit;
417 unit_convert conv;
418 } exception_t;
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. */
444 static int
445 search_unit (int unit, int *ip)
447 int low, high, mid;
449 low = -1;
450 high = n_elist;
451 while (high - low > 1)
453 mid = (low + high) / 2;
454 if (unit <= elist[mid].unit)
455 high = mid;
456 else
457 low = mid;
459 *ip = high;
460 if (elist[high].unit == unit)
461 return 1;
462 else
463 return 0;
466 /* This matches a keyword. If it is found, return the token supplied,
467 otherwise return ILLEGAL. */
469 static int
470 match_word (const char *word, int tok)
472 int res;
474 if (strncasecmp (p, word, strlen (word)) == 0)
476 p += strlen (word);
477 res = tok;
479 else
480 res = ILLEGAL;
481 return res;
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
487 to ensure this. */
489 static int
490 match_integer (void)
492 unit_num = 0;
493 while (isdigit (*p))
494 unit_num = unit_num * 10 + (*p++ - '0');
495 return INTEGER;
499 /* This reads the next token from the GFORTRAN_CONVERT_UNITS variable.
500 Returned values are the different tokens. */
502 static int
503 next_token (void)
505 int result;
507 lastpos = p;
508 switch (*p)
510 case '\0':
511 result = END;
512 break;
514 case ':':
515 case ',':
516 case '-':
517 case ';':
518 result = *p;
519 p++;
520 break;
522 case 'b':
523 case 'B':
524 result = match_word ("big_endian", BIG);
525 break;
527 case 'l':
528 case 'L':
529 result = match_word ("little_endian", LITTLE);
530 break;
532 case 'n':
533 case 'N':
534 result = match_word ("native", NATIVE);
535 break;
537 case 's':
538 case 'S':
539 result = match_word ("swap", SWAP);
540 break;
542 case '1': case '2': case '3': case '4': case '5':
543 case '6': case '7': case '8': case '9':
544 result = match_integer ();
545 break;
547 default:
548 result = ILLEGAL;
549 break;
551 return result;
554 /* Back up the last token by setting back the character pointer. */
556 static void
557 push_token (void)
559 p = lastpos;
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. */
566 static void
567 mark_single (int unit)
569 int i,j;
571 if (do_count)
573 unit_count++;
574 return;
576 if (search_unit (unit, &i))
578 elist[unit].conv = endian;
580 else
582 for (j=n_elist; j>=i; j--)
583 elist[j+1] = elist[j];
585 n_elist += 1;
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. */
595 static void
596 mark_range (int unit1, int unit2)
598 int i;
599 if (do_count)
600 unit_count += abs (unit2 - unit1) + 1;
601 else
603 if (unit2 < unit1)
604 for (i=unit2; i<=unit1; i++)
605 mark_single (i);
606 else
607 for (i=unit1; i<=unit2; i++)
608 mark_single (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
615 of units. */
617 static int
618 do_parse (void)
620 int tok;
621 int unit1;
622 int continue_ulist;
623 char *start;
625 unit_count = 0;
627 start = p;
629 /* Parse the string. First, let's look for a default. */
630 tok = next_token ();
631 switch (tok)
633 case NATIVE:
634 endian = GFC_CONVERT_NATIVE;
635 break;
637 case SWAP:
638 endian = GFC_CONVERT_SWAP;
639 break;
641 case BIG:
642 endian = GFC_CONVERT_BIG;
643 break;
645 case LITTLE:
646 endian = GFC_CONVERT_LITTLE;
647 break;
649 case INTEGER:
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. */
653 p = start;
654 goto exceptions;
655 break;
657 case END:
658 goto end;
659 break;
661 default:
662 goto error;
663 break;
666 tok = next_token ();
667 switch (tok)
669 case ';':
670 def = endian;
671 break;
673 case ':':
674 /* This isn't a default after all. Reset the position to the
675 beginning, and continue processing at the exception list. */
676 p = start;
677 goto exceptions;
678 break;
680 case END:
681 def = endian;
682 goto end;
683 break;
685 default:
686 goto error;
687 break;
690 exceptions:
692 /* Loop over all exceptions. */
693 while(1)
695 tok = next_token ();
696 switch (tok)
698 case NATIVE:
699 if (next_token () != ':')
700 goto error;
701 endian = GFC_CONVERT_NATIVE;
702 break;
704 case SWAP:
705 if (next_token () != ':')
706 goto error;
707 endian = GFC_CONVERT_SWAP;
708 break;
710 case LITTLE:
711 if (next_token () != ':')
712 goto error;
713 endian = GFC_CONVERT_LITTLE;
714 break;
716 case BIG:
717 if (next_token () != ':')
718 goto error;
719 endian = GFC_CONVERT_BIG;
720 break;
722 case INTEGER:
723 push_token ();
724 break;
726 case END:
727 goto end;
728 break;
730 default:
731 goto error;
732 break;
734 /* We arrive here when we want to parse a list of
735 numbers. */
736 continue_ulist = 1;
739 tok = next_token ();
740 if (tok != INTEGER)
741 goto error;
743 unit1 = unit_num;
744 tok = next_token ();
745 /* The number can be followed by a - and another number,
746 which means that this is a unit range, a comma
747 or a semicolon. */
748 if (tok == '-')
750 if (next_token () != INTEGER)
751 goto error;
753 mark_range (unit1, unit_num);
754 tok = next_token ();
755 if (tok == END)
756 goto end;
757 else if (tok == ';')
758 continue_ulist = 0;
759 else if (tok != ',')
760 goto error;
762 else
764 mark_single (unit1);
765 switch (tok)
767 case ';':
768 continue_ulist = 0;
769 break;
771 case ',':
772 break;
774 case END:
775 goto end;
776 break;
778 default:
779 goto error;
782 } while (continue_ulist);
784 end:
785 return 0;
786 error:
787 def = GFC_CONVERT_NONE;
788 return -1;
791 void init_unformatted (variable * v)
793 char *val;
794 val = getenv (v->name);
795 def = GFC_CONVERT_NONE;
796 n_elist = 0;
798 if (val == NULL)
799 return;
800 do_count = 1;
801 p = val;
802 do_parse ();
803 if (do_count <= 0)
805 n_elist = 0;
806 elist = NULL;
808 else
810 elist = get_mem (unit_count * sizeof (exception_t));
811 do_count = 0;
812 p = val;
813 do_parse ();
817 /* Get the default conversion for for an unformatted unit. */
819 unit_convert
820 get_unformatted_convert (int unit)
822 int i;
824 if (elist == NULL)
825 return def;
826 else if (search_unit (unit, &i))
827 return elist[i].conv;
828 else
829 return def;