]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/io/unix.c
* obj-c++.dg/encode-3.mm: Fix for 64-bit support.
[thirdparty/gcc.git] / libgfortran / io / unix.c
CommitLineData
a0007dfa 1/* Copyright (C) 2002, 2003, 2004, 2005
2 Free Software Foundation, Inc.
4ee9c684 3 Contributed by Andy Vaught
4
5This file is part of the GNU Fortran 95 runtime library (libgfortran).
6
7Libgfortran is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
b417ea8c 12In addition to the permissions in the GNU General Public License, the
13Free Software Foundation gives you unlimited permission to link the
14compiled version of this file into combinations with other programs,
15and to distribute those combinations without any restriction coming
16from the use of this file. (The General Public License restrictions
17do apply in other respects; for example, they cover modification of
18the file, and distribution when not linked into a combine
19executable.)
20
4ee9c684 21Libgfortran is distributed in the hope that it will be useful,
22but WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24GNU General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with Libgfortran; see the file COPYING. If not, write to
5ac2525b 28the Free Software Foundation, 51 Franklin Street, Fifth Floor,
29Boston, MA 02110-1301, USA. */
4ee9c684 30
31/* Unix stream I/O module */
32
33#include "config.h"
34#include <stdlib.h>
35#include <limits.h>
36
37#include <unistd.h>
91e6f54a 38#include <stdio.h>
4ee9c684 39#include <sys/stat.h>
40#include <fcntl.h>
2639e4cd 41#include <assert.h>
4ee9c684 42
4ee9c684 43#include <string.h>
44#include <errno.h>
45
46#include "libgfortran.h"
47#include "io.h"
60c514ba 48#include "unix.h"
4ee9c684 49
8df8ec57 50#ifndef SSIZE_MAX
51#define SSIZE_MAX SHRT_MAX
52#endif
53
4ee9c684 54#ifndef PATH_MAX
55#define PATH_MAX 1024
56#endif
57
d2455565 58#ifndef PROT_READ
59#define PROT_READ 1
60#endif
61
62#ifndef PROT_WRITE
63#define PROT_WRITE 2
64#endif
65
7dfba97b 66/* These flags aren't defined on all targets (mingw32), so provide them
67 here. */
68#ifndef S_IRGRP
69#define S_IRGRP 0
70#endif
71
72#ifndef S_IWGRP
73#define S_IWGRP 0
74#endif
75
76#ifndef S_IROTH
77#define S_IROTH 0
78#endif
79
80#ifndef S_IWOTH
81#define S_IWOTH 0
82#endif
83
4ee9c684 84/* This implementation of stream I/O is based on the paper:
85 *
86 * "Exploiting the advantages of mapped files for stream I/O",
87 * O. Krieger, M. Stumm and R. Umrau, "Proceedings of the 1992 Winter
88 * USENIX conference", p. 27-42.
89 *
90 * It differs in a number of ways from the version described in the
91 * paper. First of all, threads are not an issue during I/O and we
92 * also don't have to worry about having multiple regions, since
93 * fortran's I/O model only allows you to be one place at a time.
94 *
95 * On the other hand, we have to be able to writing at the end of a
96 * stream, read from the start of a stream or read and write blocks of
97 * bytes from an arbitrary position. After opening a file, a pointer
98 * to a stream structure is returned, which is used to handle file
99 * accesses until the file is closed.
100 *
101 * salloc_at_r(stream, len, where)-- Given a stream pointer, return a
102 * pointer to a block of memory that mirror the file at position
103 * 'where' that is 'len' bytes long. The len integer is updated to
104 * reflect how many bytes were actually read. The only reason for a
105 * short read is end of file. The file pointer is updated. The
106 * pointer is valid until the next call to salloc_*.
107 *
108 * salloc_at_w(stream, len, where)-- Given the stream pointer, returns
109 * a pointer to a block of memory that is updated to reflect the state
110 * of the file. The length of the buffer is always equal to that
111 * requested. The buffer must be completely set by the caller. When
112 * data has been written, the sfree() function must be called to
113 * indicate that the caller is done writing data to the buffer. This
114 * may or may not cause a physical write.
115 *
116 * Short forms of these are salloc_r() and salloc_w() which drop the
117 * 'where' parameter and use the current file pointer. */
118
119
4ee9c684 120/*move_pos_offset()-- Move the record pointer right or left
121 *relative to current position */
122
123int
124move_pos_offset (stream* st, int pos_off)
125{
126 unix_stream * str = (unix_stream*)st;
127 if (pos_off < 0)
128 {
363dcb81 129 str->logical_offset += pos_off;
4ee9c684 130
363dcb81 131 if (str->dirty_offset + str->ndirty > str->logical_offset)
4ee9c684 132 {
363dcb81 133 if (str->ndirty + pos_off > 0)
134 str->ndirty += pos_off;
4ee9c684 135 else
136 {
137 str->dirty_offset += pos_off + pos_off;
363dcb81 138 str->ndirty = 0;
4ee9c684 139 }
140 }
141
363dcb81 142 return pos_off;
4ee9c684 143 }
363dcb81 144 return 0;
4ee9c684 145}
146
147
148/* fix_fd()-- Given a file descriptor, make sure it is not one of the
149 * standard descriptors, returning a non-standard descriptor. If the
150 * user specifies that system errors should go to standard output,
151 * then closes standard output, we don't want the system errors to a
152 * file that has been given file descriptor 1 or 0. We want to send
153 * the error to the invalid descriptor. */
154
155static int
156fix_fd (int fd)
157{
158 int input, output, error;
159
160 input = output = error = 0;
161
7145fd06 162 /* Unix allocates the lowest descriptors first, so a loop is not
163 required, but this order is. */
4ee9c684 164
165 if (fd == STDIN_FILENO)
166 {
167 fd = dup (fd);
168 input = 1;
169 }
170 if (fd == STDOUT_FILENO)
171 {
172 fd = dup (fd);
173 output = 1;
174 }
175 if (fd == STDERR_FILENO)
176 {
177 fd = dup (fd);
178 error = 1;
179 }
180
181 if (input)
182 close (STDIN_FILENO);
183 if (output)
184 close (STDOUT_FILENO);
185 if (error)
186 close (STDERR_FILENO);
187
188 return fd;
189}
190
353c8a95 191int
192is_preconnected (stream * s)
193{
194 int fd;
195
196 fd = ((unix_stream *) s)->fd;
197 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
198 return 1;
199 else
200 return 0;
201}
4ee9c684 202
2488b3b6 203/* If the stream corresponds to a preconnected unit, we flush the
204 corresponding C stream. This is bugware for mixed C-Fortran codes
205 where the C code doesn't flush I/O before returning. */
206void
207flush_if_preconnected (stream * s)
208{
209 int fd;
210
211 fd = ((unix_stream *) s)->fd;
212 if (fd == STDIN_FILENO)
213 fflush (stdin);
214 else if (fd == STDOUT_FILENO)
215 fflush (stdout);
216 else if (fd == STDERR_FILENO)
217 fflush (stderr);
218}
219
4ee9c684 220
b2a112ca 221/* Reset a stream after reading/writing. Assumes that the buffers have
222 been flushed. */
223
224inline static void
225reset_stream (unix_stream * s, size_t bytes_rw)
4ee9c684 226{
b2a112ca 227 s->physical_offset += bytes_rw;
228 s->logical_offset = s->physical_offset;
229 if (s->file_length != -1 && s->physical_offset > s->file_length)
230 s->file_length = s->physical_offset;
231}
4ee9c684 232
4ee9c684 233
b2a112ca 234/* Read bytes into a buffer, allowing for short reads. If the nbytes
235 * argument is less on return than on entry, it is because we've hit
236 * the end of file. */
4ee9c684 237
b2a112ca 238static int
239do_read (unix_stream * s, void * buf, size_t * nbytes)
240{
241 ssize_t trans;
242 size_t bytes_left;
243 char *buf_st;
244 int status;
245
246 status = 0;
247 bytes_left = *nbytes;
248 buf_st = (char *) buf;
249
250 /* We must read in a loop since some systems don't restart system
251 calls in case of a signal. */
252 while (bytes_left > 0)
253 {
254 /* Requests between SSIZE_MAX and SIZE_MAX are undefined by SUSv3,
255 so we must read in chunks smaller than SSIZE_MAX. */
256 trans = (bytes_left < SSIZE_MAX) ? bytes_left : SSIZE_MAX;
257 trans = read (s->fd, buf_st, trans);
258 if (trans < 0)
259 {
260 if (errno == EINTR)
261 continue;
262 else
263 {
264 status = errno;
265 break;
266 }
267 }
268 else if (trans == 0) /* We hit EOF. */
269 break;
270 buf_st += trans;
271 bytes_left -= trans;
4ee9c684 272 }
273
b2a112ca 274 *nbytes -= bytes_left;
275 return status;
4ee9c684 276}
277
278
b2a112ca 279/* Write a buffer to a stream, allowing for short writes. */
4ee9c684 280
281static int
b2a112ca 282do_write (unix_stream * s, const void * buf, size_t * nbytes)
4ee9c684 283{
b2a112ca 284 ssize_t trans;
285 size_t bytes_left;
286 char *buf_st;
287 int status;
288
289 status = 0;
290 bytes_left = *nbytes;
291 buf_st = (char *) buf;
292
293 /* We must write in a loop since some systems don't restart system
294 calls in case of a signal. */
295 while (bytes_left > 0)
4ee9c684 296 {
b2a112ca 297 /* Requests between SSIZE_MAX and SIZE_MAX are undefined by SUSv3,
298 so we must write in chunks smaller than SSIZE_MAX. */
299 trans = (bytes_left < SSIZE_MAX) ? bytes_left : SSIZE_MAX;
300 trans = write (s->fd, buf_st, trans);
301 if (trans < 0)
302 {
303 if (errno == EINTR)
304 continue;
305 else
306 {
307 status = errno;
308 break;
309 }
310 }
311 buf_st += trans;
312 bytes_left -= trans;
4ee9c684 313 }
314
b2a112ca 315 *nbytes -= bytes_left;
316 return status;
4ee9c684 317}
4ee9c684 318
319
320/* get_oserror()-- Get the most recent operating system error. For
321 * unix, this is errno. */
322
323const char *
324get_oserror (void)
325{
4ee9c684 326 return strerror (errno);
327}
328
329
330/* sys_exit()-- Terminate the program with an exit code */
331
332void
333sys_exit (int code)
334{
4ee9c684 335 exit (code);
336}
337
338
4ee9c684 339/*********************************************************************
340 File descriptor stream functions
341*********************************************************************/
342
b2a112ca 343
4ee9c684 344/* fd_flush()-- Write bytes that need to be written */
345
346static try
347fd_flush (unix_stream * s)
348{
b2a112ca 349 size_t writelen;
350
4ee9c684 351 if (s->ndirty == 0)
352 return SUCCESS;;
353
354 if (s->physical_offset != s->dirty_offset &&
355 lseek (s->fd, s->dirty_offset, SEEK_SET) < 0)
356 return FAILURE;
357
b2a112ca 358 writelen = s->ndirty;
359 if (do_write (s, s->buffer + (s->dirty_offset - s->buffer_offset),
360 &writelen) != 0)
4ee9c684 361 return FAILURE;
362
b2a112ca 363 s->physical_offset = s->dirty_offset + writelen;
5a78b88f 364
365 /* don't increment file_length if the file is non-seekable */
366 if (s->file_length != -1 && s->physical_offset > s->file_length)
b2a112ca 367 s->file_length = s->physical_offset;
368
369 s->ndirty -= writelen;
370 if (s->ndirty != 0)
371 return FAILURE;
4ee9c684 372
373 return SUCCESS;
374}
375
376
377/* fd_alloc()-- Arrange a buffer such that the salloc() request can be
378 * satisfied. This subroutine gets the buffer ready for whatever is
379 * to come next. */
380
381static void
a0007dfa 382fd_alloc (unix_stream * s, gfc_offset where,
383 int *len __attribute__ ((unused)))
4ee9c684 384{
385 char *new_buffer;
386 int n, read_len;
387
388 if (*len <= BUFFER_SIZE)
389 {
390 new_buffer = s->small_buffer;
391 read_len = BUFFER_SIZE;
392 }
393 else
394 {
395 new_buffer = get_mem (*len);
396 read_len = *len;
397 }
398
399 /* Salvage bytes currently within the buffer. This is important for
400 * devices that cannot seek. */
401
402 if (s->buffer != NULL && s->buffer_offset <= where &&
403 where <= s->buffer_offset + s->active)
404 {
405
406 n = s->active - (where - s->buffer_offset);
407 memmove (new_buffer, s->buffer + (where - s->buffer_offset), n);
408
409 s->active = n;
410 }
411 else
412 { /* new buffer starts off empty */
413 s->active = 0;
414 }
415
416 s->buffer_offset = where;
417
418 /* free the old buffer if necessary */
419
420 if (s->buffer != NULL && s->buffer != s->small_buffer)
421 free_mem (s->buffer);
422
423 s->buffer = new_buffer;
424 s->len = read_len;
4ee9c684 425}
426
427
428/* fd_alloc_r_at()-- Allocate a stream buffer for reading. Either
429 * we've already buffered the data or we need to load it. Returns
430 * NULL on I/O error. */
431
432static char *
b093181d 433fd_alloc_r_at (unix_stream * s, int *len, gfc_offset where)
4ee9c684 434{
b093181d 435 gfc_offset m;
4ee9c684 436
437 if (where == -1)
438 where = s->logical_offset;
439
440 if (s->buffer != NULL && s->buffer_offset <= where &&
441 where + *len <= s->buffer_offset + s->active)
442 {
443
444 /* Return a position within the current buffer */
445
446 s->logical_offset = where + *len;
447 return s->buffer + where - s->buffer_offset;
448 }
449
450 fd_alloc (s, where, len);
451
452 m = where + s->active;
453
454 if (s->physical_offset != m && lseek (s->fd, m, SEEK_SET) < 0)
455 return NULL;
456
fef3501c 457 /* do_read() hangs on read from terminals for *BSD-systems. Only
458 use read() in that case. */
459
460 if (s->special_file)
461 {
462 ssize_t n;
463
464 n = read (s->fd, s->buffer + s->active, s->len - s->active);
465 if (n < 0)
466 return NULL;
467
468 s->physical_offset = where + n;
469 s->active += n;
470 }
471 else
472 {
473 size_t n;
4ee9c684 474
fef3501c 475 n = s->len - s->active;
476 if (do_read (s, s->buffer + s->active, &n) != 0)
477 return NULL;
478
479 s->physical_offset = where + n;
480 s->active += n;
481 }
4ee9c684 482
4ee9c684 483 if (s->active < *len)
484 *len = s->active; /* Bytes actually available */
485
486 s->logical_offset = where + *len;
487
488 return s->buffer;
489}
490
491
492/* fd_alloc_w_at()-- Allocate a stream buffer for writing. Either
493 * we've already buffered the data or we need to load it. */
494
495static char *
b093181d 496fd_alloc_w_at (unix_stream * s, int *len, gfc_offset where)
4ee9c684 497{
b093181d 498 gfc_offset n;
4ee9c684 499
500 if (where == -1)
501 where = s->logical_offset;
502
503 if (s->buffer == NULL || s->buffer_offset > where ||
504 where + *len > s->buffer_offset + s->len)
505 {
506
507 if (fd_flush (s) == FAILURE)
508 return NULL;
509 fd_alloc (s, where, len);
510 }
511
512 /* Return a position within the current buffer */
5a78b88f 513 if (s->ndirty == 0
514 || where > s->dirty_offset + s->ndirty
515 || s->dirty_offset > where + *len)
516 { /* Discontiguous blocks, start with a clean buffer. */
517 /* Flush the buffer. */
518 if (s->ndirty != 0)
519 fd_flush (s);
520 s->dirty_offset = where;
521 s->ndirty = *len;
4ee9c684 522 }
523 else
5a78b88f 524 {
525 gfc_offset start; /* Merge with the existing data. */
526 if (where < s->dirty_offset)
527 start = where;
528 else
529 start = s->dirty_offset;
530 if (where + *len > s->dirty_offset + s->ndirty)
531 s->ndirty = where + *len - start;
532 else
533 s->ndirty = s->dirty_offset + s->ndirty - start;
534 s->dirty_offset = start;
4ee9c684 535 }
536
537 s->logical_offset = where + *len;
538
f82543e7 539 if (where + *len > s->file_length)
540 s->file_length = where + *len;
541
4ee9c684 542 n = s->logical_offset - s->buffer_offset;
543 if (n > s->active)
544 s->active = n;
545
546 return s->buffer + where - s->buffer_offset;
547}
548
549
550static try
551fd_sfree (unix_stream * s)
552{
4ee9c684 553 if (s->ndirty != 0 &&
554 (s->buffer != s->small_buffer || options.all_unbuffered ||
555 s->unbuffered))
556 return fd_flush (s);
557
558 return SUCCESS;
559}
560
561
b2a112ca 562static try
b093181d 563fd_seek (unix_stream * s, gfc_offset offset)
4ee9c684 564{
b3ac1032 565 if (s->physical_offset == offset) /* Are we lucky and avoid syscall? */
566 {
567 s->logical_offset = offset;
568 return SUCCESS;
569 }
4ee9c684 570
b3ac1032 571 s->physical_offset = s->logical_offset = offset;
25545daf 572 s->active = 0;
b3ac1032 573
574 return (lseek (s->fd, offset, SEEK_SET) < 0) ? FAILURE : SUCCESS;
4ee9c684 575}
576
577
578/* truncate_file()-- Given a unit, truncate the file at the current
579 * position. Sets the physical location to the new end of the file.
580 * Returns nonzero on error. */
581
582static try
583fd_truncate (unix_stream * s)
584{
5a78b88f 585 if (lseek (s->fd, s->logical_offset, SEEK_SET) == -1)
4ee9c684 586 return FAILURE;
587
5a78b88f 588 /* non-seekable files, like terminals and fifo's fail the lseek.
227e9423 589 Using ftruncate on a seekable special file (like /dev/null)
1c201879 590 is undefined, so we treat it as if the ftruncate succeeded.
227e9423 591 */
a54b1ce7 592#ifdef HAVE_FTRUNCATE
227e9423 593 if (s->special_file || ftruncate (s->fd, s->logical_offset))
a54b1ce7 594#else
595#ifdef HAVE_CHSIZE
227e9423 596 if (s->special_file || chsize (s->fd, s->logical_offset))
a54b1ce7 597#endif
598#endif
72909c79 599 {
600 s->physical_offset = s->file_length = 0;
1c201879 601 return SUCCESS;
72909c79 602 }
5a78b88f 603
604 s->physical_offset = s->file_length = s->logical_offset;
8c39329b 605 s->active = 0;
4ee9c684 606 return SUCCESS;
607}
608
609
56f281a2 610/* Similar to memset(), but operating on a stream instead of a string.
611 Takes care of not using too much memory. */
612
613static try
614fd_sset (unix_stream * s, int c, size_t n)
615{
616 size_t bytes_left;
617 int trans;
618 void *p;
619
620 bytes_left = n;
621
622 while (bytes_left > 0)
623 {
624 /* memset() in chunks of BUFFER_SIZE. */
625 trans = (bytes_left < BUFFER_SIZE) ? bytes_left : BUFFER_SIZE;
626
627 p = fd_alloc_w_at (s, &trans, -1);
628 if (p)
629 memset (p, c, trans);
630 else
631 return FAILURE;
632
633 bytes_left -= trans;
634 }
635
636 return SUCCESS;
637}
b2a112ca 638
639
640/* Stream read function. Avoids using a buffer for big reads. The
641 interface is like POSIX read(), but the nbytes argument is a
642 pointer; on return it contains the number of bytes written. The
643 function return value is the status indicator (0 for success). */
644
645static int
646fd_read (unix_stream * s, void * buf, size_t * nbytes)
647{
648 void *p;
649 int tmp, status;
650
651 if (*nbytes < BUFFER_SIZE && !s->unbuffered)
652 {
653 tmp = *nbytes;
654 p = fd_alloc_r_at (s, &tmp, -1);
655 if (p)
656 {
657 *nbytes = tmp;
658 memcpy (buf, p, *nbytes);
659 return 0;
660 }
661 else
662 {
663 *nbytes = 0;
664 return errno;
665 }
666 }
667
668 /* If the request is bigger than BUFFER_SIZE we flush the buffers
669 and read directly. */
670 if (fd_flush (s) == FAILURE)
671 {
672 *nbytes = 0;
673 return errno;
674 }
675
b3ac1032 676 if (is_seekable ((stream *) s) && fd_seek (s, s->logical_offset) == FAILURE)
b2a112ca 677 {
678 *nbytes = 0;
679 return errno;
680 }
681
682 status = do_read (s, buf, nbytes);
683 reset_stream (s, *nbytes);
684 return status;
685}
686
687
688/* Stream write function. Avoids using a buffer for big writes. The
689 interface is like POSIX write(), but the nbytes argument is a
690 pointer; on return it contains the number of bytes written. The
691 function return value is the status indicator (0 for success). */
692
693static int
694fd_write (unix_stream * s, const void * buf, size_t * nbytes)
695{
696 void *p;
697 int tmp, status;
698
699 if (*nbytes < BUFFER_SIZE && !s->unbuffered)
700 {
701 tmp = *nbytes;
702 p = fd_alloc_w_at (s, &tmp, -1);
703 if (p)
704 {
705 *nbytes = tmp;
706 memcpy (p, buf, *nbytes);
707 return 0;
708 }
709 else
710 {
711 *nbytes = 0;
712 return errno;
713 }
714 }
715
716 /* If the request is bigger than BUFFER_SIZE we flush the buffers
717 and write directly. */
718 if (fd_flush (s) == FAILURE)
719 {
720 *nbytes = 0;
721 return errno;
722 }
723
b3ac1032 724 if (is_seekable ((stream *) s) && fd_seek (s, s->logical_offset) == FAILURE)
b2a112ca 725 {
726 *nbytes = 0;
727 return errno;
728 }
729
730 status = do_write (s, buf, nbytes);
731 reset_stream (s, *nbytes);
732 return status;
733}
734
735
4ee9c684 736static try
737fd_close (unix_stream * s)
738{
4ee9c684 739 if (fd_flush (s) == FAILURE)
740 return FAILURE;
741
742 if (s->buffer != NULL && s->buffer != s->small_buffer)
743 free_mem (s->buffer);
744
f8f6940b 745 if (s->fd != STDOUT_FILENO && s->fd != STDERR_FILENO)
746 {
747 if (close (s->fd) < 0)
748 return FAILURE;
749 }
4ee9c684 750
751 free_mem (s);
752
753 return SUCCESS;
754}
755
756
757static void
758fd_open (unix_stream * s)
759{
4ee9c684 760 if (isatty (s->fd))
761 s->unbuffered = 1;
762
763 s->st.alloc_r_at = (void *) fd_alloc_r_at;
764 s->st.alloc_w_at = (void *) fd_alloc_w_at;
765 s->st.sfree = (void *) fd_sfree;
766 s->st.close = (void *) fd_close;
767 s->st.seek = (void *) fd_seek;
768 s->st.truncate = (void *) fd_truncate;
b2a112ca 769 s->st.read = (void *) fd_read;
770 s->st.write = (void *) fd_write;
56f281a2 771 s->st.set = (void *) fd_sset;
4ee9c684 772
773 s->buffer = NULL;
774}
775
776
4ee9c684 777
b2a112ca 778
4ee9c684 779/*********************************************************************
780 memory stream functions - These are used for internal files
781
782 The idea here is that a single stream structure is created and all
783 requests must be satisfied from it. The location and size of the
784 buffer is the character variable supplied to the READ or WRITE
785 statement.
786
787*********************************************************************/
788
789
790static char *
b093181d 791mem_alloc_r_at (unix_stream * s, int *len, gfc_offset where)
4ee9c684 792{
b093181d 793 gfc_offset n;
4ee9c684 794
795 if (where == -1)
796 where = s->logical_offset;
797
798 if (where < s->buffer_offset || where > s->buffer_offset + s->active)
799 return NULL;
800
4ee9c684 801 s->logical_offset = where + *len;
802
11de4bf9 803 n = s->buffer_offset + s->active - where;
4ee9c684 804 if (*len > n)
805 *len = n;
806
807 return s->buffer + (where - s->buffer_offset);
808}
809
810
811static char *
b093181d 812mem_alloc_w_at (unix_stream * s, int *len, gfc_offset where)
4ee9c684 813{
b093181d 814 gfc_offset m;
4ee9c684 815
2639e4cd 816 assert (*len >= 0); /* Negative values not allowed. */
817
4ee9c684 818 if (where == -1)
819 where = s->logical_offset;
820
821 m = where + *len;
822
2639e4cd 823 if (where < s->buffer_offset)
4ee9c684 824 return NULL;
825
2639e4cd 826 if (m > s->file_length)
72231bd6 827 return NULL;
2639e4cd 828
4ee9c684 829 s->logical_offset = m;
830
831 return s->buffer + (where - s->buffer_offset);
832}
833
834
b2a112ca 835/* Stream read function for internal units. This is not actually used
836 at the moment, as all internal IO is formatted and the formatted IO
837 routines use mem_alloc_r_at. */
838
839static int
840mem_read (unix_stream * s, void * buf, size_t * nbytes)
841{
842 void *p;
843 int tmp;
844
845 tmp = *nbytes;
846 p = mem_alloc_r_at (s, &tmp, -1);
847 if (p)
848 {
849 *nbytes = tmp;
850 memcpy (buf, p, *nbytes);
851 return 0;
852 }
853 else
854 {
855 *nbytes = 0;
856 return errno;
857 }
858}
859
860
861/* Stream write function for internal units. This is not actually used
862 at the moment, as all internal IO is formatted and the formatted IO
863 routines use mem_alloc_w_at. */
864
865static int
866mem_write (unix_stream * s, const void * buf, size_t * nbytes)
867{
868 void *p;
869 int tmp;
870
871 errno = 0;
872
873 tmp = *nbytes;
874 p = mem_alloc_w_at (s, &tmp, -1);
875 if (p)
876 {
877 *nbytes = tmp;
878 memcpy (p, buf, *nbytes);
879 return 0;
880 }
881 else
882 {
883 *nbytes = 0;
884 return errno;
885 }
886}
887
888
4ee9c684 889static int
b093181d 890mem_seek (unix_stream * s, gfc_offset offset)
4ee9c684 891{
4ee9c684 892 if (offset > s->file_length)
893 {
894 errno = ESPIPE;
895 return FAILURE;
896 }
897
898 s->logical_offset = offset;
899 return SUCCESS;
900}
901
902
56f281a2 903static try
904mem_set (unix_stream * s, int c, size_t n)
905{
906 void *p;
907 int len;
908
909 len = n;
910
911 p = mem_alloc_w_at (s, &len, -1);
912 if (p)
913 {
914 memset (p, c, len);
915 return SUCCESS;
916 }
917 else
918 return FAILURE;
919}
920
921
4ee9c684 922static int
a0007dfa 923mem_truncate (unix_stream * s __attribute__ ((unused)))
4ee9c684 924{
4ee9c684 925 return SUCCESS;
926}
927
928
929static try
930mem_close (unix_stream * s)
931{
46ca759c 932 if (s != NULL)
933 free_mem (s);
4ee9c684 934
935 return SUCCESS;
936}
937
938
939static try
a0007dfa 940mem_sfree (unix_stream * s __attribute__ ((unused)))
4ee9c684 941{
4ee9c684 942 return SUCCESS;
943}
944
945
946
947/*********************************************************************
948 Public functions -- A reimplementation of this module needs to
949 define functional equivalents of the following.
950*********************************************************************/
951
952/* empty_internal_buffer()-- Zero the buffer of Internal file */
953
954void
955empty_internal_buffer(stream *strm)
956{
7145fd06 957 unix_stream * s = (unix_stream *) strm;
958 memset(s->buffer, ' ', s->file_length);
4ee9c684 959}
960
961/* open_internal()-- Returns a stream structure from an internal file */
962
963stream *
964open_internal (char *base, int length)
965{
966 unix_stream *s;
967
968 s = get_mem (sizeof (unix_stream));
8f8ad899 969 memset (s, '\0', sizeof (unix_stream));
4ee9c684 970
971 s->buffer = base;
972 s->buffer_offset = 0;
973
974 s->logical_offset = 0;
975 s->active = s->file_length = length;
976
977 s->st.alloc_r_at = (void *) mem_alloc_r_at;
978 s->st.alloc_w_at = (void *) mem_alloc_w_at;
979 s->st.sfree = (void *) mem_sfree;
980 s->st.close = (void *) mem_close;
981 s->st.seek = (void *) mem_seek;
982 s->st.truncate = (void *) mem_truncate;
b2a112ca 983 s->st.read = (void *) mem_read;
984 s->st.write = (void *) mem_write;
56f281a2 985 s->st.set = (void *) mem_set;
4ee9c684 986
987 return (stream *) s;
988}
989
990
991/* fd_to_stream()-- Given an open file descriptor, build a stream
992 * around it. */
993
994static stream *
f0b5d33f 995fd_to_stream (int fd, int prot)
4ee9c684 996{
997 struct stat statbuf;
998 unix_stream *s;
999
1000 s = get_mem (sizeof (unix_stream));
8f8ad899 1001 memset (s, '\0', sizeof (unix_stream));
4ee9c684 1002
1003 s->fd = fd;
1004 s->buffer_offset = 0;
1005 s->physical_offset = 0;
1006 s->logical_offset = 0;
1007 s->prot = prot;
1008
1009 /* Get the current length of the file. */
1010
1011 fstat (fd, &statbuf);
1012 s->file_length = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1;
227e9423 1013 s->special_file = !S_ISREG (statbuf.st_mode);
4ee9c684 1014
4ee9c684 1015 fd_open (s);
4ee9c684 1016
1017 return (stream *) s;
1018}
1019
1020
771c1b50 1021/* Given the Fortran unit number, convert it to a C file descriptor. */
1022
1023int
60c514ba 1024unit_to_fd (int unit)
771c1b50 1025{
771c1b50 1026 gfc_unit *us;
60c514ba 1027 int fd;
771c1b50 1028
60c514ba 1029 us = find_unit (unit);
771c1b50 1030 if (us == NULL)
1031 return -1;
1032
60c514ba 1033 fd = ((unix_stream *) us->s)->fd;
1034 unlock_unit (us);
1035 return fd;
771c1b50 1036}
1037
1038
4ee9c684 1039/* unpack_filename()-- Given a fortran string and a pointer to a
1040 * buffer that is PATH_MAX characters, convert the fortran string to a
1041 * C string in the buffer. Returns nonzero if this is not possible. */
1042
1dc95e51 1043int
4ee9c684 1044unpack_filename (char *cstring, const char *fstring, int len)
1045{
4ee9c684 1046 len = fstrlen (fstring, len);
1047 if (len >= PATH_MAX)
1048 return 1;
1049
1050 memmove (cstring, fstring, len);
1051 cstring[len] = '\0';
1052
1053 return 0;
1054}
1055
1056
1057/* tempfile()-- Generate a temporary filename for a scratch file and
1058 * open it. mkstemp() opens the file for reading and writing, but the
1059 * library mode prevents anything that is not allowed. The descriptor
7dfba97b 1060 * is returned, which is -1 on error. The template is pointed to by
60c514ba 1061 * opp->file, which is copied into the unit structure
4ee9c684 1062 * and freed later. */
1063
1064static int
60c514ba 1065tempfile (st_parameter_open *opp)
4ee9c684 1066{
1067 const char *tempdir;
1068 char *template;
1069 int fd;
1070
1071 tempdir = getenv ("GFORTRAN_TMPDIR");
1072 if (tempdir == NULL)
1073 tempdir = getenv ("TMP");
ac09d5cc 1074 if (tempdir == NULL)
1075 tempdir = getenv ("TEMP");
4ee9c684 1076 if (tempdir == NULL)
1077 tempdir = DEFAULT_TEMPDIR;
1078
1079 template = get_mem (strlen (tempdir) + 20);
1080
7dfba97b 1081 st_sprintf (template, "%s/gfortrantmpXXXXXX", tempdir);
1082
1083#ifdef HAVE_MKSTEMP
4ee9c684 1084
1085 fd = mkstemp (template);
1086
7dfba97b 1087#else /* HAVE_MKSTEMP */
1088
1089 if (mktemp (template))
1090 do
cf6a3896 1091#if defined(HAVE_CRLF) && defined(O_BINARY)
cf55c3cf 1092 fd = open (template, O_RDWR | O_CREAT | O_EXCL | O_BINARY,
1093 S_IREAD | S_IWRITE);
1094#else
ac09d5cc 1095 fd = open (template, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
cf55c3cf 1096#endif
7dfba97b 1097 while (!(fd == -1 && errno == EEXIST) && mktemp (template));
1098 else
1099 fd = -1;
1100
1101#endif /* HAVE_MKSTEMP */
1102
4ee9c684 1103 if (fd < 0)
1104 free_mem (template);
1105 else
1106 {
60c514ba 1107 opp->file = template;
1108 opp->file_len = strlen (template); /* Don't include trailing nul */
4ee9c684 1109 }
1110
1111 return fd;
1112}
1113
1114
6d12c489 1115/* regular_file()-- Open a regular file.
2d6ba0f9 1116 * Change flags->action if it is ACTION_UNSPECIFIED on entry,
1117 * unless an error occurs.
6d12c489 1118 * Returns the descriptor, which is less than zero on error. */
4ee9c684 1119
1120static int
60c514ba 1121regular_file (st_parameter_open *opp, unit_flags *flags)
4ee9c684 1122{
1123 char path[PATH_MAX + 1];
4ee9c684 1124 int mode;
6d12c489 1125 int rwflag;
2d6ba0f9 1126 int crflag;
6d12c489 1127 int fd;
4ee9c684 1128
60c514ba 1129 if (unpack_filename (path, opp->file, opp->file_len))
4ee9c684 1130 {
1131 errno = ENOENT; /* Fake an OS error */
1132 return -1;
1133 }
1134
6d12c489 1135 rwflag = 0;
4ee9c684 1136
6d12c489 1137 switch (flags->action)
4ee9c684 1138 {
1139 case ACTION_READ:
6d12c489 1140 rwflag = O_RDONLY;
4ee9c684 1141 break;
1142
1143 case ACTION_WRITE:
6d12c489 1144 rwflag = O_WRONLY;
4ee9c684 1145 break;
1146
1147 case ACTION_READWRITE:
6d12c489 1148 case ACTION_UNSPECIFIED:
1149 rwflag = O_RDWR;
4ee9c684 1150 break;
1151
1152 default:
60c514ba 1153 internal_error (&opp->common, "regular_file(): Bad action");
4ee9c684 1154 }
1155
6d12c489 1156 switch (flags->status)
4ee9c684 1157 {
1158 case STATUS_NEW:
2d6ba0f9 1159 crflag = O_CREAT | O_EXCL;
4ee9c684 1160 break;
1161
2d6ba0f9 1162 case STATUS_OLD: /* open will fail if the file does not exist*/
1163 crflag = 0;
4ee9c684 1164 break;
1165
1166 case STATUS_UNKNOWN:
1167 case STATUS_SCRATCH:
2d6ba0f9 1168 crflag = O_CREAT;
4ee9c684 1169 break;
1170
1171 case STATUS_REPLACE:
2d6ba0f9 1172 crflag = O_CREAT | O_TRUNC;
4ee9c684 1173 break;
1174
1175 default:
60c514ba 1176 internal_error (&opp->common, "regular_file(): Bad status");
4ee9c684 1177 }
1178
6d12c489 1179 /* rwflag |= O_LARGEFILE; */
4ee9c684 1180
cf6a3896 1181#if defined(HAVE_CRLF) && defined(O_BINARY)
cf55c3cf 1182 crflag |= O_BINARY;
1183#endif
1184
6d12c489 1185 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
2d6ba0f9 1186 fd = open (path, rwflag | crflag, mode);
1187 if (flags->action != ACTION_UNSPECIFIED)
1188 return fd;
1189
1190 if (fd >= 0)
6d12c489 1191 {
2d6ba0f9 1192 flags->action = ACTION_READWRITE;
1193 return fd;
6d12c489 1194 }
2d6ba0f9 1195 if (errno != EACCES)
1196 return fd;
1197
1198 /* retry for read-only access */
1199 rwflag = O_RDONLY;
1200 fd = open (path, rwflag | crflag, mode);
1201 if (fd >=0)
1202 {
1203 flags->action = ACTION_READ;
1204 return fd; /* success */
1205 }
1206
1207 if (errno != EACCES)
1208 return fd; /* failure */
1209
1210 /* retry for write-only access */
1211 rwflag = O_WRONLY;
1212 fd = open (path, rwflag | crflag, mode);
1213 if (fd >=0)
1214 {
1215 flags->action = ACTION_WRITE;
1216 return fd; /* success */
1217 }
1218 return fd; /* failure */
4ee9c684 1219}
1220
1221
1222/* open_external()-- Open an external file, unix specific version.
6d12c489 1223 * Change flags->action if it is ACTION_UNSPECIFIED on entry.
4ee9c684 1224 * Returns NULL on operating system error. */
1225
1226stream *
60c514ba 1227open_external (st_parameter_open *opp, unit_flags *flags)
4ee9c684 1228{
1229 int fd, prot;
1230
6d12c489 1231 if (flags->status == STATUS_SCRATCH)
1232 {
60c514ba 1233 fd = tempfile (opp);
6d12c489 1234 if (flags->action == ACTION_UNSPECIFIED)
1235 flags->action = ACTION_READWRITE;
1dc95e51 1236
1237#if HAVE_UNLINK_OPEN_FILE
6d12c489 1238 /* We can unlink scratch files now and it will go away when closed. */
60c514ba 1239 if (fd >= 0)
1240 unlink (opp->file);
1dc95e51 1241#endif
6d12c489 1242 }
1243 else
1244 {
2d6ba0f9 1245 /* regular_file resets flags->action if it is ACTION_UNSPECIFIED and
1246 * if it succeeds */
60c514ba 1247 fd = regular_file (opp, flags);
6d12c489 1248 }
4ee9c684 1249
1250 if (fd < 0)
1251 return NULL;
1252 fd = fix_fd (fd);
1253
6d12c489 1254 switch (flags->action)
4ee9c684 1255 {
1256 case ACTION_READ:
1257 prot = PROT_READ;
1258 break;
1259
1260 case ACTION_WRITE:
1261 prot = PROT_WRITE;
1262 break;
1263
1264 case ACTION_READWRITE:
1265 prot = PROT_READ | PROT_WRITE;
1266 break;
1267
1268 default:
60c514ba 1269 internal_error (&opp->common, "open_external(): Bad action");
4ee9c684 1270 }
1271
f0b5d33f 1272 return fd_to_stream (fd, prot);
4ee9c684 1273}
1274
1275
1276/* input_stream()-- Return a stream pointer to the default input stream.
1277 * Called on initialization. */
1278
1279stream *
1280input_stream (void)
1281{
f0b5d33f 1282 return fd_to_stream (STDIN_FILENO, PROT_READ);
4ee9c684 1283}
1284
1285
ff81ee3b 1286/* output_stream()-- Return a stream pointer to the default output stream.
4ee9c684 1287 * Called on initialization. */
1288
1289stream *
1290output_stream (void)
1291{
f0b5d33f 1292 return fd_to_stream (STDOUT_FILENO, PROT_WRITE);
4ee9c684 1293}
1294
1295
ff81ee3b 1296/* error_stream()-- Return a stream pointer to the default error stream.
1297 * Called on initialization. */
1298
1299stream *
1300error_stream (void)
1301{
f0b5d33f 1302 return fd_to_stream (STDERR_FILENO, PROT_WRITE);
ff81ee3b 1303}
1304
4ee9c684 1305/* init_error_stream()-- Return a pointer to the error stream. This
1306 * subroutine is called when the stream is needed, rather than at
1307 * initialization. We want to work even if memory has been seriously
1308 * corrupted. */
1309
1310stream *
60c514ba 1311init_error_stream (unix_stream *error)
4ee9c684 1312{
60c514ba 1313 memset (error, '\0', sizeof (*error));
4ee9c684 1314
60c514ba 1315 error->fd = options.use_stderr ? STDERR_FILENO : STDOUT_FILENO;
4ee9c684 1316
60c514ba 1317 error->st.alloc_w_at = (void *) fd_alloc_w_at;
1318 error->st.sfree = (void *) fd_sfree;
4ee9c684 1319
60c514ba 1320 error->unbuffered = 1;
1321 error->buffer = error->small_buffer;
4ee9c684 1322
60c514ba 1323 return (stream *) error;
4ee9c684 1324}
1325
1326
1327/* compare_file_filename()-- Given an open stream and a fortran string
1328 * that is a filename, figure out if the file is the same as the
1329 * filename. */
1330
1331int
daad4fd5 1332compare_file_filename (gfc_unit *u, const char *name, int len)
4ee9c684 1333{
1334 char path[PATH_MAX + 1];
daad4fd5 1335 struct stat st1;
1336#ifdef HAVE_WORKING_STAT
1337 struct stat st2;
1338#endif
4ee9c684 1339
1340 if (unpack_filename (path, name, len))
1341 return 0; /* Can't be the same */
1342
1343 /* If the filename doesn't exist, then there is no match with the
1344 * existing file. */
1345
1346 if (stat (path, &st1) < 0)
1347 return 0;
1348
daad4fd5 1349#ifdef HAVE_WORKING_STAT
1350 fstat (((unix_stream *) (u->s))->fd, &st2);
4ee9c684 1351 return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino);
daad4fd5 1352#else
1353 if (len != u->file_len)
1354 return 0;
1355 return (memcmp(path, u->file, len) == 0);
1356#endif
4ee9c684 1357}
1358
1359
60c514ba 1360#ifdef HAVE_WORKING_STAT
1361# define FIND_FILE0_DECL struct stat *st
1362# define FIND_FILE0_ARGS st
1363#else
1364# define FIND_FILE0_DECL const char *file, gfc_charlen_type file_len
1365# define FIND_FILE0_ARGS file, file_len
1366#endif
1367
4ee9c684 1368/* find_file0()-- Recursive work function for find_file() */
1369
f02dd226 1370static gfc_unit *
60c514ba 1371find_file0 (gfc_unit *u, FIND_FILE0_DECL)
4ee9c684 1372{
f02dd226 1373 gfc_unit *v;
4ee9c684 1374
1375 if (u == NULL)
1376 return NULL;
1377
daad4fd5 1378#ifdef HAVE_WORKING_STAT
60c514ba 1379 if (u->s != NULL
1380 && fstat (((unix_stream *) u->s)->fd, &st[1]) >= 0 &&
1381 st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino)
4ee9c684 1382 return u;
daad4fd5 1383#else
60c514ba 1384 if (compare_string (u->file_len, u->file, file_len, file) == 0)
daad4fd5 1385 return u;
1386#endif
4ee9c684 1387
60c514ba 1388 v = find_file0 (u->left, FIND_FILE0_ARGS);
4ee9c684 1389 if (v != NULL)
1390 return v;
1391
60c514ba 1392 v = find_file0 (u->right, FIND_FILE0_ARGS);
4ee9c684 1393 if (v != NULL)
1394 return v;
1395
1396 return NULL;
1397}
1398
1399
1400/* find_file()-- Take the current filename and see if there is a unit
1401 * that has the file already open. Returns a pointer to the unit if so. */
1402
f02dd226 1403gfc_unit *
60c514ba 1404find_file (const char *file, gfc_charlen_type file_len)
4ee9c684 1405{
1406 char path[PATH_MAX + 1];
60c514ba 1407 struct stat st[2];
1408 gfc_unit *u;
4ee9c684 1409
60c514ba 1410 if (unpack_filename (path, file, file_len))
4ee9c684 1411 return NULL;
1412
60c514ba 1413 if (stat (path, &st[0]) < 0)
4ee9c684 1414 return NULL;
1415
60c514ba 1416 __gthread_mutex_lock (&unit_lock);
1417retry:
1418 u = find_file0 (unit_root, FIND_FILE0_ARGS);
1419 if (u != NULL)
1420 {
1421 /* Fast path. */
1422 if (! __gthread_mutex_trylock (&u->lock))
1423 {
1424 /* assert (u->closed == 0); */
1425 __gthread_mutex_unlock (&unit_lock);
1426 return u;
1427 }
1428
1429 inc_waiting_locked (u);
1430 }
1431 __gthread_mutex_unlock (&unit_lock);
1432 if (u != NULL)
1433 {
1434 __gthread_mutex_lock (&u->lock);
1435 if (u->closed)
1436 {
1437 __gthread_mutex_lock (&unit_lock);
1438 __gthread_mutex_unlock (&u->lock);
1439 if (predec_waiting_locked (u) == 0)
1440 free_mem (u);
1441 goto retry;
1442 }
1443
1444 dec_waiting_unlocked (u);
1445 }
1446 return u;
1447}
1448
1449static gfc_unit *
1450flush_all_units_1 (gfc_unit *u, int min_unit)
1451{
1452 while (u != NULL)
1453 {
1454 if (u->unit_number > min_unit)
1455 {
1456 gfc_unit *r = flush_all_units_1 (u->left, min_unit);
1457 if (r != NULL)
1458 return r;
1459 }
1460 if (u->unit_number >= min_unit)
1461 {
1462 if (__gthread_mutex_trylock (&u->lock))
1463 return u;
1464 if (u->s)
1465 flush (u->s);
1466 __gthread_mutex_unlock (&u->lock);
1467 }
1468 u = u->right;
1469 }
1470 return NULL;
1471}
1472
1473void
1474flush_all_units (void)
1475{
1476 gfc_unit *u;
1477 int min_unit = 0;
1478
1479 __gthread_mutex_lock (&unit_lock);
1480 do
1481 {
1482 u = flush_all_units_1 (unit_root, min_unit);
1483 if (u != NULL)
1484 inc_waiting_locked (u);
1485 __gthread_mutex_unlock (&unit_lock);
1486 if (u == NULL)
1487 return;
1488
1489 __gthread_mutex_lock (&u->lock);
1490
1491 min_unit = u->unit_number + 1;
1492
1493 if (u->closed == 0)
1494 {
1495 flush (u->s);
1496 __gthread_mutex_lock (&unit_lock);
1497 __gthread_mutex_unlock (&u->lock);
1498 (void) predec_waiting_locked (u);
1499 }
1500 else
1501 {
1502 __gthread_mutex_lock (&unit_lock);
1503 __gthread_mutex_unlock (&u->lock);
1504 if (predec_waiting_locked (u) == 0)
1505 free_mem (u);
1506 }
1507 }
1508 while (1);
4ee9c684 1509}
1510
1511
1512/* stream_at_bof()-- Returns nonzero if the stream is at the beginning
1513 * of the file. */
1514
1515int
1516stream_at_bof (stream * s)
1517{
1518 unix_stream *us;
1519
5df4b62f 1520 if (!is_seekable (s))
1521 return 0;
4ee9c684 1522
5df4b62f 1523 us = (unix_stream *) s;
4ee9c684 1524
1525 return us->logical_offset == 0;
1526}
1527
1528
cf6a3896 1529/* stream_at_eof()-- Returns nonzero if the stream is at the end
4ee9c684 1530 * of the file. */
1531
1532int
1533stream_at_eof (stream * s)
1534{
1535 unix_stream *us;
1536
5df4b62f 1537 if (!is_seekable (s))
1538 return 0;
4ee9c684 1539
5df4b62f 1540 us = (unix_stream *) s;
4ee9c684 1541
1542 return us->logical_offset == us->dirty_offset;
1543}
1544
1545
1546/* delete_file()-- Given a unit structure, delete the file associated
1547 * with the unit. Returns nonzero if something went wrong. */
1548
1549int
f02dd226 1550delete_file (gfc_unit * u)
4ee9c684 1551{
1552 char path[PATH_MAX + 1];
1553
1554 if (unpack_filename (path, u->file, u->file_len))
1555 { /* Shouldn't be possible */
1556 errno = ENOENT;
1557 return 1;
1558 }
1559
1560 return unlink (path);
1561}
1562
1563
1564/* file_exists()-- Returns nonzero if the current filename exists on
1565 * the system */
1566
1567int
60c514ba 1568file_exists (const char *file, gfc_charlen_type file_len)
4ee9c684 1569{
1570 char path[PATH_MAX + 1];
1571 struct stat statbuf;
1572
60c514ba 1573 if (unpack_filename (path, file, file_len))
4ee9c684 1574 return 0;
1575
1576 if (stat (path, &statbuf) < 0)
1577 return 0;
1578
1579 return 1;
1580}
1581
1582
1583
fb35179a 1584static const char yes[] = "YES", no[] = "NO", unknown[] = "UNKNOWN";
4ee9c684 1585
1586/* inquire_sequential()-- Given a fortran string, determine if the
1587 * file is suitable for sequential access. Returns a C-style
1588 * string. */
1589
1590const char *
1591inquire_sequential (const char *string, int len)
1592{
1593 char path[PATH_MAX + 1];
1594 struct stat statbuf;
1595
1596 if (string == NULL ||
1597 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1598 return unknown;
1599
1600 if (S_ISREG (statbuf.st_mode) ||
1601 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
1602 return yes;
1603
1604 if (S_ISDIR (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
1605 return no;
1606
1607 return unknown;
1608}
1609
1610
1611/* inquire_direct()-- Given a fortran string, determine if the file is
1612 * suitable for direct access. Returns a C-style string. */
1613
1614const char *
1615inquire_direct (const char *string, int len)
1616{
1617 char path[PATH_MAX + 1];
1618 struct stat statbuf;
1619
1620 if (string == NULL ||
1621 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1622 return unknown;
1623
1624 if (S_ISREG (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
1625 return yes;
1626
1627 if (S_ISDIR (statbuf.st_mode) ||
1628 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
1629 return no;
1630
1631 return unknown;
1632}
1633
1634
1635/* inquire_formatted()-- Given a fortran string, determine if the file
1636 * is suitable for formatted form. Returns a C-style string. */
1637
1638const char *
1639inquire_formatted (const char *string, int len)
1640{
1641 char path[PATH_MAX + 1];
1642 struct stat statbuf;
1643
1644 if (string == NULL ||
1645 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1646 return unknown;
1647
1648 if (S_ISREG (statbuf.st_mode) ||
1649 S_ISBLK (statbuf.st_mode) ||
1650 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
1651 return yes;
1652
1653 if (S_ISDIR (statbuf.st_mode))
1654 return no;
1655
1656 return unknown;
1657}
1658
1659
1660/* inquire_unformatted()-- Given a fortran string, determine if the file
1661 * is suitable for unformatted form. Returns a C-style string. */
1662
1663const char *
1664inquire_unformatted (const char *string, int len)
1665{
4ee9c684 1666 return inquire_formatted (string, len);
1667}
1668
1669
1670/* inquire_access()-- Given a fortran string, determine if the file is
1671 * suitable for access. */
1672
1673static const char *
1674inquire_access (const char *string, int len, int mode)
1675{
1676 char path[PATH_MAX + 1];
1677
1678 if (string == NULL || unpack_filename (path, string, len) ||
1679 access (path, mode) < 0)
1680 return no;
1681
1682 return yes;
1683}
1684
1685
1686/* inquire_read()-- Given a fortran string, determine if the file is
1687 * suitable for READ access. */
1688
1689const char *
1690inquire_read (const char *string, int len)
1691{
4ee9c684 1692 return inquire_access (string, len, R_OK);
1693}
1694
1695
1696/* inquire_write()-- Given a fortran string, determine if the file is
1697 * suitable for READ access. */
1698
1699const char *
1700inquire_write (const char *string, int len)
1701{
4ee9c684 1702 return inquire_access (string, len, W_OK);
1703}
1704
1705
1706/* inquire_readwrite()-- Given a fortran string, determine if the file is
1707 * suitable for read and write access. */
1708
1709const char *
1710inquire_readwrite (const char *string, int len)
1711{
4ee9c684 1712 return inquire_access (string, len, R_OK | W_OK);
1713}
1714
1715
1716/* file_length()-- Return the file length in bytes, -1 if unknown */
1717
b093181d 1718gfc_offset
4ee9c684 1719file_length (stream * s)
1720{
4ee9c684 1721 return ((unix_stream *) s)->file_length;
1722}
1723
1724
1725/* file_position()-- Return the current position of the file */
1726
b093181d 1727gfc_offset
4ee9c684 1728file_position (stream * s)
1729{
4ee9c684 1730 return ((unix_stream *) s)->logical_offset;
1731}
1732
1733
1734/* is_seekable()-- Return nonzero if the stream is seekable, zero if
1735 * it is not */
1736
1737int
1738is_seekable (stream * s)
1739{
b2a112ca 1740 /* By convention, if file_length == -1, the file is not
1741 seekable. */
5a78b88f 1742 return ((unix_stream *) s)->file_length!=-1;
4ee9c684 1743}
1744
b0342e98 1745try
1746flush (stream *s)
1747{
1748 return fd_flush( (unix_stream *) s);
1749}
1750
60d77e0d 1751int
1752stream_isatty (stream *s)
1753{
1754 return isatty (((unix_stream *) s)->fd);
1755}
1756
1757char *
1758stream_ttyname (stream *s)
1759{
f2c0a16d 1760#ifdef HAVE_TTYNAME
60d77e0d 1761 return ttyname (((unix_stream *) s)->fd);
f2c0a16d 1762#else
1763 return NULL;
1764#endif
60d77e0d 1765}
1766
16de8065 1767gfc_offset
1768stream_offset (stream *s)
1769{
1770 return (((unix_stream *) s)->logical_offset);
1771}
1772
4ee9c684 1773
1774/* How files are stored: This is an operating-system specific issue,
1775 and therefore belongs here. There are three cases to consider.
1776
1777 Direct Access:
1778 Records are written as block of bytes corresponding to the record
1779 length of the file. This goes for both formatted and unformatted
1780 records. Positioning is done explicitly for each data transfer,
1781 so positioning is not much of an issue.
1782
1783 Sequential Formatted:
1784 Records are separated by newline characters. The newline character
1785 is prohibited from appearing in a string. If it does, this will be
1786 messed up on the next read. End of file is also the end of a record.
1787
1788 Sequential Unformatted:
1789 In this case, we are merely copying bytes to and from main storage,
1790 yet we need to keep track of varying record lengths. We adopt
1791 the solution used by f2c. Each record contains a pair of length
1792 markers:
1793
1794 Length of record n in bytes
1795 Data of record n
1796 Length of record n in bytes
1797
1798 Length of record n+1 in bytes
1799 Data of record n+1
1800 Length of record n+1 in bytes
1801
1802 The length is stored at the end of a record to allow backspacing to the
1803 previous record. Between data transfer statements, the file pointer
1804 is left pointing to the first length of the current record.
1805
1806 ENDFILE records are never explicitly stored.
1807
1808*/