~ubuntu-branches/ubuntu/raring/geany/raring-proposed

« back to all changes in this revision

Viewing changes to tagmanager/mio/mio-memory.c

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* memory IO implementation */
 
22
 
 
23
#include <glib.h>
 
24
#include <stdarg.h>
 
25
#include <stdio.h>
 
26
#include <string.h>
 
27
#include <errno.h>
 
28
 
 
29
#include "mio.h"
 
30
 
 
31
 
 
32
#define MEM_SET_VTABLE(mio)           \
 
33
  G_STMT_START {                      \
 
34
    mio->v_free     = mem_free;       \
 
35
    mio->v_read     = mem_read;       \
 
36
    mio->v_write    = mem_write;      \
 
37
    mio->v_getc     = mem_getc;       \
 
38
    mio->v_gets     = mem_gets;       \
 
39
    mio->v_ungetc   = mem_ungetc;     \
 
40
    mio->v_putc     = mem_putc;       \
 
41
    mio->v_puts     = mem_puts;       \
 
42
    mio->v_vprintf  = mem_vprintf;    \
 
43
    mio->v_clearerr = mem_clearerr;   \
 
44
    mio->v_eof      = mem_eof;        \
 
45
    mio->v_error    = mem_error;      \
 
46
    mio->v_seek     = mem_seek;       \
 
47
    mio->v_tell     = mem_tell;       \
 
48
    mio->v_rewind   = mem_rewind;     \
 
49
    mio->v_getpos   = mem_getpos;     \
 
50
    mio->v_setpos   = mem_setpos;     \
 
51
  } G_STMT_END
 
52
 
 
53
 
 
54
/* minimal reallocation chunk size */
 
55
#define MIO_CHUNK_SIZE 4096
 
56
 
 
57
 
 
58
static void
 
59
mem_free (MIO *mio)
 
60
{
 
61
  if (mio->impl.mem.free_func) {
 
62
    mio->impl.mem.free_func (mio->impl.mem.buf);
 
63
  }
 
64
  mio->impl.mem.buf = NULL;
 
65
  mio->impl.mem.pos = 0;
 
66
  mio->impl.mem.size = 0;
 
67
  mio->impl.mem.allocated_size = 0;
 
68
  mio->impl.mem.realloc_func = NULL;
 
69
  mio->impl.mem.free_func = NULL;
 
70
  mio->impl.mem.eof = FALSE;
 
71
  mio->impl.mem.error = FALSE;
 
72
}
 
73
 
 
74
static gsize
 
75
mem_read (MIO    *mio,
 
76
          void   *ptr,
 
77
          gsize   size,
 
78
          gsize   nmemb)
 
79
{
 
80
  gsize n_read = 0;
 
81
  
 
82
  if (size != 0 && nmemb != 0) {
 
83
    if (mio->impl.mem.ungetch != EOF) {
 
84
      *((guchar *)ptr) = (guchar)mio->impl.mem.ungetch;
 
85
      mio->impl.mem.ungetch = EOF;
 
86
      mio->impl.mem.pos++;
 
87
      if (size == 1) {
 
88
        n_read++;
 
89
      } else if (mio->impl.mem.pos + (size - 1) <= mio->impl.mem.size) {
 
90
        memcpy (&(((guchar *)ptr)[1]),
 
91
                &mio->impl.mem.buf[mio->impl.mem.pos], size - 1);
 
92
        mio->impl.mem.pos += size - 1;
 
93
        n_read++;
 
94
      }
 
95
    }
 
96
    for (; n_read < nmemb; n_read++) {
 
97
      if (mio->impl.mem.pos + size > mio->impl.mem.size) {
 
98
        break;
 
99
      } else {
 
100
        memcpy (&(((guchar *)ptr)[n_read * size]),
 
101
                &mio->impl.mem.buf[mio->impl.mem.pos], size);
 
102
        mio->impl.mem.pos += size;
 
103
      }
 
104
    }
 
105
    if (mio->impl.mem.pos >= mio->impl.mem.size) {
 
106
      mio->impl.mem.eof = TRUE;
 
107
    }
 
108
  }
 
109
  
 
110
  return n_read;
 
111
}
 
112
 
 
113
/*
 
114
 * mem_try_resize:
 
115
 * @mio: A #MIO object of the type %MIO_TYPE_MEMORY
 
116
 * @new_size: Requested new size
 
117
 * 
 
118
 * Tries to resize the underlying buffer of an in-memory #MIO object.
 
119
 * This supports both growing and shrinking.
 
120
 * 
 
121
 * Returns: %TRUE on success, %FALSE otherwise.
 
122
 */
 
