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.
22 #include "general.h" /* must always come first */
28 #if defined (HAVE_CONFIG_H)
35 #endif /* READTAGS_DSL */
47 #define MAY_HAVE_FTRUNCATE
52 #define xMalloc(n,Type) (Type *)eMalloc((size_t)(n) * sizeof (Type))
53 #define xRealloc(p,n,Type) (Type *)eRealloc((p), (n) * sizeof (Type))
55 static void *eMalloc (const size_t size
)
57 void *buffer
= malloc (size
);
61 fprintf(stderr
, "out of memory");
68 static void *eRealloc (void *const ptr
, const size_t size
)
72 buffer
= eMalloc (size
);
75 buffer
= realloc (ptr
, size
);
78 fprintf(stderr
, "out of memory");
85 static void eFree (void *const ptr
)
89 #define eFreeNoNullCheck eFree
91 # define Assert(c) do {} while(0)
92 # define AssertNotReached() do {} while(0)
93 #endif /* READTAGS_DSL */
95 /* minimal reallocation chunk size */
96 #define MIO_CHUNK_SIZE 4096
98 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
103 * @short_description: The MIO object
104 * @include: mio/mio.h
106 * The #MIO object replicates the C file I/O API with support of both standard
107 * file based operations and in-memory operations. Its goal is to ease the port
108 * of an application that uses C file I/O API to perform in-memory operations.
110 * A #MIO object is created using mio_new_file(), mio_new_memory() or mio_new_mio(),
111 * depending on whether you want file or in-memory operations.
112 * Its life is managed by reference counting. Just after calling one of functions
113 * for creating, the count is 1. mio_ref() increments the counter. mio_unref()
114 * decrements it. When the counter becomes 0, the #MIO object will be destroyed
115 * in mio_unref(). There is also some other convenient API to create file-based
116 * #MIO objects for more complex cases, such as mio_new_file_full() and
119 * Once the #MIO object is created, you can perform standard I/O operations on
120 * it transparently without the need to care about the effective underlying
123 * The I/O API is almost exactly a replication of the standard C file I/O API
124 * with the significant difference that the first parameter is always the #MIO
129 typedef struct _MIOUserData MIOUserData
;
130 struct _MIOUserData
{
138 * An object representing a #MIO stream. No assumptions should be made about
139 * what compose this object, and none of its fields should be accessed directly.
144 unsigned int refcount
;
148 MIOFCloseFunc close_func
;
155 size_t allocated_size
;
156 MIOReallocFunc realloc_func
;
157 MIODestroyNotify free_func
;
168 * @filename: Filename to open, passed as-is to @open_func as the first argument
169 * @mode: Mode in which open the file, passed as-is to @open_func as the second
171 * @open_func: A function with the fopen() semantic to use to open the file
172 * @close_func: A function with the fclose() semantic to close the file when
173 * the #MIO object is destroyed, or %NULL not to close the #FILE
176 * Creates a new #MIO object working on a file, from a filename and an opening
177 * function. See also mio_new_file().
179 * This function is generally overkill and mio_new_file() should often be used
180 * instead, but it allows to specify a custom function to open a file, as well
181 * as a close function. The former is useful e.g. if you need to wrap fopen()
182 * for some reason (like filename encoding conversion for example), and the
183 * latter allows you both to match your custom open function and to choose
184 * whether the underlying #FILE object should or not be closed when mio_unref()
185 * is called on the returned object.
187 * Free-function: mio_unref()
189 * Returns: A new #MIO on success, or %NULL on failure.
191 MIO
*mio_new_file_full (const char *filename
,
193 MIOFOpenFunc open_func
,
194 MIOFCloseFunc close_func
)
198 /* we need to create the MIO object first, because we may not be able to close
199 * the opened file if the user passed NULL as the close function, which means
200 * that everything must succeed if we've opened the file successfully */
201 mio
= xMalloc (1, MIO
);
204 FILE *fp
= open_func (filename
, mode
);
213 mio
->type
= MIO_TYPE_FILE
;
214 mio
->impl
.file
.fp
= fp
;
215 mio
->impl
.file
.close_func
= close_func
;
227 * @filename: Filename to open, same as the fopen()'s first argument
228 * @mode: Mode in which open the file, fopen()'s second argument
230 * Creates a new #MIO object working on a file from a filename; wrapping
232 * This function simply calls mio_new_file_full() with the libc's fopen() and
233 * fclose() functions.
235 * Free-function: mio_unref()
237 * Returns: A new #MIO on success, or %NULL on failure.
239 MIO
*mio_new_file (const char *filename
, const char *mode
)
241 return mio_new_file_full (filename
, mode
, fopen
, fclose
);
246 * @fp: An opened #FILE object
247 * @close_func: (allow-none): Function used to close @fp when the #MIO object
248 * gets destroyed, or %NULL not to close the #FILE object
250 * Creates a new #MIO object working on a file, from an already opened #FILE
254 * <title>Typical use of this function</title>
256 * MIO *mio = mio_new_fp (fp, fclose);
260 * Free-function: mio_unref()
262 * Returns: A new #MIO on success or %NULL on failure.
264 MIO
*mio_new_fp (FILE *fp
, MIOFCloseFunc close_func
)
271 mio
= xMalloc (1, MIO
);
274 mio
->type
= MIO_TYPE_FILE
;
275 mio
->impl
.file
.fp
= fp
;
276 mio
->impl
.file
.close_func
= close_func
;
287 * @data: Initial data (may be %NULL)
288 * @size: Length of @data in bytes
289 * @realloc_func: A function with the realloc() semantic used to grow the
290 * buffer, or %NULL to disable buffer growing
291 * @free_func: A function with the free() semantic to destroy the data together
292 * with the object, or %NULL not to destroy the data
294 * Creates a new #MIO object working on memory.
296 * To allow the buffer to grow, you must provide a @realloc_func, otherwise
297 * trying to write after the end of the current data will fail.
299 * If you want the buffer to be freed together with the #MIO object, you must
300 * give a @free_func; otherwise the data will still live after #MIO object
304 * <title>Basic creation of a non-growable, freeable #MIO object</title>
306 * MIO *mio = mio_new_memory (data, size, NULL, g_free);
311 * <title>Basic creation of an empty growable and freeable #MIO object</title>
313 * MIO *mio = mio_new_memory (NULL, 0, g_try_realloc, g_free);
317 * Free-function: mio_unref()
319 * Returns: A new #MIO on success, or %NULL on failure.
321 MIO
*mio_new_memory (unsigned char *data
,
323 MIOReallocFunc realloc_func
,
324 MIODestroyNotify free_func
)
328 mio
= xMalloc (1, MIO
);
331 mio
->type
= MIO_TYPE_MEMORY
;
332 mio
->impl
.mem
.buf
= data
;
333 mio
->impl
.mem
.ungetch
= EOF
;
334 mio
->impl
.mem
.pos
= 0;
335 mio
->impl
.mem
.size
= size
;
336 mio
->impl
.mem
.allocated_size
= size
;
337 mio
->impl
.mem
.realloc_func
= realloc_func
;
338 mio
->impl
.mem
.free_func
= free_func
;
339 mio
->impl
.mem
.eof
= false;
340 mio
->impl
.mem
.error
= false;
351 * @base: The original mio
352 * @start: stream offset of the @base where new mio starts
353 * @size: the length of the data copied from @base to new mio
355 * Creates a new #MIO object by copying data from existing #MIO (@base).
356 * The range for copying is given with @start and @size.
357 * Copying data at the range from @start to the end of @base is
358 * done if -1 is given as @size.
360 * If @size is larger than the length from @start to the end of
361 * @base, %NULL is returned.
363 * The function doesn't move the file position of @base.
365 * Free-function: mio_unref()
369 MIO
*mio_new_mio (MIO
*base
, long start
, long size
)
376 original_pos
= mio_tell (base
);
382 if (mio_seek (base
, 0, SEEK_END
) != 0)
384 end
= mio_tell (base
);
385 Assert (end
>= start
);
389 if (mio_seek (base
, start
, SEEK_SET
) != 0)
392 data
= xMalloc (size
, unsigned char);
393 r
= mio_read (base
, data
, 1, size
);
394 mio_seek (base
, original_pos
, SEEK_SET
);
399 submio
= mio_new_memory (data
, size
, eRealloc
, eFreeNoNullCheck
);
412 * @mio: A #MIO object
414 * Increments the reference counter of a #MIO.
416 * Returns: passed @mio.
418 MIO
*mio_ref (MIO
*mio
)
426 * @mio: A #MIO object
428 * Gets the underlying #FILE object associated with a #MIO file stream.
430 * <warning><para>The returned object may become invalid after a call to
431 * mio_unref() if the stream was configured to close the file when
432 * destroyed.</para></warning>
434 * Returns: The underlying #FILE object of the given stream, or %NULL if the
435 * stream is not a file stream.
437 FILE *mio_file_get_fp (MIO
*mio
)
441 if (mio
->type
== MIO_TYPE_FILE
)
442 fp
= mio
->impl
.file
.fp
;
448 * mio_memory_get_data:
449 * @mio: A #MIO object
450 * @size: (allow-none) (out): Return location for the length of the returned
453 * Gets the underlying memory buffer associated with a #MIO memory stream.
455 * <warning><para>The returned pointer and size may become invalid after a
456 * successful write on the stream or after a call to mio_unref() if the stream
457 * was configured to free the memory when destroyed.</para></warning>
459 * Returns: The memory buffer of the given #MIO stream, or %NULL if the stream
460 * is not a memory stream.
462 unsigned char *mio_memory_get_data (MIO
*mio
, size_t *size
)
464 unsigned char *ptr
= NULL
;
466 if (mio
->type
== MIO_TYPE_MEMORY
)
468 ptr
= mio
->impl
.mem
.buf
;
470 *size
= mio
->impl
.mem
.size
;
478 * @mio: A #MIO object
480 * Decrements the reference counter of a #MIO and destroys the #MIO
481 * object if its counter becomes 0.
483 * Returns: Error code obtained from the registered MIOFCloseFunc or 0 on success.
485 int mio_unref (MIO
*mio
)
494 if (mio
->udata
.d
&& mio
->udata
.f
)
495 mio
->udata
.f (mio
->udata
.d
);
497 if (mio
->type
== MIO_TYPE_FILE
)
499 if (mio
->impl
.file
.close_func
)
500 rv
= mio
->impl
.file
.close_func (mio
->impl
.file
.fp
);
501 mio
->impl
.file
.close_func
= NULL
;
502 mio
->impl
.file
.fp
= NULL
;
504 else if (mio
->type
== MIO_TYPE_MEMORY
)
506 if (mio
->impl
.mem
.free_func
)
507 mio
->impl
.mem
.free_func (mio
->impl
.mem
.buf
);
508 mio
->impl
.mem
.buf
= NULL
;
509 mio
->impl
.mem
.pos
= 0;
510 mio
->impl
.mem
.size
= 0;
511 mio
->impl
.mem
.allocated_size
= 0;
512 mio
->impl
.mem
.realloc_func
= NULL
;
513 mio
->impl
.mem
.free_func
= NULL
;
514 mio
->impl
.mem
.eof
= false;
515 mio
->impl
.mem
.error
= false;
528 * @mio: A #MIO object
529 * @ptr: Pointer to the memory to fill with the read data
530 * @size: Size of each block to read
531 * @nmemb: Number o blocks to read
533 * Reads raw data from a #MIO stream. This function behave the same as fread().
535 * Returns: The number of actually read blocks. If an error occurs or if the
536 * end of the stream is reached, the return value may be smaller than
537 * the requested block count, or even 0. This function doesn't
538 * distinguish between end-of-stream and an error, you should then use
539 * mio_eof() and mio_error() to determine which occurred.
541 size_t mio_read (MIO
*mio
,
546 if (mio
->type
== MIO_TYPE_FILE
)
547 return fread (ptr_
, size
, nmemb
, mio
->impl
.file
.fp
);
548 else if (mio
->type
== MIO_TYPE_MEMORY
)
552 if (size
!= 0 && nmemb
!= 0)
554 size_t size_avail
= mio
->impl
.mem
.size
- mio
->impl
.mem
.pos
;
555 size_t copy_bytes
= size
* nmemb
;
556 unsigned char *ptr
= ptr_
;
558 if (size_avail
< copy_bytes
)
559 copy_bytes
= size_avail
;
563 n_read
= copy_bytes
/ size
;
565 if (mio
->impl
.mem
.ungetch
!= EOF
)
567 *ptr
= (unsigned char) mio
->impl
.mem
.ungetch
;
568 mio
->impl
.mem
.ungetch
= EOF
;
574 memcpy (ptr
, &mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], copy_bytes
);
575 mio
->impl
.mem
.pos
+= copy_bytes
;
577 if (mio
->impl
.mem
.pos
>= mio
->impl
.mem
.size
)
578 mio
->impl
.mem
.eof
= true;
592 * @mio: A #MIO object of the type %MIO_TYPE_MEMORY
593 * @new_size: Requested new size
595 * Tries to resize the underlying buffer of an in-memory #MIO object.
596 * This supports both growing and shrinking.
598 * Returns: %true on success, %false otherwise.
600 static int mem_try_resize (MIO
*mio
, size_t new_size
)
604 if (mio
->impl
.mem
.realloc_func
)
606 if (new_size
== ULONG_MAX
)
614 if (new_size
> mio
->impl
.mem
.size
)
616 if (new_size
<= mio
->impl
.mem
.allocated_size
)
618 mio
->impl
.mem
.size
= new_size
;
624 unsigned char *newbuf
;
626 newsize
= MAX (mio
->impl
.mem
.allocated_size
+ MIO_CHUNK_SIZE
,
628 newbuf
= mio
->impl
.mem
.realloc_func (mio
->impl
.mem
.buf
, newsize
);
631 mio
->impl
.mem
.buf
= newbuf
;
632 mio
->impl
.mem
.allocated_size
= newsize
;
633 mio
->impl
.mem
.size
= new_size
;
640 unsigned char *newbuf
;
642 newbuf
= mio
->impl
.mem
.realloc_func (mio
->impl
.mem
.buf
, new_size
);
643 if (newbuf
|| new_size
== 0)
645 mio
->impl
.mem
.buf
= newbuf
;
646 mio
->impl
.mem
.allocated_size
= new_size
;
647 mio
->impl
.mem
.size
= new_size
;
657 static int file_try_resize (MIO
*mio
, size_t new_size
)
661 FILE *fp
= mio_file_get_fp (mio
);
663 #ifdef MAY_HAVE_FTRUNCATE
664 if (ftruncate(fileno(fp
), (off_t
)new_size
) < 0)
667 /* See https://stackoverflow.com/questions/873454/how-to-truncate-a-file-in-c/874704#874704 */
668 if ((errno
= _chsize_s(_fileno(fp
), (__int64
)new_size
)) != 0)
674 int mio_try_resize (MIO
*mio
, size_t new_size
)
676 if (mio
->type
== MIO_TYPE_MEMORY
)
677 return mem_try_resize (mio
, new_size
);
679 return file_try_resize (mio
, new_size
);
683 * mem_try_ensure_space:
684 * @mio: A #MIO object
685 * @n: Requested size from the current (cursor) position
687 * Tries to ensure there is enough space for @n bytes to be written from the
688 * current cursor position.
690 * Returns: %true if there is enough space, %false otherwise.
692 static int mem_try_ensure_space (MIO
*mio
, size_t n
)
696 if (mio
->impl
.mem
.pos
+ n
> mio
->impl
.mem
.size
)
697 success
= mem_try_resize (mio
, mio
->impl
.mem
.pos
+ n
);
704 * @mio: A #MIO object
705 * @ptr: Pointer to the memory to write on the stream
706 * @size: Size of each block to write
707 * @nmemb: Number of block to write
709 * Writes raw data to a #MIO stream. This function behaves the same as fwrite().
711 * Returns: The number of blocks actually written to the stream. This might be
712 * smaller than the requested count if a write error occurs.
714 size_t mio_write (MIO
*mio
,
719 if (mio
->type
== MIO_TYPE_FILE
)
720 return fwrite (ptr
, size
, nmemb
, mio
->impl
.file
.fp
);
721 else if (mio
->type
== MIO_TYPE_MEMORY
)
723 size_t n_written
= 0;
725 if (size
!= 0 && nmemb
!= 0)
727 if (mem_try_ensure_space (mio
, size
* nmemb
))
729 memcpy (&mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], ptr
, size
* nmemb
);
730 mio
->impl
.mem
.pos
+= size
* nmemb
;
746 * @mio: A #MIO object
747 * @c: The character to write
749 * Writes a character to a #MIO stream. This function behaves the same as
752 * Returns: The written character, or %EOF on error.
754 int mio_putc (MIO
*mio
, int c
)
756 if (mio
->type
== MIO_TYPE_FILE
)
757 return fputc (c
, mio
->impl
.file
.fp
);
758 else if (mio
->type
== MIO_TYPE_MEMORY
)
762 if (mem_try_ensure_space (mio
, 1))
764 mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
] = (unsigned char)c
;
766 rv
= (int)((unsigned char)c
);
780 * @mio: A #MIO object
781 * @s: The string to write
783 * Writes a string to a #MIO object. This function behaves the same as fputs().
785 * Returns: A non-negative integer on success or %EOF on failure.
787 int mio_puts (MIO
*mio
, const char *s
)
789 if (mio
->type
== MIO_TYPE_FILE
)
790 return fputs (s
, mio
->impl
.file
.fp
);
791 else if (mio
->type
== MIO_TYPE_MEMORY
)
797 if (mem_try_ensure_space (mio
, len
))
799 memcpy (&mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], s
, len
);
800 mio
->impl
.mem
.pos
+= len
;
815 * @mio: A #MIO object
816 * @format: A printf format string
817 * @ap: The variadic argument list for the format
819 * Writes a formatted string into a #MIO stream. This function behaves the same
822 * Returns: The number of bytes written in the stream, or a negative value on
825 int mio_vprintf (MIO
*mio
, const char *format
, va_list ap
)
827 if (mio
->type
== MIO_TYPE_FILE
)
828 return vfprintf (mio
->impl
.file
.fp
, format
, ap
);
829 else if (mio
->type
== MIO_TYPE_MEMORY
)
838 old_pos
= mio
->impl
.mem
.pos
;
839 old_size
= mio
->impl
.mem
.size
;
840 va_copy (ap_copy
, ap
);
841 /* compute the size we will need into the buffer */
842 n
= vsnprintf (&dummy
, 1, format
, ap_copy
) + 1;
844 if (mem_try_ensure_space (mio
, n
))
848 /* backup character at n+1 that will be overwritten by a \0 ... */
849 c
= mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
+ (n
- 1)];
850 rv
= vsprintf ((char *)&mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
], format
, ap
);
851 /* ...and restore it */
852 mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
+ (n
- 1)] = c
;
853 if (rv
>= 0 && (size_t)rv
== (n
- 1))
855 /* re-compute the actual size since we might have allocated one byte
856 * more than needed */
857 mio
->impl
.mem
.size
= MAX (old_size
, old_pos
+ (unsigned int)rv
);
858 mio
->impl
.mem
.pos
+= (unsigned int)rv
;
862 mio
->impl
.mem
.size
= old_size
;
878 * @mio: A #MIO object
879 * @format: A print format string
880 * @...: Arguments of the format
882 * Writes a formatted string to a #MIO stream. This function behaves the same as
885 * Returns: The number of bytes written to the stream, or a negative value on
888 int mio_printf (MIO
*mio
, const char *format
, ...)
893 va_start (ap
, format
);
894 rv
= mio_vprintf (mio
, format
, ap
);
902 * @mio: A #MIO object
904 * Gets the current character from a #MIO stream. This function behaves the same
907 * Returns: The read character as a #int, or %EOF on error.
909 int mio_getc (MIO
*mio
)
911 if (mio
->type
== MIO_TYPE_FILE
)
912 return fgetc (mio
->impl
.file
.fp
);
913 else if (mio
->type
== MIO_TYPE_MEMORY
)
917 if (mio
->impl
.mem
.ungetch
!= EOF
)
919 rv
= mio
->impl
.mem
.ungetch
;
920 mio
->impl
.mem
.ungetch
= EOF
;
923 else if (mio
->impl
.mem
.pos
< mio
->impl
.mem
.size
)
925 rv
= mio
->impl
.mem
.buf
[mio
->impl
.mem
.pos
];
929 mio
->impl
.mem
.eof
= true;
942 * @mio: A #MIO object
943 * @ch: Character to put back in the stream
945 * Puts a character back in a #MIO stream. This function behaves the sames as
948 * <warning><para>It is only guaranteed that one character can be but back at a
949 * time, even if the implementation may allow more.</para></warning>
950 * <warning><para>Using this function while the stream cursor is at offset 0 is
951 * not guaranteed to function properly. As the C99 standard says, it is "an
952 * obsolescent feature".</para></warning>
954 * Returns: The character put back, or %EOF on error.
956 int mio_ungetc (MIO
*mio
, int ch
)
958 if (mio
->type
== MIO_TYPE_FILE
)
959 return ungetc (ch
, mio
->impl
.file
.fp
);
960 else if (mio
->type
== MIO_TYPE_MEMORY
)
964 if (ch
!= EOF
&& mio
->impl
.mem
.ungetch
== EOF
)
966 rv
= mio
->impl
.mem
.ungetch
= ch
;
968 mio
->impl
.mem
.eof
= false;
982 * @mio: A #MIO object
983 * @s: A string to fill with the read data
984 * @size: The maximum number of bytes to read
986 * Reads a string from a #MIO stream, stopping after the first new-line
987 * character or at the end of the stream. This function behaves the same as
990 * Returns: @s on success, %NULL otherwise.
992 char *mio_gets (MIO
*mio
, char *s
, size_t size
)
994 if (mio
->type
== MIO_TYPE_FILE
)
995 return fgets (s
, (int)size
, mio
->impl
.file
.fp
);
996 else if (mio
->type
== MIO_TYPE_MEMORY
)
1003 bool newline
= false;
1004 /* Avoiding dereference inside the for loop below improves
1005 * performance so we do it here. */
1006 size_t pos
= mio
->impl
.mem
.pos
;
1007 size_t buf_size
= mio
->impl
.mem
.size
;
1008 unsigned char *buf
= mio
->impl
.mem
.buf
;
1010 if (mio
->impl
.mem
.ungetch
!= EOF
)
1012 s
[i
] = (char)mio
->impl
.mem
.ungetch
;
1013 mio
->impl
.mem
.ungetch
= EOF
;
1017 for (; pos
< buf_size
&& i
< (size
- 1); i
++)
1019 s
[i
] = (char)buf
[pos
];
1033 if (!newline
&& pos
>= buf_size
)
1034 mio
->impl
.mem
.eof
= true;
1035 mio
->impl
.mem
.pos
= pos
;
1036 mio
->impl
.mem
.size
= buf_size
;
1043 AssertNotReached ();
1050 * @mio: A #MIO object
1052 * Clears the error and end-of-stream indicators of a #MIO stream. This function
1053 * behaves the same as clearerr().
1055 void mio_clearerr (MIO
*mio
)
1057 if (mio
->type
== MIO_TYPE_FILE
)
1058 clearerr (mio
->impl
.file
.fp
);
1059 else if (mio
->type
== MIO_TYPE_MEMORY
)
1061 mio
->impl
.mem
.error
= false;
1062 mio
->impl
.mem
.eof
= false;
1065 AssertNotReached ();
1070 * @mio: A #MIO object
1072 * Checks whether the end-of-stream indicator of a #MIO stream is set. This
1073 * function behaves the same as feof().
1075 * Returns: A non-null value if the stream reached its end, 0 otherwise.
1077 int mio_eof (MIO
*mio
)
1079 if (mio
->type
== MIO_TYPE_FILE
)
1080 return feof (mio
->impl
.file
.fp
);
1081 else if (mio
->type
== MIO_TYPE_MEMORY
)
1082 return mio
->impl
.mem
.eof
!= false;
1085 AssertNotReached ();
1092 * @mio: A #MIO object
1094 * Checks whether the error indicator of a #MIO stream is set. This function
1095 * behaves the same as ferror().
1097 * Returns: A non-null value if the stream have an error set, 0 otherwise.
1099 int mio_error (MIO
*mio
)
1101 if (mio
->type
== MIO_TYPE_FILE
)
1102 return ferror (mio
->impl
.file
.fp
);
1103 else if (mio
->type
== MIO_TYPE_MEMORY
)
1104 return mio
->impl
.mem
.error
!= false;
1107 AssertNotReached ();
1114 * @mio: A #MIO object
1115 * @offset: Offset of the new place, from @whence
1116 * @whence: Move origin. SEEK_SET moves relative to the start of the stream,
1117 * SEEK_CUR from the current position and SEEK_SET from the end of the
1120 * Sets the cursor position on a #MIO stream. This functions behaves the same as
1121 * fseek(). See also mio_tell() and mio_setpos().
1123 * Returns: 0 on success, -1 otherwise, in which case errno should be set to
1124 * indicate the error.
1126 int mio_seek (MIO
*mio
, long offset
, int whence
)
1128 if (mio
->type
== MIO_TYPE_FILE
)
1129 return fseek (mio
->impl
.file
.fp
, offset
, whence
);
1130 else if (mio
->type
== MIO_TYPE_MEMORY
)
1132 /* FIXME: should we support seeking out of bounds like lseek() seems to do? */
1138 if (offset
< 0 || (size_t)offset
> mio
->impl
.mem
.size
)
1142 mio
->impl
.mem
.pos
= (size_t)offset
;
1148 if ((offset
< 0 && (size_t)-offset
> mio
->impl
.mem
.pos
) ||
1149 mio
->impl
.mem
.pos
+ (size_t)offset
> mio
->impl
.mem
.size
)
1155 mio
->impl
.mem
.pos
= (size_t)(mio
->impl
.mem
.pos
+ offset
);
1161 if (offset
> 0 || (size_t)-offset
> mio
->impl
.mem
.size
)
1165 mio
->impl
.mem
.pos
= mio
->impl
.mem
.size
- (size_t)-offset
;
1175 mio
->impl
.mem
.eof
= false;
1176 mio
->impl
.mem
.ungetch
= EOF
;
1183 AssertNotReached ();
1191 * @mio: A #MIO object
1193 * Gets the current cursor position of a #MIO stream. This function behaves the
1196 * Returns: The current offset from the start of the stream, or -1 or error, in
1197 * which case errno is set to indicate the error.
1199 long mio_tell (MIO
*mio
)
1201 if (mio
->type
== MIO_TYPE_FILE
)
1202 return ftell (mio
->impl
.file
.fp
);
1203 else if (mio
->type
== MIO_TYPE_MEMORY
)
1207 if (mio
->impl
.mem
.pos
> LONG_MAX
)
1214 rv
= (long)mio
->impl
.mem
.pos
;
1220 AssertNotReached ();
1227 * @mio: A #MIO object
1229 * Resets the cursor position to 0, and also the end-of-stream and the error
1230 * indicators of a #MIO stream.
1231 * See also mio_seek() and mio_clearerr().
1233 void mio_rewind (MIO
*mio
)
1235 if (mio
->type
== MIO_TYPE_FILE
)
1236 rewind (mio
->impl
.file
.fp
);
1237 else if (mio
->type
== MIO_TYPE_MEMORY
)
1239 mio
->impl
.mem
.pos
= 0;
1240 mio
->impl
.mem
.ungetch
= EOF
;
1241 mio
->impl
.mem
.eof
= false;
1242 mio
->impl
.mem
.error
= false;
1245 AssertNotReached ();
1250 * @mio: A #MIO stream
1251 * @pos: (out): A #MIOPos object to fill-in
1253 * Stores the current position (and maybe other informations about the stream
1254 * state) of a #MIO stream in order to restore it later with mio_setpos(). This
1255 * function behaves the same as fgetpos().
1257 * Returns: 0 on success, -1 otherwise, in which case errno is set to indicate
1260 int mio_getpos (MIO
*mio
, MIOPos
*pos
)
1264 pos
->type
= mio
->type
;
1265 if (mio
->type
== MIO_TYPE_FILE
)
1266 rv
= fgetpos (mio
->impl
.file
.fp
, &pos
->impl
.file
);
1267 else if (mio
->type
== MIO_TYPE_MEMORY
)
1271 if (mio
->impl
.mem
.pos
== (size_t)-1)
1273 /* this happens if ungetc() was called at the start of the stream */
1280 pos
->impl
.mem
= mio
->impl
.mem
.pos
;
1292 #endif /* MIO_DEBUG */
1299 * @mio: A #MIO object
1300 * @pos: (in): A #MIOPos object filled-in by a previous call of mio_getpos() on
1303 * Restores the position and state indicators of a #MIO stream previously saved
1306 * <warning><para>The #MIOPos object must have been initialized by a previous
1307 * call to mio_getpos() on the same stream.</para></warning>
1309 * Returns: 0 on success, -1 otherwise, in which case errno is set to indicate
1312 int mio_setpos (MIO
*mio
, MIOPos
*pos
)
1317 if (pos
->tag
!= mio
)
1319 g_critical ("mio_setpos((MIO*)%p, (MIOPos*)%p): "
1320 "Given MIOPos was not set by a previous call to mio_getpos() "
1321 "on the same MIO object, which means there is a bug in "
1323 (void *)mio
, (void *)pos
);
1327 #endif /* MIO_DEBUG */
1329 if (mio
->type
== MIO_TYPE_FILE
)
1330 rv
= fsetpos (mio
->impl
.file
.fp
, &pos
->impl
.file
);
1331 else if (mio
->type
== MIO_TYPE_MEMORY
)
1335 if (pos
->impl
.mem
> mio
->impl
.mem
.size
)
1339 mio
->impl
.mem
.ungetch
= EOF
;
1340 mio
->impl
.mem
.pos
= pos
->impl
.mem
;
1345 AssertNotReached ();
1352 * @mio: A #MIO object
1354 * Forces a write of all user-space buffered data for the given output or update
1355 * stream via the stream's underlying write function. Only applicable when using
1358 * Returns: 0 on success, error code otherwise.
1360 int mio_flush (MIO
*mio
)
1362 if (mio
->type
== MIO_TYPE_FILE
)
1363 return fflush (mio
->impl
.file
.fp
);
1369 * mio_attach_user_data:
1370 * @mio: A #MIO object
1371 * @user_data: a pointer to any data object
1372 * @user_data_free_func: a call back function to destroy the data object passed as @user_data
1374 * Attach any data object to a #MIO object. Attached data can be got with
1375 * mio_get_user_data(). The attached data is destroyed when new data is attached to
1376 * the #MIO object, or #the MIO object itself is destroyed. For destroying the data
1377 * @user_data_free_func is used.
1381 void mio_attach_user_data (MIO
*mio
, void *user_data
, MIODestroyNotify user_data_free_func
)
1383 if (mio
->udata
.d
&& mio
->udata
.f
)
1384 mio
->udata
.f (mio
->udata
.d
);
1386 mio
->udata
.d
= user_data
;
1387 mio
->udata
.f
= user_data_free_func
;
1391 * mio_get_user_data:
1392 * @mio: A #MIO object
1394 * Returns: user data attached with mio_attach_user_data() to a #MIO object.
1397 void *mio_get_user_data (MIO
*mio
)
1399 return mio
->udata
.d
;