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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [newlib-1.17.0/] [newlib/] [libc/] [stdio/] [open_memstream.c] - Blame information for rev 864

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

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

powered by: WebSVN 2.1.0

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