Don't comment global content unless it is Conf
[geany-mirror.git] / ctags / main / mio.c
blob59a3030f1302827dbef7e3a712adfb7ea4c35a41
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 #ifndef READTAGS_DSL
22 #include "general.h" /* must always come first */
24 #include "routines.h"
25 #include "debug.h"
26 #else
28 #if defined (HAVE_CONFIG_H)
29 #include <config.h>
30 #endif
32 #ifdef HAVE_STDBOOL_H
33 #include <stdbool.h>
34 #endif
35 #endif /* READTAGS_DSL */
37 #include "mio.h"
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <stdlib.h>
44 #include <limits.h>
46 #ifndef _MSC_VER
47 #define MAY_HAVE_FTRUNCATE
48 #include <unistd.h>
49 #endif
51 #ifdef READTAGS_DSL
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);
59 if (buffer == NULL)
61 fprintf(stderr, "out of memory");
62 abort ();
65 return buffer;
68 static void *eRealloc (void *const ptr, const size_t size)
70 void *buffer;
71 if (ptr == NULL)
72 buffer = eMalloc (size);
73 else
75 buffer = realloc (ptr, size);
76 if (buffer == NULL)
78 fprintf(stderr, "out of memory");
79 abort ();
82 return buffer;
85 static void eFree (void *const ptr)
87 free (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))
102 * SECTION:mio
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
117 * mio_new_fp().
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
121 * operations.
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
125 * object to work on.
129 typedef struct _MIOUserData MIOUserData;
130 struct _MIOUserData {
131 void *d;
132 MIODestroyNotify f;
136 * MIO:
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.
141 struct _MIO {
142 /*< private >*/
143 MIOType type;
144 unsigned int refcount;
145 union {
146 struct {
147 FILE *fp;
148 MIOFCloseFunc close_func;
149 } file;
150 struct {
151 unsigned char *buf;
152 int ungetch;
153 size_t pos;
154 size_t size;
155 size_t allocated_size;
156 MIOReallocFunc realloc_func;
157 MIODestroyNotify free_func;
158 bool error;
159 bool eof;
160 } mem;
161 } impl;
162 MIOUserData udata;
167 * mio_new_file_full:
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
170 * argument
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
174 * object
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,
192 const char *mode,
193 MIOFOpenFunc open_func,
194 MIOFCloseFunc close_func)
196 MIO *mio;
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);
202 if (mio)
204 FILE *fp = open_func (filename, mode);
206 if (! fp)
208 eFree (mio);
209 mio = NULL;
211 else
213 mio->type = MIO_TYPE_FILE;
214 mio->impl.file.fp = fp;
215 mio->impl.file.close_func = close_func;
216 mio->refcount = 1;
217 mio->udata.d = NULL;
218 mio->udata.f = NULL;
222 return mio;
226 * mio_new_file:
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
231 * fopen().
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);
245 * mio_new_fp:
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
251 * object.
253 * <example>
254 * <title>Typical use of this function</title>
255 * <programlisting>
256 * MIO *mio = mio_new_fp (fp, fclose);
257 * </programlisting>
258 * </example>
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)
266 MIO *mio;
268 if (!fp)
269 return NULL;
271 mio = xMalloc (1, MIO);
272 if (mio)
274 mio->type = MIO_TYPE_FILE;
275 mio->impl.file.fp = fp;
276 mio->impl.file.close_func = close_func;
277 mio->refcount = 1;
278 mio->udata.d = NULL;
279 mio->udata.f = NULL;
282 return mio;
286 * mio_new_memory:
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
301 * termination.
303 * <example>
304 * <title>Basic creation of a non-growable, freeable #MIO object</title>
305 * <programlisting>
306 * MIO *mio = mio_new_memory (data, size, NULL, g_free);
307 * </programlisting>
308 * </example>
310 * <example>
311 * <title>Basic creation of an empty growable and freeable #MIO object</title>
312 * <programlisting>
313 * MIO *mio = mio_new_memory (NULL, 0, g_try_realloc, g_free);
314 * </programlisting>
315 * </example>
317 * Free-function: mio_unref()
319 * Returns: A new #MIO on success, or %NULL on failure.
321 MIO *mio_new_memory (unsigned char *data,
322 size_t size,
323 MIOReallocFunc realloc_func,
324 MIODestroyNotify free_func)
326 MIO *mio;
328 mio = xMalloc (1, MIO);
329 if (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;
341 mio->refcount = 1;
342 mio->udata.d = NULL;
343 mio->udata.f = NULL;
346 return mio;
350 * mio_new_mio:
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)
371 unsigned char *data;
372 long original_pos;
373 MIO *submio;
374 size_t r;
376 original_pos = mio_tell (base);
378 if (size == -1)
380 long end;
382 if (mio_seek (base, 0, SEEK_END) != 0)
383 return NULL;
384 end = mio_tell (base);
385 Assert (end >= start);
386 size = end - start;
389 if (mio_seek (base, start, SEEK_SET) != 0)
390 return NULL;
392 data = xMalloc (size, unsigned char);
393 r= mio_read (base, data, 1, size);
394 mio_seek (base, original_pos, SEEK_SET);
396 if (r != size)
397 goto cleanup;
399 submio = mio_new_memory (data, size, eRealloc, eFreeNoNullCheck);
400 if (! submio)
401 goto cleanup;
403 return submio;
405 cleanup:
406 eFree (data);
407 return NULL;
411 * mio_ref:
412 * @mio: A #MIO object
414 * Increments the reference counter of a #MIO.
416 * Returns: passed @mio.
418 MIO *mio_ref (MIO *mio)
420 mio->refcount++;
421 return mio;
425 * mio_file_get_fp:
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)
439 FILE *fp = NULL;
441 if (mio->type == MIO_TYPE_FILE)
442 fp = mio->impl.file.fp;
444 return fp;
448 * mio_memory_get_data:
449 * @mio: A #MIO object
450 * @size: (allow-none) (out): Return location for the length of the returned
451 * memory, or %NULL
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;
469 if (size)
470 *size = mio->impl.mem.size;
473 return ptr;
477 * mio_unref:
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)
487 int rv = 0;
489 if (mio)
491 if (--mio->refcount)
492 return 0;
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;
517 else
518 AssertNotReached ();
520 eFree (mio);
523 return rv;
527 * mio_read:
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,
542 void *ptr_,
543 size_t size,
544 size_t nmemb)
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)
550 size_t n_read = 0;
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;
561 if (copy_bytes > 0)
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;
569 copy_bytes--;
570 mio->impl.mem.pos++;
571 ptr++;
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;
581 return n_read;
583 else
585 AssertNotReached ();
586 return 0;
591 * mem_try_resize:
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)
602 int success = false;
604 if (mio->impl.mem.realloc_func)
606 if (new_size == ULONG_MAX)
608 #ifdef EOVERFLOW
609 errno = EOVERFLOW;
610 #endif
612 else
614 if (new_size > mio->impl.mem.size)
616 if (new_size <= mio->impl.mem.allocated_size)
618 mio->impl.mem.size = new_size;
619 success = true;
621 else
623 size_t newsize;
624 unsigned char *newbuf;
626 newsize = MAX (mio->impl.mem.allocated_size + MIO_CHUNK_SIZE,
627 new_size);
628 newbuf = mio->impl.mem.realloc_func (mio->impl.mem.buf, newsize);
629 if (newbuf)
631 mio->impl.mem.buf = newbuf;
632 mio->impl.mem.allocated_size = newsize;
633 mio->impl.mem.size = new_size;
634 success = true;
638 else
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;
648 success = true;
654 return success;
657 static int file_try_resize (MIO *mio, size_t new_size)
659 mio_flush (mio);
661 FILE *fp = mio_file_get_fp (mio);
663 #ifdef MAY_HAVE_FTRUNCATE
664 if (ftruncate(fileno(fp), (off_t)new_size) < 0)
665 return false;
666 #else
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)
669 return false;
670 #endif
671 return true;
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);
678 else
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)
694 int success = true;
696 if (mio->impl.mem.pos + n > mio->impl.mem.size)
697 success = mem_try_resize (mio, mio->impl.mem.pos + n);
699 return success;
703 * mio_write:
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,
715 const void *ptr,
716 size_t size,
717 size_t nmemb)
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;
731 n_written = nmemb;
735 return n_written;
737 else
739 AssertNotReached ();
740 return 0;
745 * mio_putc:
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
750 * fputc().
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)
760 int rv = EOF;
762 if (mem_try_ensure_space (mio, 1))
764 mio->impl.mem.buf[mio->impl.mem.pos] = (unsigned char)c;
765 mio->impl.mem.pos++;
766 rv = (int)((unsigned char)c);
769 return rv;
771 else
773 AssertNotReached ();
774 return 0;
779 * mio_puts:
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)
793 int rv = EOF;
794 size_t len;
796 len = strlen (s);
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;
801 rv = 1;
804 return rv;
806 else
808 AssertNotReached ();
809 return 0;
814 * mio_vprintf:
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
820 * as vfprintf().
822 * Returns: The number of bytes written in the stream, or a negative value on
823 * failure.
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)
831 int rv = -1;
832 size_t n;
833 size_t old_pos;
834 size_t old_size;
835 va_list ap_copy;
836 char dummy;
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;
843 va_end (ap_copy);
844 if (mem_try_ensure_space (mio, n))
846 unsigned char c;
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;
860 else
862 mio->impl.mem.size = old_size;
863 rv = -1;
867 return rv;
869 else
871 AssertNotReached ();
872 return 0;
877 * mio_printf:
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
883 * fprintf().
885 * Returns: The number of bytes written to the stream, or a negative value on
886 * failure.
888 int mio_printf (MIO *mio, const char *format, ...)
890 int rv;
891 va_list ap;
893 va_start (ap, format);
894 rv = mio_vprintf (mio, format, ap);
895 va_end (ap);
897 return rv;
901 * mio_getc:
902 * @mio: A #MIO object
904 * Gets the current character from a #MIO stream. This function behaves the same
905 * as fgetc().
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)
915 int rv = EOF;
917 if (mio->impl.mem.ungetch != EOF)
919 rv = mio->impl.mem.ungetch;
920 mio->impl.mem.ungetch = EOF;
921 mio->impl.mem.pos++;
923 else if (mio->impl.mem.pos < mio->impl.mem.size)
925 rv = mio->impl.mem.buf[mio->impl.mem.pos];
926 mio->impl.mem.pos++;
928 else
929 mio->impl.mem.eof = true;
931 return rv;
933 else
935 AssertNotReached ();
936 return 0;
941 * mio_ungetc:
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
946 * ungetc().
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)
962 int rv = EOF;
964 if (ch != EOF && mio->impl.mem.ungetch == EOF)
966 rv = mio->impl.mem.ungetch = ch;
967 mio->impl.mem.pos--;
968 mio->impl.mem.eof = false;
971 return rv;
973 else
975 AssertNotReached ();
976 return 0;
981 * mio_gets:
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
988 * fgets().
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)
998 char *rv = NULL;
1000 if (size > 0)
1002 size_t i = 0;
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;
1014 pos++;
1015 i++;
1017 for (; pos < buf_size && i < (size - 1); i++)
1019 s[i] = (char)buf[pos];
1020 pos++;
1021 if (s[i] == '\n')
1023 i++;
1024 newline = true;
1025 break;
1028 if (i > 0)
1030 s[i] = 0;
1031 rv = s;
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;
1039 return rv;
1041 else
1043 AssertNotReached ();
1044 return 0;
1049 * mio_clearerr:
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;
1064 else
1065 AssertNotReached ();
1069 * mio_eof:
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;
1083 else
1085 AssertNotReached ();
1086 return 0;
1091 * mio_error:
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;
1105 else
1107 AssertNotReached ();
1108 return 0;
1113 * mio_seek:
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
1118 * stream.
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? */
1133 int rv = -1;
1135 switch (whence)
1137 case SEEK_SET:
1138 if (offset < 0 || (size_t)offset > mio->impl.mem.size)
1139 errno = EINVAL;
1140 else
1142 mio->impl.mem.pos = (size_t)offset;
1143 rv = 0;
1145 break;
1147 case SEEK_CUR:
1148 if ((offset < 0 && (size_t)-offset > mio->impl.mem.pos) ||
1149 mio->impl.mem.pos + (size_t)offset > mio->impl.mem.size)
1151 errno = EINVAL;
1153 else
1155 mio->impl.mem.pos = (size_t)(mio->impl.mem.pos + offset);
1156 rv = 0;
1158 break;
1160 case SEEK_END:
1161 if (offset > 0 || (size_t)-offset > mio->impl.mem.size)
1162 errno = EINVAL;
1163 else
1165 mio->impl.mem.pos = mio->impl.mem.size - (size_t)-offset;
1166 rv = 0;
1168 break;
1170 default:
1171 errno = EINVAL;
1173 if (rv == 0)
1175 mio->impl.mem.eof = false;
1176 mio->impl.mem.ungetch = EOF;
1179 return rv;
1181 else
1183 AssertNotReached ();
1184 return 0;
1190 * mio_tell:
1191 * @mio: A #MIO object
1193 * Gets the current cursor position of a #MIO stream. This function behaves the
1194 * same as ftell().
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)
1205 long rv = -1;
1207 if (mio->impl.mem.pos > LONG_MAX)
1209 #ifdef EOVERFLOW
1210 errno = EOVERFLOW;
1211 #endif
1213 else
1214 rv = (long)mio->impl.mem.pos;
1216 return rv;
1218 else
1220 AssertNotReached ();
1221 return 0;
1226 * mio_rewind:
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;
1244 else
1245 AssertNotReached ();
1249 * mio_getpos:
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
1258 * the error.
1260 int mio_getpos (MIO *mio, MIOPos *pos)
1262 int rv = -1;
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)
1269 rv = -1;
1271 if (mio->impl.mem.pos == (size_t)-1)
1273 /* this happens if ungetc() was called at the start of the stream */
1274 #ifdef EIO
1275 errno = EIO;
1276 #endif
1278 else
1280 pos->impl.mem = mio->impl.mem.pos;
1281 rv = 0;
1284 else
1285 AssertNotReached();
1287 #ifdef MIO_DEBUG
1288 if (rv != -1)
1290 pos->tag = mio;
1292 #endif /* MIO_DEBUG */
1294 return rv;
1298 * mio_setpos:
1299 * @mio: A #MIO object
1300 * @pos: (in): A #MIOPos object filled-in by a previous call of mio_getpos() on
1301 * the same stream
1303 * Restores the position and state indicators of a #MIO stream previously saved
1304 * by mio_getpos().
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
1310 * the error.
1312 int mio_setpos (MIO *mio, MIOPos *pos)
1314 int rv = -1;
1316 #ifdef MIO_DEBUG
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 "
1322 "someone's code.",
1323 (void *)mio, (void *)pos);
1324 errno = EINVAL;
1325 return -1;
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)
1333 rv = -1;
1335 if (pos->impl.mem > mio->impl.mem.size)
1336 errno = EINVAL;
1337 else
1339 mio->impl.mem.ungetch = EOF;
1340 mio->impl.mem.pos = pos->impl.mem;
1341 rv = 0;
1344 else
1345 AssertNotReached ();
1347 return rv;
1351 * mio_flush:
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
1356 * FILE back-end.
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);
1364 return 0;
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;