]> pd.if.org Git - pdclib/blob - internals/_PDCLIB_io.h
27c33e7dd7a50d360ee58710bacfee8213ed524d
[pdclib] / internals / _PDCLIB_io.h
1 /* PDCLib I/O support <_PDCLIB_io.h>\r
2 \r
3    This file is part of the Public Domain C Library (PDCLib).\r
4    Permission is granted to use, modify, and / or redistribute at will.\r
5 */\r
6 \r
7 #ifndef __PDCLIB_IO_H\r
8 #define __PDCLIB_IO_H __PDCLIB_IO_H\r
9 \r
10 #include "_PDCLIB_int.h"\r
11 #include "_PDCLIB_threadconfig.h"\r
12 \r
13 /* Flags for representing mode (see fopen()). Note these must fit the same\r
14    status field as the _IO?BF flags in <stdio.h> and the internal flags below.\r
15 */\r
16 #define _PDCLIB_FREAD     8u\r
17 #define _PDCLIB_FWRITE   16u\r
18 #define _PDCLIB_FAPPEND  32u\r
19 #define _PDCLIB_FRW      64u\r
20 #define _PDCLIB_FBIN    128u\r
21 \r
22 /* Internal flags, made to fit the same status field as the flags above. */\r
23 /* -------------------------------------------------------------------------- */\r
24 /* free() the buffer memory on closing (false for user-supplied buffer) */\r
25 #define _PDCLIB_FREEBUFFER   512u\r
26 /* stream has encountered error / EOF */\r
27 #define _PDCLIB_ERRORFLAG   1024u\r
28 #define _PDCLIB_EOFFLAG     2048u\r
29 /* stream is wide-oriented */\r
30 #define _PDCLIB_WIDESTREAM  4096u\r
31 /* stream is byte-oriented */\r
32 #define _PDCLIB_BYTESTREAM  8192u\r
33 /* file associated with stream should be remove()d on closing (tmpfile()) */\r
34 #define _PDCLIB_DELONCLOSE 16384u\r
35 /* stream handle should not be free()d on close (stdin, stdout, stderr) */\r
36 #define _PDCLIB_STATIC     32768u\r
37 \r
38 union _PDCLIB_fd\r
39 {\r
40 #if defined(_PDCLIB_OSFD_T)\r
41     _PDCLIB_OSFD_T      osfd;\r
42 #endif\r
43     void *              pointer;\r
44     _PDCLIB_uintptr_t   uval;\r
45     _PDCLIB_intptr_t    sval;\r
46 };\r
47 \r
48 /******************************************************************************/\r
49 /* Internal functions                                                         */\r
50 /******************************************************************************/\r
51 \r
52 /* The worker for all printf() type of functions. The pointer spec should point\r
53    to the introducing '%' of a conversion specifier. The status structure is to\r
54    be that of the current printf() function, of which the members n, s, stream\r
55    and arg will be preserved; i will be updated; and all others will be trashed\r
56    by the function.\r
57    Returns the number of characters parsed as a conversion specifier (0 if none\r
58    parsed); returns -1 if the underlying I/O callback returns failure.\r
59 */\r
60 int _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status );\r
61 \r
62 /* The worker for all scanf() type of functions. The pointer spec should point\r
63    to the introducing '%' of a conversion specifier. The status structure is to\r
64    be that of the current scanf() function, of which the member stream will be\r
65    preserved; n, i, and s will be updated; and all others will be trashed by\r
66    the function.\r
67    Returns a pointer to the first character not parsed as conversion specifier,\r
68    or NULL in case of error.\r
69    FIXME: Should distinguish between matching and input error\r
70 */\r
71 const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status );\r
72 \r
73 /* Parsing any fopen() style filemode string into a number of flags. */\r
74 unsigned int _PDCLIB_filemode( const char * mode );\r
75 \r
76 /* Sanity checking and preparing of read buffer, should be called first thing\r
77    by any stdio read-data function.\r
78    Returns 0 on success, EOF on error.\r
79    On error, EOF / error flags and errno are set appropriately.\r
80 */\r
81 int _PDCLIB_prepread( _PDCLIB_file_t * stream );\r
82 \r
83 /* Sanity checking, should be called first thing by any stdio write-data\r
84    function.\r
85    Returns 0 on success, EOF on error.\r
86    On error, error flags and errno are set appropriately.\r
87 */\r
88 int _PDCLIB_prepwrite( _PDCLIB_file_t * stream );\r
89 \r
90 /* Closing all streams on program exit */\r
91 void _PDCLIB_closeall( void );\r
92 \r
93 /* Writes a stream's buffer.\r
94    Returns 0 on success, EOF on write error.\r
95    Sets stream error flags and errno appropriately on error.\r
96 */\r
97 int _PDCLIB_flushbuffer( _PDCLIB_file_t * stream );\r
98 \r
99 /* Fills a stream's buffer.\r
100    Returns 0 on success, EOF on read error / EOF.\r
101    Sets stream EOF / error flags and errno appropriately on error.\r
102 */\r
103 int _PDCLIB_fillbuffer( _PDCLIB_file_t * stream );\r
104 \r
105 /* Repositions within a file. Returns new offset on success,\r
106    -1 / errno on error.\r
107 */\r
108 _PDCLIB_int_fast64_t _PDCLIB_seek( _PDCLIB_file_t * stream,\r
109                                   _PDCLIB_int_fast64_t offset, int whence );\r
110 \r
111 /* File backend I/O operations\r
112  *\r
113  * PDCLib will call through to these methods as needed to implement the stdio\r
114  * functions.\r
115  */\r
116 struct _PDCLIB_fileops\r
117 {\r
118     /*! Read length bytes from the file into buf; returning the number of bytes\r
119      *  actually read in *numBytesRead.\r
120      *\r
121      *  Returns true if bytes were read successfully; on end of file, returns\r
122      *  true with *numBytesRead == 0.\r
123      *\r
124      *  On error, returns false and sets errno appropriately. *numBytesRead is\r
125      *  ignored in this situation.\r
126      */\r
127     _PDCLIB_bool (*read)( _PDCLIB_fd_t self,\r
128                           void * buf,\r
129                           _PDCLIB_size_t length,\r
130                           _PDCLIB_size_t * numBytesRead );\r
131 \r
132     /*! Write length bytes to the file from buf; returning the number of bytes\r
133      *  actually written in *numBytesWritten\r
134      *\r
135      *  Returns true if bytes were written successfully. On error, returns false\r
136      *  and setss errno appropriately (as with read, *numBytesWritten is\r
137      *  ignored)\r
138      */\r
139     _PDCLIB_bool (*write)( _PDCLIB_fd_t self, const void * buf,\r
140                    _PDCLIB_size_t length, _PDCLIB_size_t * numBytesWritten );\r
141 \r
142     /* Seek to the file offset specified by offset, from location whence, which\r
143      * may be one of the standard constants SEEK_SET/SEEK_CUR/SEEK_END\r
144      */\r
145     _PDCLIB_bool (*seek)( _PDCLIB_fd_t self, _PDCLIB_int_fast64_t offset,\r
146                           int whence, _PDCLIB_int_fast64_t *newPos );\r
147 \r
148     void (*close)( _PDCLIB_fd_t self );\r
149 \r
150     /*! Behaves as read does, except for wide characters. Both length and\r
151      *  *numCharsRead represent counts of characters, not bytes.\r
152      *\r
153      *  This function is optional; if missing, PDCLib will buffer the character\r
154      *  data as bytes and perform translation directly into the user's buffers.\r
155      *  It is useful if your backend can directly take wide characters (for\r
156      *  example, the Windows console)\r
157      */\r
158     _PDCLIB_bool (*wread)( _PDCLIB_fd_t self, _PDCLIB_wchar_t * buf,\r
159                      _PDCLIB_size_t length, _PDCLIB_size_t * numCharsRead );\r
160 \r
161     /* Behaves as write does, except for wide characters. As with wread, both\r
162      * length and *numCharsWritten are character counts.\r
163      *\r
164      * This function is also optional; if missing, PDCLib will buffer the\r
165      * character data as bytes and do translation directly from the user's\r
166      * buffers. You only need to implement this if your backend can directly\r
167      * take wide characters (for example, the Windows console)\r
168      */\r
169     _PDCLIB_bool (*wwrite)( _PDCLIB_fd_t self, const _PDCLIB_wchar_t * buf,\r
170                      _PDCLIB_size_t length, _PDCLIB_size_t * numCharsWritten );\r
171 };\r
172 \r
173 /* struct _PDCLIB_file structure */\r
174 struct _PDCLIB_file\r
175 {\r
176     const _PDCLIB_fileops_t * ops;\r
177     _PDCLIB_fd_t              handle;   /* OS file handle */\r
178     _PDCLIB_MTX_T             lock;     /* file lock */\r
179     char *                    buffer;   /* Pointer to buffer memory */\r
180     _PDCLIB_size_t            bufsize;  /* Size of buffer */\r
181     _PDCLIB_size_t            bufidx;   /* Index of current position in buffer */\r
182     _PDCLIB_size_t            bufend;   /* Index of last pre-read character in buffer */\r
183 #ifdef _PDCLIB_NEED_EOL_TRANSLATION\r
184     _PDCLIB_size_t            bufnlexp; /* Current position of buffer newline expansion */\r
185 #endif\r
186     _PDCLIB_size_t            ungetidx; /* Number of ungetc()'ed characters */\r
187     unsigned char *           ungetbuf; /* ungetc() buffer */\r
188     unsigned int              status;   /* Status flags; see above */\r
189     /* multibyte parsing status to be added later */\r
190     _PDCLIB_fpos_t            pos;      /* Offset and multibyte parsing state */\r
191     char *                    filename; /* Name the current stream has been opened with */\r
192     _PDCLIB_file_t *          next;     /* Pointer to next struct (internal) */\r
193 };\r
194 \r
195 static inline _PDCLIB_size_t _PDCLIB_getchars( char * out, _PDCLIB_size_t n,\r
196                                                int stopchar,\r
197                                                _PDCLIB_file_t * stream )\r
198 {\r
199     _PDCLIB_size_t i = 0;\r
200     int c;\r
201     while ( stream->ungetidx > 0 && i != n )\r
202     {\r
203         c = (unsigned char)\r
204                 ( out[ i++ ] = stream->ungetbuf[ --(stream->ungetidx) ] );\r
205         if( c == stopchar )\r
206             return i;\r
207     }\r
208 \r
209     while ( i != n )\r
210     {\r
211         while ( stream->bufidx != stream->bufend && i != n)\r
212         {\r
213             c = (unsigned char) stream->buffer[ stream->bufidx++ ];\r
214 #ifdef _PDCLIB_NEED_EOL_TRANSLATION\r
215             if ( !( stream->status & _PDCLIB_FBIN ) && c == '\r' )\r
216             {\r
217                 if ( stream->bufidx == stream->bufend )\r
218                     break;\r
219 \r
220                 if ( stream->buffer[ stream->bufidx ] == '\n' )\r
221                 {\r
222                     c = '\n';\r
223                     stream->bufidx++;\r
224                 }\r
225             }\r
226 #endif\r
227             out[ i++ ] = c;\r
228 \r
229             if( c == stopchar )\r
230                 return i;\r
231         }\r
232 \r
233         if ( i != n )\r
234         {\r
235             if( _PDCLIB_fillbuffer( stream ) == -1 )\r
236             {\r
237                 break;\r
238             }\r
239         }\r
240     }\r
241 \r
242 #ifdef _PDCLIB_NEED_EOL_TRANSLATION\r
243     if ( i != n && stream->bufidx != stream->bufend )\r
244     {\r
245         // we must have EOF'd immediately after a \r\r
246         out[ i++ ] = stream->buffer[ stream->bufidx++ ];\r
247     }\r
248 #endif\r
249 \r
250     return i;\r
251 }\r
252 \r
253 /* Unlocked functions - internal names\r
254  *\r
255  * We can't use the functions using their "normal" names internally because that\r
256  * would cause namespace leakage. Therefore, we use them by prefixed internal\r
257  * names\r
258  */\r
259 void _PDCLIB_flockfile(struct _PDCLIB_file *file) _PDCLIB_nothrow;\r
260 int _PDCLIB_ftrylockfile(struct _PDCLIB_file *file) _PDCLIB_nothrow;\r
261 void _PDCLIB_funlockfile(struct _PDCLIB_file *file) _PDCLIB_nothrow;\r
262 \r
263 int _PDCLIB_getc_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
264 int _PDCLIB_getchar_unlocked(void) _PDCLIB_nothrow;\r
265 int _PDCLIB_putc_unlocked(int c, struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
266 int _PDCLIB_putchar_unlocked(int c) _PDCLIB_nothrow;\r
267 void _PDCLIB_clearerr_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
268 int _PDCLIB_feof_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
269 int _PDCLIB_ferror_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
270 int _PDCLIB_fflush_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
271 int _PDCLIB_fgetc_unlocked(struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
272 int _PDCLIB_fputc_unlocked(int c, struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
273 _PDCLIB_size_t _PDCLIB_fread_unlocked(void *ptr, _PDCLIB_size_t size, _PDCLIB_size_t n, struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
274 _PDCLIB_size_t _PDCLIB_fwrite_unlocked(const void *ptr, _PDCLIB_size_t size, _PDCLIB_size_t n, struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
275 char *_PDCLIB_fgets_unlocked(char *s, int n, struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
276 int _PDCLIB_fputs_unlocked(const char *s, struct _PDCLIB_file *stream) _PDCLIB_nothrow;\r
277 int _PDCLIB_fgetpos_unlocked( struct _PDCLIB_file * _PDCLIB_restrict stream, _PDCLIB_fpos_t * _PDCLIB_restrict pos ) _PDCLIB_nothrow;\r
278 int _PDCLIB_fsetpos_unlocked( struct _PDCLIB_file * stream, const _PDCLIB_fpos_t * pos ) _PDCLIB_nothrow;\r
279 long int _PDCLIB_ftell_unlocked( struct _PDCLIB_file * stream ) _PDCLIB_nothrow;\r
280 int _PDCLIB_fseek_unlocked( struct _PDCLIB_file * stream, long int offset, int whence ) _PDCLIB_nothrow;\r
281 void _PDCLIB_rewind_unlocked( struct _PDCLIB_file * stream ) _PDCLIB_nothrow;\r
282 \r
283 int _PDCLIB_puts_unlocked( const char * s ) _PDCLIB_nothrow;\r
284 int _PDCLIB_ungetc_unlocked( int c, struct _PDCLIB_file * stream ) _PDCLIB_nothrow;\r
285 \r
286 \r
287 int _PDCLIB_printf_unlocked( const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;\r
288 int _PDCLIB_vprintf_unlocked( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;\r
289 int _PDCLIB_fprintf_unlocked( struct _PDCLIB_file * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;\r
290 int _PDCLIB_vfprintf_unlocked( struct _PDCLIB_file * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;\r
291 int _PDCLIB_scanf_unlocked( const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;\r
292 int _PDCLIB_vscanf_unlocked( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;\r
293 int _PDCLIB_fscanf_unlocked( struct _PDCLIB_file * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... ) _PDCLIB_nothrow;\r
294 int _PDCLIB_vfscanf_unlocked( struct _PDCLIB_file * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg ) _PDCLIB_nothrow;\r
295 \r
296 #endif\r