Update NEWS with the latest changes
[geany-mirror.git] / ctags / main / mio.c
blobf7755e708d50e6d989f75c7b60a1f6b711156b80
1 /*
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.
21 #include "mio.h"
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <limits.h>
30 /* minimal reallocation chunk size */
31 #define MIO_CHUNK_SIZE 4096
33 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
36 /**
37 * SECTION:mio
38 * @short_description: The MIO object
39 * @include: mio/mio.h
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
49 * mio_new_fp().
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
53 * operations.
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
57 * object to work on.
61 /**
62 * mio_new_file_full:
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
65 * argument
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
69 * object
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,
87 const char *mode,
88 MIOFOpenFunc open_func,
89 MIOFCloseFunc close_func)
91 MIO *mio;
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);
97 if (mio)
99 FILE *fp = open_func (filename, mode);
101 if (! fp)
103 free (mio);
104 mio = NULL;
106 else
108 mio->type = MIO_TYPE_FILE;
109 mio->impl.file.fp = fp;
110 mio->impl.file.close_func = close_func;
114 return mio;
118 * mio_new_file:
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
123 * fopen().
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);
137 * mio_new_fp:
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
143 * object.
145 * <example>
146 * <title>Typical use of this function</title>
147 * <programlisting>
148 * MIO *mio = mio_new_fp (fp, fclose);
149 * </programlisting>
150 * </example>
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)
158 MIO *mio;
160 if (!fp)
161 return NULL;
163 mio = malloc (sizeof *mio);
164 if (mio)
166 mio->type = MIO_TYPE_FILE;
167 mio->impl.file.fp = fp;
168 mio->impl.file.close_func = close_func;
171 return mio;
175 * mio_new_memory:
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
190 * termination.
192 * <example>
193 * <title>Basic creation of a non-growable, freeable #MIO object</title>
194 * <programlisting>
195 * MIO *mio = mio_new_memory (data, size, NULL, g_free);
196 * </programlisting>
197 * </example>
199 * <example>
200 * <title>Basic creation of an empty growable and freeable #MIO object</title>
201 * <programlisting>
202 * MIO *mio = mio_new_memory (NULL, 0, g_try_realloc, g_free);
203 * </programlisting>
204 * </example>
206 * Free-function: mio_free()
208 * Returns: A new #MIO on success, or %NULL on failure.
210 MIO *mio_new_memory (unsigned char *data,
211 size_t size,
212 MIOReallocFunc realloc_func,
213 MIODestroyNotify free_func)
215 MIO *mio;
217 mio = malloc (sizeof *mio);
218 if (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;
232 return mio;
236 * mio_file_get_fp:
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)
250 FILE *fp = NULL;
252 if (mio->type == MIO_TYPE_FILE)
253 fp = mio->impl.file.fp;
255 return fp;
259 * mio_memory_get_data:
260 * @mio: A #MIO object
261 * @size: (allow-none) (out): Return location for the length of the returned
262 * memory, or %NULL
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;
280 if (size)
281 *size = mio->impl.mem.size;
284 return ptr;
288 * mio_free:
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)
297 int rv = 0;
299 if (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;
308 else
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;
322 free (mio);
325 return rv;
329 * mio_read:
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,
344 void *ptr_,
345 size_t size,
346 size_t nmemb)
348 if (mio->type == MIO_TYPE_FILE)
349 return fread (ptr_, size, nmemb, mio->impl.file.fp);
350 else
352 size_t n_read = 0;
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;
363 if (copy_bytes > 0)
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;
371 copy_bytes--;
372 mio->impl.mem.pos++;
373 ptr++;
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;
383 return n_read;
388 * mem_try_resize:
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)
399 int success = false;
401 if (mio->impl.mem.realloc_func)
403 if (new_size == ULONG_MAX)
405 #ifdef EOVERFLOW
406 errno = EOVERFLOW;
407 #endif
409 else
411 if (new_size > mio->impl.mem.size)
413 if (new_size <= mio->impl.mem.allocated_size)
415 mio->impl.mem.size = new_size;
416 success = true;
418 else
420 size_t newsize;
421 unsigned char *newbuf;
423 newsize = MAX (mio->impl.mem.allocated_size + MIO_CHUNK_SIZE,
424 new_size);
425 newbuf = mio->impl.mem.realloc_func (mio->impl.mem.buf, newsize);
426 if (newbuf)
428 mio->impl.mem.buf = newbuf;
429 mio->impl.mem.allocated_size = newsize;
430 mio->impl.mem.size = new_size;
431 success = true;
435 else
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;
445 success = true;
451 return success;
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)
466 int success = true;
468 if (mio->impl.mem.pos + n > mio->impl.mem.size)
469 success = mem_try_resize (mio, mio->impl.mem.pos + n);
471 return success;
475 * mio_write:
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,
487 const void *ptr,
488 size_t size,
489 size_t nmemb)
491 if (mio->type == MIO_TYPE_FILE)
492 return fwrite (ptr, size, nmemb, mio->impl.file.fp);
493 else
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;
503 n_written = nmemb;
507 return n_written;
512 * mio_putc:
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
517 * fputc().
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);
525 else
527 int rv = EOF;
529 if (mem_try_ensure_space (mio, 1))
531 mio->impl.mem.buf[mio->impl.mem.pos] = (unsigned char)c;
532 mio->impl.mem.pos++;
533 rv = (int)((unsigned char)c);
536 return rv;
541 * mio_puts:
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);
553 else
555 int rv = EOF;
556 size_t len;
558 len = strlen (s);
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;
563 rv = 1;
566 return rv;
571 * mio_vprintf:
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
577 * as vfprintf().
579 * Returns: The number of bytes written in the stream, or a negative value on
580 * failure.
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);
586 else
588 int rv = -1;
589 size_t n;
590 size_t old_pos;
591 size_t old_size;
592 va_list ap_copy;
593 char dummy;
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);
600 va_end (ap_copy);
601 if (mem_try_ensure_space (mio, n))
603 unsigned char c;
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;
617 else
619 mio->impl.mem.size = old_size;
620 rv = -1;
624 return rv;
629 * mio_printf:
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
635 * fprintf().
637 * Returns: The number of bytes written to the stream, or a negative value on
638 * failure.
640 int mio_printf (MIO *mio, const char *format, ...)
642 int rv;
643 va_list ap;
645 va_start (ap, format);
646 rv = mio_vprintf (mio, format, ap);
647 va_end (ap);
649 return rv;
653 * mio_getc:
654 * @mio: A #MIO object
656 * Gets the current character from a #MIO stream. This function behaves the same
657 * as fgetc().
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);
665 else
667 int rv = EOF;
669 if (mio->impl.mem.ungetch != EOF)
671 rv = mio->impl.mem.ungetch;
672 mio->impl.mem.ungetch = EOF;
673 mio->impl.mem.pos++;
675 else if (mio->impl.mem.pos < mio->impl.mem.size)
677 rv = mio->impl.mem.buf[mio->impl.mem.pos];
678 mio->impl.mem.pos++;
680 else
681 mio->impl.mem.eof = true;
683 return rv;
688 * mio_ungetc:
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
693 * ungetc().
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);
707 else
709 int rv = EOF;
711 if (ch != EOF && mio->impl.mem.ungetch == EOF)
713 rv = mio->impl.mem.ungetch = ch;
714 mio->impl.mem.pos--;
715 mio->impl.mem.eof = false;
718 return rv;
723 * mio_gets:
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
730 * fgets().
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);
738 else
740 char *rv = NULL;
742 if (size > 0)
744 size_t i = 0;
746 if (mio->impl.mem.ungetch != EOF)
748 s[i] = (char)mio->impl.mem.ungetch;
749 mio->impl.mem.ungetch = EOF;
750 mio->impl.mem.pos++;
751 i++;
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];
756 mio->impl.mem.pos++;
757 if (s[i] == '\n')
759 i++;
760 break;
763 if (i > 0)
765 s[i] = 0;
766 rv = s;
768 if (mio->impl.mem.pos >= mio->impl.mem.size)
769 mio->impl.mem.eof = true;
772 return rv;
777 * mio_clearerr:
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);
787 else
789 mio->impl.mem.error = false;
790 mio->impl.mem.eof = false;
795 * mio_eof:
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);
807 else
808 return mio->impl.mem.eof != false;
812 * mio_error:
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);
824 else
825 return mio->impl.mem.error != false;
829 * mio_seek:
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
834 * stream.
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);
846 else
848 /* FIXME: should we support seeking out of bounds like lseek() seems to do? */
849 int rv = -1;
851 switch (whence)
853 case SEEK_SET:
854 if (offset < 0 || (size_t)offset > mio->impl.mem.size)
855 errno = EINVAL;
856 else
858 mio->impl.mem.pos = (size_t)offset;
859 rv = 0;
861 break;
863 case SEEK_CUR:
864 if ((offset < 0 && (size_t)-offset > mio->impl.mem.pos) ||
865 mio->impl.mem.pos + (size_t)offset > mio->impl.mem.size)
867 errno = EINVAL;
869 else
871 mio->impl.mem.pos = (size_t)(mio->impl.mem.pos + offset);
872 rv = 0;
874 break;
876 case SEEK_END:
877 if (offset > 0 || (size_t)-offset > mio->impl.mem.size)
878 errno = EINVAL;
879 else
881 mio->impl.mem.pos = mio->impl.mem.size - (size_t)-offset;
882 rv = 0;
884 break;
886 default:
887 errno = EINVAL;
889 if (rv == 0)
891 mio->impl.mem.eof = false;
892 mio->impl.mem.ungetch = EOF;
895 return rv;
900 * mio_tell:
901 * @mio: A #MIO object
903 * Gets the current cursor position of a #MIO stream. This function behaves the
904 * same as ftell().
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);
913 else
915 long rv = -1;
917 if (mio->impl.mem.pos > LONG_MAX)
919 #ifdef EOVERFLOW
920 errno = EOVERFLOW;
921 #endif
923 else
924 rv = (long)mio->impl.mem.pos;
926 return rv;
931 * mio_rewind:
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);
942 else
944 mio->impl.mem.pos = 0;
945 mio->impl.mem.ungetch = EOF;
946 mio->impl.mem.eof = false;
947 mio->impl.mem.error = false;
952 * mio_getpos:
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
961 * the error.
963 int mio_getpos (MIO *mio, MIOPos *pos)
965 int rv = -1;
967 pos->type = mio->type;
968 if (mio->type == MIO_TYPE_FILE)
969 rv = fgetpos (mio->impl.file.fp, &pos->impl.file);
970 else
972 rv = -1;
974 if (mio->impl.mem.pos == (size_t)-1)
976 /* this happens if ungetc() was called at the start of the stream */
977 #ifdef EIO
978 errno = EIO;
979 #endif
981 else
983 pos->impl.mem = mio->impl.mem.pos;
984 rv = 0;
987 #ifdef MIO_DEBUG
988 if (rv != -1)
990 pos->tag = mio;
992 #endif /* MIO_DEBUG */
994 return rv;
998 * mio_setpos:
999 * @mio: A #MIO object
1000 * @pos: (in): A #MIOPos object filled-in by a previous call of mio_getpos() on
1001 * the same stream
1003 * Restores the position and state indicators of a #MIO stream previously saved
1004 * by mio_getpos().
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
1010 * the error.
1012 int mio_setpos (MIO *mio, MIOPos *pos)
1014 int rv = -1;
1016 #ifdef MIO_DEBUG
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 "
1022 "someone's code.",
1023 (void *)mio, (void *)pos);
1024 errno = EINVAL;
1025 return -1;
1027 #endif /* MIO_DEBUG */
1029 if (mio->type == MIO_TYPE_FILE)
1030 rv = fsetpos (mio->impl.file.fp, &pos->impl.file);
1031 else
1033 rv = -1;
1035 if (pos->impl.mem > mio->impl.mem.size)
1036 errno = EINVAL;
1037 else
1039 mio->impl.mem.ungetch = EOF;
1040 mio->impl.mem.pos = pos->impl.mem;
1041 rv = 0;
1045 return rv;
1049 * mio_flush:
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
1054 * FILE back-end.
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);
1062 return 0;