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