gfc_offset buffer_offset; /* File offset of the start of the buffer */
gfc_offset physical_offset; /* Current physical file offset */
gfc_offset logical_offset; /* Current logical file offset */
- gfc_offset file_length; /* Length of the file, -1 if not seekable. */
+ gfc_offset file_length; /* Length of the file. */
char *buffer; /* Pointer to the buffer. */
int fd; /* The POSIX file descriptor. */
int ndirty; /* Dirty bytes starting at buffer_offset */
- int special_file; /* =1 if the fd refers to a special file */
-
/* Cached stat(2) values. */
dev_t st_dev;
ino_t st_ino;
return lseek (s->fd, 0, SEEK_CUR);
}
+static gfc_offset
+raw_size (unix_stream * s)
+{
+ struct stat statbuf;
+ int ret = fstat (s->fd, &statbuf);
+ if (ret == -1)
+ return ret;
+ return statbuf.st_size;
+}
+
static int
raw_truncate (unix_stream * s, gfc_offset length)
{
s->st.write = (void *) raw_write;
s->st.seek = (void *) raw_seek;
s->st.tell = (void *) raw_tell;
+ s->st.size = (void *) raw_size;
s->st.trunc = (void *) raw_truncate;
s->st.close = (void *) raw_close;
s->st.flush = (void *) raw_flush;
Buffered I/O functions. These functions have the same semantics as the
raw I/O functions above, except that they are buffered in order to
improve performance. The buffer must be flushed when switching from
-reading to writing and vice versa.
+reading to writing and vice versa. Only supported for regular files.
*********************************************************************/
static int
if (s->ndirty == 0)
return 0;
- if (s->file_length != -1 && s->physical_offset != s->buffer_offset
+ if (s->physical_offset != s->buffer_offset
&& lseek (s->fd, s->buffer_offset, SEEK_SET) < 0)
return -1;
s->physical_offset = s->buffer_offset + writelen;
- /* Don't increment file_length if the file is non-seekable. */
- if (s->file_length != -1 && s->physical_offset > s->file_length)
+ if (s->physical_offset > s->file_length)
s->file_length = s->physical_offset;
s->ndirty -= writelen;
/* At this point we consider all bytes in the buffer discarded. */
to_read = nbyte - nread;
new_logical = s->logical_offset + nread;
- if (s->file_length != -1 && s->physical_offset != new_logical
+ if (s->physical_offset != new_logical
&& lseek (s->fd, new_logical, SEEK_SET) < 0)
return -1;
s->buffer_offset = s->physical_offset = new_logical;
}
else
{
- if (s->file_length != -1 && s->physical_offset != s->logical_offset)
+ if (s->physical_offset != s->logical_offset)
{
if (lseek (s->fd, s->logical_offset, SEEK_SET) < 0)
return -1;
}
}
s->logical_offset += nbyte;
- /* Don't increment file_length if the file is non-seekable. */
- if (s->file_length != -1 && s->logical_offset > s->file_length)
+ if (s->logical_offset > s->file_length)
s->file_length = s->logical_offset;
return nbyte;
}
static gfc_offset
buf_tell (unix_stream * s)
{
- return s->logical_offset;
+ return buf_seek (s, 0, SEEK_CUR);
+}
+
+static gfc_offset
+buf_size (unix_stream * s)
+{
+ return s->file_length;
}
static int
s->st.write = (void *) buf_write;
s->st.seek = (void *) buf_seek;
s->st.tell = (void *) buf_tell;
+ s->st.size = (void *) buf_size;
s->st.trunc = (void *) buf_truncate;
s->st.close = (void *) buf_close;
s->st.flush = (void *) buf_flush;
s->st.close = (void *) mem_close;
s->st.seek = (void *) mem_seek;
s->st.tell = (void *) mem_tell;
+ /* buf_size is not a typo, we just reuse an identical
+ implementation. */
+ s->st.size = (void *) buf_size;
s->st.trunc = (void *) mem_truncate;
s->st.read = (void *) mem_read;
s->st.write = (void *) mem_write;
s->st.close = (void *) mem_close;
s->st.seek = (void *) mem_seek;
s->st.tell = (void *) mem_tell;
+ /* buf_size is not a typo, we just reuse an identical
+ implementation. */
+ s->st.size = (void *) buf_size;
s->st.trunc = (void *) mem_truncate;
s->st.read = (void *) mem_read4;
s->st.write = (void *) mem_write4;
s->st_dev = statbuf.st_dev;
s->st_ino = statbuf.st_ino;
- s->special_file = !S_ISREG (statbuf.st_mode);
-
- if (S_ISREG (statbuf.st_mode))
- s->file_length = statbuf.st_size;
+ s->file_length = statbuf.st_size;
+
+ /* Only use buffered IO for regular files. */
+ if (S_ISREG (statbuf.st_mode)
+ && !options.all_unbuffered
+ && !(options.unbuffered_preconnected &&
+ (s->fd == STDIN_FILENO
+ || s->fd == STDOUT_FILENO
+ || s->fd == STDERR_FILENO)))
+ buf_init (s);
else
- {
- /* Some character special files are seekable but most are not,
- so figure it out by trying to seek. On Linux, /dev/null is
- an example of such a special file. */
- s->file_length = lseek (fd, 0, SEEK_END);
- if (s->file_length > 0)
- lseek (fd, 0, SEEK_SET);
- }
-
- if (!(S_ISREG (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
- || options.all_unbuffered
- ||(options.unbuffered_preconnected &&
- (s->fd == STDIN_FILENO
- || s->fd == STDOUT_FILENO
- || s->fd == STDERR_FILENO))
- || isatty (s->fd))
raw_init (s);
- else
- buf_init (s);
return (stream *) s;
}
}
-/* file_length()-- Return the file length in bytes, -1 if unknown */
-
-gfc_offset
-file_length (stream * s)
-{
- gfc_offset curr, end;
- if (!is_seekable (s))
- return -1;
- curr = stell (s);
- if (curr == -1)
- return curr;
- end = sseek (s, 0, SEEK_END);
- sseek (s, curr, SEEK_SET);
- return end;
-}
-
-
-/* is_seekable()-- Return nonzero if the stream is seekable, zero if
- * it is not */
-
-int
-is_seekable (stream *s)
-{
- /* By convention, if file_length == -1, the file is not
- seekable. */
- return ((unix_stream *) s)->file_length!=-1;
-}
-
-
-/* is_special()-- Return nonzero if the stream is not a regular file. */
-
-int
-is_special (stream *s)
-{
- return ((unix_stream *) s)->special_file;
-}
-
-
int
stream_isatty (stream *s)
{