123
static gboolean
 
124
mem_try_resize (MIO  *mio,
 
125
                gsize new_size)
 
126
{
 
127
  gboolean success = FALSE;
 
128
  
 
129
  if (mio->impl.mem.realloc_func) {
 
130
    if (G_UNLIKELY (new_size == G_MAXSIZE)) {
 
131
      #ifdef EOVERFLOW
 
132
      errno = EOVERFLOW;
 
133
      #endif
 
134
    } else {
 
135
      if (new_size > mio->impl.mem.size) {
 
136
        if (new_size <= mio->impl.mem.allocated_size) {
 
137
          mio->impl.mem.size = new_size;
 
138
          success = TRUE;
 
139
        } else {
 
140
          gsize   newsize;
 
141
          guchar *newbuf;
 
142
          
 
143
          newsize = MAX (mio->impl.mem.allocated_size + MIO_CHUNK_SIZE,
 
144
                         new_size);
 
145
          newbuf = mio->impl.mem.realloc_func (mio->impl.mem.buf, newsize);
 
146
          if (newbuf) {
 
147
            mio->impl.mem.buf = newbuf;
 
148
            mio->impl.mem.allocated_size = newsize;
 
149
            mio->impl.mem.size = new_size;
 
150
            success = TRUE;
 
151
          }
 
152
        }
 
153
      } else {
 
154
        guchar *newbuf;
 
155
        
 
156
        newbuf = mio->impl.mem.realloc_func (mio->impl.mem.buf, new_size);
 
157
        if (G_LIKELY (newbuf || new_size == 0)) {
 
158
          mio->impl.mem.buf = newbuf;
 
159
          mio->impl.mem.allocated_size = new_size;
 
160
          mio->impl.mem.size = new_size;
 
161
          success = TRUE;
 
162
        }
 
163
      }
 
164
    }
 
165
  }
 
166
  
 
167
  return success;
 
168
}
 
169
 
 
170
/*
 
171
 * mem_try_ensure_space:
 
172
 * @mio: A #MIO object
 
173
 * @n: Requested size from the current (cursor) position
 
174
 * 
 
175
 * Tries to ensure there is enough space for @n bytes to be written from the
 
176
 * current cursor position.
 
177
 * 
 
178
 * Returns: %TRUE if there is enough space, %FALSE otherwise.
 
179
 */
 
180
static gboolean
 
181
mem_try_ensure_space (MIO  *mio,
 
182
                      gsize n)
 
183
{
 
184
  gboolean success = TRUE;
 
185
  
 
186
  if (mio->impl.mem.pos + n > mio->impl.mem.size) {
 
187
    success = mem_try_resize (mio, mio->impl.mem.pos + n);
 
188
  }
 
189
  
 
190
  return success;
 
191
}
 
192
 
 
193
static gsize
 
194
mem_write (MIO         *mio,
 
195
           const void  *ptr,
 
196
           gsize        size,
 
197
           gsize        nmemb)
 
198
{
 
199
  gsize n_written = 0;
 
200
  
 
201
  if (size != 0 && nmemb != 0) {
 
202
    if (mem_try_ensure_space (mio, size * nmemb)) {
 
203
      memcpy (&mio->impl.mem.buf[mio->impl.mem.pos], ptr, size * nmemb);
 
204
      mio->impl.mem.pos += size * nmemb;
 
205
      n_written = nmemb;
 
206
    }
 
207
  }
 
208
  
 
209
  return n_written;
 
210
}
 
211
 
 
212
static gint
 
213
mem_putc (MIO  *mio,
 
214
          gint  c)
 
215
{
 
216
  gint rv = EOF;
 
217
  
 
218
  if (mem_try_ensure_space (mio, 1)) {
 
219
    mio->impl.mem.buf[mio->impl.mem.pos] = (guchar)c;
 
220
    mio->impl.mem.pos++;
 
221
    rv = (gint)((guchar)c);
 
222
  }
 
223
  
 
224
  return rv;
 
225
}
 
226
 
 
227
static gint
 
228
mem_puts (MIO          *mio,
 
229
          const gchar  *s)
 
230
{
 
231
  gint  rv = EOF;
 
232
  gsize len;
 
233
  
 
234
  len = strlen (s);
 
235
  if (mem_try_ensure_space (mio, len)) {
 
236
    memcpy (&mio->impl.mem.buf[mio->impl.mem.pos], s, len);
 
237
    mio->impl.mem.pos += len;
 
238
    rv = 1;
 
239
  }
 
240
  
 
241
  return rv;
 
242
}
 
