OSDN Git Service

2009-04-05 Daniel Kraft <d@domob.eu>
[pf3gnuchains/gcc-fork.git] / libgfortran / io / open.c
1 /* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008
2    Free Software Foundation, Inc.
3    Contributed by Andy Vaught
4    F2003 I/O support contributed by Jerry DeLisle
5
6 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7
8 Libgfortran is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file.  (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
20 executable.)
21
22 Libgfortran is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with Libgfortran; see the file COPYING.  If not, write to
29 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
30 Boston, MA 02110-1301, USA.  */
31
32 #include "io.h"
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36
37
38 static const st_option access_opt[] = {
39   {"sequential", ACCESS_SEQUENTIAL},
40   {"direct", ACCESS_DIRECT},
41   {"append", ACCESS_APPEND},
42   {"stream", ACCESS_STREAM},
43   {NULL, 0}
44 };
45
46 static const st_option action_opt[] =
47 {
48   { "read", ACTION_READ},
49   { "write", ACTION_WRITE},
50   { "readwrite", ACTION_READWRITE},
51   { NULL, 0}
52 };
53
54 static const st_option blank_opt[] =
55 {
56   { "null", BLANK_NULL},
57   { "zero", BLANK_ZERO},
58   { NULL, 0}
59 };
60
61 static const st_option delim_opt[] =
62 {
63   { "none", DELIM_NONE},
64   { "apostrophe", DELIM_APOSTROPHE},
65   { "quote", DELIM_QUOTE},
66   { NULL, 0}
67 };
68
69 static const st_option form_opt[] =
70 {
71   { "formatted", FORM_FORMATTED},
72   { "unformatted", FORM_UNFORMATTED},
73   { NULL, 0}
74 };
75
76 static const st_option position_opt[] =
77 {
78   { "asis", POSITION_ASIS},
79   { "rewind", POSITION_REWIND},
80   { "append", POSITION_APPEND},
81   { NULL, 0}
82 };
83
84 static const st_option status_opt[] =
85 {
86   { "unknown", STATUS_UNKNOWN},
87   { "old", STATUS_OLD},
88   { "new", STATUS_NEW},
89   { "replace", STATUS_REPLACE},
90   { "scratch", STATUS_SCRATCH},
91   { NULL, 0}
92 };
93
94 static const st_option pad_opt[] =
95 {
96   { "yes", PAD_YES},
97   { "no", PAD_NO},
98   { NULL, 0}
99 };
100
101 static const st_option decimal_opt[] =
102 {
103   { "point", DECIMAL_POINT},
104   { "comma", DECIMAL_COMMA},
105   { NULL, 0}
106 };
107
108 static const st_option encoding_opt[] =
109 {
110   { "utf-8", ENCODING_UTF8},
111   { "default", ENCODING_DEFAULT},
112   { NULL, 0}
113 };
114
115 static const st_option round_opt[] =
116 {
117   { "up", ROUND_UP},
118   { "down", ROUND_DOWN},
119   { "zero", ROUND_ZERO},
120   { "nearest", ROUND_NEAREST},
121   { "compatible", ROUND_COMPATIBLE},
122   { "processor_defined", ROUND_PROCDEFINED},
123   { NULL, 0}
124 };
125
126 static const st_option sign_opt[] =
127 {
128   { "plus", SIGN_PLUS},
129   { "suppress", SIGN_SUPPRESS},
130   { "processor_defined", SIGN_PROCDEFINED},
131   { NULL, 0}
132 };
133
134 static const st_option convert_opt[] =
135 {
136   { "native", GFC_CONVERT_NATIVE},
137   { "swap", GFC_CONVERT_SWAP},
138   { "big_endian", GFC_CONVERT_BIG},
139   { "little_endian", GFC_CONVERT_LITTLE},
140   { NULL, 0}
141 };
142
143 static const st_option async_opt[] =
144 {
145   { "yes", ASYNC_YES},
146   { "no", ASYNC_NO},
147   { NULL, 0}
148 };
149
150 /* Given a unit, test to see if the file is positioned at the terminal
151    point, and if so, change state from NO_ENDFILE flag to AT_ENDFILE.
152    This prevents us from changing the state from AFTER_ENDFILE to
153    AT_ENDFILE.  */
154
155 static void
156 test_endfile (gfc_unit * u)
157 {
158   if (u->endfile == NO_ENDFILE && file_length (u->s) == stell (u->s))
159     u->endfile = AT_ENDFILE;
160 }
161
162
163 /* Change the modes of a file, those that are allowed * to be
164    changed.  */
165
166 static void
167 edit_modes (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
168 {
169   /* Complain about attempts to change the unchangeable.  */
170
171   if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD && 
172       u->flags.status != flags->status)
173     generate_error (&opp->common, LIBERROR_BAD_OPTION,
174                     "Cannot change STATUS parameter in OPEN statement");
175
176   if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access)
177     generate_error (&opp->common, LIBERROR_BAD_OPTION,
178                     "Cannot change ACCESS parameter in OPEN statement");
179
180   if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form)
181     generate_error (&opp->common, LIBERROR_BAD_OPTION,
182                     "Cannot change FORM parameter in OPEN statement");
183
184   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN)
185       && opp->recl_in != u->recl)
186     generate_error (&opp->common, LIBERROR_BAD_OPTION,
187                     "Cannot change RECL parameter in OPEN statement");
188
189   if (flags->action != ACTION_UNSPECIFIED && u->flags.action != flags->action)
190     generate_error (&opp->common, LIBERROR_BAD_OPTION,
191                     "Cannot change ACTION parameter in OPEN statement");
192
193   /* Status must be OLD if present.  */
194
195   if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD &&
196       flags->status != STATUS_UNKNOWN)
197     {
198       if (flags->status == STATUS_SCRATCH)
199         notify_std (&opp->common, GFC_STD_GNU,
200                     "OPEN statement must have a STATUS of OLD or UNKNOWN");
201       else
202         generate_error (&opp->common, LIBERROR_BAD_OPTION,
203                     "OPEN statement must have a STATUS of OLD or UNKNOWN");
204     }
205
206   if (u->flags.form == FORM_UNFORMATTED)
207     {
208       if (flags->delim != DELIM_UNSPECIFIED)
209         generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
210                         "DELIM parameter conflicts with UNFORMATTED form in "
211                         "OPEN statement");
212
213       if (flags->blank != BLANK_UNSPECIFIED)
214         generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
215                         "BLANK parameter conflicts with UNFORMATTED form in "
216                         "OPEN statement");
217
218       if (flags->pad != PAD_UNSPECIFIED)
219         generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
220                         "PAD parameter conflicts with UNFORMATTED form in "
221                         "OPEN statement");
222
223       if (flags->decimal != DECIMAL_UNSPECIFIED)
224         generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
225                         "DECIMAL parameter conflicts with UNFORMATTED form in "
226                         "OPEN statement");
227
228       if (flags->encoding != ENCODING_UNSPECIFIED)
229         generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
230                         "ENCODING parameter conflicts with UNFORMATTED form in "
231                         "OPEN statement");
232
233       if (flags->round != ROUND_UNSPECIFIED)
234         generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
235                         "ROUND parameter conflicts with UNFORMATTED form in "
236                         "OPEN statement");
237
238       if (flags->sign != SIGN_UNSPECIFIED)
239         generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
240                         "SIGN parameter conflicts with UNFORMATTED form in "
241                         "OPEN statement");
242     }
243
244   if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
245     {
246       /* Change the changeable:  */
247       if (flags->blank != BLANK_UNSPECIFIED)
248         u->flags.blank = flags->blank;
249       if (flags->delim != DELIM_UNSPECIFIED)
250         u->flags.delim = flags->delim;
251       if (flags->pad != PAD_UNSPECIFIED)
252         u->flags.pad = flags->pad;
253       if (flags->decimal != DECIMAL_UNSPECIFIED)
254         u->flags.decimal = flags->decimal;
255       if (flags->encoding != ENCODING_UNSPECIFIED)
256         u->flags.encoding = flags->encoding;
257       if (flags->async != ASYNC_UNSPECIFIED)
258         u->flags.async = flags->async;
259       if (flags->round != ROUND_UNSPECIFIED)
260         u->flags.round = flags->round;
261       if (flags->sign != SIGN_UNSPECIFIED)
262         u->flags.sign = flags->sign;
263     }
264
265   /* Reposition the file if necessary.  */
266
267   switch (flags->position)
268     {
269     case POSITION_UNSPECIFIED:
270     case POSITION_ASIS:
271       break;
272
273     case POSITION_REWIND:
274       if (sseek (u->s, 0, SEEK_SET) != 0)
275         goto seek_error;
276
277       u->current_record = 0;
278       u->last_record = 0;
279
280       test_endfile (u);
281       break;
282
283     case POSITION_APPEND:
284       if (sseek (u->s, 0, SEEK_END) < 0)
285         goto seek_error;
286
287       if (flags->access != ACCESS_STREAM)
288         u->current_record = 0;
289
290       u->endfile = AT_ENDFILE;  /* We are at the end.  */
291       break;
292
293     seek_error:
294       generate_error (&opp->common, LIBERROR_OS, NULL);
295       break;
296     }
297
298   unlock_unit (u);
299 }
300
301
302 /* Open an unused unit.  */
303
304 gfc_unit *
305 new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
306 {
307   gfc_unit *u2;
308   stream *s;
309   char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */];
310
311   /* Change unspecifieds to defaults.  Leave (flags->action ==
312      ACTION_UNSPECIFIED) alone so open_external() can set it based on
313      what type of open actually works.  */
314
315   if (flags->access == ACCESS_UNSPECIFIED)
316     flags->access = ACCESS_SEQUENTIAL;
317
318   if (flags->form == FORM_UNSPECIFIED)
319     flags->form = (flags->access == ACCESS_SEQUENTIAL)
320       ? FORM_FORMATTED : FORM_UNFORMATTED;
321
322   if (flags->async == ASYNC_UNSPECIFIED)
323     flags->async = ASYNC_NO;
324
325   if (flags->status == STATUS_UNSPECIFIED)
326     flags->status = STATUS_UNKNOWN;
327
328   /* Checks.  */
329
330   if (flags->delim == DELIM_UNSPECIFIED)
331     flags->delim = DELIM_NONE;
332   else
333     {
334       if (flags->form == FORM_UNFORMATTED)
335         {
336           generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
337                           "DELIM parameter conflicts with UNFORMATTED form in "
338                           "OPEN statement");
339           goto fail;
340         }
341     }
342
343   if (flags->blank == BLANK_UNSPECIFIED)
344     flags->blank = BLANK_NULL;
345   else
346     {
347       if (flags->form == FORM_UNFORMATTED)
348         {
349           generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
350                           "BLANK parameter conflicts with UNFORMATTED form in "
351                           "OPEN statement");
352           goto fail;
353         }
354     }
355
356   if (flags->pad == PAD_UNSPECIFIED)
357     flags->pad = PAD_YES;
358   else
359     {
360       if (flags->form == FORM_UNFORMATTED)
361         {
362           generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
363                           "PAD parameter conflicts with UNFORMATTED form in "
364                           "OPEN statement");
365           goto fail;
366         }
367     }
368
369   if (flags->decimal == DECIMAL_UNSPECIFIED)
370     flags->decimal = DECIMAL_POINT;
371   else
372     {
373       if (flags->form == FORM_UNFORMATTED)
374         {
375           generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
376                           "DECIMAL parameter conflicts with UNFORMATTED form "
377                           "in OPEN statement");
378           goto fail;
379         }
380     }
381
382   if (flags->encoding == ENCODING_UNSPECIFIED)
383     flags->encoding = ENCODING_DEFAULT;
384   else
385     {
386       if (flags->form == FORM_UNFORMATTED)
387         {
388           generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
389                           "ENCODING parameter conflicts with UNFORMATTED form in "
390                           "OPEN statement");
391           goto fail;
392         }
393     }
394
395   /* NB: the value for ROUND when it's not specified by the user does not
396          have to be PROCESSOR_DEFINED; the standard says that it is
397          processor dependent, and requires that it is one of the
398          possible value (see F2003, 9.4.5.13).  */
399   if (flags->round == ROUND_UNSPECIFIED)
400     flags->round = ROUND_PROCDEFINED;
401   else
402     {
403       if (flags->form == FORM_UNFORMATTED)
404         {
405           generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
406                           "ROUND parameter conflicts with UNFORMATTED form in "
407                           "OPEN statement");
408           goto fail;
409         }
410     }
411
412   if (flags->sign == SIGN_UNSPECIFIED)
413     flags->sign = SIGN_PROCDEFINED;
414   else
415     {
416       if (flags->form == FORM_UNFORMATTED)
417         {
418           generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
419                           "SIGN parameter conflicts with UNFORMATTED form in "
420                           "OPEN statement");
421           goto fail;
422         }
423     }
424
425   if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT)
426    {
427      generate_error (&opp->common, LIBERROR_OPTION_CONFLICT,
428                      "ACCESS parameter conflicts with SEQUENTIAL access in "
429                      "OPEN statement");
430      goto fail;
431    }
432   else
433    if (flags->position == POSITION_UNSPECIFIED)
434      flags->position = POSITION_ASIS;
435
436   if (flags->access == ACCESS_DIRECT
437       && (opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) == 0)
438     {
439       generate_error (&opp->common, LIBERROR_MISSING_OPTION,
440                       "Missing RECL parameter in OPEN statement");
441       goto fail;
442     }
443
444   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN) && opp->recl_in <= 0)
445     {
446       generate_error (&opp->common, LIBERROR_BAD_OPTION,
447                       "RECL parameter is non-positive in OPEN statement");
448       goto fail;
449     }
450
451   switch (flags->status)
452     {
453     case STATUS_SCRATCH:
454       if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
455         {
456           opp->file = NULL;
457           break;
458         }
459
460       generate_error (&opp->common, LIBERROR_BAD_OPTION,
461                       "FILE parameter must not be present in OPEN statement");
462       goto fail;
463
464     case STATUS_OLD:
465     case STATUS_NEW:
466     case STATUS_REPLACE:
467     case STATUS_UNKNOWN:
468       if ((opp->common.flags & IOPARM_OPEN_HAS_FILE))
469         break;
470
471       opp->file = tmpname;
472 #ifdef HAVE_SNPRINTF
473       opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d", 
474                                (int) opp->common.unit);
475 #else
476       opp->file_len = sprintf(opp->file, "fort.%d", (int) opp->common.unit);
477 #endif
478       break;
479
480     default:
481       internal_error (&opp->common, "new_unit(): Bad status");
482     }
483
484   /* Make sure the file isn't already open someplace else.
485      Do not error if opening file preconnected to stdin, stdout, stderr.  */
486
487   u2 = NULL;
488   if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) != 0)
489     u2 = find_file (opp->file, opp->file_len);
490   if (u2 != NULL
491       && (options.stdin_unit < 0 || u2->unit_number != options.stdin_unit)
492       && (options.stdout_unit < 0 || u2->unit_number != options.stdout_unit)
493       && (options.stderr_unit < 0 || u2->unit_number != options.stderr_unit))
494     {
495       unlock_unit (u2);
496       generate_error (&opp->common, LIBERROR_ALREADY_OPEN, NULL);
497       goto cleanup;
498     }
499
500   if (u2 != NULL)
501     unlock_unit (u2);
502
503   /* Open file.  */
504
505   s = open_external (opp, flags);
506   if (s == NULL)
507     {
508       char *path, *msg;
509       path = (char *) gfc_alloca (opp->file_len + 1);
510       msg = (char *) gfc_alloca (opp->file_len + 51);
511       unpack_filename (path, opp->file, opp->file_len);
512
513       switch (errno)
514         {
515         case ENOENT: 
516           sprintf (msg, "File '%s' does not exist", path);
517           break;
518
519         case EEXIST:
520           sprintf (msg, "File '%s' already exists", path);
521           break;
522
523         case EACCES:
524           sprintf (msg, "Permission denied trying to open file '%s'", path);
525           break;
526
527         case EISDIR:
528           sprintf (msg, "'%s' is a directory", path);
529           break;
530
531         default:
532           msg = NULL;
533         }
534
535       generate_error (&opp->common, LIBERROR_OS, msg);
536       goto cleanup;
537     }
538
539   if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE)
540     flags->status = STATUS_OLD;
541
542   /* Create the unit structure.  */
543
544   u->file = get_mem (opp->file_len);
545   if (u->unit_number != opp->common.unit)
546     internal_error (&opp->common, "Unit number changed");
547   u->s = s;
548   u->flags = *flags;
549   u->read_bad = 0;
550   u->endfile = NO_ENDFILE;
551   u->last_record = 0;
552   u->current_record = 0;
553   u->mode = READING;
554   u->maxrec = 0;
555   u->bytes_left = 0;
556   u->saved_pos = 0;
557
558   if (flags->position == POSITION_APPEND)
559     {
560       if (sseek (u->s, 0, SEEK_END) < 0)
561         generate_error (&opp->common, LIBERROR_OS, NULL);
562       u->endfile = AT_ENDFILE;
563     }
564
565   /* Unspecified recl ends up with a processor dependent value.  */
566
567   if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
568     {
569       u->flags.has_recl = 1;
570       u->recl = opp->recl_in;
571       u->recl_subrecord = u->recl;
572       u->bytes_left = u->recl;
573     }
574   else
575     {
576       u->flags.has_recl = 0;
577       u->recl = max_offset;
578       if (compile_options.max_subrecord_length)
579         {
580           u->recl_subrecord = compile_options.max_subrecord_length;
581         }
582       else
583         {
584           switch (compile_options.record_marker)
585             {
586             case 0:
587               /* Fall through */
588             case sizeof (GFC_INTEGER_4):
589               u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
590               break;
591
592             case sizeof (GFC_INTEGER_8):
593               u->recl_subrecord = max_offset - 16;
594               break;
595
596             default:
597               runtime_error ("Illegal value for record marker");
598               break;
599             }
600         }
601     }
602
603   /* If the file is direct access, calculate the maximum record number
604      via a division now instead of letting the multiplication overflow
605      later.  */
606
607   if (flags->access == ACCESS_DIRECT)
608     u->maxrec = max_offset / u->recl;
609   
610   if (flags->access == ACCESS_STREAM)
611     {
612       u->maxrec = max_offset;
613       u->recl = 1;
614       u->bytes_left = 1;
615       u->strm_pos = stell (u->s) + 1;
616     }
617
618   memmove (u->file, opp->file, opp->file_len);
619   u->file_len = opp->file_len;
620
621   /* Curiously, the standard requires that the
622      position specifier be ignored for new files so a newly connected
623      file starts out at the initial point.  We still need to figure
624      out if the file is at the end or not.  */
625
626   test_endfile (u);
627
628   if (flags->status == STATUS_SCRATCH && opp->file != NULL)
629     free_mem (opp->file);
630     
631   if (flags->form == FORM_FORMATTED)
632     {
633       if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
634         fbuf_init (u, u->recl);
635       else
636         fbuf_init (u, 0);
637     }
638   else
639     u->fbuf = NULL;
640
641     
642     
643   return u;
644
645  cleanup:
646
647   /* Free memory associated with a temporary filename.  */
648
649   if (flags->status == STATUS_SCRATCH && opp->file != NULL)
650     free_mem (opp->file);
651
652  fail:
653
654   close_unit (u);
655   return NULL;
656 }
657
658
659 /* Open a unit which is already open.  This involves changing the
660    modes or closing what is there now and opening the new file.  */
661
662 static void
663 already_open (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
664 {
665   if ((opp->common.flags & IOPARM_OPEN_HAS_FILE) == 0)
666     {
667       edit_modes (opp, u, flags);
668       return;
669     }
670
671   /* If the file is connected to something else, close it and open a
672      new unit.  */
673
674   if (!compare_file_filename (u, opp->file, opp->file_len))
675     {
676 #if !HAVE_UNLINK_OPEN_FILE
677       char *path = NULL;
678       if (u->file && u->flags.status == STATUS_SCRATCH)
679         {
680           path = (char *) gfc_alloca (u->file_len + 1);
681           unpack_filename (path, u->file, u->file_len);
682         }
683 #endif
684
685       if (sclose (u->s) == FAILURE)
686         {
687           unlock_unit (u);
688           generate_error (&opp->common, LIBERROR_OS,
689                           "Error closing file in OPEN statement");
690           return;
691         }
692
693       u->s = NULL;
694       if (u->file)
695         free_mem (u->file);
696       u->file = NULL;
697       u->file_len = 0;
698
699 #if !HAVE_UNLINK_OPEN_FILE
700       if (path != NULL)
701         unlink (path);
702 #endif
703
704       u = new_unit (opp, u, flags);
705       if (u != NULL)
706         unlock_unit (u);
707       return;
708     }
709
710   edit_modes (opp, u, flags);
711 }
712
713
714 /* Open file.  */
715
716 extern void st_open (st_parameter_open *opp);
717 export_proto(st_open);
718
719 void
720 st_open (st_parameter_open *opp)
721 {
722   unit_flags flags;
723   gfc_unit *u = NULL;
724   GFC_INTEGER_4 cf = opp->common.flags;
725   unit_convert conv;
726  
727   library_start (&opp->common);
728
729   /* Decode options.  */
730
731   flags.access = !(cf & IOPARM_OPEN_HAS_ACCESS) ? ACCESS_UNSPECIFIED :
732     find_option (&opp->common, opp->access, opp->access_len,
733                  access_opt, "Bad ACCESS parameter in OPEN statement");
734
735   flags.action = !(cf & IOPARM_OPEN_HAS_ACTION) ? ACTION_UNSPECIFIED :
736     find_option (&opp->common, opp->action, opp->action_len,
737                  action_opt, "Bad ACTION parameter in OPEN statement");
738
739   flags.blank = !(cf & IOPARM_OPEN_HAS_BLANK) ? BLANK_UNSPECIFIED :
740     find_option (&opp->common, opp->blank, opp->blank_len,
741                  blank_opt, "Bad BLANK parameter in OPEN statement");
742
743   flags.delim = !(cf & IOPARM_OPEN_HAS_DELIM) ? DELIM_UNSPECIFIED :
744     find_option (&opp->common, opp->delim, opp->delim_len,
745                  delim_opt, "Bad DELIM parameter in OPEN statement");
746
747   flags.pad = !(cf & IOPARM_OPEN_HAS_PAD) ? PAD_UNSPECIFIED :
748     find_option (&opp->common, opp->pad, opp->pad_len,
749                  pad_opt, "Bad PAD parameter in OPEN statement");
750
751   flags.decimal = !(cf & IOPARM_OPEN_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
752     find_option (&opp->common, opp->decimal, opp->decimal_len,
753                  decimal_opt, "Bad DECIMAL parameter in OPEN statement");
754
755   flags.encoding = !(cf & IOPARM_OPEN_HAS_ENCODING) ? ENCODING_UNSPECIFIED :
756     find_option (&opp->common, opp->encoding, opp->encoding_len,
757                  encoding_opt, "Bad ENCODING parameter in OPEN statement");
758
759   flags.async = !(cf & IOPARM_OPEN_HAS_ASYNCHRONOUS) ? ASYNC_UNSPECIFIED :
760     find_option (&opp->common, opp->asynchronous, opp->asynchronous_len,
761                  async_opt, "Bad ASYNCHRONOUS parameter in OPEN statement");
762
763   flags.round = !(cf & IOPARM_OPEN_HAS_ROUND) ? ROUND_UNSPECIFIED :
764     find_option (&opp->common, opp->round, opp->round_len,
765                  round_opt, "Bad ROUND parameter in OPEN statement");
766
767   flags.sign = !(cf & IOPARM_OPEN_HAS_SIGN) ? SIGN_UNSPECIFIED :
768     find_option (&opp->common, opp->sign, opp->sign_len,
769                  sign_opt, "Bad SIGN parameter in OPEN statement");
770
771   flags.form = !(cf & IOPARM_OPEN_HAS_FORM) ? FORM_UNSPECIFIED :
772     find_option (&opp->common, opp->form, opp->form_len,
773                  form_opt, "Bad FORM parameter in OPEN statement");
774
775   flags.position = !(cf & IOPARM_OPEN_HAS_POSITION) ? POSITION_UNSPECIFIED :
776     find_option (&opp->common, opp->position, opp->position_len,
777                  position_opt, "Bad POSITION parameter in OPEN statement");
778
779   flags.status = !(cf & IOPARM_OPEN_HAS_STATUS) ? STATUS_UNSPECIFIED :
780     find_option (&opp->common, opp->status, opp->status_len,
781                  status_opt, "Bad STATUS parameter in OPEN statement");
782
783   /* First, we check wether the convert flag has been set via environment
784      variable.  This overrides the convert tag in the open statement.  */
785
786   conv = get_unformatted_convert (opp->common.unit);
787
788   if (conv == GFC_CONVERT_NONE)
789     {
790       /* Nothing has been set by environment variable, check the convert tag.  */
791       if (cf & IOPARM_OPEN_HAS_CONVERT)
792         conv = find_option (&opp->common, opp->convert, opp->convert_len,
793                             convert_opt,
794                             "Bad CONVERT parameter in OPEN statement");
795       else
796         conv = compile_options.convert;
797     }
798   
799   /* We use big_endian, which is 0 on little-endian machines
800      and 1 on big-endian machines.  */
801   switch (conv)
802     {
803     case GFC_CONVERT_NATIVE:
804     case GFC_CONVERT_SWAP:
805       break;
806       
807     case GFC_CONVERT_BIG:
808       conv = big_endian ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
809       break;
810       
811     case GFC_CONVERT_LITTLE:
812       conv = big_endian ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
813       break;
814       
815     default:
816       internal_error (&opp->common, "Illegal value for CONVERT");
817       break;
818     }
819
820   flags.convert = conv;
821
822   if (opp->common.unit < 0)
823     generate_error (&opp->common, LIBERROR_BAD_OPTION,
824                     "Bad unit number in OPEN statement");
825
826   if (flags.position != POSITION_UNSPECIFIED
827       && flags.access == ACCESS_DIRECT)
828     generate_error (&opp->common, LIBERROR_BAD_OPTION,
829                     "Cannot use POSITION with direct access files");
830
831   if (flags.access == ACCESS_APPEND)
832     {
833       if (flags.position != POSITION_UNSPECIFIED
834           && flags.position != POSITION_APPEND)
835         generate_error (&opp->common, LIBERROR_BAD_OPTION,
836                         "Conflicting ACCESS and POSITION flags in"
837                         " OPEN statement");
838
839       notify_std (&opp->common, GFC_STD_GNU,
840                   "Extension: APPEND as a value for ACCESS in OPEN statement");
841       flags.access = ACCESS_SEQUENTIAL;
842       flags.position = POSITION_APPEND;
843     }
844
845   if (flags.position == POSITION_UNSPECIFIED)
846     flags.position = POSITION_ASIS;
847
848   if ((opp->common.flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_OK)
849     {
850       u = find_or_create_unit (opp->common.unit);
851
852       if (u->s == NULL)
853         {
854           u = new_unit (opp, u, &flags);
855           if (u != NULL)
856             unlock_unit (u);
857         }
858       else
859         already_open (opp, u, &flags);
860     }
861
862   library_end ();
863 }