2011-04-04 Tobias Burnus <burnus@net-b.de>
[official-gcc.git] / libgfortran / io / unix.c
blobd14d2b4ec147043b44be5d367294bd1270fa999e
1 /* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2 2011
3 Free Software Foundation, Inc.
4 Contributed by Andy Vaught
5 F2003 I/O support contributed by Jerry DeLisle
7 This file is part of the GNU Fortran runtime library (libgfortran).
9 Libgfortran is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
12 any later version.
14 Libgfortran is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 Under Section 7 of GPL version 3, you are granted additional
20 permissions described in the GCC Runtime Library Exception, version
21 3.1, as published by the Free Software Foundation.
23 You should have received a copy of the GNU General Public License and
24 a copy of the GCC Runtime Library Exception along with this program;
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
26 <http://www.gnu.org/licenses/>. */
28 /* Unix stream I/O module */
30 #include "io.h"
31 #include "unix.h"
32 #include <stdlib.h>
33 #include <limits.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <assert.h>
40 #include <string.h>
41 #include <errno.h>
44 /* For mingw, we don't identify files by their inode number, but by a
45 64-bit identifier created from a BY_HANDLE_FILE_INFORMATION. */
46 #ifdef __MINGW32__
48 #define WIN32_LEAN_AND_MEAN
49 #include <windows.h>
51 #if !defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64
52 #undef lseek
53 #define lseek _lseeki64
54 #undef fstat
55 #define fstat _fstati64
56 #undef stat
57 #define stat _stati64
58 #endif
60 #ifndef HAVE_WORKING_STAT
61 static uint64_t
62 id_from_handle (HANDLE hFile)
64 BY_HANDLE_FILE_INFORMATION FileInformation;
66 if (hFile == INVALID_HANDLE_VALUE)
67 return 0;
69 memset (&FileInformation, 0, sizeof(FileInformation));
70 if (!GetFileInformationByHandle (hFile, &FileInformation))
71 return 0;
73 return ((uint64_t) FileInformation.nFileIndexLow)
74 | (((uint64_t) FileInformation.nFileIndexHigh) << 32);
78 static uint64_t
79 id_from_path (const char *path)
81 HANDLE hFile;
82 uint64_t res;
84 if (!path || !*path || access (path, F_OK))
85 return (uint64_t) -1;
87 hFile = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
88 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY,
89 NULL);
90 res = id_from_handle (hFile);
91 CloseHandle (hFile);
92 return res;
96 static uint64_t
97 id_from_fd (const int fd)
99 return id_from_handle ((HANDLE) _get_osfhandle (fd));
102 #endif
103 #endif
105 #ifndef PATH_MAX
106 #define PATH_MAX 1024
107 #endif
109 /* These flags aren't defined on all targets (mingw32), so provide them
110 here. */
111 #ifndef S_IRGRP
112 #define S_IRGRP 0
113 #endif
115 #ifndef S_IWGRP
116 #define S_IWGRP 0
117 #endif
119 #ifndef S_IROTH
120 #define S_IROTH 0
121 #endif
123 #ifndef S_IWOTH
124 #define S_IWOTH 0
125 #endif
128 #ifndef HAVE_ACCESS
130 #ifndef W_OK
131 #define W_OK 2
132 #endif
134 #ifndef R_OK
135 #define R_OK 4
136 #endif
138 #ifndef F_OK
139 #define F_OK 0
140 #endif
142 /* Fallback implementation of access() on systems that don't have it.
143 Only modes R_OK, W_OK and F_OK are used in this file. */
145 static int
146 fallback_access (const char *path, int mode)
148 int fd;
150 if ((mode & R_OK) && (fd = open (path, O_RDONLY)) < 0)
151 return -1;
152 close (fd);
154 if ((mode & W_OK) && (fd = open (path, O_WRONLY)) < 0)
155 return -1;
156 close (fd);
158 if (mode == F_OK)
160 struct stat st;
161 return stat (path, &st);
164 return 0;
167 #undef access
168 #define access fallback_access
169 #endif
172 /* Unix and internal stream I/O module */
174 static const int BUFFER_SIZE = 8192;
176 typedef struct
178 stream st;
180 gfc_offset buffer_offset; /* File offset of the start of the buffer */
181 gfc_offset physical_offset; /* Current physical file offset */
182 gfc_offset logical_offset; /* Current logical file offset */
183 gfc_offset file_length; /* Length of the file, -1 if not seekable. */
185 char *buffer; /* Pointer to the buffer. */
186 int fd; /* The POSIX file descriptor. */
188 int active; /* Length of valid bytes in the buffer */
190 int ndirty; /* Dirty bytes starting at buffer_offset */
192 int special_file; /* =1 if the fd refers to a special file */
194 /* Cached stat(2) values. */
195 dev_t st_dev;
196 ino_t st_ino;
198 unix_stream;
201 /* fix_fd()-- Given a file descriptor, make sure it is not one of the
202 * standard descriptors, returning a non-standard descriptor. If the
203 * user specifies that system errors should go to standard output,
204 * then closes standard output, we don't want the system errors to a
205 * file that has been given file descriptor 1 or 0. We want to send
206 * the error to the invalid descriptor. */
208 static int
209 fix_fd (int fd)
211 #ifdef HAVE_DUP
212 int input, output, error;
214 input = output = error = 0;
216 /* Unix allocates the lowest descriptors first, so a loop is not
217 required, but this order is. */
218 if (fd == STDIN_FILENO)
220 fd = dup (fd);
221 input = 1;
223 if (fd == STDOUT_FILENO)
225 fd = dup (fd);
226 output = 1;
228 if (fd == STDERR_FILENO)
230 fd = dup (fd);
231 error = 1;
234 if (input)
235 close (STDIN_FILENO);
236 if (output)
237 close (STDOUT_FILENO);
238 if (error)
239 close (STDERR_FILENO);
240 #endif
242 return fd;
246 /* If the stream corresponds to a preconnected unit, we flush the
247 corresponding C stream. This is bugware for mixed C-Fortran codes
248 where the C code doesn't flush I/O before returning. */
249 void
250 flush_if_preconnected (stream * s)
252 int fd;
254 fd = ((unix_stream *) s)->fd;
255 if (fd == STDIN_FILENO)
256 fflush (stdin);
257 else if (fd == STDOUT_FILENO)
258 fflush (stdout);
259 else if (fd == STDERR_FILENO)
260 fflush (stderr);
264 /********************************************************************
265 Raw I/O functions (read, write, seek, tell, truncate, close).
267 These functions wrap the basic POSIX I/O syscalls. Any deviation in
268 semantics is a bug, except the following: write restarts in case
269 of being interrupted by a signal, and as the first argument the
270 functions take the unix_stream struct rather than an integer file
271 descriptor. Also, for POSIX read() and write() a nbyte argument larger
272 than SSIZE_MAX is undefined; here the type of nbyte is ssize_t rather
273 than size_t as for POSIX read/write.
274 *********************************************************************/
276 static int
277 raw_flush (unix_stream * s __attribute__ ((unused)))
279 return 0;
282 static ssize_t
283 raw_read (unix_stream * s, void * buf, ssize_t nbyte)
285 /* For read we can't do I/O in a loop like raw_write does, because
286 that will break applications that wait for interactive I/O. */
287 return read (s->fd, buf, nbyte);
290 static ssize_t
291 raw_write (unix_stream * s, const void * buf, ssize_t nbyte)
293 ssize_t trans, bytes_left;
294 char *buf_st;
296 bytes_left = nbyte;
297 buf_st = (char *) buf;
299 /* We must write in a loop since some systems don't restart system
300 calls in case of a signal. */
301 while (bytes_left > 0)
303 trans = write (s->fd, buf_st, bytes_left);
304 if (trans < 0)
306 if (errno == EINTR)
307 continue;
308 else
309 return trans;
311 buf_st += trans;
312 bytes_left -= trans;
315 return nbyte - bytes_left;
318 static gfc_offset
319 raw_seek (unix_stream * s, gfc_offset offset, int whence)
321 return lseek (s->fd, offset, whence);
324 static gfc_offset
325 raw_tell (unix_stream * s)
327 return lseek (s->fd, 0, SEEK_CUR);
330 static int
331 raw_truncate (unix_stream * s, gfc_offset length)
333 #ifdef __MINGW32__
334 HANDLE h;
335 gfc_offset cur;
337 if (isatty (s->fd))
339 errno = EBADF;
340 return -1;
342 h = (HANDLE) _get_osfhandle (s->fd);
343 if (h == INVALID_HANDLE_VALUE)
345 errno = EBADF;
346 return -1;
348 cur = lseek (s->fd, 0, SEEK_CUR);
349 if (cur == -1)
350 return -1;
351 if (lseek (s->fd, length, SEEK_SET) == -1)
352 goto error;
353 if (!SetEndOfFile (h))
355 errno = EBADF;
356 goto error;
358 if (lseek (s->fd, cur, SEEK_SET) == -1)
359 return -1;
360 return 0;
361 error:
362 lseek (s->fd, cur, SEEK_SET);
363 return -1;
364 #elif defined HAVE_FTRUNCATE
365 return ftruncate (s->fd, length);
366 #elif defined HAVE_CHSIZE
367 return chsize (s->fd, length);
368 #else
369 runtime_error ("required ftruncate or chsize support not present");
370 return -1;
371 #endif
374 static int
375 raw_close (unix_stream * s)
377 int retval;
379 if (s->fd != STDOUT_FILENO
380 && s->fd != STDERR_FILENO
381 && s->fd != STDIN_FILENO)
382 retval = close (s->fd);
383 else
384 retval = 0;
385 free (s);
386 return retval;
389 static int
390 raw_init (unix_stream * s)
392 s->st.read = (void *) raw_read;
393 s->st.write = (void *) raw_write;
394 s->st.seek = (void *) raw_seek;
395 s->st.tell = (void *) raw_tell;
396 s->st.trunc = (void *) raw_truncate;
397 s->st.close = (void *) raw_close;
398 s->st.flush = (void *) raw_flush;
400 s->buffer = NULL;
401 return 0;
405 /*********************************************************************
406 Buffered I/O functions. These functions have the same semantics as the
407 raw I/O functions above, except that they are buffered in order to
408 improve performance. The buffer must be flushed when switching from
409 reading to writing and vice versa.
410 *********************************************************************/
412 static int
413 buf_flush (unix_stream * s)
415 int writelen;
417 /* Flushing in read mode means discarding read bytes. */
418 s->active = 0;
420 if (s->ndirty == 0)
421 return 0;
423 if (s->file_length != -1 && s->physical_offset != s->buffer_offset
424 && lseek (s->fd, s->buffer_offset, SEEK_SET) < 0)
425 return -1;
427 writelen = raw_write (s, s->buffer, s->ndirty);
429 s->physical_offset = s->buffer_offset + writelen;
431 /* Don't increment file_length if the file is non-seekable. */
432 if (s->file_length != -1 && s->physical_offset > s->file_length)
433 s->file_length = s->physical_offset;
435 s->ndirty -= writelen;
436 if (s->ndirty != 0)
437 return -1;
439 #ifdef _WIN32
440 _commit (s->fd);
441 #endif
443 return 0;
446 static ssize_t
447 buf_read (unix_stream * s, void * buf, ssize_t nbyte)
449 if (s->active == 0)
450 s->buffer_offset = s->logical_offset;
452 /* Is the data we want in the buffer? */
453 if (s->logical_offset + nbyte <= s->buffer_offset + s->active
454 && s->buffer_offset <= s->logical_offset)
455 memcpy (buf, s->buffer + (s->logical_offset - s->buffer_offset), nbyte);
456 else
458 /* First copy the active bytes if applicable, then read the rest
459 either directly or filling the buffer. */
460 char *p;
461 int nread = 0;
462 ssize_t to_read, did_read;
463 gfc_offset new_logical;
465 p = (char *) buf;
466 if (s->logical_offset >= s->buffer_offset
467 && s->buffer_offset + s->active >= s->logical_offset)
469 nread = s->active - (s->logical_offset - s->buffer_offset);
470 memcpy (buf, s->buffer + (s->logical_offset - s->buffer_offset),
471 nread);
472 p += nread;
474 /* At this point we consider all bytes in the buffer discarded. */
475 to_read = nbyte - nread;
476 new_logical = s->logical_offset + nread;
477 if (s->file_length != -1 && s->physical_offset != new_logical
478 && lseek (s->fd, new_logical, SEEK_SET) < 0)
479 return -1;
480 s->buffer_offset = s->physical_offset = new_logical;
481 if (to_read <= BUFFER_SIZE/2)
483 did_read = raw_read (s, s->buffer, BUFFER_SIZE);
484 s->physical_offset += did_read;
485 s->active = did_read;
486 did_read = (did_read > to_read) ? to_read : did_read;
487 memcpy (p, s->buffer, did_read);
489 else
491 did_read = raw_read (s, p, to_read);
492 s->physical_offset += did_read;
493 s->active = 0;
495 nbyte = did_read + nread;
497 s->logical_offset += nbyte;
498 return nbyte;
501 static ssize_t
502 buf_write (unix_stream * s, const void * buf, ssize_t nbyte)
504 if (s->ndirty == 0)
505 s->buffer_offset = s->logical_offset;
507 /* Does the data fit into the buffer? As a special case, if the
508 buffer is empty and the request is bigger than BUFFER_SIZE/2,
509 write directly. This avoids the case where the buffer would have
510 to be flushed at every write. */
511 if (!(s->ndirty == 0 && nbyte > BUFFER_SIZE/2)
512 && s->logical_offset + nbyte <= s->buffer_offset + BUFFER_SIZE
513 && s->buffer_offset <= s->logical_offset
514 && s->buffer_offset + s->ndirty >= s->logical_offset)
516 memcpy (s->buffer + (s->logical_offset - s->buffer_offset), buf, nbyte);
517 int nd = (s->logical_offset - s->buffer_offset) + nbyte;
518 if (nd > s->ndirty)
519 s->ndirty = nd;
521 else
523 /* Flush, and either fill the buffer with the new data, or if
524 the request is bigger than the buffer size, write directly
525 bypassing the buffer. */
526 buf_flush (s);
527 if (nbyte <= BUFFER_SIZE/2)
529 memcpy (s->buffer, buf, nbyte);
530 s->buffer_offset = s->logical_offset;
531 s->ndirty += nbyte;
533 else
535 if (s->file_length != -1 && s->physical_offset != s->logical_offset)
537 if (lseek (s->fd, s->logical_offset, SEEK_SET) < 0)
538 return -1;
539 s->physical_offset = s->logical_offset;
542 nbyte = raw_write (s, buf, nbyte);
543 s->physical_offset += nbyte;
546 s->logical_offset += nbyte;
547 /* Don't increment file_length if the file is non-seekable. */
548 if (s->file_length != -1 && s->logical_offset > s->file_length)
549 s->file_length = s->logical_offset;
550 return nbyte;
553 static gfc_offset
554 buf_seek (unix_stream * s, gfc_offset offset, int whence)
556 switch (whence)
558 case SEEK_SET:
559 break;
560 case SEEK_CUR:
561 offset += s->logical_offset;
562 break;
563 case SEEK_END:
564 offset += s->file_length;
565 break;
566 default:
567 return -1;
569 if (offset < 0)
571 errno = EINVAL;
572 return -1;
574 s->logical_offset = offset;
575 return offset;
578 static gfc_offset
579 buf_tell (unix_stream * s)
581 return s->logical_offset;
584 static int
585 buf_truncate (unix_stream * s, gfc_offset length)
587 int r;
589 if (buf_flush (s) != 0)
590 return -1;
591 r = raw_truncate (s, length);
592 if (r == 0)
593 s->file_length = length;
594 return r;
597 static int
598 buf_close (unix_stream * s)
600 if (buf_flush (s) != 0)
601 return -1;
602 free (s->buffer);
603 return raw_close (s);
606 static int
607 buf_init (unix_stream * s)
609 s->st.read = (void *) buf_read;
610 s->st.write = (void *) buf_write;
611 s->st.seek = (void *) buf_seek;
612 s->st.tell = (void *) buf_tell;
613 s->st.trunc = (void *) buf_truncate;
614 s->st.close = (void *) buf_close;
615 s->st.flush = (void *) buf_flush;
617 s->buffer = get_mem (BUFFER_SIZE);
618 return 0;
622 /*********************************************************************
623 memory stream functions - These are used for internal files
625 The idea here is that a single stream structure is created and all
626 requests must be satisfied from it. The location and size of the
627 buffer is the character variable supplied to the READ or WRITE
628 statement.
630 *********************************************************************/
632 char *
633 mem_alloc_r (stream * strm, int * len)
635 unix_stream * s = (unix_stream *) strm;
636 gfc_offset n;
637 gfc_offset where = s->logical_offset;
639 if (where < s->buffer_offset || where > s->buffer_offset + s->active)
640 return NULL;
642 n = s->buffer_offset + s->active - where;
643 if (*len > n)
644 *len = n;
646 s->logical_offset = where + *len;
648 return s->buffer + (where - s->buffer_offset);
652 char *
653 mem_alloc_r4 (stream * strm, int * len)
655 unix_stream * s = (unix_stream *) strm;
656 gfc_offset n;
657 gfc_offset where = s->logical_offset;
659 if (where < s->buffer_offset || where > s->buffer_offset + s->active)
660 return NULL;
662 n = s->buffer_offset + s->active - where;
663 if (*len > n)
664 *len = n;
666 s->logical_offset = where + *len;
668 return s->buffer + (where - s->buffer_offset) * 4;
672 char *
673 mem_alloc_w (stream * strm, int * len)
675 unix_stream * s = (unix_stream *) strm;
676 gfc_offset m;
677 gfc_offset where = s->logical_offset;
679 m = where + *len;
681 if (where < s->buffer_offset)
682 return NULL;
684 if (m > s->file_length)
685 return NULL;
687 s->logical_offset = m;
689 return s->buffer + (where - s->buffer_offset);
693 gfc_char4_t *
694 mem_alloc_w4 (stream * strm, int * len)
696 unix_stream * s = (unix_stream *) strm;
697 gfc_offset m;
698 gfc_offset where = s->logical_offset;
699 gfc_char4_t *result = (gfc_char4_t *) s->buffer;
701 m = where + *len;
703 if (where < s->buffer_offset)
704 return NULL;
706 if (m > s->file_length)
707 return NULL;
709 s->logical_offset = m;
710 return &result[where - s->buffer_offset];
714 /* Stream read function for character(kine=1) internal units. */
716 static ssize_t
717 mem_read (stream * s, void * buf, ssize_t nbytes)
719 void *p;
720 int nb = nbytes;
722 p = mem_alloc_r (s, &nb);
723 if (p)
725 memcpy (buf, p, nb);
726 return (ssize_t) nb;
728 else
729 return 0;
733 /* Stream read function for chracter(kind=4) internal units. */
735 static ssize_t
736 mem_read4 (stream * s, void * buf, ssize_t nbytes)
738 void *p;
739 int nb = nbytes;
741 p = mem_alloc_r (s, &nb);
742 if (p)
744 memcpy (buf, p, nb);
745 return (ssize_t) nb;
747 else
748 return 0;
752 /* Stream write function for character(kind=1) internal units. */
754 static ssize_t
755 mem_write (stream * s, const void * buf, ssize_t nbytes)
757 void *p;
758 int nb = nbytes;
760 p = mem_alloc_w (s, &nb);
761 if (p)
763 memcpy (p, buf, nb);
764 return (ssize_t) nb;
766 else
767 return 0;
771 /* Stream write function for character(kind=4) internal units. */
773 static ssize_t
774 mem_write4 (stream * s, const void * buf, ssize_t nwords)
776 gfc_char4_t *p;
777 int nw = nwords;
779 p = mem_alloc_w4 (s, &nw);
780 if (p)
782 while (nw--)
783 *p++ = (gfc_char4_t) *((char *) buf);
784 return nwords;
786 else
787 return 0;
791 static gfc_offset
792 mem_seek (stream * strm, gfc_offset offset, int whence)
794 unix_stream * s = (unix_stream *) strm;
795 switch (whence)
797 case SEEK_SET:
798 break;
799 case SEEK_CUR:
800 offset += s->logical_offset;
801 break;
802 case SEEK_END:
803 offset += s->file_length;
804 break;
805 default:
806 return -1;
809 /* Note that for internal array I/O it's actually possible to have a
810 negative offset, so don't check for that. */
811 if (offset > s->file_length)
813 errno = EINVAL;
814 return -1;
817 s->logical_offset = offset;
819 /* Returning < 0 is the error indicator for sseek(), so return 0 if
820 offset is negative. Thus if the return value is 0, the caller
821 has to use stell() to get the real value of logical_offset. */
822 if (offset >= 0)
823 return offset;
824 return 0;
828 static gfc_offset
829 mem_tell (stream * s)
831 return ((unix_stream *)s)->logical_offset;
835 static int
836 mem_truncate (unix_stream * s __attribute__ ((unused)),
837 gfc_offset length __attribute__ ((unused)))
839 return 0;
843 static int
844 mem_flush (unix_stream * s __attribute__ ((unused)))
846 return 0;
850 static int
851 mem_close (unix_stream * s)
853 if (s != NULL)
854 free (s);
856 return 0;
860 /*********************************************************************
861 Public functions -- A reimplementation of this module needs to
862 define functional equivalents of the following.
863 *********************************************************************/
865 /* open_internal()-- Returns a stream structure from a character(kind=1)
866 internal file */
868 stream *
869 open_internal (char *base, int length, gfc_offset offset)
871 unix_stream *s;
873 s = get_mem (sizeof (unix_stream));
874 memset (s, '\0', sizeof (unix_stream));
876 s->buffer = base;
877 s->buffer_offset = offset;
879 s->logical_offset = 0;
880 s->active = s->file_length = length;
882 s->st.close = (void *) mem_close;
883 s->st.seek = (void *) mem_seek;
884 s->st.tell = (void *) mem_tell;
885 s->st.trunc = (void *) mem_truncate;
886 s->st.read = (void *) mem_read;
887 s->st.write = (void *) mem_write;
888 s->st.flush = (void *) mem_flush;
890 return (stream *) s;
893 /* open_internal4()-- Returns a stream structure from a character(kind=4)
894 internal file */
896 stream *
897 open_internal4 (char *base, int length, gfc_offset offset)
899 unix_stream *s;
901 s = get_mem (sizeof (unix_stream));
902 memset (s, '\0', sizeof (unix_stream));
904 s->buffer = base;
905 s->buffer_offset = offset;
907 s->logical_offset = 0;
908 s->active = s->file_length = length;
910 s->st.close = (void *) mem_close;
911 s->st.seek = (void *) mem_seek;
912 s->st.tell = (void *) mem_tell;
913 s->st.trunc = (void *) mem_truncate;
914 s->st.read = (void *) mem_read4;
915 s->st.write = (void *) mem_write4;
916 s->st.flush = (void *) mem_flush;
918 return (stream *) s;
922 /* fd_to_stream()-- Given an open file descriptor, build a stream
923 * around it. */
925 static stream *
926 fd_to_stream (int fd)
928 struct stat statbuf;
929 unix_stream *s;
931 s = get_mem (sizeof (unix_stream));
932 memset (s, '\0', sizeof (unix_stream));
934 s->fd = fd;
935 s->buffer_offset = 0;
936 s->physical_offset = 0;
937 s->logical_offset = 0;
939 /* Get the current length of the file. */
941 fstat (fd, &statbuf);
943 s->st_dev = statbuf.st_dev;
944 s->st_ino = statbuf.st_ino;
945 s->special_file = !S_ISREG (statbuf.st_mode);
947 if (S_ISREG (statbuf.st_mode))
948 s->file_length = statbuf.st_size;
949 else if (S_ISBLK (statbuf.st_mode))
951 /* Hopefully more portable than ioctl(fd, BLKGETSIZE64, &size)? */
952 gfc_offset cur = lseek (fd, 0, SEEK_CUR);
953 s->file_length = lseek (fd, 0, SEEK_END);
954 lseek (fd, cur, SEEK_SET);
956 else
957 s->file_length = -1;
959 if (!(S_ISREG (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
960 || options.all_unbuffered
961 ||(options.unbuffered_preconnected &&
962 (s->fd == STDIN_FILENO
963 || s->fd == STDOUT_FILENO
964 || s->fd == STDERR_FILENO))
965 || isatty (s->fd))
966 raw_init (s);
967 else
968 buf_init (s);
970 return (stream *) s;
974 /* Given the Fortran unit number, convert it to a C file descriptor. */
977 unit_to_fd (int unit)
979 gfc_unit *us;
980 int fd;
982 us = find_unit (unit);
983 if (us == NULL)
984 return -1;
986 fd = ((unix_stream *) us->s)->fd;
987 unlock_unit (us);
988 return fd;
992 /* unpack_filename()-- Given a fortran string and a pointer to a
993 * buffer that is PATH_MAX characters, convert the fortran string to a
994 * C string in the buffer. Returns nonzero if this is not possible. */
997 unpack_filename (char *cstring, const char *fstring, int len)
999 if (fstring == NULL)
1000 return 1;
1001 len = fstrlen (fstring, len);
1002 if (len >= PATH_MAX)
1003 return 1;
1005 memmove (cstring, fstring, len);
1006 cstring[len] = '\0';
1008 return 0;
1012 /* tempfile()-- Generate a temporary filename for a scratch file and
1013 * open it. mkstemp() opens the file for reading and writing, but the
1014 * library mode prevents anything that is not allowed. The descriptor
1015 * is returned, which is -1 on error. The template is pointed to by
1016 * opp->file, which is copied into the unit structure
1017 * and freed later. */
1019 static int
1020 tempfile (st_parameter_open *opp)
1022 const char *tempdir;
1023 char *template;
1024 const char *slash = "/";
1025 int fd;
1026 size_t tempdirlen;
1028 #ifndef HAVE_MKSTEMP
1029 int count;
1030 size_t slashlen;
1031 #endif
1033 tempdir = getenv ("GFORTRAN_TMPDIR");
1034 #ifdef __MINGW32__
1035 if (tempdir == NULL)
1037 char buffer[MAX_PATH + 1];
1038 DWORD ret;
1039 ret = GetTempPath (MAX_PATH, buffer);
1040 /* If we are not able to get a temp-directory, we use
1041 current directory. */
1042 if (ret > MAX_PATH || !ret)
1043 buffer[0] = 0;
1044 else
1045 buffer[ret] = 0;
1046 tempdir = strdup (buffer);
1048 #else
1049 if (tempdir == NULL)
1050 tempdir = getenv ("TMP");
1051 if (tempdir == NULL)
1052 tempdir = getenv ("TEMP");
1053 if (tempdir == NULL)
1054 tempdir = DEFAULT_TEMPDIR;
1055 #endif
1057 /* Check for special case that tempdir contains slash
1058 or backslash at end. */
1059 tempdirlen = strlen (tempdir);
1060 if (*tempdir == 0 || tempdir[tempdirlen - 1] == '/'
1061 #ifdef __MINGW32__
1062 || tempdir[tempdirlen - 1] == '\\'
1063 #endif
1065 slash = "";
1067 // Take care that the template is longer in the mktemp() branch.
1068 template = get_mem (tempdirlen + 23);
1070 #ifdef HAVE_MKSTEMP
1071 sprintf (template, "%s%sgfortrantmpXXXXXX", tempdir, slash);
1073 fd = mkstemp (template);
1075 #else /* HAVE_MKSTEMP */
1076 fd = -1;
1077 count = 0;
1078 slashlen = strlen (slash);
1081 sprintf (template, "%s%sgfortrantmpaaaXXXXXX", tempdir, slash);
1082 if (count > 0)
1084 int c = count;
1085 template[tempdirlen + slashlen + 13] = 'a' + (c% 26);
1086 c /= 26;
1087 template[tempdirlen + slashlen + 12] = 'a' + (c % 26);
1088 c /= 26;
1089 template[tempdirlen + slashlen + 11] = 'a' + (c % 26);
1090 if (c >= 26)
1091 break;
1094 if (!mktemp (template))
1096 errno = EEXIST;
1097 count++;
1098 continue;
1101 #if defined(HAVE_CRLF) && defined(O_BINARY)
1102 fd = open (template, O_RDWR | O_CREAT | O_EXCL | O_BINARY,
1103 S_IREAD | S_IWRITE);
1104 #else
1105 fd = open (template, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
1106 #endif
1108 while (fd == -1 && errno == EEXIST);
1109 #endif /* HAVE_MKSTEMP */
1111 opp->file = template;
1112 opp->file_len = strlen (template); /* Don't include trailing nul */
1114 return fd;
1118 /* regular_file()-- Open a regular file.
1119 * Change flags->action if it is ACTION_UNSPECIFIED on entry,
1120 * unless an error occurs.
1121 * Returns the descriptor, which is less than zero on error. */
1123 static int
1124 regular_file (st_parameter_open *opp, unit_flags *flags)
1126 char path[PATH_MAX + 1];
1127 int mode;
1128 int rwflag;
1129 int crflag;
1130 int fd;
1132 if (unpack_filename (path, opp->file, opp->file_len))
1134 errno = ENOENT; /* Fake an OS error */
1135 return -1;
1138 #ifdef __CYGWIN__
1139 if (opp->file_len == 7)
1141 if (strncmp (path, "CONOUT$", 7) == 0
1142 || strncmp (path, "CONERR$", 7) == 0)
1144 fd = open ("/dev/conout", O_WRONLY);
1145 flags->action = ACTION_WRITE;
1146 return fd;
1150 if (opp->file_len == 6 && strncmp (path, "CONIN$", 6) == 0)
1152 fd = open ("/dev/conin", O_RDONLY);
1153 flags->action = ACTION_READ;
1154 return fd;
1156 #endif
1159 #ifdef __MINGW32__
1160 if (opp->file_len == 7)
1162 if (strncmp (path, "CONOUT$", 7) == 0
1163 || strncmp (path, "CONERR$", 7) == 0)
1165 fd = open ("CONOUT$", O_WRONLY);
1166 flags->action = ACTION_WRITE;
1167 return fd;
1171 if (opp->file_len == 6 && strncmp (path, "CONIN$", 6) == 0)
1173 fd = open ("CONIN$", O_RDONLY);
1174 flags->action = ACTION_READ;
1175 return fd;
1177 #endif
1179 rwflag = 0;
1181 switch (flags->action)
1183 case ACTION_READ:
1184 rwflag = O_RDONLY;
1185 break;
1187 case ACTION_WRITE:
1188 rwflag = O_WRONLY;
1189 break;
1191 case ACTION_READWRITE:
1192 case ACTION_UNSPECIFIED:
1193 rwflag = O_RDWR;
1194 break;
1196 default:
1197 internal_error (&opp->common, "regular_file(): Bad action");
1200 switch (flags->status)
1202 case STATUS_NEW:
1203 crflag = O_CREAT | O_EXCL;
1204 break;
1206 case STATUS_OLD: /* open will fail if the file does not exist*/
1207 crflag = 0;
1208 break;
1210 case STATUS_UNKNOWN:
1211 case STATUS_SCRATCH:
1212 crflag = O_CREAT;
1213 break;
1215 case STATUS_REPLACE:
1216 crflag = O_CREAT | O_TRUNC;
1217 break;
1219 default:
1220 internal_error (&opp->common, "regular_file(): Bad status");
1223 /* rwflag |= O_LARGEFILE; */
1225 #if defined(HAVE_CRLF) && defined(O_BINARY)
1226 crflag |= O_BINARY;
1227 #endif
1229 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
1230 fd = open (path, rwflag | crflag, mode);
1231 if (flags->action != ACTION_UNSPECIFIED)
1232 return fd;
1234 if (fd >= 0)
1236 flags->action = ACTION_READWRITE;
1237 return fd;
1239 if (errno != EACCES && errno != EROFS)
1240 return fd;
1242 /* retry for read-only access */
1243 rwflag = O_RDONLY;
1244 fd = open (path, rwflag | crflag, mode);
1245 if (fd >=0)
1247 flags->action = ACTION_READ;
1248 return fd; /* success */
1251 if (errno != EACCES)
1252 return fd; /* failure */
1254 /* retry for write-only access */
1255 rwflag = O_WRONLY;
1256 fd = open (path, rwflag | crflag, mode);
1257 if (fd >=0)
1259 flags->action = ACTION_WRITE;
1260 return fd; /* success */
1262 return fd; /* failure */
1266 /* open_external()-- Open an external file, unix specific version.
1267 * Change flags->action if it is ACTION_UNSPECIFIED on entry.
1268 * Returns NULL on operating system error. */
1270 stream *
1271 open_external (st_parameter_open *opp, unit_flags *flags)
1273 int fd;
1275 if (flags->status == STATUS_SCRATCH)
1277 fd = tempfile (opp);
1278 if (flags->action == ACTION_UNSPECIFIED)
1279 flags->action = ACTION_READWRITE;
1281 #if HAVE_UNLINK_OPEN_FILE
1282 /* We can unlink scratch files now and it will go away when closed. */
1283 if (fd >= 0)
1284 unlink (opp->file);
1285 #endif
1287 else
1289 /* regular_file resets flags->action if it is ACTION_UNSPECIFIED and
1290 * if it succeeds */
1291 fd = regular_file (opp, flags);
1294 if (fd < 0)
1295 return NULL;
1296 fd = fix_fd (fd);
1298 return fd_to_stream (fd);
1302 /* input_stream()-- Return a stream pointer to the default input stream.
1303 * Called on initialization. */
1305 stream *
1306 input_stream (void)
1308 return fd_to_stream (STDIN_FILENO);
1312 /* output_stream()-- Return a stream pointer to the default output stream.
1313 * Called on initialization. */
1315 stream *
1316 output_stream (void)
1318 stream * s;
1320 #if defined(HAVE_CRLF) && defined(HAVE_SETMODE)
1321 setmode (STDOUT_FILENO, O_BINARY);
1322 #endif
1324 s = fd_to_stream (STDOUT_FILENO);
1325 return s;
1329 /* error_stream()-- Return a stream pointer to the default error stream.
1330 * Called on initialization. */
1332 stream *
1333 error_stream (void)
1335 stream * s;
1337 #if defined(HAVE_CRLF) && defined(HAVE_SETMODE)
1338 setmode (STDERR_FILENO, O_BINARY);
1339 #endif
1341 s = fd_to_stream (STDERR_FILENO);
1342 return s;
1346 /* st_vprintf()-- vprintf function for error output. To avoid buffer
1347 overruns, we limit the length of the buffer to ST_VPRINTF_SIZE. 2k
1348 is big enough to completely fill a 80x25 terminal, so it shuld be
1349 OK. We use a direct write() because it is simpler and least likely
1350 to be clobbered by memory corruption. Writing an error message
1351 longer than that is an error. */
1353 #define ST_VPRINTF_SIZE 2048
1356 st_vprintf (const char *format, va_list ap)
1358 static char buffer[ST_VPRINTF_SIZE];
1359 int written;
1360 int fd;
1362 fd = options.use_stderr ? STDERR_FILENO : STDOUT_FILENO;
1363 #ifdef HAVE_VSNPRINTF
1364 written = vsnprintf(buffer, ST_VPRINTF_SIZE, format, ap);
1365 #else
1366 written = vsprintf(buffer, format, ap);
1368 if (written >= ST_VPRINTF_SIZE-1)
1370 /* The error message was longer than our buffer. Ouch. Because
1371 we may have messed up things badly, report the error and
1372 quit. */
1373 #define ERROR_MESSAGE "Internal error: buffer overrun in st_vprintf()\n"
1374 write (fd, buffer, ST_VPRINTF_SIZE-1);
1375 write (fd, ERROR_MESSAGE, strlen(ERROR_MESSAGE));
1376 sys_exit(2);
1377 #undef ERROR_MESSAGE
1380 #endif
1382 written = write (fd, buffer, written);
1383 return written;
1386 /* st_printf()-- printf() function for error output. This just calls
1387 st_vprintf() to do the actual work. */
1390 st_printf (const char *format, ...)
1392 int written;
1393 va_list ap;
1394 va_start (ap, format);
1395 written = st_vprintf(format, ap);
1396 va_end (ap);
1397 return written;
1401 /* compare_file_filename()-- Given an open stream and a fortran string
1402 * that is a filename, figure out if the file is the same as the
1403 * filename. */
1406 compare_file_filename (gfc_unit *u, const char *name, int len)
1408 char path[PATH_MAX + 1];
1409 struct stat st;
1410 #ifdef HAVE_WORKING_STAT
1411 unix_stream *s;
1412 #else
1413 # ifdef __MINGW32__
1414 uint64_t id1, id2;
1415 # endif
1416 #endif
1418 if (unpack_filename (path, name, len))
1419 return 0; /* Can't be the same */
1421 /* If the filename doesn't exist, then there is no match with the
1422 * existing file. */
1424 if (stat (path, &st) < 0)
1425 return 0;
1427 #ifdef HAVE_WORKING_STAT
1428 s = (unix_stream *) (u->s);
1429 return (st.st_dev == s->st_dev) && (st.st_ino == s->st_ino);
1430 #else
1432 # ifdef __MINGW32__
1433 /* We try to match files by a unique ID. On some filesystems (network
1434 fs and FAT), we can't generate this unique ID, and will simply compare
1435 filenames. */
1436 id1 = id_from_path (path);
1437 id2 = id_from_fd (((unix_stream *) (u->s))->fd);
1438 if (id1 || id2)
1439 return (id1 == id2);
1440 # endif
1442 if (len != u->file_len)
1443 return 0;
1444 return (memcmp(path, u->file, len) == 0);
1445 #endif
1449 #ifdef HAVE_WORKING_STAT
1450 # define FIND_FILE0_DECL struct stat *st
1451 # define FIND_FILE0_ARGS st
1452 #else
1453 # define FIND_FILE0_DECL uint64_t id, const char *file, gfc_charlen_type file_len
1454 # define FIND_FILE0_ARGS id, file, file_len
1455 #endif
1457 /* find_file0()-- Recursive work function for find_file() */
1459 static gfc_unit *
1460 find_file0 (gfc_unit *u, FIND_FILE0_DECL)
1462 gfc_unit *v;
1463 #if defined(__MINGW32__) && !HAVE_WORKING_STAT
1464 uint64_t id1;
1465 #endif
1467 if (u == NULL)
1468 return NULL;
1470 #ifdef HAVE_WORKING_STAT
1471 if (u->s != NULL)
1473 unix_stream *s = (unix_stream *) (u->s);
1474 if (st[0].st_dev == s->st_dev && st[0].st_ino == s->st_ino)
1475 return u;
1477 #else
1478 # ifdef __MINGW32__
1479 if (u->s && ((id1 = id_from_fd (((unix_stream *) u->s)->fd)) || id1))
1481 if (id == id1)
1482 return u;
1484 else
1485 # endif
1486 if (compare_string (u->file_len, u->file, file_len, file) == 0)
1487 return u;
1488 #endif
1490 v = find_file0 (u->left, FIND_FILE0_ARGS);
1491 if (v != NULL)
1492 return v;
1494 v = find_file0 (u->right, FIND_FILE0_ARGS);
1495 if (v != NULL)
1496 return v;
1498 return NULL;
1502 /* find_file()-- Take the current filename and see if there is a unit
1503 * that has the file already open. Returns a pointer to the unit if so. */
1505 gfc_unit *
1506 find_file (const char *file, gfc_charlen_type file_len)
1508 char path[PATH_MAX + 1];
1509 struct stat st[1];
1510 gfc_unit *u;
1511 #if defined(__MINGW32__) && !HAVE_WORKING_STAT
1512 uint64_t id = 0ULL;
1513 #endif
1515 if (unpack_filename (path, file, file_len))
1516 return NULL;
1518 if (stat (path, &st[0]) < 0)
1519 return NULL;
1521 #if defined(__MINGW32__) && !HAVE_WORKING_STAT
1522 id = id_from_path (path);
1523 #endif
1525 __gthread_mutex_lock (&unit_lock);
1526 retry:
1527 u = find_file0 (unit_root, FIND_FILE0_ARGS);
1528 if (u != NULL)
1530 /* Fast path. */
1531 if (! __gthread_mutex_trylock (&u->lock))
1533 /* assert (u->closed == 0); */
1534 __gthread_mutex_unlock (&unit_lock);
1535 return u;
1538 inc_waiting_locked (u);
1540 __gthread_mutex_unlock (&unit_lock);
1541 if (u != NULL)
1543 __gthread_mutex_lock (&u->lock);
1544 if (u->closed)
1546 __gthread_mutex_lock (&unit_lock);
1547 __gthread_mutex_unlock (&u->lock);
1548 if (predec_waiting_locked (u) == 0)
1549 free (u);
1550 goto retry;
1553 dec_waiting_unlocked (u);
1555 return u;
1558 static gfc_unit *
1559 flush_all_units_1 (gfc_unit *u, int min_unit)
1561 while (u != NULL)
1563 if (u->unit_number > min_unit)
1565 gfc_unit *r = flush_all_units_1 (u->left, min_unit);
1566 if (r != NULL)
1567 return r;
1569 if (u->unit_number >= min_unit)
1571 if (__gthread_mutex_trylock (&u->lock))
1572 return u;
1573 if (u->s)
1574 sflush (u->s);
1575 __gthread_mutex_unlock (&u->lock);
1577 u = u->right;
1579 return NULL;
1582 void
1583 flush_all_units (void)
1585 gfc_unit *u;
1586 int min_unit = 0;
1588 __gthread_mutex_lock (&unit_lock);
1591 u = flush_all_units_1 (unit_root, min_unit);
1592 if (u != NULL)
1593 inc_waiting_locked (u);
1594 __gthread_mutex_unlock (&unit_lock);
1595 if (u == NULL)
1596 return;
1598 __gthread_mutex_lock (&u->lock);
1600 min_unit = u->unit_number + 1;
1602 if (u->closed == 0)
1604 sflush (u->s);
1605 __gthread_mutex_lock (&unit_lock);
1606 __gthread_mutex_unlock (&u->lock);
1607 (void) predec_waiting_locked (u);
1609 else
1611 __gthread_mutex_lock (&unit_lock);
1612 __gthread_mutex_unlock (&u->lock);
1613 if (predec_waiting_locked (u) == 0)
1614 free (u);
1617 while (1);
1621 /* delete_file()-- Given a unit structure, delete the file associated
1622 * with the unit. Returns nonzero if something went wrong. */
1625 delete_file (gfc_unit * u)
1627 char path[PATH_MAX + 1];
1629 if (unpack_filename (path, u->file, u->file_len))
1630 { /* Shouldn't be possible */
1631 errno = ENOENT;
1632 return 1;
1635 return unlink (path);
1639 /* file_exists()-- Returns nonzero if the current filename exists on
1640 * the system */
1643 file_exists (const char *file, gfc_charlen_type file_len)
1645 char path[PATH_MAX + 1];
1647 if (unpack_filename (path, file, file_len))
1648 return 0;
1650 return !(access (path, F_OK));
1654 /* file_size()-- Returns the size of the file. */
1656 GFC_IO_INT
1657 file_size (const char *file, gfc_charlen_type file_len)
1659 char path[PATH_MAX + 1];
1660 struct stat statbuf;
1662 if (unpack_filename (path, file, file_len))
1663 return -1;
1665 if (stat (path, &statbuf) < 0)
1666 return -1;
1668 return (GFC_IO_INT) statbuf.st_size;
1671 static const char yes[] = "YES", no[] = "NO", unknown[] = "UNKNOWN";
1673 /* inquire_sequential()-- Given a fortran string, determine if the
1674 * file is suitable for sequential access. Returns a C-style
1675 * string. */
1677 const char *
1678 inquire_sequential (const char *string, int len)
1680 char path[PATH_MAX + 1];
1681 struct stat statbuf;
1683 if (string == NULL ||
1684 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1685 return unknown;
1687 if (S_ISREG (statbuf.st_mode) ||
1688 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
1689 return unknown;
1691 if (S_ISDIR (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
1692 return no;
1694 return unknown;
1698 /* inquire_direct()-- Given a fortran string, determine if the file is
1699 * suitable for direct access. Returns a C-style string. */
1701 const char *
1702 inquire_direct (const char *string, int len)
1704 char path[PATH_MAX + 1];
1705 struct stat statbuf;
1707 if (string == NULL ||
1708 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1709 return unknown;
1711 if (S_ISREG (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
1712 return unknown;
1714 if (S_ISDIR (statbuf.st_mode) ||
1715 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
1716 return no;
1718 return unknown;
1722 /* inquire_formatted()-- Given a fortran string, determine if the file
1723 * is suitable for formatted form. Returns a C-style string. */
1725 const char *
1726 inquire_formatted (const char *string, int len)
1728 char path[PATH_MAX + 1];
1729 struct stat statbuf;
1731 if (string == NULL ||
1732 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1733 return unknown;
1735 if (S_ISREG (statbuf.st_mode) ||
1736 S_ISBLK (statbuf.st_mode) ||
1737 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
1738 return unknown;
1740 if (S_ISDIR (statbuf.st_mode))
1741 return no;
1743 return unknown;
1747 /* inquire_unformatted()-- Given a fortran string, determine if the file
1748 * is suitable for unformatted form. Returns a C-style string. */
1750 const char *
1751 inquire_unformatted (const char *string, int len)
1753 return inquire_formatted (string, len);
1757 /* inquire_access()-- Given a fortran string, determine if the file is
1758 * suitable for access. */
1760 static const char *
1761 inquire_access (const char *string, int len, int mode)
1763 char path[PATH_MAX + 1];
1765 if (string == NULL || unpack_filename (path, string, len) ||
1766 access (path, mode) < 0)
1767 return no;
1769 return yes;
1773 /* inquire_read()-- Given a fortran string, determine if the file is
1774 * suitable for READ access. */
1776 const char *
1777 inquire_read (const char *string, int len)
1779 return inquire_access (string, len, R_OK);
1783 /* inquire_write()-- Given a fortran string, determine if the file is
1784 * suitable for READ access. */
1786 const char *
1787 inquire_write (const char *string, int len)
1789 return inquire_access (string, len, W_OK);
1793 /* inquire_readwrite()-- Given a fortran string, determine if the file is
1794 * suitable for read and write access. */
1796 const char *
1797 inquire_readwrite (const char *string, int len)
1799 return inquire_access (string, len, R_OK | W_OK);
1803 /* file_length()-- Return the file length in bytes, -1 if unknown */
1805 gfc_offset
1806 file_length (stream * s)
1808 gfc_offset curr, end;
1809 if (!is_seekable (s))
1810 return -1;
1811 curr = stell (s);
1812 if (curr == -1)
1813 return curr;
1814 end = sseek (s, 0, SEEK_END);
1815 sseek (s, curr, SEEK_SET);
1816 return end;
1820 /* is_seekable()-- Return nonzero if the stream is seekable, zero if
1821 * it is not */
1824 is_seekable (stream *s)
1826 /* By convention, if file_length == -1, the file is not
1827 seekable. */
1828 return ((unix_stream *) s)->file_length!=-1;
1832 /* is_special()-- Return nonzero if the stream is not a regular file. */
1835 is_special (stream *s)
1837 return ((unix_stream *) s)->special_file;
1842 stream_isatty (stream *s)
1844 return isatty (((unix_stream *) s)->fd);
1848 stream_ttyname (stream *s __attribute__ ((unused)),
1849 char * buf __attribute__ ((unused)),
1850 size_t buflen __attribute__ ((unused)))
1852 #ifdef HAVE_TTYNAME_R
1853 return ttyname_r (((unix_stream *) s)->fd, buf, buflen);
1854 #elif defined HAVE_TTYNAME
1855 char *p;
1856 size_t plen;
1857 p = ttyname (((unix_stream *) s)->fd);
1858 if (!p)
1859 return errno;
1860 plen = strlen (p);
1861 if (buflen < plen)
1862 plen = buflen;
1863 memcpy (buf, p, plen);
1864 return 0;
1865 #else
1866 return ENOSYS;
1867 #endif
1873 /* How files are stored: This is an operating-system specific issue,
1874 and therefore belongs here. There are three cases to consider.
1876 Direct Access:
1877 Records are written as block of bytes corresponding to the record
1878 length of the file. This goes for both formatted and unformatted
1879 records. Positioning is done explicitly for each data transfer,
1880 so positioning is not much of an issue.
1882 Sequential Formatted:
1883 Records are separated by newline characters. The newline character
1884 is prohibited from appearing in a string. If it does, this will be
1885 messed up on the next read. End of file is also the end of a record.
1887 Sequential Unformatted:
1888 In this case, we are merely copying bytes to and from main storage,
1889 yet we need to keep track of varying record lengths. We adopt
1890 the solution used by f2c. Each record contains a pair of length
1891 markers:
1893 Length of record n in bytes
1894 Data of record n
1895 Length of record n in bytes
1897 Length of record n+1 in bytes
1898 Data of record n+1
1899 Length of record n+1 in bytes
1901 The length is stored at the end of a record to allow backspacing to the
1902 previous record. Between data transfer statements, the file pointer
1903 is left pointing to the first length of the current record.
1905 ENDFILE records are never explicitly stored.