geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

mio.c
Go to the documentation of this file.
1/*
2 * MIO, an I/O abstraction layer replicating C file I/O API.
3 * Copyright (C) 2010 Colomban Wendling <ban@herbesfolles.org>
4 *
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.
9 *
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.
14 *
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.
18 *
19 */
20
21#ifndef READTAGS_DSL
22#include "general.h" /* must always come first */
23
24#include "routines.h"
25#include "debug.h"
26#else
27
28#if defined (HAVE_CONFIG_H)
29#include <config.h>
30#endif
31
32#ifdef HAVE_STDBOOL_H
33#include <stdbool.h>
34#endif
35#endif /* READTAGS_DSL */
36
37#include "mio.h"
38
39#include <stdarg.h>
40#include <stdio.h>
41#include <string.h>
42#include <errno.h>
43#include <stdlib.h>
44#include <limits.h>
45
46#ifdef READTAGS_DSL
47#define xMalloc(n,Type) (Type *)eMalloc((size_t)(n) * sizeof (Type))
48#define xRealloc(p,n,Type) (Type *)eRealloc((p), (n) * sizeof (Type))
49
50static void *eMalloc (const size_t size)
51{
52 void *buffer = malloc (size);
53
54 if (buffer == NULL)
55 {
56 fprintf(stderr, "out of memory");
57 abort ();
58 }
59
60 return buffer;
61}
62
63static void *eRealloc (void *const ptr, const size_t size)
64{
65 void *buffer;
66 if (ptr == NULL)
67 buffer = eMalloc (size);
68 else
69 {
70 buffer = realloc (ptr, size);
71 if (buffer == NULL)
72 {
73 fprintf(stderr, "out of memory");
74 abort ();
75 }
76 }
77 return buffer;
78}
79
80static void eFree (void *const ptr)
81{
82 free (ptr);
83}
84#define eFreeNoNullCheck eFree
85
86# define Assert(c) do {} while(0)
87# define AssertNotReached() do {} while(0)
88#endif /* READTAGS_DSL */
89
90/* minimal reallocation chunk size */
91#define MIO_CHUNK_SIZE 4096
92
93#define MAX(a, b) (((a) > (b)) ? (a) : (b))
94
95
96/**
97 * SECTION:mio
98 * @short_description: The MIO object
99 * @include: mio/mio.h
100 *
101 * The #MIO object replicates the C file I/O API with support of both standard
102 * file based operations and in-memory operations. Its goal is to ease the port
103 * of an application that uses C file I/O API to perform in-memory operations.
104 *
105 * A #MIO object is created using mio_new_file(), mio_new_memory() or mio_new_mio(),
106 * depending on whether you want file or in-memory operations.
107 * Its life is managed by reference counting. Just after calling one of functions
108 * for creating, the count is 1. mio_ref() increments the counter. mio_unref()
109 * decrements it. When the counter becomes 0, the #MIO object will be destroyed
110 * in mio_unref(). There is also some other convenient API to create file-based
111 * #MIO objects for more complex cases, such as mio_new_file_full() and
112 * mio_new_fp().
113 *
114 * Once the #MIO object is created, you can perform standard I/O operations on
115 * it transparently without the need to care about the effective underlying
116 * operations.
117 *
118 * The I/O API is almost exactly a replication of the standard C file I/O API
119 * with the significant difference that the first parameter is always the #MIO
120 * object to work on.
121 */
122
123
126 void *d;
128};
129
130/**
131 * MIO:
132 *
133 * An object representing a #MIO stream. No assumptions should be made about
134 * what compose this object, and none of its fields should be accessed directly.
135 */
136struct _MIO {
137 /*< private >*/
139 unsigned int refcount;
140 union {
141 struct {
142 FILE *fp;
145 struct {
146 unsigned char *buf;
148 size_t pos;
149 size_t size;
153 bool error;
154 bool eof;
158};
159
160
161/**
162 * mio_new_file_full:
163 * @filename: Filename to open, passed as-is to @open_func as the first argument
164 * @mode: Mode in which open the file, passed as-is to @open_func as the second
165 * argument
166 * @open_func: A function with the fopen() semantic to use to open the file
167 * @close_func: A function with the fclose() semantic to close the file when
168 * the #MIO object is destroyed, or %NULL not to close the #FILE
169 * object
170 *
171 * Creates a new #MIO object working on a file, from a filename and an opening
172 * function. See also mio_new_file().
173 *
174 * This function is generally overkill and mio_new_file() should often be used
175 * instead, but it allows to specify a custom function to open a file, as well
176 * as a close function. The former is useful e.g. if you need to wrap fopen()
177 * for some reason (like filename encoding conversion for example), and the
178 * latter allows you both to match your custom open function and to choose
179 * whether the underlying #FILE object should or not be closed when mio_unref()
180 * is called on the returned object.
181 *
182 * Free-function: mio_unref()
183 *
184 * Returns: A new #MIO on success, or %NULL on failure.
185 */
187 const char *mode,
188 MIOFOpenFunc open_func,
189 MIOFCloseFunc close_func)
190{
191 MIO *mio;
192
193 /* we need to create the MIO object first, because we may not be able to close
194 * the opened file if the user passed NULL as the close function, which means
195 * that everything must succeed if we've opened the file successfully */
196 mio = xMalloc (1, MIO);
197 if (mio)
198 {
199 FILE *fp = open_func (filename, mode);
200
201 if (! fp)
202 {
203 eFree (mio);
204 mio = NULL;
205 }
206 else
207 {
208 mio->type = MIO_TYPE_FILE;
209 mio->impl.file.fp = fp;
210 mio->impl.file.close_func = close_func;
211 mio->refcount = 1;
212 mio->udata.d = NULL;
213 mio->udata.f = NULL;
214 }
215 }
216
217 return mio;
218}
219
220/**
221 * mio_new_file:
222 * @filename: Filename to open, same as the fopen()'s first argument
223 * @mode: Mode in which open the file, fopen()'s second argument
224 *
225 * Creates a new #MIO object working on a file from a filename; wrapping
226 * fopen().
227 * This function simply calls mio_new_file_full() with the libc's fopen() and
228 * fclose() functions.
229 *
230 * Free-function: mio_unref()
231 *
232 * Returns: A new #MIO on success, or %NULL on failure.
233 */
234MIO *mio_new_file (const char *filename, const char *mode)
235{
236 return mio_new_file_full (filename, mode, fopen, fclose);
237}
238
239/**
240 * mio_new_fp:
241 * @fp: An opened #FILE object
242 * @close_func: (allow-none): Function used to close @fp when the #MIO object
243 * gets destroyed, or %NULL not to close the #FILE object
244 *
245 * Creates a new #MIO object working on a file, from an already opened #FILE
246 * object.
247 *
248 * <example>
249 * <title>Typical use of this function</title>
250 * <programlisting>
251 * MIO *mio = mio_new_fp (fp, fclose);
252 * </programlisting>
253 * </example>
254 *
255 * Free-function: mio_unref()
256 *
257 * Returns: A new #MIO on success or %NULL on failure.
258 */
259MIO *mio_new_fp (FILE *fp, MIOFCloseFunc close_func)
260{
261 MIO *mio;
262
263 if (!fp)
264 return NULL;
265
266 mio = xMalloc (1, MIO);
267 if (mio)
268 {
269 mio->type = MIO_TYPE_FILE;
270 mio->impl.file.fp = fp;
271 mio->impl.file.close_func = close_func;
272 mio->refcount = 1;
273 mio->udata.d = NULL;
274 mio->udata.f = NULL;
275 }
276
277 return mio;
278}
279
280/**
281 * mio_new_memory:
282 * @data: Initial data (may be %NULL)
283 * @size: Length of @data in bytes
284 * @realloc_func: A function with the realloc() semantic used to grow the
285 * buffer, or %NULL to disable buffer growing
286 * @free_func: A function with the free() semantic to destroy the data together
287 * with the object, or %NULL not to destroy the data
288 *
289 * Creates a new #MIO object working on memory.
290 *
291 * To allow the buffer to grow, you must provide a @realloc_func, otherwise
292 * trying to write after the end of the current data will fail.
293 *
294 * If you want the buffer to be freed together with the #MIO object, you must
295 * give a @free_func; otherwise the data will still live after #MIO object
296 * termination.
297 *
298 * <example>
299 * <title>Basic creation of a non-growable, freeable #MIO object</title>
300 * <programlisting>
301 * MIO *mio = mio_new_memory (data, size, NULL, g_free);
302 * </programlisting>
303 * </example>
304 *
305 * <example>
306 * <title>Basic creation of an empty growable and freeable #MIO object</title>
307 * <programlisting>
308 * MIO *mio = mio_new_memory (NULL, 0, g_try_realloc, g_free);
309 * </programlisting>
310 * </example>
311 *
312 * Free-function: mio_unref()
313 *
314 * Returns: A new #MIO on success, or %NULL on failure.
315 */
316MIO *mio_new_memory (unsigned char *data,
317 size_t size,
318 MIOReallocFunc realloc_func,
319 MIODestroyNotify free_func)
320{
321 MIO *mio;
322
323 mio = xMalloc (1, MIO);
324 if (mio)
325 {
326 mio->type = MIO_TYPE_MEMORY;
327 mio->impl.mem.buf = data;
328 mio->impl.mem.ungetch = EOF;
329 mio->impl.mem.pos = 0;
330 mio->impl.mem.size = size;
331 mio->impl.mem.allocated_size = size;
332 mio->impl.mem.realloc_func = realloc_func;
333 mio->impl.mem.free_func = free_func;
334 mio->impl.mem.eof = false;
335 mio->impl.mem.error = false;
336 mio->refcount = 1;
337 mio->udata.d = NULL;
338 mio->udata.f = NULL;
339 }
340
341 return mio;
342}
343
344/**
345 * mio_new_mio:
346 * @base: The original mio
347 * @start: stream offset of the @base where new mio starts
348 * @size: the length of the data copied from @base to new mio
349 *
350 * Creates a new #MIO object by copying data from existing #MIO (@base).
351 * The range for copying is given with @start and @size.
352 * Copying data at the range from @start to the end of @base is
353 * done if -1 is given as @size.
354 *
355 * If @size is larger than the length from @start to the end of
356 * @base, %NULL is returned.
357 *
358 * The function doesn't move the file position of @base.
359 *
360 * Free-function: mio_unref()
361 *
362 */
363
364MIO *mio_new_mio (MIO *base, long start, long size)
365{
366 unsigned char *data;
367 long original_pos;
368 MIO *submio;
369 size_t r;
370
371 original_pos = mio_tell (base);
372
373 if (size == -1)
374 {
375 long end;
376
377 if (mio_seek (base, 0, SEEK_END) != 0)
378 return NULL;
379 end = mio_tell (base);
380 Assert (end >= start);
381 size = end - start;
382 }
383
384 if (mio_seek (base, start, SEEK_SET) != 0)
385 return NULL;
386
387 data = xMalloc (size, unsigned char);
388 r= mio_read (base, data, 1, size);
389 mio_seek (base, original_pos, SEEK_SET);
390
391 if (r != size)
392 goto cleanup;
393
394 submio = mio_new_memory (data, size, eRealloc, eFreeNoNullCheck);
395 if (! submio)
396 goto cleanup;
397
398 return submio;
399
400cleanup:
401 eFree (data);
402 return NULL;
403}
404
405/**
406 * mio_ref:
407 * @mio: A #MIO object
408 *
409 * Increments the reference counter of a #MIO.
410 *
411 * Returns: passed @mio.
412 */
414{
415 mio->refcount++;
416 return mio;
417}
418
419/**
420 * mio_file_get_fp:
421 * @mio: A #MIO object
422 *
423 * Gets the underlying #FILE object associated with a #MIO file stream.
424 *
425 * <warning><para>The returned object may become invalid after a call to
426 * mio_unref() if the stream was configured to close the file when
427 * destroyed.</para></warning>
428 *
429 * Returns: The underlying #FILE object of the given stream, or %NULL if the
430 * stream is not a file stream.
431 */
433{
434 FILE *fp = NULL;
435
436 if (mio->type == MIO_TYPE_FILE)
437 fp = mio->impl.file.fp;
438
439 return fp;
440}
441
442/**
443 * mio_memory_get_data:
444 * @mio: A #MIO object
445 * @size: (allow-none) (out): Return location for the length of the returned
446 * memory, or %NULL
447 *
448 * Gets the underlying memory buffer associated with a #MIO memory stream.
449 *
450 * <warning><para>The returned pointer and size may become invalid after a
451 * successful write on the stream or after a call to mio_unref() if the stream
452 * was configured to free the memory when destroyed.</para></warning>
453 *
454 * Returns: The memory buffer of the given #MIO stream, or %NULL if the stream
455 * is not a memory stream.
456 */
457unsigned char *mio_memory_get_data (MIO *mio, size_t *size)
458{
459 unsigned char *ptr = NULL;
460
461 if (mio->type == MIO_TYPE_MEMORY)
462 {
463 ptr = mio->impl.mem.buf;
464 if (size)
465 *size = mio->impl.mem.size;
466 }
467
468 return ptr;
469}
470
471/**
472 * mio_unref:
473 * @mio: A #MIO object
474 *
475 * Decrements the reference counter of a #MIO and destroys the #MIO
476 * object if its counter becomes 0.
477 *
478 * Returns: Error code obtained from the registered MIOFCloseFunc or 0 on success.
479 */
480int mio_unref (MIO *mio)
481{
482 int rv = 0;
483
484 if (mio)
485 {
486 if (--mio->refcount)
487 return 0;
488
489 if (mio->udata.d && mio->udata.f)
490 mio->udata.f (mio->udata.d);
491
492 if (mio->type == MIO_TYPE_FILE)
493 {
494 if (mio->impl.file.close_func)
495 rv = mio->impl.file.close_func (mio->impl.file.fp);
496 mio->impl.file.close_func = NULL;
497 mio->impl.file.fp = NULL;
498 }
499 else if (mio->type == MIO_TYPE_MEMORY)
500 {
501 if (mio->impl.mem.free_func)
502 mio->impl.mem.free_func (mio->impl.mem.buf);
503 mio->impl.mem.buf = NULL;
504 mio->impl.mem.pos = 0;
505 mio->impl.mem.size = 0;
506 mio->impl.mem.allocated_size = 0;
507 mio->impl.mem.realloc_func = NULL;
508 mio->impl.mem.free_func = NULL;
509 mio->impl.mem.eof = false;
510 mio->impl.mem.error = false;
511 }
512 else
514
515 eFree (mio);
516 }
517
518 return rv;
519}
520
521/**
522 * mio_read:
523 * @mio: A #MIO object
524 * @ptr: Pointer to the memory to fill with the read data
525 * @size: Size of each block to read
526 * @nmemb: Number o blocks to read
527 *
528 * Reads raw data from a #MIO stream. This function behave the same as fread().
529 *
530 * Returns: The number of actually read blocks. If an error occurs or if the
531 * end of the stream is reached, the return value may be smaller than
532 * the requested block count, or even 0. This function doesn't
533 * distinguish between end-of-stream and an error, you should then use
534 * mio_eof() and mio_error() to determine which occurred.
535 */
536size_t mio_read (MIO *mio,
537 void *ptr_,
538 size_t size,
539 size_t nmemb)
540{
541 if (mio->type == MIO_TYPE_FILE)
542 return fread (ptr_, size, nmemb, mio->impl.file.fp);
543 else if (mio->type == MIO_TYPE_MEMORY)
544 {
545 size_t n_read = 0;
546
547 if (size != 0 && nmemb != 0)
548 {
549 size_t size_avail = mio->impl.mem.size - mio->impl.mem.pos;
550 size_t copy_bytes = size * nmemb;
551 unsigned char *ptr = ptr_;
552
553 if (size_avail < copy_bytes)
554 copy_bytes = size_avail;
555
556 if (copy_bytes > 0)
557 {
558 n_read = copy_bytes / size;
559
560 if (mio->impl.mem.ungetch != EOF)
561 {
562 *ptr = (unsigned char) mio->impl.mem.ungetch;
563 mio->impl.mem.ungetch = EOF;
564 copy_bytes--;
565 mio->impl.mem.pos++;
566 ptr++;
567 }
568
569 memcpy (ptr, &mio->impl.mem.buf[mio->impl.mem.pos], copy_bytes);
570 mio->impl.mem.pos += copy_bytes;
571 }
572 if (mio->impl.mem.pos >= mio->impl.mem.size)
573 mio->impl.mem.eof = true;
574 }
575
576 return n_read;
577 }
578 else
579 {
581 return 0;
582 }
583}
584
585/*
586 * mem_try_resize:
587 * @mio: A #MIO object of the type %MIO_TYPE_MEMORY
588 * @new_size: Requested new size
589 *
590 * Tries to resize the underlying buffer of an in-memory #MIO object.
591 * This supports both growing and shrinking.
592 *
593 * Returns: %true on success, %false otherwise.
594 */
595static int mem_try_resize (MIO *mio, size_t new_size)
596{
597 int success = false;
598
599 if (mio->impl.mem.realloc_func)
600 {
601 if (new_size == ULONG_MAX)
602 {
603#ifdef EOVERFLOW
604 errno = EOVERFLOW;
605#endif
606 }
607 else
608 {
609 if (new_size > mio->impl.mem.size)
610 {
611 if (new_size <= mio->impl.mem.allocated_size)
612 {
613 mio->impl.mem.size = new_size;
614 success = true;
615 }
616 else
617 {
618 size_t newsize;
619 unsigned char *newbuf;
620
621 newsize = MAX (mio->impl.mem.allocated_size + MIO_CHUNK_SIZE,
622 new_size);
623 newbuf = mio->impl.mem.realloc_func (mio->impl.mem.buf, newsize);
624 if (newbuf)
625 {
626 mio->impl.mem.buf = newbuf;
627 mio->impl.mem.allocated_size = newsize;
628 mio->impl.mem.size = new_size;
629 success = true;
630 }
631 }
632 }
633 else
634 {
635 unsigned char *newbuf;
636
637 newbuf = mio->impl.mem.realloc_func (mio->impl.mem.buf, new_size);
638 if (newbuf || new_size == 0)
639 {
640 mio->impl.mem.buf = newbuf;
641 mio->impl.mem.allocated_size = new_size;
642 mio->impl.mem.size = new_size;
643 success = true;
644 }
645 }
646 }
647 }
648
649 return success;
650}
651
652int mio_try_resize (MIO *mio, size_t new_size)
653{
654 return mem_try_resize (mio, new_size);
655}
656
657/*
658 * mem_try_ensure_space:
659 * @mio: A #MIO object
660 * @n: Requested size from the current (cursor) position
661 *
662 * Tries to ensure there is enough space for @n bytes to be written from the
663 * current cursor position.
664 *
665 * Returns: %true if there is enough space, %false otherwise.
666 */
667static int mem_try_ensure_space (MIO *mio, size_t n)
668{
669 int success = true;
670
671 if (mio->impl.mem.pos + n > mio->impl.mem.size)
672 success = mem_try_resize (mio, mio->impl.mem.pos + n);
673
674 return success;
675}
676
677/**
678 * mio_write:
679 * @mio: A #MIO object
680 * @ptr: Pointer to the memory to write on the stream
681 * @size: Size of each block to write
682 * @nmemb: Number of block to write
683 *
684 * Writes raw data to a #MIO stream. This function behaves the same as fwrite().
685 *
686 * Returns: The number of blocks actually written to the stream. This might be
687 * smaller than the requested count if a write error occurs.
688 */
689size_t mio_write (MIO *mio,
690 const void *ptr,
691 size_t size,
692 size_t nmemb)
693{
694 if (mio->type == MIO_TYPE_FILE)
695 return fwrite (ptr, size, nmemb, mio->impl.file.fp);
696 else if (mio->type == MIO_TYPE_MEMORY)
697 {
698 size_t n_written = 0;
699
700 if (size != 0 && nmemb != 0)
701 {
702 if (mem_try_ensure_space (mio, size * nmemb))
703 {
704 memcpy (&mio->impl.mem.buf[mio->impl.mem.pos], ptr, size * nmemb);
705 mio->impl.mem.pos += size * nmemb;
706 n_written = nmemb;
707 }
708 }
709
710 return n_written;
711 }
712 else
713 {
715 return 0;
716 }
717}
718
719/**
720 * mio_putc:
721 * @mio: A #MIO object
722 * @c: The character to write
723 *
724 * Writes a character to a #MIO stream. This function behaves the same as
725 * fputc().
726 *
727 * Returns: The written character, or %EOF on error.
728 */
729int mio_putc (MIO *mio, int c)
730{
731 if (mio->type == MIO_TYPE_FILE)
732 return fputc (c, mio->impl.file.fp);
733 else if (mio->type == MIO_TYPE_MEMORY)
734 {
735 int rv = EOF;
736
737 if (mem_try_ensure_space (mio, 1))
738 {
739 mio->impl.mem.buf[mio->impl.mem.pos] = (unsigned char)c;
740 mio->impl.mem.pos++;
741 rv = (int)((unsigned char)c);
742 }
743
744 return rv;
745 }
746 else
747 {
749 return 0;
750 }
751}
752
753/**
754 * mio_puts:
755 * @mio: A #MIO object
756 * @s: The string to write
757 *
758 * Writes a string to a #MIO object. This function behaves the same as fputs().
759 *
760 * Returns: A non-negative integer on success or %EOF on failure.
761 */
762int mio_puts (MIO *mio, const char *s)
763{
764 if (mio->type == MIO_TYPE_FILE)
765 return fputs (s, mio->impl.file.fp);
766 else if (mio->type == MIO_TYPE_MEMORY)
767 {
768 int rv = EOF;
769 size_t len;
770
771 len = strlen (s);
772 if (mem_try_ensure_space (mio, len))
773 {
774 memcpy (&mio->impl.mem.buf[mio->impl.mem.pos], s, len);
775 mio->impl.mem.pos += len;
776 rv = 1;
777 }
778
779 return rv;
780 }
781 else
782 {
784 return 0;
785 }
786}
787
788/**
789 * mio_vprintf:
790 * @mio: A #MIO object
791 * @format: A printf format string
792 * @ap: The variadic argument list for the format
793 *
794 * Writes a formatted string into a #MIO stream. This function behaves the same
795 * as vfprintf().
796 *
797 * Returns: The number of bytes written in the stream, or a negative value on
798 * failure.
799 */
800int mio_vprintf (MIO *mio, const char *format, va_list ap)
801{
802 if (mio->type == MIO_TYPE_FILE)
803 return vfprintf (mio->impl.file.fp, format, ap);
804 else if (mio->type == MIO_TYPE_MEMORY)
805 {
806 int rv = -1;
807 size_t n;
808 size_t old_pos;
809 size_t old_size;
810 va_list ap_copy;
811 char dummy;
812
813 old_pos = mio->impl.mem.pos;
814 old_size = mio->impl.mem.size;
815 va_copy (ap_copy, ap);
816 /* compute the size we will need into the buffer */
817 n = vsnprintf (&dummy, 1, format, ap_copy) + 1;
818 va_end (ap_copy);
819 if (mem_try_ensure_space (mio, n))
820 {
821 unsigned char c;
822
823 /* backup character at n+1 that will be overwritten by a \0 ... */
824 c = mio->impl.mem.buf[mio->impl.mem.pos + (n - 1)];
825 rv = vsprintf ((char *)&mio->impl.mem.buf[mio->impl.mem.pos], format, ap);
826 /* ...and restore it */
827 mio->impl.mem.buf[mio->impl.mem.pos + (n - 1)] = c;
828 if (rv >= 0 && (size_t)rv == (n - 1))
829 {
830 /* re-compute the actual size since we might have allocated one byte
831 * more than needed */
832 mio->impl.mem.size = MAX (old_size, old_pos + (unsigned int)rv);
833 mio->impl.mem.pos += (unsigned int)rv;
834 }
835 else
836 {
837 mio->impl.mem.size = old_size;
838 rv = -1;
839 }
840 }
841
842 return rv;
843 }
844 else
845 {
847 return 0;
848 }
849}
850
851/**
852 * mio_printf:
853 * @mio: A #MIO object
854 * @format: A print format string
855 * @...: Arguments of the format
856 *
857 * Writes a formatted string to a #MIO stream. This function behaves the same as
858 * fprintf().
859 *
860 * Returns: The number of bytes written to the stream, or a negative value on
861 * failure.
862 */
863int mio_printf (MIO *mio, const char *format, ...)
864{
865 int rv;
866 va_list ap;
867
868 va_start (ap, format);
869 rv = mio_vprintf (mio, format, ap);
870 va_end (ap);
871
872 return rv;
873}
874
875/**
876 * mio_getc:
877 * @mio: A #MIO object
878 *
879 * Gets the current character from a #MIO stream. This function behaves the same
880 * as fgetc().
881 *
882 * Returns: The read character as a #int, or %EOF on error.
883 */
884int mio_getc (MIO *mio)
885{
886 if (mio->type == MIO_TYPE_FILE)
887 return fgetc (mio->impl.file.fp);
888 else if (mio->type == MIO_TYPE_MEMORY)
889 {
890 int rv = EOF;
891
892 if (mio->impl.mem.ungetch != EOF)
893 {
894 rv = mio->impl.mem.ungetch;
895 mio->impl.mem.ungetch = EOF;
896 mio->impl.mem.pos++;
897 }
898 else if (mio->impl.mem.pos < mio->impl.mem.size)
899 {
900 rv = mio->impl.mem.buf[mio->impl.mem.pos];
901 mio->impl.mem.pos++;
902 }
903 else
904 mio->impl.mem.eof = true;
905
906 return rv;
907 }
908 else
909 {
911 return 0;
912 }
913}
914
915/**
916 * mio_ungetc:
917 * @mio: A #MIO object
918 * @ch: Character to put back in the stream
919 *
920 * Puts a character back in a #MIO stream. This function behaves the sames as
921 * ungetc().
922 *
923 * <warning><para>It is only guaranteed that one character can be but back at a
924 * time, even if the implementation may allow more.</para></warning>
925 * <warning><para>Using this function while the stream cursor is at offset 0 is
926 * not guaranteed to function properly. As the C99 standard says, it is "an
927 * obsolescent feature".</para></warning>
928 *
929 * Returns: The character put back, or %EOF on error.
930 */
931int mio_ungetc (MIO *mio, int ch)
932{
933 if (mio->type == MIO_TYPE_FILE)
934 return ungetc (ch, mio->impl.file.fp);
935 else if (mio->type == MIO_TYPE_MEMORY)
936 {
937 int rv = EOF;
938
939 if (ch != EOF && mio->impl.mem.ungetch == EOF)
940 {
941 rv = mio->impl.mem.ungetch = ch;
942 mio->impl.mem.pos--;
943 mio->impl.mem.eof = false;
944 }
945
946 return rv;
947 }
948 else
949 {
951 return 0;
952 }
953}
954
955/**
956 * mio_gets:
957 * @mio: A #MIO object
958 * @s: A string to fill with the read data
959 * @size: The maximum number of bytes to read
960 *
961 * Reads a string from a #MIO stream, stopping after the first new-line
962 * character or at the end of the stream. This function behaves the same as
963 * fgets().
964 *
965 * Returns: @s on success, %NULL otherwise.
966 */
967char *mio_gets (MIO *mio, char *s, size_t size)
968{
969 if (mio->type == MIO_TYPE_FILE)
970 return fgets (s, (int)size, mio->impl.file.fp);
971 else if (mio->type == MIO_TYPE_MEMORY)
972 {
973 char *rv = NULL;
974
975 if (size > 0)
976 {
977 size_t i = 0;
978 bool newline = false;
979 /* Avoiding dereference inside the for loop below improves
980 * performance so we do it here. */
981 size_t pos = mio->impl.mem.pos;
982 size_t buf_size = mio->impl.mem.size;
983 unsigned char *buf = mio->impl.mem.buf;
984
985 if (mio->impl.mem.ungetch != EOF)
986 {
987 s[i] = (char)mio->impl.mem.ungetch;
988 mio->impl.mem.ungetch = EOF;
989 pos++;
990 i++;
991 }
992 for (; pos < buf_size && i < (size - 1); i++)
993 {
994 s[i] = (char)buf[pos];
995 pos++;
996 if (s[i] == '\n')
997 {
998 i++;
999 newline = true;
1000 break;
1001 }
1002 }
1003 if (i > 0)
1004 {
1005 s[i] = 0;
1006 rv = s;
1007 }
1008 if (!newline && pos >= buf_size)
1009 mio->impl.mem.eof = true;
1010 mio->impl.mem.pos = pos;
1011 mio->impl.mem.size = buf_size;
1012 }
1013
1014 return rv;
1015 }
1016 else
1017 {
1019 return 0;
1020 }
1021}
1022
1023/**
1024 * mio_clearerr:
1025 * @mio: A #MIO object
1026 *
1027 * Clears the error and end-of-stream indicators of a #MIO stream. This function
1028 * behaves the same as clearerr().
1029 */
1031{
1032 if (mio->type == MIO_TYPE_FILE)
1033 clearerr (mio->impl.file.fp);
1034 else if (mio->type == MIO_TYPE_MEMORY)
1035 {
1036 mio->impl.mem.error = false;
1037 mio->impl.mem.eof = false;
1038 }
1039 else
1041}
1042
1043/**
1044 * mio_eof:
1045 * @mio: A #MIO object
1046 *
1047 * Checks whether the end-of-stream indicator of a #MIO stream is set. This
1048 * function behaves the same as feof().
1049 *
1050 * Returns: A non-null value if the stream reached its end, 0 otherwise.
1051 */
1052int mio_eof (MIO *mio)
1053{
1054 if (mio->type == MIO_TYPE_FILE)
1055 return feof (mio->impl.file.fp);
1056 else if (mio->type == MIO_TYPE_MEMORY)
1057 return mio->impl.mem.eof != false;
1058 else
1059 {
1061 return 0;
1062 }
1063}
1064
1065/**
1066 * mio_error:
1067 * @mio: A #MIO object
1068 *
1069 * Checks whether the error indicator of a #MIO stream is set. This function
1070 * behaves the same as ferror().
1071 *
1072 * Returns: A non-null value if the stream have an error set, 0 otherwise.
1073 */
1074int mio_error (MIO *mio)
1075{
1076 if (mio->type == MIO_TYPE_FILE)
1077 return ferror (mio->impl.file.fp);
1078 else if (mio->type == MIO_TYPE_MEMORY)
1079 return mio->impl.mem.error != false;
1080 else
1081 {
1083 return 0;
1084 }
1085}
1086
1087/**
1088 * mio_seek:
1089 * @mio: A #MIO object
1090 * @offset: Offset of the new place, from @whence
1091 * @whence: Move origin. SEEK_SET moves relative to the start of the stream,
1092 * SEEK_CUR from the current position and SEEK_SET from the end of the
1093 * stream.
1094 *
1095 * Sets the cursor position on a #MIO stream. This functions behaves the same as
1096 * fseek(). See also mio_tell() and mio_setpos().
1097 *
1098 * Returns: 0 on success, -1 otherwise, in which case errno should be set to
1099 * indicate the error.
1100 */
1101int mio_seek (MIO *mio, long offset, int whence)
1102{
1103 if (mio->type == MIO_TYPE_FILE)
1104 return fseek (mio->impl.file.fp, offset, whence);
1105 else if (mio->type == MIO_TYPE_MEMORY)
1106 {
1107 /* FIXME: should we support seeking out of bounds like lseek() seems to do? */
1108 int rv = -1;
1109
1110 switch (whence)
1111 {
1112 case SEEK_SET:
1113 if (offset < 0 || (size_t)offset > mio->impl.mem.size)
1114 errno = EINVAL;
1115 else
1116 {
1117 mio->impl.mem.pos = (size_t)offset;
1118 rv = 0;
1119 }
1120 break;
1121
1122 case SEEK_CUR:
1123 if ((offset < 0 && (size_t)-offset > mio->impl.mem.pos) ||
1124 mio->impl.mem.pos + (size_t)offset > mio->impl.mem.size)
1125 {
1126 errno = EINVAL;
1127 }
1128 else
1129 {
1130 mio->impl.mem.pos = (size_t)(mio->impl.mem.pos + offset);
1131 rv = 0;
1132 }
1133 break;
1134
1135 case SEEK_END:
1136 if (offset > 0 || (size_t)-offset > mio->impl.mem.size)
1137 errno = EINVAL;
1138 else
1139 {
1140 mio->impl.mem.pos = mio->impl.mem.size - (size_t)-offset;
1141 rv = 0;
1142 }
1143 break;
1144
1145 default:
1146 errno = EINVAL;
1147 }
1148 if (rv == 0)
1149 {
1150 mio->impl.mem.eof = false;
1151 mio->impl.mem.ungetch = EOF;
1152 }
1153
1154 return rv;
1155 }
1156 else
1157 {
1159 return 0;
1160 }
1161
1162}
1163
1164/**
1165 * mio_tell:
1166 * @mio: A #MIO object
1167 *
1168 * Gets the current cursor position of a #MIO stream. This function behaves the
1169 * same as ftell().
1170 *
1171 * Returns: The current offset from the start of the stream, or -1 or error, in
1172 * which case errno is set to indicate the error.
1173 */
1174long mio_tell (MIO *mio)
1175{
1176 if (mio->type == MIO_TYPE_FILE)
1177 return ftell (mio->impl.file.fp);
1178 else if (mio->type == MIO_TYPE_MEMORY)
1179 {
1180 long rv = -1;
1181
1182 if (mio->impl.mem.pos > LONG_MAX)
1183 {
1184#ifdef EOVERFLOW
1185 errno = EOVERFLOW;
1186#endif
1187 }
1188 else
1189 rv = (long)mio->impl.mem.pos;
1190
1191 return rv;
1192 }
1193 else
1194 {
1196 return 0;
1197 }
1198}
1199
1200/**
1201 * mio_rewind:
1202 * @mio: A #MIO object
1203 *
1204 * Resets the cursor position to 0, and also the end-of-stream and the error
1205 * indicators of a #MIO stream.
1206 * See also mio_seek() and mio_clearerr().
1207 */
1208void mio_rewind (MIO *mio)
1209{
1210 if (mio->type == MIO_TYPE_FILE)
1211 rewind (mio->impl.file.fp);
1212 else if (mio->type == MIO_TYPE_MEMORY)
1213 {
1214 mio->impl.mem.pos = 0;
1215 mio->impl.mem.ungetch = EOF;
1216 mio->impl.mem.eof = false;
1217 mio->impl.mem.error = false;
1218 }
1219 else
1221}
1222
1223/**
1224 * mio_getpos:
1225 * @mio: A #MIO stream
1226 * @pos: (out): A #MIOPos object to fill-in
1227 *
1228 * Stores the current position (and maybe other informations about the stream
1229 * state) of a #MIO stream in order to restore it later with mio_setpos(). This
1230 * function behaves the same as fgetpos().
1231 *
1232 * Returns: 0 on success, -1 otherwise, in which case errno is set to indicate
1233 * the error.
1234 */
1236{
1237 int rv = -1;
1238
1239 pos->type = mio->type;
1240 if (mio->type == MIO_TYPE_FILE)
1241 rv = fgetpos (mio->impl.file.fp, &pos->impl.file);
1242 else if (mio->type == MIO_TYPE_MEMORY)
1243 {
1244 rv = -1;
1245
1246 if (mio->impl.mem.pos == (size_t)-1)
1247 {
1248 /* this happens if ungetc() was called at the start of the stream */
1249#ifdef EIO
1250 errno = EIO;
1251#endif
1252 }
1253 else
1254 {
1255 pos->impl.mem = mio->impl.mem.pos;
1256 rv = 0;
1257 }
1258 }
1259 else
1261
1262#ifdef MIO_DEBUG
1263 if (rv != -1)
1264 {
1265 pos->tag = mio;
1266 }
1267#endif /* MIO_DEBUG */
1268
1269 return rv;
1270}
1271
1272/**
1273 * mio_setpos:
1274 * @mio: A #MIO object
1275 * @pos: (in): A #MIOPos object filled-in by a previous call of mio_getpos() on
1276 * the same stream
1277 *
1278 * Restores the position and state indicators of a #MIO stream previously saved
1279 * by mio_getpos().
1280 *
1281 * <warning><para>The #MIOPos object must have been initialized by a previous
1282 * call to mio_getpos() on the same stream.</para></warning>
1283 *
1284 * Returns: 0 on success, -1 otherwise, in which case errno is set to indicate
1285 * the error.
1286 */
1288{
1289 int rv = -1;
1290
1291#ifdef MIO_DEBUG
1292 if (pos->tag != mio)
1293 {
1294 g_critical ("mio_setpos((MIO*)%p, (MIOPos*)%p): "
1295 "Given MIOPos was not set by a previous call to mio_getpos() "
1296 "on the same MIO object, which means there is a bug in "
1297 "someone's code.",
1298 (void *)mio, (void *)pos);
1299 errno = EINVAL;
1300 return -1;
1301 }
1302#endif /* MIO_DEBUG */
1303
1304 if (mio->type == MIO_TYPE_FILE)
1305 rv = fsetpos (mio->impl.file.fp, &pos->impl.file);
1306 else if (mio->type == MIO_TYPE_MEMORY)
1307 {
1308 rv = -1;
1309
1310 if (pos->impl.mem > mio->impl.mem.size)
1311 errno = EINVAL;
1312 else
1313 {
1314 mio->impl.mem.ungetch = EOF;
1315 mio->impl.mem.pos = pos->impl.mem;
1316 rv = 0;
1317 }
1318 }
1319 else
1321
1322 return rv;
1323}
1324
1325/**
1326 * mio_flush:
1327 * @mio: A #MIO object
1328 *
1329 * Forces a write of all user-space buffered data for the given output or update
1330 * stream via the stream's underlying write function. Only applicable when using
1331 * FILE back-end.
1332 *
1333 * Returns: 0 on success, error code otherwise.
1334 */
1335int mio_flush (MIO *mio)
1336{
1337 if (mio->type == MIO_TYPE_FILE)
1338 return fflush (mio->impl.file.fp);
1339 return 0;
1340}
1341
1342
1343/**
1344 * mio_attach_user_data:
1345 * @mio: A #MIO object
1346 * @user_data: a pointer to any data object
1347 * @user_data_free_func: a call back function to destroy the data object passed as @user_data
1348 *
1349 * Attach any data object to a #MIO object. Attached data can be got with
1350 * mio_get_user_data(). The attached data is destroyed when new data is attached to
1351 * the #MIO object, or #the MIO object itself is destroyed. For destroying the data
1352 * @user_data_free_func is used.
1353 *
1354 */
1355
1356void mio_attach_user_data (MIO *mio, void *user_data, MIODestroyNotify user_data_free_func)
1357{
1358 if (mio->udata.d && mio->udata.f)
1359 mio->udata.f (mio->udata.d);
1360
1361 mio->udata.d = user_data;
1362 mio->udata.f = user_data_free_func;
1363}
1364
1365/**
1366 * mio_get_user_data:
1367 * @mio: A #MIO object
1368 *
1369 * Returns: user data attached with mio_attach_user_data() to a #MIO object.
1370 *
1371 */
1373{
1374 return mio->udata.d;
1375}
GeanyBuildCommand ** ptr
Definition: build.c:2679
#define Assert(c)
Definition: debug.h:47
#define AssertNotReached()
Definition: debug.h:48
gint pos
Definition: editor.c:87
int errno
CobolFormat format
Definition: geany_cobol.c:137
implType impl
Definition: geany_php.c:233
static gboolean dummy
Definition: libmain.c:115
unsigned char * mio_memory_get_data(MIO *mio, size_t *size)
mio_memory_get_data: @mio: A MIO object @size: (allow-none) (out): Return location for the length of ...
Definition: mio.c:457
MIO * mio_new_fp(FILE *fp, MIOFCloseFunc close_func)
mio_new_fp: @fp: An opened #FILE object @close_func: (allow-none): Function used to close @fp when th...
Definition: mio.c:259
size_t mio_write(MIO *mio, const void *ptr, size_t size, size_t nmemb)
mio_write: @mio: A MIO object @ptr: Pointer to the memory to write on the stream @size: Size of each ...
Definition: mio.c:689
int mio_getc(MIO *mio)
mio_getc: @mio: A MIO object
Definition: mio.c:884
static int mem_try_ensure_space(MIO *mio, size_t n)
Definition: mio.c:667
long mio_tell(MIO *mio)
mio_tell: @mio: A MIO object
Definition: mio.c:1174
MIO * mio_new_file(const char *filename, const char *mode)
mio_new_file: @filename: Filename to open, same as the fopen()'s first argument @mode: Mode in which ...
Definition: mio.c:234
int mio_vprintf(MIO *mio, const char *format, va_list ap)
mio_vprintf: @mio: A MIO object @format: A printf format string @ap: The variadic argument list for t...
Definition: mio.c:800
size_t mio_read(MIO *mio, void *ptr_, size_t size, size_t nmemb)
mio_read: @mio: A MIO object @ptr: Pointer to the memory to fill with the read data @size: Size of ea...
Definition: mio.c:536
void mio_clearerr(MIO *mio)
mio_clearerr: @mio: A MIO object
Definition: mio.c:1030
int mio_seek(MIO *mio, long offset, int whence)
mio_seek: @mio: A MIO object @offset: Offset of the new place, from @whence @whence: Move origin.
Definition: mio.c:1101
static int mem_try_resize(MIO *mio, size_t new_size)
Definition: mio.c:595
int mio_eof(MIO *mio)
mio_eof: @mio: A MIO object
Definition: mio.c:1052
void * mio_get_user_data(MIO *mio)
mio_get_user_data: @mio: A MIO object
Definition: mio.c:1372
int mio_try_resize(MIO *mio, size_t new_size)
Definition: mio.c:652
int mio_getpos(MIO *mio, MIOPos *pos)
mio_getpos: @mio: A MIO stream @pos: (out): A MIOPos object to fill-in
Definition: mio.c:1235
int mio_flush(MIO *mio)
mio_flush: @mio: A MIO object
Definition: mio.c:1335
MIO * mio_new_file_full(const char *filename, const char *mode, MIOFOpenFunc open_func, MIOFCloseFunc close_func)
mio_new_file_full: @filename: Filename to open, passed as-is to @open_func as the first argument @mod...
Definition: mio.c:186
int mio_error(MIO *mio)
mio_error: @mio: A MIO object
Definition: mio.c:1074
void mio_rewind(MIO *mio)
mio_rewind: @mio: A MIO object
Definition: mio.c:1208
FILE * mio_file_get_fp(MIO *mio)
mio_file_get_fp: @mio: A MIO object
Definition: mio.c:432
char * mio_gets(MIO *mio, char *s, size_t size)
mio_gets: @mio: A MIO object @s: A string to fill with the read data @size: The maximum number of byt...
Definition: mio.c:967
MIO * mio_new_memory(unsigned char *data, size_t size, MIOReallocFunc realloc_func, MIODestroyNotify free_func)
mio_new_memory: @data: Initial data (may be NULL) @size: Length of @data in bytes @realloc_func: A fu...
Definition: mio.c:316
MIO * mio_new_mio(MIO *base, long start, long size)
mio_new_mio: @base: The original mio @start: stream offset of the @base where new mio starts @size: t...
Definition: mio.c:364
int mio_printf(MIO *mio, const char *format,...)
mio_printf: @mio: A MIO object @format: A print format string ...: Arguments of the format
Definition: mio.c:863
int mio_puts(MIO *mio, const char *s)
mio_puts: @mio: A MIO object @s: The string to write
Definition: mio.c:762
#define MIO_CHUNK_SIZE
Definition: mio.c:91
MIO * mio_ref(MIO *mio)
mio_ref: @mio: A MIO object
Definition: mio.c:413
int mio_ungetc(MIO *mio, int ch)
mio_ungetc: @mio: A MIO object @ch: Character to put back in the stream
Definition: mio.c:931
int mio_putc(MIO *mio, int c)
mio_putc: @mio: A MIO object : The character to write
Definition: mio.c:729
int mio_unref(MIO *mio)
mio_unref: @mio: A MIO object
Definition: mio.c:480
void mio_attach_user_data(MIO *mio, void *user_data, MIODestroyNotify user_data_free_func)
mio_attach_user_data: @mio: A MIO object @user_data: a pointer to any data object @user_data_free_fun...
Definition: mio.c:1356
#define MAX(a, b)
Definition: mio.c:93
int mio_setpos(MIO *mio, MIOPos *pos)
mio_setpos: @mio: A MIO object @pos: (in): A MIOPos object filled-in by a previous call of mio_getpos...
Definition: mio.c:1287
@ MIO_TYPE_MEMORY
Definition: mio.h:43
@ MIO_TYPE_FILE
Definition: mio.h:42
void(* MIODestroyNotify)(void *data)
MIODestroyNotify: @data: Data element being destroyed.
Definition: mio.h:92
void *(* MIOReallocFunc)(void *ptr, size_t size)
MIOReallocFunc: @ptr: Pointer to the memory to resize @size: New size of the memory pointed by @ptr.
Definition: mio.h:59
FILE *(* MIOFOpenFunc)(const char *filename, const char *mode)
MIOFOpenFunc: @filename: The filename to open @mode: fopen() modes for opening @filename.
Definition: mio.h:71
enum _MIOType MIOType
Definition: mio.h:46
int(* MIOFCloseFunc)(FILE *fp)
MIOFCloseFunc: @fp: An opened #FILE object.
Definition: mio.h:82
#define va_copy(dest, src)
Definition: options.c:613
#define NULL
Definition: rbtree.h:150
void * eMalloc(const size_t size)
Definition: routines.c:218
void eFreeNoNullCheck(void *const ptr)
Definition: routines.c:258
void * eRealloc(void *const ptr, const size_t size)
Definition: routines.c:238
void eFree(void *const ptr)
Definition: routines.c:252
#define xMalloc(n, Type)
Definition: routines.h:23
const gchar filename[]
Definition: stash-example.c:4
MIOPos:
Definition: mio.h:101
void * d
Definition: mio.c:126
MIODestroyNotify f
Definition: mio.c:127
MIO:
Definition: mio.c:136
size_t pos
Definition: mio.c:148
struct _MIO::@13::@15 mem
MIOUserData udata
Definition: mio.c:157
struct _MIO::@13::@14 file
FILE * fp
Definition: mio.c:142
bool eof
Definition: mio.c:154
MIODestroyNotify free_func
Definition: mio.c:152
unsigned int refcount
Definition: mio.c:139
MIOFCloseFunc close_func
Definition: mio.c:143
bool error
Definition: mio.c:153
size_t allocated_size
Definition: mio.c:150
union _MIO::@13 impl
MIOType type
Definition: mio.c:138
size_t size
Definition: mio.c:149
unsigned char * buf
Definition: mio.c:146
MIOReallocFunc realloc_func
Definition: mio.c:151
int ungetch
Definition: mio.c:147