OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.18.0/] [newlib/] [libc/] [stdio/] [open_memstream.c] - Blame information for rev 309

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/* Copyright (C) 2007 Eric Blake
2
 * Permission to use, copy, modify, and distribute this software
3
 * is freely granted, provided that this notice is preserved.
4
 */
5
 
6
/*
7
FUNCTION
8
<<open_memstream>>, <<open_wmemstream>>---open a write stream around an arbitrary-length string
9
 
10
INDEX
11
        open_memstream
12
INDEX
13
        open_wmemstream
14
 
15
ANSI_SYNOPSIS
16
        #include <stdio.h>
17
        FILE *open_memstream(char **restrict <[buf]>,
18
                             size_t *restrict <[size]>);
19
 
20
        #include <wchar.h>
21
        FILE *open_wmemstream(wchar_t **restrict <[buf]>,
22
                              size_t *restrict <[size]>);
23
 
24
DESCRIPTION
25
<<open_memstream>> creates a seekable, byte-oriented <<FILE>> stream that
26
wraps an arbitrary-length buffer, created as if by <<malloc>>.  The current
27
contents of *<[buf]> are ignored; this implementation uses *<[size]>
28
as a hint of the maximum size expected, but does not fail if the hint
29
was wrong.  The parameters <[buf]> and <[size]> are later stored
30
through following any call to <<fflush>> or <<fclose>>, set to the
31
current address and usable size of the allocated string; although
32
after fflush, the pointer is only valid until another stream operation
33
that results in a write.  Behavior is undefined if the user alters
34
either *<[buf]> or *<[size]> prior to <<fclose>>.
35
 
36
<<open_wmemstream>> is like <<open_memstream>> just with the associated
37
stream being wide-oriented.  The size set in <[size]> in subsequent
38
operations is the number of wide characters.
39
 
40
The stream is write-only, since the user can directly read *<[buf]>
41
after a flush; see <<fmemopen>> for a way to wrap a string with a
42
readable stream.  The user is responsible for calling <<free>> on
43
the final *<[buf]> after <<fclose>>.
44
 
45
Any time the stream is flushed, a NUL byte is written at the current
46
position (but is not counted in the buffer length), so that the string
47
is always NUL-terminated after at most *<[size]> bytes (or wide characters
48
in case of <<open_wmemstream>>).  However, data previously written beyond
49
the current stream offset is not lost, and the NUL value written during a
50
flush is restored to its previous value when seeking elsewhere in the string.
51
 
52
RETURNS
53
The return value is an open FILE pointer on success.  On error,
54
<<NULL>> is returned, and <<errno>> will be set to EINVAL if <[buf]>
55
or <[size]> is NULL, ENOMEM if memory could not be allocated, or
56
EMFILE if too many streams are already open.
57
 
58
PORTABILITY
59
POSIX.1-2008
60
 
61
Supporting OS subroutines required: <<sbrk>>.
62
*/
63
 
64
#include <stdio.h>
65
#include <wchar.h>
66
#include <errno.h>
67
#include <string.h>
68
#include <sys/lock.h>
69
#include <stdint.h>
70
#include "local.h"
71
 
72
#ifndef __LARGE64_FILES
73
# define OFF_T off_t
74
#else
75
# define OFF_T _off64_t
76
#endif
77
 
78
/* Describe details of an open memstream.  */
79
typedef struct memstream {
80
  void *storage; /* storage to free on close */
81
  char **pbuf; /* pointer to the current buffer */
82
  size_t *psize; /* pointer to the current size, smaller of pos or eof */
83
  size_t pos; /* current position */
84
  size_t eof; /* current file size */
85
  size_t max; /* current malloc buffer size, always > eof */
86
  union {
87
    char c;
88
    wchar_t w;
89
  } saved; /* saved character that lived at *psize before NUL */
90
  int8_t wide; /* wide-oriented (>0) or byte-oriented (<0) */
91
} memstream;
92
 
