1/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>.
17
18 As a special exception, if you link the code in this file with
19 files compiled with a GNU compiler to produce an executable,
20 that does not cause the resulting executable to be covered by
21 the GNU Lesser General Public License. This exception does not
22 however invalidate any other reasons why the executable file
23 might be covered by the GNU Lesser General Public License.
24 This exception applies to code released by its copyright holders
25 in files containing the exception. */
26
27#include <assert.h>
28#include "strfile.h"
29#include "libioP.h"
30#include <string.h>
31#include <stdio_ext.h>
32
33void
34_IO_str_init_static_internal (_IO_strfile *sf, char *ptr, _IO_size_t size,
35 char *pstart)
36{
37 _IO_FILE *fp = &sf->_sbf._f;
38 char *end;
39
40 if (size == 0)
41 end = __rawmemchr (ptr, '\0');
42 else if ((_IO_size_t) ptr + size > (_IO_size_t) ptr)
43 end = ptr + size;
44 else
45 end = (char *) -1;
46 _IO_setb (fp, ptr, end, 0);
47
48 fp->_IO_write_base = ptr;
49 fp->_IO_read_base = ptr;
50 fp->_IO_read_ptr = ptr;
51 if (pstart)
52 {
53 fp->_IO_write_ptr = pstart;
54 fp->_IO_write_end = end;
55 fp->_IO_read_end = pstart;
56 }
57 else
58 {
59 fp->_IO_write_ptr = ptr;
60 fp->_IO_write_end = ptr;
61 fp->_IO_read_end = end;
62 }
63 /* A null _allocate_buffer function flags the strfile as being static. */
64 sf->_s._allocate_buffer = (_IO_alloc_type) 0;
65}
66
67void
68_IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
69{
70 return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
71}
72
73void
74_IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
75{
76 _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
77 sf->_sbf._f._IO_file_flags |= _IO_NO_WRITES;
78}
79
80int
81_IO_str_overflow (_IO_FILE *fp, int c)
82{
83 int flush_only = c == EOF;
84 _IO_size_t pos;
85 if (fp->_flags & _IO_NO_WRITES)
86 return flush_only ? 0 : EOF;
87 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
88 {
89 fp->_flags |= _IO_CURRENTLY_PUTTING;
90 fp->_IO_write_ptr = fp->_IO_read_ptr;
91 fp->_IO_read_ptr = fp->_IO_read_end;
92 }
93 pos = fp->_IO_write_ptr - fp->_IO_write_base;
94 if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only))
95 {
96 if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
97 return EOF;
98 else
99 {
100 char *new_buf;
101 char *old_buf = fp->_IO_buf_base;
102 size_t old_blen = _IO_blen (fp);
103 _IO_size_t new_size = 2 * old_blen + 100;
104 if (new_size < old_blen)
105 return EOF;
106 new_buf
107 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);
108 if (new_buf == NULL)
109 {
110 /* __ferror(fp) = 1; */
111 return EOF;
112 }
113 if (old_buf)
114 {
115 memcpy (new_buf, old_buf, old_blen);
116 (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
117 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
118 fp->_IO_buf_base = NULL;
119 }
120 memset (new_buf + old_blen, '\0', new_size - old_blen);
121
122 _IO_setb (fp, new_buf, new_buf + new_size, 1);
123 fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
124 fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
125 fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
126 fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
127
128 fp->_IO_write_base = new_buf;
129 fp->_IO_write_end = fp->_IO_buf_end;
130 }
131 }
132
133 if (!flush_only)
134 *fp->_IO_write_ptr++ = (unsigned char) c;
135 if (fp->_IO_write_ptr > fp->_IO_read_end)
136 fp->_IO_read_end = fp->_IO_write_ptr;
137 return c;
138}
139libc_hidden_def (_IO_str_overflow)
140
141int
142_IO_str_underflow (_IO_FILE *fp)
143{
144 if (fp->_IO_write_ptr > fp->_IO_read_end)
145 fp->_IO_read_end = fp->_IO_write_ptr;
146 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
147 {
148 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
149 fp->_IO_read_ptr = fp->_IO_write_ptr;
150 fp->_IO_write_ptr = fp->_IO_write_end;
151 }
152 if (fp->_IO_read_ptr < fp->_IO_read_end)
153 return *((unsigned char *) fp->_IO_read_ptr);
154 else
155 return EOF;
156}
157libc_hidden_def (_IO_str_underflow)
158
159/* The size of the valid part of the buffer. */
160
161_IO_ssize_t
162_IO_str_count (_IO_FILE *fp)
163{
164 return ((fp->_IO_write_ptr > fp->_IO_read_end
165 ? fp->_IO_write_ptr : fp->_IO_read_end)
166 - fp->_IO_read_base);
167}
168
169
170static int
171enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
172{
173 if ((_IO_ssize_t) offset <= _IO_blen (fp))
174 return 0;
175
176 _IO_ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
177
178 /* Try to enlarge the buffer. */
179 if (fp->_flags & _IO_USER_BUF)
180 /* User-provided buffer. */
181 return 1;
182
183 _IO_size_t newsize = offset + 100;
184 char *oldbuf = fp->_IO_buf_base;
185 char *newbuf
186 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize);
187 if (newbuf == NULL)
188 return 1;
189
190 if (oldbuf != NULL)
191 {
192 memcpy (newbuf, oldbuf, _IO_blen (fp));
193 (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
194 /* Make sure _IO_setb won't try to delete
195 _IO_buf_base. */
196 fp->_IO_buf_base = NULL;
197 }
198
199 _IO_setb (fp, newbuf, newbuf + newsize, 1);
200
201 if (reading)
202 {
203 fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
204 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
205 fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
206 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
207
208 fp->_IO_read_base = newbuf;
209 fp->_IO_read_end = fp->_IO_buf_end;
210 }
211 else
212 {
213 fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
214 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
215 fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
216 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
217
218 fp->_IO_write_base = newbuf;
219 fp->_IO_write_end = fp->_IO_buf_end;
220 }
221
222 /* Clear the area between the last write position and th
223 new position. */
224 assert (offset >= oldend);
225 if (reading)
226 memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
227 else
228 memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
229
230 return 0;
231}
232
233static void
234_IO_str_switch_to_get_mode (_IO_FILE *fp)
235{
236 if (_IO_in_backup (fp))
237 fp->_IO_read_base = fp->_IO_backup_base;
238 else
239 {
240 fp->_IO_read_base = fp->_IO_buf_base;
241 if (fp->_IO_write_ptr > fp->_IO_read_end)
242 fp->_IO_read_end = fp->_IO_write_ptr;
243 }
244 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
245
246 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
247}
248
249_IO_off64_t
250_IO_str_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
251{
252 _IO_off64_t new_pos;
253
254 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
255 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
256
257 bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
258 || _IO_in_put_mode (fp));
259 if (was_writing)
260 _IO_str_switch_to_get_mode (fp);
261
262 if (mode == 0)
263 {
264 new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
265 }
266 else
267 {
268 _IO_ssize_t cur_size = _IO_str_count(fp);
269 new_pos = EOF;
270
271 /* Move the get pointer, if requested. */
272 if (mode & _IOS_INPUT)
273 {
274 _IO_ssize_t base;
275 switch (dir)
276 {
277 case _IO_seek_set:
278 base = 0;
279 break;
280 case _IO_seek_cur:
281 base = fp->_IO_read_ptr - fp->_IO_read_base;
282 break;
283 default: /* case _IO_seek_end: */
284 base = cur_size;
285 break;
286 }
287 _IO_ssize_t maxval = SSIZE_MAX - base;
288 if (offset < -base || offset > maxval)
289 {
290 __set_errno (EINVAL);
291 return EOF;
292 }
293 base += offset;
294 if (base > cur_size
295 && enlarge_userbuf (fp, base, 1) != 0)
296 return EOF;
297 fp->_IO_read_ptr = fp->_IO_read_base + base;
298 fp->_IO_read_end = fp->_IO_read_base + cur_size;
299 new_pos = base;
300 }
301
302 /* Move the put pointer, if requested. */
303 if (mode & _IOS_OUTPUT)
304 {
305 _IO_ssize_t base;
306 switch (dir)
307 {
308 case _IO_seek_set:
309 base = 0;
310 break;
311 case _IO_seek_cur:
312 base = fp->_IO_write_ptr - fp->_IO_write_base;
313 break;
314 default: /* case _IO_seek_end: */
315 base = cur_size;
316 break;
317 }
318 _IO_ssize_t maxval = SSIZE_MAX - base;
319 if (offset < -base || offset > maxval)
320 {
321 __set_errno (EINVAL);
322 return EOF;
323 }
324 base += offset;
325 if (base > cur_size
326 && enlarge_userbuf (fp, base, 0) != 0)
327 return EOF;
328 fp->_IO_write_ptr = fp->_IO_write_base + base;
329 new_pos = base;
330 }
331 }
332 return new_pos;
333}
334libc_hidden_def (_IO_str_seekoff)
335
336int
337_IO_str_pbackfail (_IO_FILE *fp, int c)
338{
339 if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
340 return EOF;
341 return _IO_default_pbackfail (fp, c);
342}
343libc_hidden_def (_IO_str_pbackfail)
344
345void
346_IO_str_finish (_IO_FILE *fp, int dummy)
347{
348 if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
349 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);
350 fp->_IO_buf_base = NULL;
351
352 _IO_default_finish (fp, 0);
353}
354
355const struct _IO_jump_t _IO_str_jumps libio_vtable =
356{
357 JUMP_INIT_DUMMY,
358 JUMP_INIT(finish, _IO_str_finish),
359 JUMP_INIT(overflow, _IO_str_overflow),
360 JUMP_INIT(underflow, _IO_str_underflow),
361 JUMP_INIT(uflow, _IO_default_uflow),
362 JUMP_INIT(pbackfail, _IO_str_pbackfail),
363 JUMP_INIT(xsputn, _IO_default_xsputn),
364 JUMP_INIT(xsgetn, _IO_default_xsgetn),
365 JUMP_INIT(seekoff, _IO_str_seekoff),
366 JUMP_INIT(seekpos, _IO_default_seekpos),
367 JUMP_INIT(setbuf, _IO_default_setbuf),
368 JUMP_INIT(sync, _IO_default_sync),
369 JUMP_INIT(doallocate, _IO_default_doallocate),
370 JUMP_INIT(read, _IO_default_read),
371 JUMP_INIT(write, _IO_default_write),
372 JUMP_INIT(seek, _IO_default_seek),
373 JUMP_INIT(close, _IO_default_close),
374 JUMP_INIT(stat, _IO_default_stat),
375 JUMP_INIT(showmanyc, _IO_default_showmanyc),
376 JUMP_INIT(imbue, _IO_default_imbue)
377};
378