2 * MIO, an I/O abstraction layer replicating C file I/O API.
3 * Copyright (C) 2010 Colomban Wendling <ban@herbesfolles.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 /* minimal reallocation chunk size */
31 #define MIO_CHUNK_SIZE 4096
33 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
38 * @short_description: The MIO object
41 * The #MIO object replicates the C file I/O API with support of both standard
42 * file based operations and in-memory operations. Its goal is to ease the port
43 * of an application that uses C file I/O API to perform in-memory operations.
45 * A #MIO object is created using mio_new_file() or mio_new_memory(), depending
46 * on whether you want file or in-memory operations, and destroyed using
47 * mio_free(). There is also some other convenient API to create file-based
48 * #MIO objects for more complex cases, such as mio_new_file_full() and
51 * Once the #MIO object is created, you can perform standard I/O operations on
52 * it transparently without the need to care about the effective underlying
55 * The I/O API is almost exactly a replication of the standard C file I/O API
56 * with the significant difference that the first parameter is always the #MIO
63 * @filename: Filename to open, passed as-is to @open_func as the first argument
64 * @mode: Mode in which open the file, passed as-is to @open_func as the second
66 * @open_func: A function with the fopen() semantic to use to open the file
67 * @close_func: A function with the fclose() semantic to close the file when
68 * the #MIO object is destroyed, or %NULL not to close the #FILE
71 * Creates a new #MIO object working on a file, from a filename and an opening
72 * function. See also mio_new_file().
74 * This function is generally overkill and mio_new_file() should often be used
75 * instead, but it allows to specify a custom function to open a file, as well
76 * as a close function. The former is useful e.g. if you need to wrap fopen()
77 * for some reason (like filename encoding conversion for example), and the
78 * latter allows you both to match your custom open function and to choose
79 * whether the underlying #FILE object should or not be closed when mio_free()
80 * is called on the returned object.
82 * Free-function: mio_free()
84 * Returns: A new #MIO on success, or %NULL on failure.
86 MIO
*mio_new_file_full (const char *filename
,
88 MIOFOpenFunc open_func
,
89 MIOFCloseFunc close_func
)
93 /* we need to create the MIO object first, because we may not be able to close
94 * the opened file if the user passed NULL as the close function, which means
95 * that everything must succeed if we've opened the file successfully */
96 mio
= malloc (sizeof *mio
);
99 FILE *fp
= open_func (filename
, mode
);
108 mio
->type
= MIO_TYPE_FILE
;
109 mio
->impl
.file
.fp
= fp
;
110 mio
->impl
.file
.close_func
= close_func
;
119 * @filename: Filename to open, same as the fopen()'s first argument
120 * @mode: Mode in which open the file, fopen()'s second argument
122 * Creates a new #MIO object working on a file from a filename; wrapping
124 * This function simply calls mio_new_file_full() with the libc's fopen() and
125 * fclose() functions.
127 * Free-function: mio_free()
129 * Returns: A new #MIO on success, or %NULL on failure.
131 MIO
*mio_new_file (const char *filename
, const char *mode
)
133 return mio_new_file_full (filename
, mode
, fopen
, fclose
);
138 * @fp: An opened #FILE object
139 * @close_func: (allow-none): Function used to close @fp when the #MIO object
140 * gets destroyed, or %NULL not to close the #FILE object
142 * Creates a new #MIO object working on a file, from an already opened #FILE
146 * <title>Typical use of this function</title>
148 * MIO *mio = mio_new_fp (fp, fclose);
152 * Free-function: mio_free()
154 * Returns: A new #MIO on success or %NULL on failure.
156 MIO
*mio_new_fp (FILE *fp
, MIOFCloseFunc close_func
)
163 mio
= malloc (sizeof *mio
);
166 mio
->type
= MIO_TYPE_FILE
;
167 mio
->impl
.file
.fp
= fp
;
168 mio
->impl
.file
.close_func
= close_func
;
176 * @data: Initial data (may be %NULL)
177 * @size: Length of @data in bytes
178 * @realloc_func: A function with the realloc() semantic used to grow the
179 * buffer, or %NULL to disable buffer growing
180 * @free_func: A function with the free() semantic to destroy the data together
181 * with the object, or %NULL not to destroy the data
183 * Creates a new #MIO object working on memory.
185 * To allow the buffer to grow, you must provide a @realloc_func, otherwise
186 * trying to write after the end of the current data will fail.
188 * If you want the buffer to be freed together with the #MIO object, you must
189 * give a @free_func; otherwise the data will still live after #MIO object
193 * <title>Basic creation of a non-growable, freeable #MIO object</title>
195 * MIO *mio = mio_new_memory (data, size, NULL, g_free);
200 * <title>Basic creation of an empty growable and freeable #MIO object</title>
202 * MIO *mio = mio_new_memory (NULL, 0, g_try_realloc, g_free);
206 * Free-function: mio_free()
208 * Returns: A new #MIO on success, or %NULL on failure.
210 MIO
*mio_new_memory (unsigned char *data
,
212 MIOReallocFunc realloc_func
,
213 MIODestroyNotify free_func
)
217 mio
= malloc (sizeof *mio
);
220 mio
->type
= MIO_TYPE_MEMORY
;
221 mio
->impl
.mem
.buf
= data
;
222 mio
->impl
.mem
.ungetch
= EOF
;
223 mio
->impl
.mem
.pos
= 0;
224 mio
->impl
.mem
.size
= size
;
225 mio
->impl
.mem
.allocated_size
= size
;
226 mio
->impl
.mem
.realloc_func
= realloc_func
;
227 mio
->impl
.mem
.free_func
= free_func
;
228 mio
->impl
.mem
.eof
= false;
229 mio
->impl
.mem
.error
= false;
237 * @mio: A #MIO object
239 * Gets the underlying #FILE object associated with a #MIO file stream.
241 * <warning><para>The returned object may become invalid after a call to
242 * mio_free() if the stream was configured to close the file when
243 * destroyed.</para></warning>
245 * Returns: The underlying #FILE object of the given stream, or %NULL if the
246 * stream is not a file stream.
248 FILE *mio_file_get_fp (MIO
*mio
)
252 if (mio
->type
== MIO_TYPE_FILE
)
253 fp
= mio
->impl
.file
.fp
;
259 * mio_memory_get_data:
260 * @mio: A #MIO object
261 * @size: (allow-none) (out): Return location for the length of the returned
264 * Gets the underlying memory buffer associated with a #MIO memory stream.
266 * <warning><para>The returned pointer and size may become invalid after a
267 * successful write on the stream or after a call to mio_free() if the stream
268 * was configured to free the memory when destroyed.</para></warning>
270 * Returns: The memory buffer of the given #MIO stream, or %NULL if the stream
271 * is not a memory stream.
273 unsigned char *mio_memory_get_data (MIO
*mio
, size_t *size
)
275 unsigned char *ptr
= NULL
;
277 if (mio
->type
== MIO_TYPE_MEMORY
)
279 ptr
= mio
->impl
.mem
.buf
;
281 *size
= mio
->impl
.mem
.size
;
289 * @mio: A #MIO object
291 * Destroys a #MIO object.
293 * Returns: Error code obtained from the registered MIOFCloseFunc or 0 on success.
295 int mio_free (MIO
*mio
)
301 if (mio
->type
== MIO_TYPE_FILE
)
303 if (mio
->impl
.file
.close_func
)
304 rv
= mio
->impl
.file
.close_func (mio
->impl
.file
.fp
);
305 mio
->impl
.file
.close_func
= NULL
;
306 mio
->impl
.file
.fp
= NULL
;
310 if (mio
->impl
.mem
.free_func
)
311 mio
->impl
.mem
.free_func (mio
->impl
.mem
.buf
);
312 mio
->impl
.mem
.buf
= NULL
;
313 mio
->impl
.mem
.pos
= 0;
314 mio
->impl
.mem
.size
= 0;
315 mio
->impl
.mem
.allocated_size
= 0;
316 mio
->impl
.mem
.realloc_func
= NULL
;
317 mio
->impl
.mem
.free_func
= NULL
;
318 mio
->impl
.mem
.eof
= false;
319 mio
->impl
.mem
.error
= false;
330 * @mio: A #MIO object
331 * @ptr: Pointer to the memory to fill with the read data
332 * @size: Size of each block to read
333 * @nmemb: Number o blocks to read
335 * Reads raw data from a #MIO stream. This function behave the same as fread().
337 * Returns: The number of actually read blocks. If an error occurs or if the
338 * end of the stream is reached, the return value may be smaller than
339 * the requested block count, or even 0. This function doesn't
340 * distinguish between end-of-stream and an error, you should then use
341 * mio_eof() and mio_error() to determine which occurred.
343 size_t mio_read (MIO
*mio
,
348 if (mio
->type
== MIO_TYPE_FILE
)
349 return fread (ptr_
, size
, nmemb
, mio
->impl
.file
.fp
);
354 if (size
!= 0 && nmemb
!= 0)
356 size_t size_avail
= mio
->impl
.mem
.size
- mio
->impl
.mem
.pos
;
357 size_t copy_bytes
= size
* nmemb
;
358 unsigned char *ptr
= ptr_
;
360 if (size_avail
< copy_bytes
)
361 copy_bytes
= size_avail
;
365 n_read
= copy_bytes
/ size
;
367 if (mio
->impl
.mem
.ungetch
!= EOF
)
369 *ptr
= (unsigned char) mio
->impl
.mem
.ungetch
;
370 mio
->impl
.mem
.ungetch
= EOF
;
376 memcpy (ptr
, &mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], copy_bytes
);
377 mio
->impl
.mem
.pos
+= copy_bytes
;
379 if (mio
->impl
.mem
.pos
>= mio
->impl
.mem
.size
)
380 mio
->impl
.mem
.eof
= true;
389 * @mio: A #MIO object of the type %MIO_TYPE_MEMORY
390 * @new_size: Requested new size
392 * Tries to resize the underlying buffer of an in-memory #MIO object.
393 * This supports both growing and shrinking.
395 * Returns: %true on success, %false otherwise.
397 static int mem_try_resize (MIO
*mio
, size_t new_size
)
401 if (mio
->impl
.mem
.realloc_func
)
403 if (new_size
== ULONG_MAX
)
411 if (new_size
> mio
->impl
.mem
.size
)
413 if (new_size
<= mio
->impl
.mem
.allocated_size
)
415 mio
->impl
.mem
.size
= new_size
;
421 unsigned char *newbuf
;
423 newsize
= MAX (mio
->impl
.mem
.allocated_size
+ MIO_CHUNK_SIZE
,
425 newbuf
= mio
->impl
.mem
.realloc_func (mio
->impl
.mem
.buf
, newsize
);
428 mio
->impl
.mem
.buf
= newbuf
;
429 mio
->impl
.mem
.allocated_size
= newsize
;
430 mio
->impl
.mem
.size
= new_size
;
437 unsigned char *newbuf
;
439 newbuf
= mio
->impl
.mem
.realloc_func (mio
->impl
.mem
.buf
, new_size
);
440 if (newbuf
|| new_size
== 0)
442 mio
->impl
.mem
.buf
= newbuf
;
443 mio
->impl
.mem
.allocated_size
= new_size
;
444 mio
->impl
.mem
.size
= new_size
;
455 * mem_try_ensure_space:
456 * @mio: A #MIO object
457 * @n: Requested size from the current (cursor) position
459 * Tries to ensure there is enough space for @n bytes to be written from the
460 * current cursor position.
462 * Returns: %true if there is enough space, %false otherwise.
464 static int mem_try_ensure_space (MIO
*mio
, size_t n
)
468 if (mio
->impl
.mem
.pos
+ n
> mio
->impl
.mem
.size
)
469 success
= mem_try_resize (mio
, mio
->impl
.mem
.pos
+ n
);
476 * @mio: A #MIO object
477 * @ptr: Pointer to the memory to write on the stream
478 * @size: Size of each block to write
479 * @nmemb: Number of block to write
481 * Writes raw data to a #MIO stream. This function behaves the same as fwrite().
483 * Returns: The number of blocks actually written to the stream. This might be
484 * smaller than the requested count if a write error occurs.
486 size_t mio_write (MIO
*mio
,
491 if (mio
->type
== MIO_TYPE_FILE
)
492 return fwrite (ptr
, size
, nmemb
, mio
->impl
.file
.fp
);
495 size_t n_written
= 0;
497 if (size
!= 0 && nmemb
!= 0)
499 if (mem_try_ensure_space (mio
, size
* nmemb
))
501 memcpy (&mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], ptr
, size
* nmemb
);
502 mio
->impl
.mem
.pos
+= size
* nmemb
;
513 * @mio: A #MIO object
514 * @c: The character to write
516 * Writes a character to a #MIO stream. This function behaves the same as
519 * Returns: The written wharacter, or %EOF on error.
521 int mio_putc (MIO
*mio
, int c
)
523 if (mio
->type
== MIO_TYPE_FILE
)
524 return fputc (c
, mio
->impl
.file
.fp
);
529 if (mem_try_ensure_space (mio
, 1))
531 mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
] = (unsigned char)c
;
533 rv
= (int)((unsigned char)c
);
542 * @mio: A #MIO object
543 * @s: The string to write
545 * Writes a string to a #MIO object. This function behaves the same as fputs().
547 * Returns: A non-negative integer on success or %EOF on failure.
549 int mio_puts (MIO
*mio
, const char *s
)
551 if (mio
->type
== MIO_TYPE_FILE
)
552 return fputs (s
, mio
->impl
.file
.fp
);
559 if (mem_try_ensure_space (mio
, len
))
561 memcpy (&mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], s
, len
);
562 mio
->impl
.mem
.pos
+= len
;
572 * @mio: A #MIO object
573 * @format: A printf fomrat string
574 * @ap: The variadic argument list for the format
576 * Writes a formatted string into a #MIO stream. This function behaves the same
579 * Returns: The number of bytes written in the stream, or a negative value on
582 int mio_vprintf (MIO
*mio
, const char *format
, va_list ap
)
584 if (mio
->type
== MIO_TYPE_FILE
)
585 return vfprintf (mio
->impl
.file
.fp
, format
, ap
);
595 old_pos
= mio
->impl
.mem
.pos
;
596 old_size
= mio
->impl
.mem
.size
;
597 va_copy (ap_copy
, ap
);
598 /* compute the size we will need into the buffer */
599 n
= vsnprintf (&dummy
, 1, format
, ap_copy
);
601 if (mem_try_ensure_space (mio
, n
))
605 /* backup character at n+1 that will be overwritten by a \0 ... */
606 c
= mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
+ (n
- 1)];
607 rv
= vsprintf ((char *)&mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], format
, ap
);
608 /* ...and restore it */
609 mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
+ (n
- 1)] = c
;
610 if (rv
>= 0 && (size_t)rv
== (n
- 1))
612 /* re-compute the actual size since we might have allocated one byte
613 * more than needed */
614 mio
->impl
.mem
.size
= MAX (old_size
, old_pos
+ (unsigned int)rv
);
615 mio
->impl
.mem
.pos
+= (unsigned int)rv
;
619 mio
->impl
.mem
.size
= old_size
;
630 * @mio: A #MIO object
631 * @format: A print format string
632 * @...: Arguments of the format
634 * Writes a formatted string to a #MIO stream. This function behaves the same as
637 * Returns: The number of bytes written to the stream, or a negative value on
640 int mio_printf (MIO
*mio
, const char *format
, ...)
645 va_start (ap
, format
);
646 rv
= mio_vprintf (mio
, format
, ap
);
654 * @mio: A #MIO object
656 * Gets the current character from a #MIO stream. This function behaves the same
659 * Returns: The read character as a #int, or %EOF on error.
661 int mio_getc (MIO
*mio
)
663 if (mio
->type
== MIO_TYPE_FILE
)
664 return fgetc (mio
->impl
.file
.fp
);
669 if (mio
->impl
.mem
.ungetch
!= EOF
)
671 rv
= mio
->impl
.mem
.ungetch
;
672 mio
->impl
.mem
.ungetch
= EOF
;
675 else if (mio
->impl
.mem
.pos
< mio
->impl
.mem
.size
)
677 rv
= mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
];
681 mio
->impl
.mem
.eof
= true;
689 * @mio: A #MIO object
690 * @ch: Character to put back in the stream
692 * Puts a character back in a #MIO stream. This function behaves the sames as
695 * <warning><para>It is only guaranteed that one character can be but back at a
696 * time, even if the implementation may allow more.</para></warning>
697 * <warning><para>Using this function while the stream cursor is at offset 0 is
698 * not guaranteed to function properly. As the C99 standard says, it is "an
699 * obsolescent feature".</para></warning>
701 * Returns: The character put back, or %EOF on error.
703 int mio_ungetc (MIO
*mio
, int ch
)
705 if (mio
->type
== MIO_TYPE_FILE
)
706 return ungetc (ch
, mio
->impl
.file
.fp
);
711 if (ch
!= EOF
&& mio
->impl
.mem
.ungetch
== EOF
)
713 rv
= mio
->impl
.mem
.ungetch
= ch
;
715 mio
->impl
.mem
.eof
= false;
724 * @mio: A #MIO object
725 * @s: A string to fill with the read data
726 * @size: The maximum number of bytes to read
728 * Reads a string from a #MIO stream, stopping after the first new-line
729 * character or at the end of the stream. This function behaves the same as
732 * Returns: @s on success, %NULL otherwise.
734 char *mio_gets (MIO
*mio
, char *s
, size_t size
)
736 if (mio
->type
== MIO_TYPE_FILE
)
737 return fgets (s
, (int)size
, mio
->impl
.file
.fp
);
746 if (mio
->impl
.mem
.ungetch
!= EOF
)
748 s
[i
] = (char)mio
->impl
.mem
.ungetch
;
749 mio
->impl
.mem
.ungetch
= EOF
;
753 for (; mio
->impl
.mem
.pos
< mio
->impl
.mem
.size
&& i
< (size
- 1); i
++)
755 s
[i
] = (char)mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
];
768 if (mio
->impl
.mem
.pos
>= mio
->impl
.mem
.size
)
769 mio
->impl
.mem
.eof
= true;
778 * @mio: A #MIO object
780 * Clears the error and end-of-stream indicators of a #MIO stream. This function
781 * behaves the same as clearerr().
783 void mio_clearerr (MIO
*mio
)
785 if (mio
->type
== MIO_TYPE_FILE
)
786 clearerr (mio
->impl
.file
.fp
);
789 mio
->impl
.mem
.error
= false;
790 mio
->impl
.mem
.eof
= false;
796 * @mio: A #MIO object
798 * Checks whether the end-of-stream indicator of a #MIO stream is set. This
799 * function behaves the same as feof().
801 * Returns: A non-null value if the stream reached its end, 0 otherwise.
803 int mio_eof (MIO
*mio
)
805 if (mio
->type
== MIO_TYPE_FILE
)
806 return feof (mio
->impl
.file
.fp
);
808 return mio
->impl
.mem
.eof
!= false;
813 * @mio: A #MIO object
815 * Checks whether the error indicator of a #MIO stream is set. This function
816 * behaves the same as ferror().
818 * Returns: A non-null value if the stream have an error set, 0 otherwise.
820 int mio_error (MIO
*mio
)
822 if (mio
->type
== MIO_TYPE_FILE
)
823 return ferror (mio
->impl
.file
.fp
);
825 return mio
->impl
.mem
.error
!= false;
830 * @mio: A #MIO object
831 * @offset: Offset of the new place, from @whence
832 * @whence: Move origin. SEEK_SET moves relative to the start of the stream,
833 * SEEK_CUR from the current position and SEEK_SET from the end of the
836 * Sets the curosr position on a #MIO stream. This functions behaves the same as
837 * fseek(). See also mio_tell() and mio_setpos().
839 * Returns: 0 on success, -1 otherwise, in which case errno should be set to
840 * indicate the error.
842 int mio_seek (MIO
*mio
, long offset
, int whence
)
844 if (mio
->type
== MIO_TYPE_FILE
)
845 return fseek (mio
->impl
.file
.fp
, offset
, whence
);
848 /* FIXME: should we support seeking out of bounds like lseek() seems to do? */
854 if (offset
< 0 || (size_t)offset
> mio
->impl
.mem
.size
)
858 mio
->impl
.mem
.pos
= (size_t)offset
;
864 if ((offset
< 0 && (size_t)-offset
> mio
->impl
.mem
.pos
) ||
865 mio
->impl
.mem
.pos
+ (size_t)offset
> mio
->impl
.mem
.size
)
871 mio
->impl
.mem
.pos
= (size_t)(mio
->impl
.mem
.pos
+ offset
);
877 if (offset
> 0 || (size_t)-offset
> mio
->impl
.mem
.size
)
881 mio
->impl
.mem
.pos
= mio
->impl
.mem
.size
- (size_t)-offset
;
891 mio
->impl
.mem
.eof
= false;
892 mio
->impl
.mem
.ungetch
= EOF
;
901 * @mio: A #MIO object
903 * Gets the current cursor position of a #MIO stream. This function behaves the
906 * Returns: The current offset from the start of the stream, or -1 or error, in
907 * which case errno is set to indicate the error.
909 long mio_tell (MIO
*mio
)
911 if (mio
->type
== MIO_TYPE_FILE
)
912 return ftell (mio
->impl
.file
.fp
);
917 if (mio
->impl
.mem
.pos
> LONG_MAX
)
924 rv
= (long)mio
->impl
.mem
.pos
;
932 * @mio: A #MIO object
934 * Resets the cursor position to 0, and also the end-of-stream and the error
935 * indicators of a #MIO stream.
936 * See also mio_seek() and mio_clearerr().
938 void mio_rewind (MIO
*mio
)
940 if (mio
->type
== MIO_TYPE_FILE
)
941 rewind (mio
->impl
.file
.fp
);
944 mio
->impl
.mem
.pos
= 0;
945 mio
->impl
.mem
.ungetch
= EOF
;
946 mio
->impl
.mem
.eof
= false;
947 mio
->impl
.mem
.error
= false;
953 * @mio: A #MIO stream
954 * @pos: (out): A #MIOPos object to fill-in
956 * Stores the current position (and maybe other informations about the stream
957 * state) of a #MIO stream in order to restore it later with mio_setpos(). This
958 * function behaves the same as fgetpos().
960 * Returns: 0 on success, -1 otherwise, in which case errno is set to indicate
963 int mio_getpos (MIO
*mio
, MIOPos
*pos
)
967 pos
->type
= mio
->type
;
968 if (mio
->type
== MIO_TYPE_FILE
)
969 rv
= fgetpos (mio
->impl
.file
.fp
, &pos
->impl
.file
);
974 if (mio
->impl
.mem
.pos
== (size_t)-1)
976 /* this happens if ungetc() was called at the start of the stream */
983 pos
->impl
.mem
= mio
->impl
.mem
.pos
;
992 #endif /* MIO_DEBUG */
999 * @mio: A #MIO object
1000 * @pos: (in): A #MIOPos object filled-in by a previous call of mio_getpos() on
1003 * Restores the position and state indicators of a #MIO stream previously saved
1006 * <warning><para>The #MIOPos object must have been initialized by a previous
1007 * call to mio_getpos() on the same stream.</para></warning>
1009 * Returns: 0 on success, -1 otherwise, in which case errno is set to indicate
1012 int mio_setpos (MIO
*mio
, MIOPos
*pos
)
1017 if (pos
->tag
!= mio
)
1019 g_critical ("mio_setpos((MIO*)%p, (MIOPos*)%p): "
1020 "Given MIOPos was not set by a previous call to mio_getpos() "
1021 "on the same MIO object, which means there is a bug in "
1023 (void *)mio
, (void *)pos
);
1027 #endif /* MIO_DEBUG */
1029 if (mio
->type
== MIO_TYPE_FILE
)
1030 rv
= fsetpos (mio
->impl
.file
.fp
, &pos
->impl
.file
);
1035 if (pos
->impl
.mem
> mio
->impl
.mem
.size
)
1039 mio
->impl
.mem
.ungetch
= EOF
;
1040 mio
->impl
.mem
.pos
= pos
->impl
.mem
;
1050 * @mio: A #MIO object
1052 * Forces a write of all user-space buffered data for the given output or update
1053 * stream via the stream's underlying write function. Only applicable when using
1056 * Returns: 0 on success, error code otherwise.
1058 int mio_flush (MIO
*mio
)
1060 if (mio
->type
== MIO_TYPE_FILE
)
1061 return fflush (mio
->impl
.file
.fp
);