93
/* Write up to non-zero N bytes of BUF into the stream described by COOKIE,
94
   returning the number of bytes written or EOF on failure.  */
95
static _READ_WRITE_RETURN_TYPE
96
_DEFUN(memwriter, (ptr, cookie, buf, n),
97
       struct _reent *ptr _AND
98
       void *cookie _AND
99
       const char *buf _AND
100
       int n)
101
{
102
  memstream *c = (memstream *) cookie;
103
  char *cbuf = *c->pbuf;
104
 
105
  /* size_t is unsigned, but off_t is signed.  Don't let stream get so
106
     big that user cannot do ftello.  */
107
  if (sizeof (OFF_T) == sizeof (size_t) && (ssize_t) (c->pos + n) < 0)
108
    {
109
      ptr->_errno = EFBIG;
110
      return EOF;
111
    }
112
  /* Grow the buffer, if necessary.  Choose a geometric growth factor
113
     to avoid quadratic realloc behavior, but use a rate less than
114
     (1+sqrt(5))/2 to accomodate malloc overhead.  Overallocate, so
115
     that we can add a trailing \0 without reallocating.  The new
116
     allocation should thus be max(prev_size*1.5, c->pos+n+1). */
117
  if (c->pos + n >= c->max)
118
    {
119
      size_t newsize = c->max * 3 / 2;
120
      if (newsize < c->pos + n + 1)
121
        newsize = c->pos + n + 1;
122
      cbuf = _realloc_r (ptr, cbuf, newsize);
123
      if (! cbuf)
124
        return EOF; /* errno already set to ENOMEM */
125
      *c->pbuf = cbuf;
126
      c->max = newsize;
127
    }
128
  /* If we have previously done a seek beyond eof, ensure all
129
     intermediate bytes are NUL.  */
130
  if (c->pos > c->eof)
131
    memset (cbuf + c->eof, '\0', c->pos - c->eof);
132
  memcpy (cbuf + c->pos, buf, n);
133
  c->pos += n;
134
  /* If the user has previously written further, remember what the
135
     trailing NUL is overwriting.  Otherwise, extend the stream.  */
136
  if (c->pos > c->eof)
137
    c->eof = c->pos;
138
  else if (c->wide > 0)
139
    c->saved.w = *(wchar_t *)(cbuf + c->pos);
140
  else
141
    c->saved.c = cbuf[c->pos];
142
  cbuf[c->pos] = '\0';
143
  *c->psize = (c->wide > 0) ? c->pos / sizeof (wchar_t) : c->pos;
144
  return n;
145
}
146
 
147
/* Seek to position POS relative to WHENCE within stream described by
148
   COOKIE; return resulting position or fail with EOF.  */
149
static _fpos_t
150
_DEFUN(memseeker, (ptr, cookie, pos, whence),
151
       struct _reent *ptr _AND
152
       void *cookie _AND
153
       _fpos_t pos _AND
154
       int whence)
155
{
156
  memstream *c = (memstream *) cookie;
157
  OFF_T offset = (OFF_T) pos;
158
 
159
  if (whence == SEEK_CUR)
160
    offset += c->pos;
161
  else if (whence == SEEK_END)
162
    offset += c->eof;
163
  if (offset < 0)
164
    {
165
      ptr->_errno = EINVAL;
166
      offset = -1;
167
    }
168
  else if ((size_t) offset != offset)
169
    {
170
      ptr->_errno = ENOSPC;
171
      offset = -1;
172
    }
173
#ifdef __LARGE64_FILES
174
  else if ((_fpos_t) offset != offset)
175
    {
176
      ptr->_errno = EOVERFLOW;
177
      offset = -1;
178
    }
179
#endif /* __LARGE64_FILES */
180
  else
181
    {
182
      if (c->pos < c->eof)
183
        {
184
          if (c->wide > 0)
185
            *(wchar_t *)((*c->pbuf) + c->pos) = c->saved.w;
186
          else
187
            (*c->pbuf)[c->pos] = c->saved.c;
188
          c->saved.w = L'\0';
189
        }
190
      c->pos = offset;
191
      if (c->pos < c->eof)
192
        {
193
          if (c->wide > 0)
194
            {
195
              c->saved.w = *(wchar_t *)((*c->pbuf) + c->pos);
196
              *(wchar_t *)((*c->pbuf) + c->pos) = L'\0';
197
              *c->psize = c->pos / sizeof (wchar_t);
198
            }
199
          else
200
            {
201
              c->saved.c = (*c->pbuf)[c->pos];
202
              (*c->pbuf)[c->pos] = '\0';
203
              *c->psize = c->pos;
204
            }
205
        }
206
      else if (c->wide > 0)
207
        *c->psize = c->eof / sizeof (wchar_t);
208
      else
209
        *c->psize = c->eof;
210
    }
211
  return (_fpos_t) offset;
212
}
213
 
