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