]> git.ipfire.org Git - thirdparty/glibc.git/blob - libio/strops.c
e3a5ae3ca47adbf7ea596664b3df16b13ed93420
[thirdparty/glibc.git] / libio / strops.c
1 /* Copyright (C) 1993-2014 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
33 void
34 _IO_str_init_static_internal (sf, ptr, size, pstart)
35 _IO_strfile *sf;
36 char *ptr;
37 _IO_size_t size;
38 char *pstart;
39 {
40 _IO_FILE *fp = &sf->_sbf._f;
41 char *end;
42
43 if (size == 0)
44 end = __rawmemchr (ptr, '\0');
45 else if ((_IO_size_t) ptr + size > (_IO_size_t) ptr)
46 end = ptr + size;
47 else
48 end = (char *) -1;
49 _IO_setb (fp, ptr, end, 0);
50
51 fp->_IO_write_base = ptr;
52 fp->_IO_read_base = ptr;
53 fp->_IO_read_ptr = ptr;
54 if (pstart)
55 {
56 fp->_IO_write_ptr = pstart;
57 fp->_IO_write_end = end;
58 fp->_IO_read_end = pstart;
59 }
60 else
61 {
62 fp->_IO_write_ptr = ptr;
63 fp->_IO_write_end = ptr;
64 fp->_IO_read_end = end;
65 }
66 /* A null _allocate_buffer function flags the strfile as being static. */
67 sf->_s._allocate_buffer = (_IO_alloc_type) 0;
68 }
69
70 void
71 _IO_str_init_static (sf, ptr, size, pstart)
72 _IO_strfile *sf;
73 char *ptr;
74 int size;
75 char *pstart;
76 {
77 return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
78 }
79
80 void
81 _IO_str_init_readonly (sf, ptr, size)
82 _IO_strfile *sf;
83 const char *ptr;
84 int size;
85 {
86 _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
87 sf->_sbf._f._IO_file_flags |= _IO_NO_WRITES;
88 }
89
90 int
91 _IO_str_overflow (fp, c)
92 _IO_FILE *fp;
93 int c;
94 {
95 int flush_only = c == EOF;
96 _IO_size_t pos;
97 if (fp->_flags & _IO_NO_WRITES)
98 return flush_only ? 0 : EOF;
99 if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
100 {
101 fp->_flags |= _IO_CURRENTLY_PUTTING;
102 fp->_IO_write_ptr = fp->_IO_read_ptr;
103 fp->_IO_read_ptr = fp->_IO_read_end;
104 }
105 pos = fp->_IO_write_ptr - fp->_IO_write_base;
106 if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only))
107 {
108 if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
109 return EOF;
110 else
111 {
112 char *new_buf;
113 char *old_buf = fp->_IO_buf_base;
114 size_t old_blen = _IO_blen (fp);
115 _IO_size_t new_size = 2 * old_blen + 100;
116 if (new_size < old_blen)
117 return EOF;
118 new_buf
119 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);
120 if (new_buf == NULL)
121 {
122 /* __ferror(fp) = 1; */
123 return EOF;
124 }
125 if (old_buf)
126 {
127 memcpy (new_buf, old_buf, old_blen);
128 (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
129 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
130 fp->_IO_buf_base = NULL;
131 }
132 memset (new_buf + old_blen, '\0', new_size - old_blen);
133
134 _IO_setb (fp, new_buf, new_buf + new_size, 1);
135 fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
136 fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
137 fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
138 fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
139
140 fp->_IO_write_base = new_buf;
141 fp->_IO_write_end = fp->_IO_buf_end;
142 }
143 }
144
145 if (!flush_only)
146 *fp->_IO_write_ptr++ = (unsigned char) c;
147 if (fp->_IO_write_ptr > fp->_IO_read_end)
148 fp->_IO_read_end = fp->_IO_write_ptr;
149 return c;
150 }
151 libc_hidden_def (_IO_str_overflow)
152
153 int
154 _IO_str_underflow (fp)
155 _IO_FILE *fp;
156 {
157 if (fp->_IO_write_ptr > fp->_IO_read_end)
158 fp->_IO_read_end = fp->_IO_write_ptr;
159 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
160 {
161 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
162 fp->_IO_read_ptr = fp->_IO_write_ptr;
163 fp->_IO_write_ptr = fp->_IO_write_end;
164 }
165 if (fp->_IO_read_ptr < fp->_IO_read_end)
166 return *((unsigned char *) fp->_IO_read_ptr);
167 else
168 return EOF;
169 }
170 libc_hidden_def (_IO_str_underflow)
171
172 /* The size of the valid part of the buffer. */
173
174 _IO_ssize_t
175 _IO_str_count (fp)
176 _IO_FILE *fp;
177 {
178 return ((fp->_IO_write_ptr > fp->_IO_read_end
179 ? fp->_IO_write_ptr : fp->_IO_read_end)
180 - fp->_IO_read_base);
181 }
182
183
184 static int
185 enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
186 {
187 if ((_IO_ssize_t) offset <= _IO_blen (fp))
188 return 0;
189
190 _IO_ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
191
192 /* Try to enlarge the buffer. */
193 if (fp->_flags & _IO_USER_BUF)
194 /* User-provided buffer. */
195 return 1;
196
197 _IO_size_t newsize = offset + 100;
198 char *oldbuf = fp->_IO_buf_base;
199 char *newbuf
200 = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize);
201 if (newbuf == NULL)
202 return 1;
203
204 if (oldbuf != NULL)
205 {
206 memcpy (newbuf, oldbuf, _IO_blen (fp));
207 (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
208 /* Make sure _IO_setb won't try to delete
209 _IO_buf_base. */
210 fp->_IO_buf_base = NULL;
211 }
212
213 _IO_setb (fp, newbuf, newbuf + newsize, 1);
214
215 if (reading)
216 {
217 fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
218 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
219 fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
220 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
221
222 fp->_IO_read_base = newbuf;
223 fp->_IO_read_end = fp->_IO_buf_end;
224 }
225 else
226 {
227 fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
228 fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
229 fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
230 fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
231
232 fp->_IO_write_base = newbuf;
233 fp->_IO_write_end = fp->_IO_buf_end;
234 }
235
236 /* Clear the area between the last write position and th
237 new position. */
238 assert (offset >= oldend);
239 if (reading)
240 memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
241 else
242 memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
243
244 return 0;
245 }
246
247
248 _IO_off64_t
249 _IO_str_seekoff (fp, offset, dir, mode)
250 _IO_FILE *fp;
251 _IO_off64_t offset;
252 int dir;
253 int mode;
254 {
255 _IO_off64_t new_pos;
256
257 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
258 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
259
260 if (mode == 0)
261 {
262 /* Don't move any pointers. But there is no clear indication what
263 mode FP is in. Let's guess. */
264 if (fp->_IO_file_flags & _IO_NO_WRITES)
265 new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
266 else
267 new_pos = fp->_IO_write_ptr - fp->_IO_write_base;
268 }
269 else
270 {
271 _IO_ssize_t cur_size = _IO_str_count(fp);
272 new_pos = EOF;
273
274 /* Move the get pointer, if requested. */
275 if (mode & _IOS_INPUT)
276 {
277 switch (dir)
278 {
279 case _IO_seek_end:
280 offset += cur_size;
281 break;
282 case _IO_seek_cur:
283 offset += fp->_IO_read_ptr - fp->_IO_read_base;
284 break;
285 default: /* case _IO_seek_set: */
286 break;
287 }
288 if (offset < 0)
289 return EOF;
290 if ((_IO_ssize_t) offset > cur_size
291 && enlarge_userbuf (fp, offset, 1) != 0)
292 return EOF;
293 fp->_IO_read_ptr = fp->_IO_read_base + offset;
294 fp->_IO_read_end = fp->_IO_read_base + cur_size;
295 new_pos = offset;
296 }
297
298 /* Move the put pointer, if requested. */
299 if (mode & _IOS_OUTPUT)
300 {
301 switch (dir)
302 {
303 case _IO_seek_end:
304 offset += cur_size;
305 break;
306 case _IO_seek_cur:
307 offset += fp->_IO_write_ptr - fp->_IO_write_base;
308 break;
309 default: /* case _IO_seek_set: */
310 break;
311 }
312 if (offset < 0)
313 return EOF;
314 if ((_IO_ssize_t) offset > cur_size
315 && enlarge_userbuf (fp, offset, 0) != 0)
316 return EOF;
317 fp->_IO_write_ptr = fp->_IO_write_base + offset;
318 new_pos = offset;
319 }
320 }
321 return new_pos;
322 }
323 libc_hidden_def (_IO_str_seekoff)
324
325 int
326 _IO_str_pbackfail (fp, c)
327 _IO_FILE *fp;
328 int c;
329 {
330 if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
331 return EOF;
332 return _IO_default_pbackfail (fp, c);
333 }
334 libc_hidden_def (_IO_str_pbackfail)
335
336 void
337 _IO_str_finish (fp, dummy)
338 _IO_FILE *fp;
339 int dummy;
340 {
341 if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
342 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);
343 fp->_IO_buf_base = NULL;
344
345 _IO_default_finish (fp, 0);
346 }
347
348 const struct _IO_jump_t _IO_str_jumps =
349 {
350 JUMP_INIT_DUMMY,
351 JUMP_INIT(finish, _IO_str_finish),
352 JUMP_INIT(overflow, _IO_str_overflow),
353 JUMP_INIT(underflow, _IO_str_underflow),
354 JUMP_INIT(uflow, _IO_default_uflow),
355 JUMP_INIT(pbackfail, _IO_str_pbackfail),
356 JUMP_INIT(xsputn, _IO_default_xsputn),
357 JUMP_INIT(xsgetn, _IO_default_xsgetn),
358 JUMP_INIT(seekoff, _IO_str_seekoff),
359 JUMP_INIT(seekpos, _IO_default_seekpos),
360 JUMP_INIT(setbuf, _IO_default_setbuf),
361 JUMP_INIT(sync, _IO_default_sync),
362 JUMP_INIT(doallocate, _IO_default_doallocate),
363 JUMP_INIT(read, _IO_default_read),
364 JUMP_INIT(write, _IO_default_write),
365 JUMP_INIT(seek, _IO_default_seek),
366 JUMP_INIT(close, _IO_default_close),
367 JUMP_INIT(stat, _IO_default_stat),
368 JUMP_INIT(showmanyc, _IO_default_showmanyc),
369 JUMP_INIT(imbue, _IO_default_imbue)
370 };