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