* config/i386/i386.md (*<absneg:code>extendsfdf2): Remove.
[official-gcc.git] / libgfortran / runtime / environ.c
blob484b569f1db280f9f746de50a8c96a9a0e922c3c
1 /* Copyright (C) 2002-2018 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
4 This file is part of the GNU Fortran 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 <strings.h>
29 #include <ctype.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
36 /* Implementation of secure_getenv() for targets where it is not
37 provided. */
39 #ifdef FALLBACK_SECURE_GETENV
41 #if SUPPORTS_WEAKREF && defined(HAVE___SECURE_GETENV)
42 static char* weak_secure_getenv (const char*)
43 __attribute__((__weakref__("__secure_getenv")));
44 #endif
46 char *
47 secure_getenv (const char *name)
49 #if SUPPORTS_WEAKREF && defined(HAVE___SECURE_GETENV)
50 if (weak_secure_getenv)
51 return weak_secure_getenv (name);
52 #endif
54 if ((getuid () == geteuid ()) && (getgid () == getegid ()))
55 return getenv (name);
56 else
57 return NULL;
59 #endif
63 /* Examine the environment for controlling aspects of the program's
64 execution. Our philosophy here that the environment should not prevent
65 the program from running, so any invalid value will be ignored. */
68 options_t options;
70 typedef struct variable
72 const char *name;
73 int default_value;
74 int *var;
75 void (*init) (struct variable *);
77 variable;
79 static void init_unformatted (variable *);
82 /* Initialize an integer environment variable. */
84 static void
85 init_integer (variable * v)
87 char *p, *q;
89 p = getenv (v->name);
90 if (p == NULL)
91 return;
93 for (q = p; *q; q++)
94 if (!isdigit (*q) && (p != q || *q != '-'))
95 return;
97 *v->var = atoi (p);
101 /* Initialize a boolean environment variable. We only look at the first
102 letter of the value. */
104 static void
105 init_boolean (variable * v)
107 char *p;
109 p = getenv (v->name);
110 if (p == NULL)
111 return;
113 if (*p == '1' || *p == 'Y' || *p == 'y')
114 *v->var = 1;
115 else if (*p == '0' || *p == 'N' || *p == 'n')
116 *v->var = 0;
120 /* Initialize a list output separator. It may contain any number of spaces
121 and at most one comma. */
123 static void
124 init_sep (variable * v)
126 int seen_comma;
127 char *p;
129 p = getenv (v->name);
130 if (p == NULL)
131 goto set_default;
133 options.separator = p;
134 options.separator_len = strlen (p);
136 /* Make sure the separator is valid */
138 if (options.separator_len == 0)
139 goto set_default;
140 seen_comma = 0;
142 while (*p)
144 if (*p == ',')
146 if (seen_comma)
147 goto set_default;
148 seen_comma = 1;
149 p++;
150 continue;
153 if (*p++ != ' ')
154 goto set_default;
157 return;
159 set_default:
160 options.separator = " ";
161 options.separator_len = 1;
165 static variable variable_table[] = {
167 /* Unit number that will be preconnected to standard input */
168 { "GFORTRAN_STDIN_UNIT", GFC_STDIN_UNIT_NUMBER, &options.stdin_unit,
169 init_integer },
171 /* Unit number that will be preconnected to standard output */
172 { "GFORTRAN_STDOUT_UNIT", GFC_STDOUT_UNIT_NUMBER, &options.stdout_unit,
173 init_integer },
175 /* Unit number that will be preconnected to standard error */
176 { "GFORTRAN_STDERR_UNIT", GFC_STDERR_UNIT_NUMBER, &options.stderr_unit,
177 init_integer },
179 /* If TRUE, all output will be unbuffered */
180 { "GFORTRAN_UNBUFFERED_ALL", 0, &options.all_unbuffered, init_boolean },
182 /* If TRUE, output to preconnected units will be unbuffered */
183 { "GFORTRAN_UNBUFFERED_PRECONNECTED", 0, &options.unbuffered_preconnected,
184 init_boolean },
186 /* Whether to print filename and line number on runtime error */
187 { "GFORTRAN_SHOW_LOCUS", 1, &options.locus, init_boolean },
189 /* Print optional plus signs in numbers where permitted */
190 { "GFORTRAN_OPTIONAL_PLUS", 0, &options.optional_plus, init_boolean },
192 /* Separator to use when writing list output */
193 { "GFORTRAN_LIST_SEPARATOR", 0, NULL, init_sep },
195 /* Set the default data conversion for unformatted I/O */
196 { "GFORTRAN_CONVERT_UNIT", 0, 0, init_unformatted },
198 /* Print out a backtrace if possible on runtime error */
199 { "GFORTRAN_ERROR_BACKTRACE", -1, &options.backtrace, init_boolean },
201 { NULL, 0, NULL, NULL }
205 /* Initialize most runtime variables from
206 * environment variables. */
208 void
209 init_variables (void)
211 variable *v;
213 for (v = variable_table; v->name; v++)
215 if (v->var)
216 *v->var = v->default_value;
217 v->init (v);
222 /* This is the handling of the GFORTRAN_CONVERT_UNITS environment variable.
223 It is called from environ.c to parse this variable, and from
224 open.c to determine if the user specified a default for an
225 unformatted file.
226 The syntax of the environment variable is, in bison grammar:
228 GFORTRAN_CONVERT_UNITS: mode | mode ';' exception ;
229 mode: 'native' | 'swap' | 'big_endian' | 'little_endian' ;
230 exception: mode ':' unit_list | unit_list ;
231 unit_list: unit_spec | unit_list unit_spec ;
232 unit_spec: INTEGER | INTEGER '-' INTEGER ;
235 /* Defines for the tokens. Other valid tokens are ',', ':', '-'. */
238 #define NATIVE 257
239 #define SWAP 258
240 #define BIG 259
241 #define LITTLE 260
242 /* Some space for additional tokens later. */
243 #define INTEGER 273
244 #define END (-1)
245 #define ILLEGAL (-2)
247 typedef struct
249 int unit;
250 unit_convert conv;
251 } exception_t;
254 static char *p; /* Main character pointer for parsing. */
255 static char *lastpos; /* Auxiliary pointer, for backing up. */
256 static int unit_num; /* The last unit number read. */
257 static int unit_count; /* The number of units found. */
258 static int do_count; /* Parsing is done twice - first to count the number
259 of units, then to fill in the table. This
260 variable controls what to do. */
261 static exception_t *elist; /* The list of exceptions to the default. This is
262 sorted according to unit number. */
263 static int n_elist; /* Number of exceptions to the default. */
265 static unit_convert endian; /* Current endianness. */
267 static unit_convert def; /* Default as specified (if any). */
269 /* Search for a unit number, using a binary search. The
270 first argument is the unit number to search for. The second argument
271 is a pointer to an index.
272 If the unit number is found, the function returns 1, and the index
273 is that of the element.
274 If the unit number is not found, the function returns 0, and the
275 index is the one where the element would be inserted. */
277 static int
278 search_unit (int unit, int *ip)
280 int low, high, mid;
282 if (n_elist == 0)
284 *ip = 0;
285 return 0;
288 low = 0;
289 high = n_elist - 1;
293 mid = (low + high) / 2;
294 if (unit == elist[mid].unit)
296 *ip = mid;
297 return 1;
299 else if (unit > elist[mid].unit)
300 low = mid + 1;
301 else
302 high = mid - 1;
303 } while (low <= high);
305 if (unit > elist[mid].unit)
306 *ip = mid + 1;
307 else
308 *ip = mid;
310 return 0;
313 /* This matches a keyword. If it is found, return the token supplied,
314 otherwise return ILLEGAL. */
316 static int
317 match_word (const char *word, int tok)
319 int res;
321 if (strncasecmp (p, word, strlen (word)) == 0)
323 p += strlen (word);
324 res = tok;
326 else
327 res = ILLEGAL;
328 return res;
331 /* Match an integer and store its value in unit_num. This only works
332 if p actually points to the start of an integer. The caller has
333 to ensure this. */
335 static int
336 match_integer (void)
338 unit_num = 0;
339 while (isdigit (*p))
340 unit_num = unit_num * 10 + (*p++ - '0');
341 return INTEGER;
344 /* This reads the next token from the GFORTRAN_CONVERT_UNITS variable.
345 Returned values are the different tokens. */
347 static int
348 next_token (void)
350 int result;
352 lastpos = p;
353 switch (*p)
355 case '\0':
356 result = END;
357 break;
359 case ':':
360 case ',':
361 case '-':
362 case ';':
363 result = *p;
364 p++;
365 break;
367 case 'b':
368 case 'B':
369 result = match_word ("big_endian", BIG);
370 break;
372 case 'l':
373 case 'L':
374 result = match_word ("little_endian", LITTLE);
375 break;
377 case 'n':
378 case 'N':
379 result = match_word ("native", NATIVE);
380 break;
382 case 's':
383 case 'S':
384 result = match_word ("swap", SWAP);
385 break;
387 case '1': case '2': case '3': case '4': case '5':
388 case '6': case '7': case '8': case '9':
389 result = match_integer ();
390 break;
392 default:
393 result = ILLEGAL;
394 break;
396 return result;
399 /* Back up the last token by setting back the character pointer. */
401 static void
402 push_token (void)
404 p = lastpos;
407 /* This is called when a unit is identified. If do_count is nonzero,
408 increment the number of units by one. If do_count is zero,
409 put the unit into the table. */
411 static void
412 mark_single (int unit)
414 int i,j;
416 if (do_count)
418 unit_count++;
419 return;
421 if (search_unit (unit, &i))
423 elist[i].conv = endian;
425 else
427 for (j=n_elist-1; j>=i; j--)
428 elist[j+1] = elist[j];
430 n_elist += 1;
431 elist[i].unit = unit;
432 elist[i].conv = endian;
436 /* This is called when a unit range is identified. If do_count is
437 nonzero, increase the number of units. If do_count is zero,
438 put the unit into the table. */
440 static void
441 mark_range (int unit1, int unit2)
443 int i;
444 if (do_count)
445 unit_count += abs (unit2 - unit1) + 1;
446 else
448 if (unit2 < unit1)
449 for (i=unit2; i<=unit1; i++)
450 mark_single (i);
451 else
452 for (i=unit1; i<=unit2; i++)
453 mark_single (i);
457 /* Parse the GFORTRAN_CONVERT_UNITS variable. This is called
458 twice, once to count the units and once to actually mark them in
459 the table. When counting, we don't check for double occurrences
460 of units. */
462 static int
463 do_parse (void)
465 int tok;
466 int unit1;
467 int continue_ulist;
468 char *start;
470 unit_count = 0;
472 start = p;
474 /* Parse the string. First, let's look for a default. */
475 tok = next_token ();
476 switch (tok)
478 case NATIVE:
479 endian = GFC_CONVERT_NATIVE;
480 break;
482 case SWAP:
483 endian = GFC_CONVERT_SWAP;
484 break;
486 case BIG:
487 endian = GFC_CONVERT_BIG;
488 break;
490 case LITTLE:
491 endian = GFC_CONVERT_LITTLE;
492 break;
494 case INTEGER:
495 /* A leading digit means that we are looking at an exception.
496 Reset the position to the beginning, and continue processing
497 at the exception list. */
498 p = start;
499 goto exceptions;
500 break;
502 case END:
503 goto end;
504 break;
506 default:
507 goto error;
508 break;
511 tok = next_token ();
512 switch (tok)
514 case ';':
515 def = endian;
516 break;
518 case ':':
519 /* This isn't a default after all. Reset the position to the
520 beginning, and continue processing at the exception list. */
521 p = start;
522 goto exceptions;
523 break;
525 case END:
526 def = endian;
527 goto end;
528 break;
530 default:
531 goto error;
532 break;
535 exceptions:
537 /* Loop over all exceptions. */
538 while(1)
540 tok = next_token ();
541 switch (tok)
543 case NATIVE:
544 if (next_token () != ':')
545 goto error;
546 endian = GFC_CONVERT_NATIVE;
547 break;
549 case SWAP:
550 if (next_token () != ':')
551 goto error;
552 endian = GFC_CONVERT_SWAP;
553 break;
555 case LITTLE:
556 if (next_token () != ':')
557 goto error;
558 endian = GFC_CONVERT_LITTLE;
559 break;
561 case BIG:
562 if (next_token () != ':')
563 goto error;
564 endian = GFC_CONVERT_BIG;
565 break;
567 case INTEGER:
568 push_token ();
569 break;
571 case END:
572 goto end;
573 break;
575 default:
576 goto error;
577 break;
579 /* We arrive here when we want to parse a list of
580 numbers. */
581 continue_ulist = 1;
584 tok = next_token ();
585 if (tok != INTEGER)
586 goto error;
588 unit1 = unit_num;
589 tok = next_token ();
590 /* The number can be followed by a - and another number,
591 which means that this is a unit range, a comma
592 or a semicolon. */
593 if (tok == '-')
595 if (next_token () != INTEGER)
596 goto error;
598 mark_range (unit1, unit_num);
599 tok = next_token ();
600 if (tok == END)
601 goto end;
602 else if (tok == ';')
603 continue_ulist = 0;
604 else if (tok != ',')
605 goto error;
607 else
609 mark_single (unit1);
610 switch (tok)
612 case ';':
613 continue_ulist = 0;
614 break;
616 case ',':
617 break;
619 case END:
620 goto end;
621 break;
623 default:
624 goto error;
627 } while (continue_ulist);
629 end:
630 return 0;
631 error:
632 def = GFC_CONVERT_NONE;
633 return -1;
636 void init_unformatted (variable * v)
638 char *val;
639 val = getenv (v->name);
640 def = GFC_CONVERT_NONE;
641 n_elist = 0;
643 if (val == NULL)
644 return;
645 do_count = 1;
646 p = val;
647 do_parse ();
648 if (do_count <= 0)
650 n_elist = 0;
651 elist = NULL;
653 else
655 elist = xmallocarray (unit_count, sizeof (exception_t));
656 do_count = 0;
657 p = val;
658 do_parse ();
662 /* Get the default conversion for for an unformatted unit. */
664 unit_convert
665 get_unformatted_convert (int unit)
667 int i;
669 if (elist == NULL)
670 return def;
671 else if (search_unit (unit, &i))
672 return elist[i].conv;
673 else
674 return def;