OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libgfortran/] [io/] [unix.c] - Blame information for rev 14

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.