243
 
 
244
static gint
 
245
mem_vprintf (MIO         *mio,
 
246
             const gchar *format,
 
247
             va_list      ap)
 
248
{
 
249
  gint    rv = -1;
 
250
  gsize   n;
 
251
  gsize   old_pos;
 
252
  gsize   old_size;
 
253
  va_list ap_copy;
 
254
  
 
255
  old_pos = mio->impl.mem.pos;
 
256
  old_size = mio->impl.mem.size;
 
257
  G_VA_COPY (ap_copy, ap);
 
258
  /* compute the size we will need into the buffer */
 
259
  n = g_printf_string_upper_bound (format, ap_copy);
 
260
  va_end (ap_copy);
 
261
  if (mem_try_ensure_space (mio, n)) {
 
262
    guchar c;
 
263
    
 
264
    /* backup character at n+1 that will be overwritten by a \0 ... */
 
265
    c = mio->impl.mem.buf[mio->impl.mem.pos + (n - 1)];
 
266
    rv = vsprintf ((gchar *)&mio->impl.mem.buf[mio->impl.mem.pos], format, ap);
 
267
    /* ...and restore it */
 
268
    mio->impl.mem.buf[mio->impl.mem.pos + (n - 1)] = c;
 
269
    if (G_LIKELY (rv >= 0 && (gsize)rv == (n - 1))) {
 
270
      /* re-compute the actual size since we might have allocated one byte
 
271
       * more than needed */
 
272
      mio->impl.mem.size = MAX (old_size, old_pos + (guint)rv);
 
273
      mio->impl.mem.pos += (guint)rv;
 
274
    } else {
 
275
      mio->impl.mem.size = old_size;
 
276
      rv = -1;
 
277
    }
 
278
  }
 
279
  
 
280
  return rv;
 
281
}
 
282
 
 
283
static gint
 
284
mem_getc (MIO *mio)
 
285
{
 
286
  gint rv = EOF;
 
287
  
 
288
  if (mio->impl.mem.ungetch != EOF) {
 
289
    rv = mio->impl.mem.ungetch;
 
290
    mio->impl.mem.ungetch = EOF;
 
291
    mio->impl.mem.pos++;
 
292
  } else if (mio->impl.mem.pos < mio->impl.mem.size) {
 
293
    rv = mio->impl.mem.buf[mio->impl.mem.pos];
 
294
    mio->impl.mem.pos++;
 
295
  } else {
 
296
    mio->impl.mem.eof = TRUE;
 
297
  }
 
298
  
 
299
  return rv;
 
300
}
 
301
 
 
302
static gint
 
303
mem_ungetc (MIO  *mio,
 
304
            gint  ch)
 
305
{
 
306
  gint rv = EOF;
 
307
  
 
308
  if (ch != EOF && mio->impl.mem.ungetch == EOF) {
 
309
    rv = mio->impl.mem.ungetch = ch;
 
310
    mio->impl.mem.pos--;
 
311
    mio->impl.mem.eof = FALSE;
 
312
  }
 
313
  
 
314
  return rv;
 
315
}
 
316
 
 
317
static gchar *
 
318
mem_gets (MIO    *mio,
 
319
          gchar  *s,
 
320
          gsize   size)
 
321
{
 
322
  gchar *rv = NULL;
 
323
  
 
324
  if (size > 0) {
 
325
    gsize i = 0;
 
326
    
 
327
    if (mio->impl.mem.ungetch != EOF) {
 
328
      s[i] = (gchar)mio->impl.mem.ungetch;
 
329
      mio->impl.mem.ungetch = EOF;
 
330
      mio->impl.mem.pos++;
 
331
      i++;
 
332
    }
 
333
    for (; mio->impl.mem.pos < mio->impl.mem.size && i < (size - 1); i++) {
 
334
      s[i] = (gchar)mio->impl.mem.buf[mio->impl.mem.pos];
 
335
      mio->impl.mem.pos++;
 
336
      if (s[i] == '\n') {
 
337
        i++;
 
338
        break;
 
339
      }
 
340
    }
 
341
    if (i > 0) {
 
342
      s[i] = 0;
 
343
      rv = s;
 
344
    }
 
345
    if (mio->impl.mem.pos >= mio->impl.mem.size) {
 
346
      mio->impl.mem.eof = TRUE;
 
347
    }
 
348
  }
 
349
  
 
350
  return rv;
 
351
}
 