214
/* Seek to position POS relative to WHENCE within stream described by
215
   COOKIE; return resulting position or fail with EOF.  */
216
#ifdef __LARGE64_FILES
217
static _fpos64_t
218
_DEFUN(memseeker64, (ptr, cookie, pos, whence),
219
       struct _reent *ptr _AND
220
       void *cookie _AND
221
       _fpos64_t pos _AND
222
       int whence)
223
{
224
  _off64_t offset = (_off64_t) pos;
225
  memstream *c = (memstream *) cookie;
226
 
227
  if (whence == SEEK_CUR)
228
    offset += c->pos;
229
  else if (whence == SEEK_END)
230
    offset += c->eof;
231
  if (offset < 0)
232
    {
233
      ptr->_errno = EINVAL;
234
      offset = -1;
235
    }
236
  else if ((size_t) offset != offset)
237
    {
238
      ptr->_errno = ENOSPC;
239
      offset = -1;
240
    }
241
  else
242
    {
243
      if (c->pos < c->eof)
244
        {
245
          if (c->wide > 0)
246
            *(wchar_t *)((*c->pbuf) + c->pos) = c->saved.w;
247
          else
248
            (*c->pbuf)[c->pos] = c->saved.c;
249
          c->saved.w = L'\0';
250
        }
251
      c->pos = offset;
252
      if (c->pos < c->eof)
253
        {
254
          if (c->wide > 0)
255
            {
256
              c->saved.w = *(wchar_t *)((*c->pbuf) + c->pos);
257
              *(wchar_t *)((*c->pbuf) + c->pos) = L'\0';
258
              *c->psize = c->pos / sizeof (wchar_t);
259
            }
260
          else
261
            {
262
              c->saved.c = (*c->pbuf)[c->pos];
263
              (*c->pbuf)[c->pos] = '\0';
264
              *c->psize = c->pos;
265
            }
266
        }
267
      else if (c->wide > 0)
268
        *c->psize = c->eof / sizeof (wchar_t);
269
      else
270
        *c->psize = c->eof;
271
    }
272
  return (_fpos64_t) offset;
273
}
274
#endif /* __LARGE64_FILES */
275
 
276
/* Reclaim resources used by stream described by COOKIE.  */
277
static int
278
_DEFUN(memcloser, (ptr, cookie),
279
       struct _reent *ptr _AND
280
       void *cookie)
281
{
282
  memstream *c = (memstream *) cookie;
283
  char *buf;
284
 
285
  /* Be nice and try to reduce any unused memory.  */
286
  buf = _realloc_r (ptr, *c->pbuf,
287
                    c->wide > 0 ? (*c->psize + 1) * sizeof (wchar_t)
288
                                : *c->psize + 1);
289
  if (buf)
290
    *c->pbuf = buf;
291
  _free_r (ptr, c->storage);
292
  return 0;
293
}
294
 
295
/* Open a memstream that tracks a dynamic buffer in BUF and SIZE.
296
   Return the new stream, or fail with NULL.  */
