Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / libcc.ansi / stdio / fopen.c
1 /*
2  * fopen.c - open a stream
3  */
4 /* $Id: fopen.c,v 1.9 1994/06/24 11:49:28 ceriel Exp $ */
5
6 #include        <stdio.h>
7 #include        <stdlib.h>
8 #include        "loc_incl.h"
9
10 #define PMODE           0666
11
12 /* The next 3 defines are true in all UNIX systems known to me.
13  */
14 #define O_RDONLY        0
15 #define O_WRONLY        1
16 #define O_RDWR          2
17
18 /* Since the O_CREAT flag is not available on all systems, we can't get it
19  * from the standard library. Furthermore, even if we know that <fcntl.h>
20  * contains such a flag, it's not sure whether it can be used, since we
21  * might be cross-compiling for another system, which may use an entirely
22  * different value for O_CREAT (or not support such a mode). The safest
23  * thing is to just use the Version 7 semantics for open, and use creat()
24  * whenever necessary.
25  *
26  * Another problem is O_APPEND, for which the same holds. When "a"
27  * open-mode is used, an lseek() to the end is done before every write()
28  * system-call.
29  *
30  * The O_CREAT, O_TRUNC and O_APPEND given here, are only for convenience.
31  * They are not passed to open(), so the values don't have to match a value
32  * from the real world. It is enough when they are unique.
33  */
34 #define O_CREAT         0x010
35 #define O_TRUNC         0x020
36 #define O_APPEND        0x040
37
38 int _open(const char *path, int flags);
39 int _creat(const char *path, int mode);
40 int _close(int d);
41
42 FILE *
43 fopen(const char *name, const char *mode)
44 {
45         register int i;
46         int rwmode = 0, rwflags = 0;
47         FILE *stream;
48         int fd, flags = 0;
49
50         for (i = 0; __iotab[i] != 0 ; i++) 
51                 if ( i >= FOPEN_MAX-1 )
52                         return (FILE *)NULL;
53
54         switch(*mode++) {
55         case 'r':
56                 flags |= _IOREAD | _IOREADING;  
57                 rwmode = O_RDONLY;
58                 break;
59         case 'w':
60                 flags |= _IOWRITE | _IOWRITING;
61                 rwmode = O_WRONLY;
62                 rwflags = O_CREAT | O_TRUNC;
63                 break;
64         case 'a': 
65                 flags |= _IOWRITE | _IOWRITING | _IOAPPEND;
66                 rwmode = O_WRONLY;
67                 rwflags |= O_APPEND | O_CREAT;
68                 break;         
69         default:
70                 return (FILE *)NULL;
71         }
72
73         while (*mode) {
74                 switch(*mode++) {
75                 case 'b':
76                         continue;
77                 case '+':
78                         rwmode = O_RDWR;
79                         flags |= _IOREAD | _IOWRITE;
80                         continue;
81                 /* The sequence may be followed by additional characters */
82                 default:
83                         break;
84                 }
85                 break;
86         }
87
88         /* Perform a creat() when the file should be truncated or when
89          * the file is opened for writing and the open() failed.
90          */
91         if ((rwflags & O_TRUNC)
92             || (((fd = _open(name, rwmode)) < 0)
93                     && (rwflags & O_CREAT))) {
94                 if (((fd = _creat(name, PMODE)) > 0) && flags  | _IOREAD) {
95                         (void) _close(fd);
96                         fd = _open(name, rwmode);
97                 }
98                         
99         }
100
101         if (fd < 0) return (FILE *)NULL;
102
103         if (( stream = (FILE *) malloc(sizeof(FILE))) == NULL ) {
104                 _close(fd);
105                 return (FILE *)NULL;
106         }
107
108         if ((flags & (_IOREAD | _IOWRITE))  == (_IOREAD | _IOWRITE))
109                 flags &= ~(_IOREADING | _IOWRITING);
110
111         stream->_count = 0;
112         stream->_fd = fd;
113         stream->_flags = flags;
114         stream->_buf = NULL;
115         __iotab[i] = stream;
116         return stream;
117 }