Home | History | Annotate | Line # | Download | only in runtime
      1  1.1.1.3  mrg /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
      2      1.1  mrg    Contributed by Andy Vaught
      3      1.1  mrg 
      4      1.1  mrg This file is part of the GNU Fortran runtime library (libgfortran).
      5      1.1  mrg 
      6      1.1  mrg Libgfortran is free software; you can redistribute it and/or modify
      7      1.1  mrg it under the terms of the GNU General Public License as published by
      8      1.1  mrg the Free Software Foundation; either version 3, or (at your option)
      9      1.1  mrg any later version.
     10      1.1  mrg 
     11      1.1  mrg Libgfortran is distributed in the hope that it will be useful,
     12      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  mrg GNU General Public License for more details.
     15      1.1  mrg 
     16      1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     17      1.1  mrg permissions described in the GCC Runtime Library Exception, version
     18      1.1  mrg 3.1, as published by the Free Software Foundation.
     19      1.1  mrg 
     20      1.1  mrg You should have received a copy of the GNU General Public License and
     21      1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     22      1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23      1.1  mrg <http://www.gnu.org/licenses/>.  */
     24      1.1  mrg 
     25      1.1  mrg #include "libgfortran.h"
     26      1.1  mrg 
     27      1.1  mrg #include <string.h>
     28      1.1  mrg #include <strings.h>
     29      1.1  mrg 
     30      1.1  mrg #ifdef HAVE_UNISTD_H
     31      1.1  mrg #include <unistd.h>
     32      1.1  mrg #endif
     33      1.1  mrg 
     34      1.1  mrg 
     35      1.1  mrg /* Implementation of secure_getenv() for targets where it is not
     36      1.1  mrg    provided. */
     37      1.1  mrg 
     38      1.1  mrg #ifdef FALLBACK_SECURE_GETENV
     39      1.1  mrg 
     40      1.1  mrg #if SUPPORTS_WEAKREF && defined(HAVE___SECURE_GETENV)
     41      1.1  mrg static char* weak_secure_getenv (const char*)
     42      1.1  mrg   __attribute__((__weakref__("__secure_getenv")));
     43      1.1  mrg #endif
     44      1.1  mrg 
     45      1.1  mrg char *
     46      1.1  mrg secure_getenv (const char *name)
     47      1.1  mrg {
     48      1.1  mrg #if SUPPORTS_WEAKREF && defined(HAVE___SECURE_GETENV)
     49      1.1  mrg   if (weak_secure_getenv)
     50      1.1  mrg     return weak_secure_getenv (name);
     51      1.1  mrg #endif
     52      1.1  mrg 
     53      1.1  mrg   if ((getuid () == geteuid ()) && (getgid () == getegid ()))
     54      1.1  mrg     return getenv (name);
     55      1.1  mrg   else
     56      1.1  mrg     return NULL;
     57      1.1  mrg }
     58      1.1  mrg #endif
     59      1.1  mrg 
     60      1.1  mrg 
     61      1.1  mrg 
     62      1.1  mrg /* Examine the environment for controlling aspects of the program's
     63      1.1  mrg    execution.  Our philosophy here that the environment should not prevent
     64      1.1  mrg    the program from running, so any invalid value will be ignored.  */
     65      1.1  mrg 
     66      1.1  mrg 
     67      1.1  mrg options_t options;
     68      1.1  mrg 
     69      1.1  mrg typedef struct variable
     70      1.1  mrg {
     71      1.1  mrg   const char *name;
     72      1.1  mrg   int default_value;
     73      1.1  mrg   int *var;
     74      1.1  mrg   void (*init) (struct variable *);
     75      1.1  mrg }
     76      1.1  mrg variable;
     77      1.1  mrg 
     78      1.1  mrg static void init_unformatted (variable *);
     79      1.1  mrg 
     80      1.1  mrg 
     81      1.1  mrg /* Initialize an integer environment variable.  */
     82      1.1  mrg 
     83      1.1  mrg static void
     84      1.1  mrg init_integer (variable * v)
     85      1.1  mrg {
     86      1.1  mrg   char *p, *q;
     87      1.1  mrg 
     88      1.1  mrg   p = getenv (v->name);
     89      1.1  mrg   if (p == NULL)
     90      1.1  mrg     return;
     91      1.1  mrg 
     92      1.1  mrg   for (q = p; *q; q++)
     93  1.1.1.3  mrg     if (!safe_isdigit (*q) && (p != q || *q != '-'))
     94      1.1  mrg       return;
     95      1.1  mrg 
     96      1.1  mrg   *v->var = atoi (p);
     97      1.1  mrg }
     98      1.1  mrg 
     99      1.1  mrg 
    100      1.1  mrg /* Initialize a boolean environment variable. We only look at the first
    101      1.1  mrg    letter of the value. */
    102      1.1  mrg 
    103      1.1  mrg static void
    104      1.1  mrg init_boolean (variable * v)
    105      1.1  mrg {
    106      1.1  mrg   char *p;
    107      1.1  mrg 
    108      1.1  mrg   p = getenv (v->name);
    109      1.1  mrg   if (p == NULL)
    110      1.1  mrg     return;
    111      1.1  mrg 
    112      1.1  mrg   if (*p == '1' || *p == 'Y' || *p == 'y')
    113      1.1  mrg     *v->var = 1;
    114      1.1  mrg   else if (*p == '0' || *p == 'N' || *p == 'n')
    115      1.1  mrg     *v->var = 0;
    116      1.1  mrg }
    117      1.1  mrg 
    118      1.1  mrg 
    119      1.1  mrg /* Initialize a list output separator.  It may contain any number of spaces
    120      1.1  mrg    and at most one comma.  */
    121      1.1  mrg 
    122      1.1  mrg static void
    123      1.1  mrg init_sep (variable * v)
    124      1.1  mrg {
    125      1.1  mrg   int seen_comma;
    126      1.1  mrg   char *p;
    127      1.1  mrg 
    128      1.1  mrg   p = getenv (v->name);
    129      1.1  mrg   if (p == NULL)
    130      1.1  mrg     goto set_default;
    131      1.1  mrg 
    132      1.1  mrg   options.separator = p;
    133      1.1  mrg   options.separator_len = strlen (p);
    134      1.1  mrg 
    135      1.1  mrg   /* Make sure the separator is valid */
    136      1.1  mrg 
    137      1.1  mrg   if (options.separator_len == 0)
    138      1.1  mrg     goto set_default;
    139      1.1  mrg   seen_comma = 0;
    140      1.1  mrg 
    141      1.1  mrg   while (*p)
    142      1.1  mrg     {
    143      1.1  mrg       if (*p == ',')
    144      1.1  mrg 	{
    145      1.1  mrg 	  if (seen_comma)
    146      1.1  mrg 	    goto set_default;
    147      1.1  mrg 	  seen_comma = 1;
    148      1.1  mrg 	  p++;
    149      1.1  mrg 	  continue;
    150      1.1  mrg 	}
    151      1.1  mrg 
    152      1.1  mrg       if (*p++ != ' ')
    153      1.1  mrg 	goto set_default;
    154      1.1  mrg     }
    155      1.1  mrg 
    156      1.1  mrg   return;
    157      1.1  mrg 
    158      1.1  mrg set_default:
    159      1.1  mrg   options.separator = " ";
    160      1.1  mrg   options.separator_len = 1;
    161      1.1  mrg }
    162      1.1  mrg 
    163      1.1  mrg 
    164      1.1  mrg static variable variable_table[] = {
    165      1.1  mrg 
    166      1.1  mrg   /* Unit number that will be preconnected to standard input */
    167      1.1  mrg   { "GFORTRAN_STDIN_UNIT", GFC_STDIN_UNIT_NUMBER, &options.stdin_unit,
    168      1.1  mrg     init_integer },
    169      1.1  mrg 
    170      1.1  mrg   /* Unit number that will be preconnected to standard output */
    171      1.1  mrg   { "GFORTRAN_STDOUT_UNIT", GFC_STDOUT_UNIT_NUMBER, &options.stdout_unit,
    172      1.1  mrg     init_integer },
    173      1.1  mrg 
    174      1.1  mrg   /* Unit number that will be preconnected to standard error */
    175      1.1  mrg   { "GFORTRAN_STDERR_UNIT", GFC_STDERR_UNIT_NUMBER, &options.stderr_unit,
    176      1.1  mrg     init_integer },
    177      1.1  mrg 
    178      1.1  mrg   /* If TRUE, all output will be unbuffered */
    179      1.1  mrg   { "GFORTRAN_UNBUFFERED_ALL", 0, &options.all_unbuffered, init_boolean },
    180      1.1  mrg 
    181      1.1  mrg   /* If TRUE, output to preconnected units will be unbuffered */
    182      1.1  mrg   { "GFORTRAN_UNBUFFERED_PRECONNECTED", 0, &options.unbuffered_preconnected,
    183      1.1  mrg     init_boolean },
    184      1.1  mrg 
    185      1.1  mrg   /* Whether to print filename and line number on runtime error */
    186      1.1  mrg   { "GFORTRAN_SHOW_LOCUS", 1, &options.locus, init_boolean },
    187      1.1  mrg 
    188      1.1  mrg   /* Print optional plus signs in numbers where permitted */
    189      1.1  mrg   { "GFORTRAN_OPTIONAL_PLUS", 0, &options.optional_plus, init_boolean },
    190      1.1  mrg 
    191      1.1  mrg   /* Separator to use when writing list output */
    192      1.1  mrg   { "GFORTRAN_LIST_SEPARATOR", 0, NULL, init_sep },
    193      1.1  mrg 
    194      1.1  mrg   /* Set the default data conversion for unformatted I/O */
    195      1.1  mrg   { "GFORTRAN_CONVERT_UNIT", 0, 0, init_unformatted },
    196      1.1  mrg 
    197      1.1  mrg   /* Print out a backtrace if possible on runtime error */
    198      1.1  mrg   { "GFORTRAN_ERROR_BACKTRACE", -1, &options.backtrace, init_boolean },
    199      1.1  mrg 
    200      1.1  mrg   /* Buffer size for unformatted files.  */
    201      1.1  mrg   { "GFORTRAN_UNFORMATTED_BUFFER_SIZE", 0, &options.unformatted_buffer_size,
    202      1.1  mrg     init_integer },
    203      1.1  mrg 
    204      1.1  mrg   /* Buffer size for formatted files.  */
    205      1.1  mrg   { "GFORTRAN_FORMATTED_BUFFER_SIZE", 0, &options.formatted_buffer_size,
    206      1.1  mrg     init_integer },
    207      1.1  mrg 
    208      1.1  mrg   { NULL, 0, NULL, NULL }
    209      1.1  mrg };
    210      1.1  mrg 
    211      1.1  mrg 
    212      1.1  mrg /* Initialize most runtime variables from
    213      1.1  mrg  * environment variables. */
    214      1.1  mrg 
    215      1.1  mrg void
    216      1.1  mrg init_variables (void)
    217      1.1  mrg {
    218      1.1  mrg   variable *v;
    219      1.1  mrg 
    220      1.1  mrg   for (v = variable_table; v->name; v++)
    221      1.1  mrg     {
    222      1.1  mrg       if (v->var)
    223      1.1  mrg 	*v->var = v->default_value;
    224      1.1  mrg       v->init (v);
    225      1.1  mrg     }
    226      1.1  mrg }
    227      1.1  mrg 
    228      1.1  mrg 
    229      1.1  mrg /* This is the handling of the GFORTRAN_CONVERT_UNITS environment variable.
    230      1.1  mrg    It is called from environ.c to parse this variable, and from
    231      1.1  mrg    open.c to determine if the user specified a default for an
    232      1.1  mrg    unformatted file.
    233      1.1  mrg    The syntax of the environment variable is, in bison grammar:
    234      1.1  mrg 
    235      1.1  mrg    GFORTRAN_CONVERT_UNITS: mode | mode ';' exception ;
    236      1.1  mrg    mode: 'native' | 'swap' | 'big_endian' | 'little_endian' ;
    237      1.1  mrg    exception: mode ':' unit_list | unit_list ;
    238      1.1  mrg    unit_list: unit_spec | unit_list unit_spec ;
    239      1.1  mrg    unit_spec: INTEGER | INTEGER '-' INTEGER ;
    240      1.1  mrg */
    241      1.1  mrg 
    242      1.1  mrg /* Defines for the tokens.  Other valid tokens are ',', ':', '-'.  */
    243      1.1  mrg 
    244      1.1  mrg 
    245      1.1  mrg #define NATIVE   257
    246      1.1  mrg #define SWAP     258
    247      1.1  mrg #define BIG      259
    248      1.1  mrg #define LITTLE   260
    249  1.1.1.3  mrg #ifdef HAVE_GFC_REAL_17
    250  1.1.1.3  mrg #define R16_IEEE 261
    251  1.1.1.3  mrg #define R16_IBM  262
    252  1.1.1.3  mrg #endif
    253  1.1.1.3  mrg 
    254      1.1  mrg /* Some space for additional tokens later.  */
    255      1.1  mrg #define INTEGER  273
    256      1.1  mrg #define END      (-1)
    257      1.1  mrg #define ILLEGAL  (-2)
    258      1.1  mrg 
    259      1.1  mrg typedef struct
    260      1.1  mrg {
    261      1.1  mrg   int unit;
    262      1.1  mrg   unit_convert conv;
    263      1.1  mrg } exception_t;
    264      1.1  mrg 
    265      1.1  mrg 
    266      1.1  mrg static char *p;            /* Main character pointer for parsing.  */
    267      1.1  mrg static char *lastpos;      /* Auxiliary pointer, for backing up.  */
    268      1.1  mrg static int unit_num;       /* The last unit number read.  */
    269      1.1  mrg static int unit_count;     /* The number of units found. */
    270      1.1  mrg static int do_count;       /* Parsing is done twice - first to count the number
    271      1.1  mrg 			      of units, then to fill in the table.  This
    272      1.1  mrg 			      variable controls what to do.  */
    273      1.1  mrg static exception_t *elist; /* The list of exceptions to the default. This is
    274      1.1  mrg 			      sorted according to unit number.  */
    275      1.1  mrg static int n_elist;        /* Number of exceptions to the default.  */
    276      1.1  mrg 
    277      1.1  mrg static unit_convert endian; /* Current endianness.  */
    278      1.1  mrg 
    279      1.1  mrg static unit_convert def; /* Default as specified (if any).  */
    280      1.1  mrg 
    281      1.1  mrg /* Search for a unit number, using a binary search.  The
    282      1.1  mrg    first argument is the unit number to search for.  The second argument
    283      1.1  mrg    is a pointer to an index.
    284      1.1  mrg    If the unit number is found, the function returns 1, and the index
    285      1.1  mrg    is that of the element.
    286      1.1  mrg    If the unit number is not found, the function returns 0, and the
    287      1.1  mrg    index is the one where the element would be inserted.  */
    288      1.1  mrg 
    289      1.1  mrg static int
    290      1.1  mrg search_unit (int unit, int *ip)
    291      1.1  mrg {
    292      1.1  mrg   int low, high, mid;
    293      1.1  mrg 
    294      1.1  mrg   if (n_elist == 0)
    295      1.1  mrg     {
    296      1.1  mrg       *ip = 0;
    297      1.1  mrg       return 0;
    298      1.1  mrg     }
    299      1.1  mrg 
    300      1.1  mrg   low = 0;
    301      1.1  mrg   high = n_elist - 1;
    302      1.1  mrg 
    303      1.1  mrg   do
    304      1.1  mrg     {
    305      1.1  mrg       mid = (low + high) / 2;
    306      1.1  mrg       if (unit == elist[mid].unit)
    307      1.1  mrg 	{
    308      1.1  mrg 	  *ip = mid;
    309      1.1  mrg 	  return 1;
    310      1.1  mrg 	}
    311      1.1  mrg       else if (unit > elist[mid].unit)
    312      1.1  mrg 	low = mid + 1;
    313      1.1  mrg       else
    314      1.1  mrg 	high = mid - 1;
    315      1.1  mrg     } while (low <= high);
    316      1.1  mrg 
    317      1.1  mrg   if (unit > elist[mid].unit)
    318      1.1  mrg     *ip = mid + 1;
    319      1.1  mrg   else
    320      1.1  mrg     *ip = mid;
    321      1.1  mrg 
    322      1.1  mrg   return 0;
    323      1.1  mrg }
    324      1.1  mrg 
    325      1.1  mrg /* This matches a keyword.  If it is found, return the token supplied,
    326      1.1  mrg    otherwise return ILLEGAL.  */
    327      1.1  mrg 
    328      1.1  mrg static int
    329      1.1  mrg match_word (const char *word, int tok)
    330      1.1  mrg {
    331      1.1  mrg   int res;
    332      1.1  mrg 
    333      1.1  mrg   if (strncasecmp (p, word, strlen (word)) == 0)
    334      1.1  mrg     {
    335      1.1  mrg       p += strlen (word);
    336      1.1  mrg       res = tok;
    337      1.1  mrg     }
    338      1.1  mrg   else
    339      1.1  mrg     res = ILLEGAL;
    340      1.1  mrg   return res;
    341      1.1  mrg }
    342      1.1  mrg 
    343      1.1  mrg /* Match an integer and store its value in unit_num.  This only works
    344      1.1  mrg    if p actually points to the start of an integer.  The caller has
    345      1.1  mrg    to ensure this.  */
    346      1.1  mrg 
    347      1.1  mrg static int
    348      1.1  mrg match_integer (void)
    349      1.1  mrg {
    350      1.1  mrg   unit_num = 0;
    351  1.1.1.3  mrg   while (safe_isdigit (*p))
    352      1.1  mrg     unit_num = unit_num * 10 + (*p++ - '0');
    353      1.1  mrg   return INTEGER;
    354      1.1  mrg }
    355      1.1  mrg 
    356      1.1  mrg /* This reads the next token from the GFORTRAN_CONVERT_UNITS variable.
    357      1.1  mrg    Returned values are the different tokens.  */
    358      1.1  mrg 
    359      1.1  mrg static int
    360      1.1  mrg next_token (void)
    361      1.1  mrg {
    362      1.1  mrg   int result;
    363      1.1  mrg 
    364      1.1  mrg   lastpos = p;
    365      1.1  mrg   switch (*p)
    366      1.1  mrg     {
    367      1.1  mrg     case '\0':
    368      1.1  mrg       result = END;
    369      1.1  mrg       break;
    370      1.1  mrg 
    371      1.1  mrg     case ':':
    372      1.1  mrg     case ',':
    373      1.1  mrg     case '-':
    374      1.1  mrg     case ';':
    375      1.1  mrg       result = *p;
    376      1.1  mrg       p++;
    377      1.1  mrg       break;
    378      1.1  mrg 
    379      1.1  mrg     case 'b':
    380      1.1  mrg     case 'B':
    381      1.1  mrg       result = match_word ("big_endian", BIG);
    382      1.1  mrg       break;
    383      1.1  mrg 
    384      1.1  mrg     case 'l':
    385      1.1  mrg     case 'L':
    386      1.1  mrg       result = match_word ("little_endian", LITTLE);
    387      1.1  mrg       break;
    388      1.1  mrg 
    389      1.1  mrg     case 'n':
    390      1.1  mrg     case 'N':
    391      1.1  mrg       result = match_word ("native", NATIVE);
    392      1.1  mrg       break;
    393      1.1  mrg 
    394      1.1  mrg     case 's':
    395      1.1  mrg     case 'S':
    396      1.1  mrg       result = match_word ("swap", SWAP);
    397      1.1  mrg       break;
    398      1.1  mrg 
    399  1.1.1.3  mrg #ifdef HAVE_GFC_REAL_17
    400  1.1.1.3  mrg     case 'r':
    401  1.1.1.3  mrg     case 'R':
    402  1.1.1.3  mrg       result = match_word ("r16_ieee", R16_IEEE);
    403  1.1.1.3  mrg       if (result == ILLEGAL)
    404  1.1.1.3  mrg 	result = match_word ("r16_ibm", R16_IBM);
    405  1.1.1.3  mrg       break;
    406  1.1.1.3  mrg 
    407  1.1.1.3  mrg #endif
    408      1.1  mrg     case '1': case '2': case '3': case '4': case '5':
    409      1.1  mrg     case '6': case '7': case '8': case '9':
    410      1.1  mrg       result = match_integer ();
    411      1.1  mrg       break;
    412      1.1  mrg 
    413      1.1  mrg     default:
    414      1.1  mrg       result = ILLEGAL;
    415      1.1  mrg       break;
    416      1.1  mrg     }
    417      1.1  mrg   return result;
    418      1.1  mrg }
    419      1.1  mrg 
    420      1.1  mrg /* Back up the last token by setting back the character pointer.  */
    421      1.1  mrg 
    422      1.1  mrg static void
    423      1.1  mrg push_token (void)
    424      1.1  mrg {
    425      1.1  mrg   p = lastpos;
    426      1.1  mrg }
    427      1.1  mrg 
    428      1.1  mrg /* This is called when a unit is identified.  If do_count is nonzero,
    429      1.1  mrg    increment the number of units by one.  If do_count is zero,
    430  1.1.1.3  mrg    put the unit into the table.  For POWER, we have to make sure that
    431  1.1.1.3  mrg    we can also put in the conversion btween IBM and IEEE long double.  */
    432      1.1  mrg 
    433      1.1  mrg static void
    434      1.1  mrg mark_single (int unit)
    435      1.1  mrg {
    436      1.1  mrg   int i,j;
    437      1.1  mrg 
    438      1.1  mrg   if (do_count)
    439      1.1  mrg     {
    440      1.1  mrg       unit_count++;
    441      1.1  mrg       return;
    442      1.1  mrg     }
    443      1.1  mrg   if (search_unit (unit, &i))
    444      1.1  mrg     {
    445  1.1.1.3  mrg #ifdef HAVE_GFC_REAL_17
    446  1.1.1.3  mrg       elist[i].conv |= endian;
    447  1.1.1.3  mrg #else
    448      1.1  mrg       elist[i].conv = endian;
    449  1.1.1.3  mrg #endif
    450      1.1  mrg     }
    451      1.1  mrg   else
    452      1.1  mrg     {
    453      1.1  mrg       for (j=n_elist-1; j>=i; j--)
    454      1.1  mrg 	elist[j+1] = elist[j];
    455      1.1  mrg 
    456      1.1  mrg       n_elist += 1;
    457      1.1  mrg       elist[i].unit = unit;
    458  1.1.1.3  mrg #ifdef HAVE_GFC_REAL_17
    459  1.1.1.3  mrg       elist[i].conv |= endian;
    460  1.1.1.3  mrg #else
    461      1.1  mrg       elist[i].conv = endian;
    462  1.1.1.3  mrg #endif
    463      1.1  mrg     }
    464      1.1  mrg }
    465      1.1  mrg 
    466      1.1  mrg /* This is called when a unit range is identified.  If do_count is
    467      1.1  mrg    nonzero, increase the number of units.  If do_count is zero,
    468      1.1  mrg    put the unit into the table.  */
    469      1.1  mrg 
    470      1.1  mrg static void
    471      1.1  mrg mark_range (int unit1, int unit2)
    472      1.1  mrg {
    473      1.1  mrg   int i;
    474      1.1  mrg   if (do_count)
    475      1.1  mrg     unit_count += abs (unit2 - unit1) + 1;
    476      1.1  mrg   else
    477      1.1  mrg     {
    478      1.1  mrg       if (unit2 < unit1)
    479      1.1  mrg 	for (i=unit2; i<=unit1; i++)
    480      1.1  mrg 	  mark_single (i);
    481      1.1  mrg       else
    482      1.1  mrg 	for (i=unit1; i<=unit2; i++)
    483      1.1  mrg 	  mark_single (i);
    484      1.1  mrg     }
    485      1.1  mrg }
    486      1.1  mrg 
    487      1.1  mrg /* Parse the GFORTRAN_CONVERT_UNITS variable.  This is called
    488      1.1  mrg    twice, once to count the units and once to actually mark them in
    489      1.1  mrg    the table.  When counting, we don't check for double occurrences
    490      1.1  mrg    of units.  */
    491      1.1  mrg 
    492      1.1  mrg static int
    493      1.1  mrg do_parse (void)
    494      1.1  mrg {
    495      1.1  mrg   int tok;
    496      1.1  mrg   int unit1;
    497      1.1  mrg   int continue_ulist;
    498      1.1  mrg   char *start;
    499      1.1  mrg 
    500      1.1  mrg   unit_count = 0;
    501      1.1  mrg 
    502      1.1  mrg   /* Parse the string.  First, let's look for a default.  */
    503  1.1.1.3  mrg   endian = 0;
    504  1.1.1.3  mrg   while (1)
    505      1.1  mrg     {
    506  1.1.1.3  mrg       start = p;
    507  1.1.1.3  mrg       tok = next_token ();
    508  1.1.1.3  mrg       switch (tok)
    509  1.1.1.3  mrg 	{
    510  1.1.1.3  mrg 	case NATIVE:
    511  1.1.1.3  mrg 	  endian = GFC_CONVERT_NATIVE;
    512  1.1.1.3  mrg 	  break;
    513      1.1  mrg 
    514  1.1.1.3  mrg 	case SWAP:
    515  1.1.1.3  mrg 	  endian = GFC_CONVERT_SWAP;
    516  1.1.1.3  mrg 	  break;
    517      1.1  mrg 
    518  1.1.1.3  mrg 	case BIG:
    519  1.1.1.3  mrg 	  endian = GFC_CONVERT_BIG;
    520  1.1.1.3  mrg 	  break;
    521      1.1  mrg 
    522  1.1.1.3  mrg 	case LITTLE:
    523  1.1.1.3  mrg 	  endian = GFC_CONVERT_LITTLE;
    524  1.1.1.3  mrg 	  break;
    525      1.1  mrg 
    526  1.1.1.3  mrg #ifdef HAVE_GFC_REAL_17
    527  1.1.1.3  mrg 	case R16_IEEE:
    528  1.1.1.3  mrg 	  endian = GFC_CONVERT_R16_IEEE;
    529  1.1.1.3  mrg 	  break;
    530      1.1  mrg 
    531  1.1.1.3  mrg 	case R16_IBM:
    532  1.1.1.3  mrg 	  endian = GFC_CONVERT_R16_IBM;
    533  1.1.1.3  mrg 	  break;
    534  1.1.1.3  mrg #endif
    535  1.1.1.3  mrg 	case INTEGER:
    536  1.1.1.3  mrg 	  /* A leading digit means that we are looking at an exception.
    537  1.1.1.3  mrg 	     Reset the position to the beginning, and continue processing
    538  1.1.1.3  mrg 	     at the exception list.  */
    539  1.1.1.3  mrg 	  p = start;
    540  1.1.1.3  mrg 	  goto exceptions;
    541  1.1.1.3  mrg 	  break;
    542      1.1  mrg 
    543  1.1.1.3  mrg 	case END:
    544  1.1.1.3  mrg 	  goto end;
    545  1.1.1.3  mrg 	  break;
    546  1.1.1.3  mrg 
    547  1.1.1.3  mrg 	default:
    548  1.1.1.3  mrg 	  goto error;
    549  1.1.1.3  mrg 	  break;
    550      1.1  mrg     }
    551      1.1  mrg 
    552  1.1.1.3  mrg       tok = next_token ();
    553  1.1.1.3  mrg       switch (tok)
    554  1.1.1.3  mrg 	{
    555  1.1.1.3  mrg 	case ';':
    556  1.1.1.3  mrg 	  def = def == GFC_CONVERT_NONE ? endian : def | endian;
    557  1.1.1.3  mrg 	  break;
    558      1.1  mrg 
    559  1.1.1.3  mrg 	case ':':
    560  1.1.1.3  mrg 	  /* This isn't a default after all.  Reset the position to the
    561  1.1.1.3  mrg 	     beginning, and continue processing at the exception list.  */
    562  1.1.1.3  mrg 	  p = start;
    563  1.1.1.3  mrg 	  goto exceptions;
    564  1.1.1.3  mrg 	  break;
    565      1.1  mrg 
    566  1.1.1.3  mrg 	case END:
    567  1.1.1.3  mrg 	  def = def == GFC_CONVERT_NONE ? endian : def | endian;
    568  1.1.1.3  mrg 	  goto end;
    569  1.1.1.3  mrg 	  break;
    570      1.1  mrg 
    571  1.1.1.3  mrg 	default:
    572  1.1.1.3  mrg 	  goto error;
    573  1.1.1.3  mrg 	  break;
    574  1.1.1.3  mrg 	}
    575      1.1  mrg     }
    576      1.1  mrg 
    577      1.1  mrg  exceptions:
    578      1.1  mrg 
    579      1.1  mrg   /* Loop over all exceptions.  */
    580      1.1  mrg   while(1)
    581      1.1  mrg     {
    582      1.1  mrg       tok = next_token ();
    583      1.1  mrg       switch (tok)
    584      1.1  mrg 	{
    585      1.1  mrg 	case NATIVE:
    586      1.1  mrg 	  if (next_token () != ':')
    587      1.1  mrg 	    goto error;
    588      1.1  mrg 	  endian = GFC_CONVERT_NATIVE;
    589      1.1  mrg 	  break;
    590      1.1  mrg 
    591      1.1  mrg 	case SWAP:
    592      1.1  mrg 	  if (next_token () != ':')
    593      1.1  mrg 	    goto error;
    594      1.1  mrg 	  endian = GFC_CONVERT_SWAP;
    595      1.1  mrg 	  break;
    596      1.1  mrg 
    597      1.1  mrg 	case LITTLE:
    598      1.1  mrg 	  if (next_token () != ':')
    599      1.1  mrg 	    goto error;
    600      1.1  mrg 	  endian = GFC_CONVERT_LITTLE;
    601      1.1  mrg 	  break;
    602      1.1  mrg 
    603      1.1  mrg 	case BIG:
    604      1.1  mrg 	  if (next_token () != ':')
    605      1.1  mrg 	    goto error;
    606      1.1  mrg 	  endian = GFC_CONVERT_BIG;
    607      1.1  mrg 	  break;
    608  1.1.1.3  mrg #ifdef HAVE_GFC_REAL_17
    609  1.1.1.3  mrg 	case R16_IEEE:
    610  1.1.1.3  mrg 	  if (next_token () != ':')
    611  1.1.1.3  mrg 	    goto error;
    612  1.1.1.3  mrg 	  endian = GFC_CONVERT_R16_IEEE;
    613  1.1.1.3  mrg 	  break;
    614  1.1.1.3  mrg 
    615  1.1.1.3  mrg 	case R16_IBM:
    616  1.1.1.3  mrg 	  if (next_token () != ':')
    617  1.1.1.3  mrg 	    goto error;
    618  1.1.1.3  mrg 	  endian = GFC_CONVERT_R16_IBM;
    619  1.1.1.3  mrg 	  break;
    620  1.1.1.3  mrg #endif
    621      1.1  mrg 
    622      1.1  mrg 	case INTEGER:
    623      1.1  mrg 	  push_token ();
    624      1.1  mrg 	  break;
    625      1.1  mrg 
    626      1.1  mrg 	case END:
    627      1.1  mrg 	  goto end;
    628      1.1  mrg 	  break;
    629      1.1  mrg 
    630      1.1  mrg 	default:
    631      1.1  mrg 	  goto error;
    632      1.1  mrg 	  break;
    633      1.1  mrg 	}
    634      1.1  mrg       /* We arrive here when we want to parse a list of
    635      1.1  mrg 	 numbers.  */
    636      1.1  mrg       continue_ulist = 1;
    637      1.1  mrg       do
    638      1.1  mrg 	{
    639      1.1  mrg 	  tok = next_token ();
    640      1.1  mrg 	  if (tok != INTEGER)
    641      1.1  mrg 	    goto error;
    642      1.1  mrg 
    643      1.1  mrg 	  unit1 = unit_num;
    644      1.1  mrg 	  tok = next_token ();
    645      1.1  mrg 	  /* The number can be followed by a - and another number,
    646      1.1  mrg 	     which means that this is a unit range, a comma
    647      1.1  mrg 	     or a semicolon.  */
    648      1.1  mrg 	  if (tok == '-')
    649      1.1  mrg 	    {
    650      1.1  mrg 	      if (next_token () != INTEGER)
    651      1.1  mrg 		goto error;
    652      1.1  mrg 
    653      1.1  mrg 	      mark_range (unit1, unit_num);
    654      1.1  mrg 	      tok = next_token ();
    655      1.1  mrg 	      if (tok == END)
    656      1.1  mrg 		goto end;
    657      1.1  mrg 	      else if (tok == ';')
    658      1.1  mrg 		continue_ulist = 0;
    659      1.1  mrg 	      else if (tok != ',')
    660      1.1  mrg 		goto error;
    661      1.1  mrg 	    }
    662      1.1  mrg 	  else
    663      1.1  mrg 	    {
    664      1.1  mrg 	      mark_single (unit1);
    665      1.1  mrg 	      switch (tok)
    666      1.1  mrg 		{
    667      1.1  mrg 		case ';':
    668      1.1  mrg 		  continue_ulist = 0;
    669      1.1  mrg 		  break;
    670      1.1  mrg 
    671      1.1  mrg 		case ',':
    672      1.1  mrg 		  break;
    673      1.1  mrg 
    674      1.1  mrg 		case END:
    675      1.1  mrg 		  goto end;
    676      1.1  mrg 		  break;
    677      1.1  mrg 
    678      1.1  mrg 		default:
    679      1.1  mrg 		  goto error;
    680      1.1  mrg 		}
    681      1.1  mrg 	    }
    682      1.1  mrg 	} while (continue_ulist);
    683      1.1  mrg     }
    684      1.1  mrg  end:
    685      1.1  mrg   return 0;
    686      1.1  mrg  error:
    687      1.1  mrg   def = GFC_CONVERT_NONE;
    688      1.1  mrg   return -1;
    689      1.1  mrg }
    690      1.1  mrg 
    691      1.1  mrg void init_unformatted (variable * v)
    692      1.1  mrg {
    693      1.1  mrg   char *val;
    694      1.1  mrg   val = getenv (v->name);
    695      1.1  mrg   def = GFC_CONVERT_NONE;
    696      1.1  mrg   n_elist = 0;
    697      1.1  mrg 
    698      1.1  mrg   if (val == NULL)
    699      1.1  mrg     return;
    700      1.1  mrg   do_count = 1;
    701      1.1  mrg   p = val;
    702      1.1  mrg   do_parse ();
    703      1.1  mrg   if (do_count <= 0)
    704      1.1  mrg     {
    705      1.1  mrg       n_elist = 0;
    706      1.1  mrg       elist = NULL;
    707      1.1  mrg     }
    708      1.1  mrg   else
    709      1.1  mrg     {
    710      1.1  mrg       elist = xmallocarray (unit_count, sizeof (exception_t));
    711      1.1  mrg       do_count = 0;
    712      1.1  mrg       p = val;
    713      1.1  mrg       do_parse ();
    714      1.1  mrg     }
    715      1.1  mrg }
    716      1.1  mrg 
    717      1.1  mrg /* Get the default conversion for for an unformatted unit.  */
    718      1.1  mrg 
    719      1.1  mrg unit_convert
    720      1.1  mrg get_unformatted_convert (int unit)
    721      1.1  mrg {
    722      1.1  mrg   int i;
    723      1.1  mrg 
    724      1.1  mrg   if (elist == NULL)
    725      1.1  mrg     return def;
    726      1.1  mrg   else if (search_unit (unit, &i))
    727      1.1  mrg     return elist[i].conv;
    728      1.1  mrg   else
    729      1.1  mrg     return def;
    730      1.1  mrg }
    731