297
static FILE *
298
_DEFUN(internal_open_memstream_r, (ptr, buf, size, wide),
299
       struct _reent *ptr _AND
300
       char **buf _AND
301
       size_t *size _AND
302
       int wide)
303
{
304
  FILE *fp;
305
  memstream *c;
306
 
307
  if (!buf || !size)
308
    {
309
      ptr->_errno = EINVAL;
310
      return NULL;
311
    }
312
  if ((fp = __sfp (ptr)) == NULL)
313
    return NULL;
314
  if ((c = (memstream *) _malloc_r (ptr, sizeof *c)) == NULL)
315
    {
316
      __sfp_lock_acquire ();
317
      fp->_flags = 0;            /* release */
318
#ifndef __SINGLE_THREAD__
319
      __lock_close_recursive (fp->_lock);
320
#endif
321
      __sfp_lock_release ();
322
      return NULL;
323
    }
324
  /* Use *size as a hint for initial sizing, but bound the initial
325
     malloc between 64 bytes (same as asprintf, to avoid frequent
326
     mallocs on small strings) and 64k bytes (to avoid overusing the
327
     heap if *size was garbage).  */
328
  c->max = *size;
329
  if (wide == 1)
330
    c->max *= sizeof(wchar_t);
331
  if (c->max < 64)
332
    c->max = 64;
333
  else if (c->max > 64 * 1024)
334
    c->max = 64 * 1024;
335
  *size = 0;
336
  *buf = _malloc_r (ptr, c->max);
337
  if (!*buf)
338
    {
339
      __sfp_lock_acquire ();
340
      fp->_flags = 0;            /* release */
341
#ifndef __SINGLE_THREAD__
342
      __lock_close_recursive (fp->_lock);
343
#endif
344
      __sfp_lock_release ();
345
      _free_r (ptr, c);
346
      return NULL;
347
    }
348
  if (wide == 1)
349
    **((wchar_t **)buf) = L'\0';
350
  else
351
    **buf = '\0';
352
 
353
  c->storage = c;
354
  c->pbuf = buf;
355
  c->psize = size;
356
  c->eof = 0;
357
  c->saved.w = L'\0';
358
  c->wide = (int8_t) wide;
359
 
360
  _flockfile (fp);
361
  fp->_file = -1;
362
  fp->_flags = __SWR;
363
  fp->_cookie = c;
364
  fp->_read = NULL;
365
  fp->_write = memwriter;
366
  fp->_seek = memseeker;
367
#ifdef __LARGE64_FILES
368
  fp->_seek64 = memseeker64;
369
  fp->_flags |= __SL64;
370
#endif
371
  fp->_close = memcloser;
372
  ORIENT (fp, wide);
373
  _funlockfile (fp);
374
  return fp;
375
}
376
 
377
FILE *
378
_DEFUN(_open_memstream_r, (ptr, buf, size),
379
       struct _reent *ptr _AND
380
       char **buf _AND
381
       size_t *size)
382
{
383
  return internal_open_memstream_r (ptr, buf, size, -1);
384
}
385
 
386
FILE *
387
_DEFUN(_open_wmemstream_r, (ptr, buf, size),
388
       struct _reent *ptr _AND
389
       wchar_t **buf _AND
390
       size_t *size)
391
{
392
  return internal_open_memstream_r (ptr, (char **)buf, size, 1);
393
}
394
 
395
#ifndef _REENT_ONLY
396
FILE *
397
_DEFUN(open_memstream, (buf, size),
398
       char **buf _AND
399
       size_t *size)
400
{
401
  return _open_memstream_r (_REENT, buf, size);
402
}
403
 
404
FILE *
405
_DEFUN(open_wmemstream, (buf, size),
406
       wchar_t **buf _AND
407
       size_t *size)
408
{
409
  return _open_wmemstream_r (_REENT, buf, size);
410
}
411
#endif /* !_REENT_ONLY */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.