352
 
 
353
static void
 
354
mem_clearerr (MIO *mio)
 
355
{
 
356
  mio->impl.mem.error = FALSE;
 
357
  mio->impl.mem.eof = FALSE;
 
358
}
 
359
 
 
360
static gint
 
361
mem_eof (MIO *mio)
 
362
{
 
363
  return mio->impl.mem.eof != FALSE;
 
364
}
 
365
 
 
366
static gint
 
367
mem_error (MIO *mio)
 
368
{
 
369
  return mio->impl.mem.error != FALSE;
 
370
}
 
371
 
 
372
/* FIXME: should we support seeking out of bounds like lseek() seems to do? */
 
373
static gint
 
374
mem_seek (MIO  *mio,
 
375
          glong offset,
 
376
          gint  whence)
 
377
{
 
378
  gint rv = -1;
 
379
  
 
380
  switch (whence) {
 
381
    case SEEK_SET:
 
382
      if (offset < 0 || (gsize)offset > mio->impl.mem.size) {
 
383
        errno = EINVAL;
 
384
      } else {
 
385
        mio->impl.mem.pos = (gsize)offset;
 
386
        rv = 0;
 
387
      }
 
388
      break;
 
389
    
 
390
    case SEEK_CUR:
 
391
      if ((offset < 0 && (gsize)-offset > mio->impl.mem.pos) ||
 
392
          mio->impl.mem.pos + (gsize)offset > mio->impl.mem.size) {
 
393
        errno = EINVAL;
 
394
      } else {
 
395
        mio->impl.mem.pos = (gsize)((gssize)mio->impl.mem.pos + offset);
 
396
        rv = 0;
 
397
      }
 
398
      break;
 
399
    
 
400
    case SEEK_END:
 
401
      if (offset > 0 || (gsize)-offset > mio->impl.mem.size) {
 
402
        errno = EINVAL;
 
403
      } else {
 
404
        mio->impl.mem.pos = mio->impl.mem.size - (gsize)-offset;
 
405
        rv = 0;
 
406
      }
 
407
      break;
 
408
    
 
409
    default:
 
410
      errno = EINVAL;
 
411
  }
 
412
  if (rv == 0) {
 
413
    mio->impl.mem.eof = FALSE;
 
414
    mio->impl.mem.ungetch = EOF;
 
415
  }
 
416
  
 
417
  return rv;
 
418
}
 
419
 
 
420
static glong
 
421
mem_tell (MIO *mio)
 
422
{
 
423
  glong rv = -1;
 
424
  
 
425
  if (mio->impl.mem.pos > G_MAXLONG) {
 
426
    #ifdef EOVERFLOW
 
427
    errno = EOVERFLOW;
 
428
    #endif
 
429
  } else {
 
430
    rv = (glong)mio->impl.mem.pos;
 
431
  }
 
432
  
 
433
  return rv;
 
434
}
 
435
 
 
436
static void
 
437
mem_rewind (MIO *mio)
 
438
{
 
439
  mio->impl.mem.pos = 0;
 
440
  mio->impl.mem.ungetch = EOF;
 
441
  mio->impl.mem.eof = FALSE;
 
442
  mio->impl.mem.error = FALSE;
 
443
}
 
444
 
 
445
static gint
 
446
mem_getpos (MIO    *mio,
 
447
            MIOPos *pos)
 
448
{
 
449
  gint rv = -1;
 
450
  
 
451
  if (mio->impl.mem.pos == (gsize)-1) {
 
452
    /* this happens if ungetc() was called at the start of the stream */
 
453
    #ifdef EIO
 
454
    errno = EIO;
 
455
    #endif
 
456
  } else {
 
457
    pos->impl.mem = mio->impl.mem.pos;
 
458
    rv = 0;
 
459
  }
 
460
  
 
461
  return rv;
 
462
}
 
463
 
 
464
static gint
 
465
mem_setpos (MIO    *mio,
 
466
            MIOPos *pos)
 
467
{
 
468
  gint rv = -1;
 
469
  
 
470
  if (pos->impl.mem > mio->impl.mem.size) {
 
471
    errno = EINVAL;
 
472
  } else {
 
473
    mio->impl.mem.ungetch = EOF;
 
474
    mio->impl.mem.pos = pos->impl.mem;
 
475
    rv = 0;
 
476
  }
 
477
  
 
478
  return rv;
 
479
}