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