]> sourceware.org Git - glibc.git/blame - stdio/memstream.c
Mon Sep 18 15:06:00 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
[glibc.git] / stdio / memstream.c
CommitLineData
28f540f4
RM
1/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc.
2This file is part of the GNU C Library.
3
4The GNU C Library is free software; you can redistribute it and/or
5modify it under the terms of the GNU Library General Public License as
6published by the Free Software Foundation; either version 2 of the
7License, or (at your option) any later version.
8
9The GNU C Library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12Library General Public License for more details.
13
14You should have received a copy of the GNU Library General Public
15License along with the GNU C Library; see the file COPYING.LIB. If
16not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17Cambridge, MA 02139, USA. */
18
19#include <ansidecl.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24struct memstream_info
25 {
26 char **buffer;
27 size_t *bufsize;
28 };
29
30/* Enlarge STREAM's buffer. */
31static void
32DEFUN(enlarge_buffer, (stream, c),
33 register FILE *stream AND int c)
34{
35 struct memstream_info *info = (struct memstream_info *) stream->__cookie;
36 size_t need;
37
38 if (stream->__put_limit != stream->__buffer)
39 /* Record how much has actually been written into the buffer. */
40 *info->bufsize = stream->__bufp - stream->__buffer;
41
42 if (stream->__target != -1
43 && stream->__target > *info->bufsize)
44 /* Our target (where the buffer maps to) is always zero except when
45 the user just did a SEEK_END fseek. If he sought within the
46 buffer, we need do nothing and will zero the target below. If he
47 sought past the end of the object, grow and zero-fill the buffer
48 up to the target address. */
49 need = stream->__target;
50 else
51 need = *info->bufsize;
52
53 /* We always need an extra character in the buffer. Either we are
54 writing C, or we are flushing and need to write a NUL terminator. */
55 ++need;
56
57 if (stream->__bufsize < need)
58 {
59 /* Enlarge the buffer. */
60 char *newbuf;
61 size_t newsize;
62 if (stream->__bufsize * 2 < need)
63 newsize = need;
64 else
65 newsize = stream->__bufsize * 2;
66 newbuf = (char *) realloc ((PTR) stream->__buffer, newsize);
67 if (newbuf == NULL)
68 {
69 stream->__error = 1;
70 return;
71 }
72 *info->buffer = stream->__buffer = newbuf;
73 stream->__bufsize = newsize;
74 }
75
76 stream->__target = stream->__offset = 0;
77 stream->__get_limit = stream->__bufp = stream->__buffer + *info->bufsize;
78 stream->__put_limit = stream->__buffer + stream->__bufsize;
79
80 need -= stream->__bufp - stream->__buffer + 1;
81 if (need > 0)
82 {
83 /* We are extending the buffer after an fseek; zero-fill new space. */
84 bzero (stream->__bufp, need);
85 stream->__bufp += need;
86 }
87
88 if (c != EOF)
89 *stream->__bufp++ = (unsigned char) c;
90 else
91 *stream->__bufp = '\0';
92}
93
94/* Seek function for memstreams.
95 There is no external state to munge. */
96
97static int
98DEFUN(seek, (cookie, pos, whence),
99 PTR cookie AND fpos_t *pos AND int whence)
100{
101 switch (whence)
102 {
103 case SEEK_SET:
104 case SEEK_CUR:
105 return 0;
106
107 case SEEK_END:
108 /* Return the position relative to the end of the object.
109 fseek has just flushed us, so the info is consistent. */
110 *pos += *((struct memstream_info *) cookie)->bufsize;
111 return 0;
112
113 default:
114 __libc_fatal ("memstream::seek called with bogus WHENCE\n");
115 return -1;
116 }
117}
118
119static int
120DEFUN(free_info, (cookie), PTR cookie)
121{
122#if 0
123 struct memstream_info *info = (struct memstream_info *) cookie;
124 char *buf;
125
126 buf = (char *) realloc ((PTR) *info->buffer, *info->bufsize);
127 if (buf != NULL)
128 *info->buffer = buf;
129#endif
130
131 free (cookie);
132
133 return 0;
134}
135\f
136/* Open a stream that writes into a malloc'd buffer that is expanded as
137 necessary. *BUFLOC and *SIZELOC are updated with the buffer's location
138 and the number of characters written on fflush or fclose. */
139FILE *
140DEFUN(open_memstream, (bufloc, sizeloc),
141 char **bufloc AND size_t *sizeloc)
142{
143 FILE *stream;
144 struct memstream_info *info;
145
146 if (bufloc == NULL || sizeloc == NULL)
147 {
148 errno = EINVAL;
149 return NULL;
150 }
151
152 stream = fmemopen ((char *) NULL, BUFSIZ, "w+");
153 if (stream == NULL)
154 return NULL;
155
156 info = (struct memstream_info *) malloc (sizeof (struct memstream_info));
157 if (info == NULL)
158 {
159 int save = errno;
160 (void) fclose (stream);
161 errno = save;
162 return NULL;
163 }
164
165 stream->__room_funcs.__output = enlarge_buffer;
166 stream->__io_funcs.__seek = seek;
167 stream->__io_funcs.__close = free_info;
168 stream->__cookie = (PTR) info;
169 stream->__userbuf = 1;
170
171 info->buffer = bufloc;
172 info->bufsize = sizeloc;
173
174 *bufloc = stream->__buffer;
175
176 return stream;
177}
This page took 0.047866 seconds and 5 git commands to generate.