]> git.ipfire.org Git - thirdparty/glibc.git/blame - libio/strops.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / libio / strops.c
CommitLineData
2b778ceb 1/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
41bdb6e2 2 This file is part of the GNU C Library.
96aa2d94 3
41bdb6e2
AJ
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.
96aa2d94 8
41bdb6e2
AJ
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
40a55d20 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2
AJ
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>.
41bdb6e2
AJ
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. */
96aa2d94 26
107b8a92 27#include <assert.h>
96aa2d94
RM
28#include "strfile.h"
29#include "libioP.h"
30#include <string.h>
0d875352 31#include <stdio_ext.h>
96aa2d94 32
96aa2d94 33void
9964a145 34_IO_str_init_static_internal (_IO_strfile *sf, char *ptr, size_t size,
9dd346ff 35 char *pstart)
96aa2d94 36{
9964a145 37 FILE *fp = &sf->_sbf._f;
40a54e4d 38 char *end;
2ca8b1ee 39
96aa2d94 40 if (size == 0)
40a54e4d 41 end = __rawmemchr (ptr, '\0');
9964a145 42 else if ((size_t) ptr + size > (size_t) ptr)
40a54e4d
UD
43 end = ptr + size;
44 else
45 end = (char *) -1;
d18ea0c5 46 _IO_setb (fp, ptr, end, 0);
96aa2d94
RM
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;
40a54e4d 54 fp->_IO_write_end = end;
96aa2d94
RM
55 fp->_IO_read_end = pstart;
56 }
57 else
58 {
59 fp->_IO_write_ptr = ptr;
60 fp->_IO_write_end = ptr;
40a54e4d 61 fp->_IO_read_end = end;
96aa2d94 62 }
96aa2d94 63 /* A null _allocate_buffer function flags the strfile as being static. */
4e8a6346 64 sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
96aa2d94 65}
40a54e4d
UD
66
67void
9dd346ff 68_IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
40a54e4d
UD
69{
70 return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
71}
96aa2d94
RM
72
73void
9dd346ff 74_IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
96aa2d94 75{
40a54e4d 76 _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
df6c012b 77 sf->_sbf._f._flags |= _IO_NO_WRITES;
96aa2d94
RM
78}
79
80int
9964a145 81_IO_str_overflow (FILE *fp, int c)
96aa2d94
RM
82{
83 int flush_only = c == EOF;
9964a145 84 size_t pos;
96aa2d94
RM
85 if (fp->_flags & _IO_NO_WRITES)
86 return flush_only ? 0 : EOF;
96aa2d94
RM
87 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
88 {
96aa2d94 89 fp->_flags |= _IO_CURRENTLY_PUTTING;
8a523922
UD
90 fp->_IO_write_ptr = fp->_IO_read_ptr;
91 fp->_IO_read_ptr = fp->_IO_read_end;
96aa2d94 92 }
107b8a92 93 pos = fp->_IO_write_ptr - fp->_IO_write_base;
9964a145 94 if (pos >= (size_t) (_IO_blen (fp) + flush_only))
96aa2d94
RM
95 {
96 if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
8a523922 97 return EOF;
96aa2d94
RM
98 else
99 {
100 char *new_buf;
8a523922 101 char *old_buf = fp->_IO_buf_base;
107b8a92 102 size_t old_blen = _IO_blen (fp);
9964a145 103 size_t new_size = 2 * old_blen + 100;
107b8a92
UD
104 if (new_size < old_blen)
105 return EOF;
4e8a6346 106 new_buf = malloc (new_size);
96aa2d94
RM
107 if (new_buf == NULL)
108 {
109 /* __ferror(fp) = 1; */
110 return EOF;
111 }
d64b6ad0 112 if (old_buf)
96aa2d94 113 {
107b8a92 114 memcpy (new_buf, old_buf, old_blen);
4e8a6346 115 free (old_buf);
96aa2d94
RM
116 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
117 fp->_IO_buf_base = NULL;
118 }
107b8a92
UD
119 memset (new_buf + old_blen, '\0', new_size - old_blen);
120
d18ea0c5 121 _IO_setb (fp, new_buf, new_buf + new_size, 1);
8a523922
UD
122 fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
123 fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
124 fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
125 fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
126
96aa2d94 127 fp->_IO_write_base = new_buf;
f21acc89 128 fp->_IO_write_end = fp->_IO_buf_end;
96aa2d94 129 }
96aa2d94
RM
130 }
131
96aa2d94
RM
132 if (!flush_only)
133 *fp->_IO_write_ptr++ = (unsigned char) c;
8a523922
UD
134 if (fp->_IO_write_ptr > fp->_IO_read_end)
135 fp->_IO_read_end = fp->_IO_write_ptr;
96aa2d94
RM
136 return c;
137}
d18ea0c5 138libc_hidden_def (_IO_str_overflow)
96aa2d94
RM
139
140int
9964a145 141_IO_str_underflow (FILE *fp)
96aa2d94 142{
8a523922
UD
143 if (fp->_IO_write_ptr > fp->_IO_read_end)
144 fp->_IO_read_end = fp->_IO_write_ptr;
96aa2d94
RM
145 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
146 {
147 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
8a523922 148 fp->_IO_read_ptr = fp->_IO_write_ptr;
96aa2d94
RM
149 fp->_IO_write_ptr = fp->_IO_write_end;
150 }
96aa2d94 151 if (fp->_IO_read_ptr < fp->_IO_read_end)
195d0dd4 152 return *((unsigned char *) fp->_IO_read_ptr);
96aa2d94 153 else
0923a2c8 154 return EOF;
96aa2d94 155}
d18ea0c5 156libc_hidden_def (_IO_str_underflow)
96aa2d94 157
8a523922
UD
158/* The size of the valid part of the buffer. */
159
9964a145
ZW
160ssize_t
161_IO_str_count (FILE *fp)
96aa2d94 162{
2604afb1
UD
163 return ((fp->_IO_write_ptr > fp->_IO_read_end
164 ? fp->_IO_write_ptr : fp->_IO_read_end)
40a55d20 165 - fp->_IO_read_base);
a68b0d31 166}
96aa2d94 167
107b8a92
UD
168
169static int
9964a145 170enlarge_userbuf (FILE *fp, off64_t offset, int reading)
107b8a92 171{
9964a145 172 if ((ssize_t) offset <= _IO_blen (fp))
107b8a92
UD
173 return 0;
174
9964a145 175 ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
107b8a92
UD
176
177 /* Try to enlarge the buffer. */
178 if (fp->_flags & _IO_USER_BUF)
179 /* User-provided buffer. */
180 return 1;
181
9964a145 182 size_t newsize = offset + 100;
107b8a92 183 char *oldbuf = fp->_IO_buf_base;
4e8a6346 184 char *newbuf = malloc (newsize);
107b8a92
UD
185 if (newbuf == NULL)
186 return 1;
187
188 if (oldbuf != NULL)
189 {
190 memcpy (newbuf, oldbuf, _IO_blen (fp));
4e8a6346 191 free (oldbuf);
107b8a92
UD
192 /* Make sure _IO_setb won't try to delete
193 _IO_buf_base. */
194 fp->_IO_buf_base = NULL;
195 }
196
d18ea0c5 197 _IO_setb (fp, newbuf, newbuf + newsize, 1);
107b8a92
UD
198
199 if (reading)
200 {
201 fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
202 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
203 fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
204 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
205
206 fp->_IO_read_base = newbuf;
207 fp->_IO_read_end = fp->_IO_buf_end;
208 }
209 else
210 {
211 fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
212 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
213 fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
214 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
215
216 fp->_IO_write_base = newbuf;
217 fp->_IO_write_end = fp->_IO_buf_end;
218 }
219
220 /* Clear the area between the last write position and th
221 new position. */
222 assert (offset >= oldend);
223 if (reading)
224 memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
225 else
226 memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
227
228 return 0;
229}
230
645f97ce 231static void
9964a145 232_IO_str_switch_to_get_mode (FILE *fp)
645f97ce
AZ
233{
234 if (_IO_in_backup (fp))
235 fp->_IO_read_base = fp->_IO_backup_base;
236 else
237 {
238 fp->_IO_read_base = fp->_IO_buf_base;
239 if (fp->_IO_write_ptr > fp->_IO_read_end)
240 fp->_IO_read_end = fp->_IO_write_ptr;
241 }
242 fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
243
244 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
245}
107b8a92 246
9964a145
ZW
247off64_t
248_IO_str_seekoff (FILE *fp, off64_t offset, int dir, int mode)
96aa2d94 249{
9964a145 250 off64_t new_pos;
96aa2d94 251
dd7d45e8
UD
252 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
253 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
254
645f97ce
AZ
255 bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
256 || _IO_in_put_mode (fp));
257 if (was_writing)
258 _IO_str_switch_to_get_mode (fp);
259
2eb45444 260 if (mode == 0)
96aa2d94 261 {
645f97ce 262 new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
2eb45444
UD
263 }
264 else
265 {
9964a145 266 ssize_t cur_size = _IO_str_count(fp);
2eb45444
UD
267 new_pos = EOF;
268
269 /* Move the get pointer, if requested. */
270 if (mode & _IOS_INPUT)
96aa2d94 271 {
9964a145 272 ssize_t base;
2eb45444
UD
273 switch (dir)
274 {
645f97ce
AZ
275 case _IO_seek_set:
276 base = 0;
2eb45444
UD
277 break;
278 case _IO_seek_cur:
645f97ce 279 base = fp->_IO_read_ptr - fp->_IO_read_base;
2eb45444 280 break;
645f97ce
AZ
281 default: /* case _IO_seek_end: */
282 base = cur_size;
2eb45444
UD
283 break;
284 }
9964a145 285 ssize_t maxval = SSIZE_MAX - base;
645f97ce
AZ
286 if (offset < -base || offset > maxval)
287 {
288 __set_errno (EINVAL);
289 return EOF;
290 }
291 base += offset;
292 if (base > cur_size
293 && enlarge_userbuf (fp, base, 1) != 0)
2eb45444 294 return EOF;
645f97ce 295 fp->_IO_read_ptr = fp->_IO_read_base + base;
2eb45444 296 fp->_IO_read_end = fp->_IO_read_base + cur_size;
645f97ce 297 new_pos = base;
96aa2d94 298 }
96aa2d94 299
2eb45444
UD
300 /* Move the put pointer, if requested. */
301 if (mode & _IOS_OUTPUT)
96aa2d94 302 {
9964a145 303 ssize_t base;
2eb45444
UD
304 switch (dir)
305 {
645f97ce
AZ
306 case _IO_seek_set:
307 base = 0;
2eb45444
UD
308 break;
309 case _IO_seek_cur:
645f97ce 310 base = fp->_IO_write_ptr - fp->_IO_write_base;
2eb45444 311 break;
645f97ce
AZ
312 default: /* case _IO_seek_end: */
313 base = cur_size;
2eb45444
UD
314 break;
315 }
9964a145 316 ssize_t maxval = SSIZE_MAX - base;
645f97ce
AZ
317 if (offset < -base || offset > maxval)
318 {
319 __set_errno (EINVAL);
320 return EOF;
321 }
322 base += offset;
323 if (base > cur_size
324 && enlarge_userbuf (fp, base, 0) != 0)
2eb45444 325 return EOF;
645f97ce
AZ
326 fp->_IO_write_ptr = fp->_IO_write_base + base;
327 new_pos = base;
96aa2d94 328 }
96aa2d94
RM
329 }
330 return new_pos;
331}
d18ea0c5 332libc_hidden_def (_IO_str_seekoff)
96aa2d94
RM
333
334int
9964a145 335_IO_str_pbackfail (FILE *fp, int c)
96aa2d94
RM
336{
337 if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
338 return EOF;
d18ea0c5 339 return _IO_default_pbackfail (fp, c);
96aa2d94 340}
d18ea0c5 341libc_hidden_def (_IO_str_pbackfail)
96aa2d94
RM
342
343void
9964a145 344_IO_str_finish (FILE *fp, int dummy)
96aa2d94
RM
345{
346 if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
4e8a6346 347 free (fp->_IO_buf_base);
96aa2d94
RM
348 fp->_IO_buf_base = NULL;
349
d18ea0c5 350 _IO_default_finish (fp, 0);
96aa2d94
RM
351}
352
db3476af 353const struct _IO_jump_t _IO_str_jumps libio_vtable =
40a55d20 354{
96aa2d94
RM
355 JUMP_INIT_DUMMY,
356 JUMP_INIT(finish, _IO_str_finish),
d18ea0c5
AS
357 JUMP_INIT(overflow, _IO_str_overflow),
358 JUMP_INIT(underflow, _IO_str_underflow),
359 JUMP_INIT(uflow, _IO_default_uflow),
360 JUMP_INIT(pbackfail, _IO_str_pbackfail),
361 JUMP_INIT(xsputn, _IO_default_xsputn),
362 JUMP_INIT(xsgetn, _IO_default_xsgetn),
363 JUMP_INIT(seekoff, _IO_str_seekoff),
96aa2d94
RM
364 JUMP_INIT(seekpos, _IO_default_seekpos),
365 JUMP_INIT(setbuf, _IO_default_setbuf),
366 JUMP_INIT(sync, _IO_default_sync),
d18ea0c5 367 JUMP_INIT(doallocate, _IO_default_doallocate),
96aa2d94
RM
368 JUMP_INIT(read, _IO_default_read),
369 JUMP_INIT(write, _IO_default_write),
370 JUMP_INIT(seek, _IO_default_seek),
371 JUMP_INIT(close, _IO_default_close),
dfd2257a
UD
372 JUMP_INIT(stat, _IO_default_stat),
373 JUMP_INIT(showmanyc, _IO_default_showmanyc),
374 JUMP_INIT(imbue, _IO_default_imbue)
96aa2d94 375};