OSDN Git Service

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