Fix unsafe compiler optimization
[glibc.git] / libio / strops.c
blobccbfc9982d045e488816406d97015d93830bbc2d
1 /* Copyright (C) 1993-2012 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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/>.
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. */
27 #include <assert.h>
28 #include "strfile.h"
29 #include "libioP.h"
30 #include <string.h>
31 #include <stdio_ext.h>
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;
40 _IO_FILE *fp = &sf->_sbf._f;
41 char *end;
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);
51 fp->_IO_write_base = ptr;
52 fp->_IO_read_base = ptr;
53 fp->_IO_read_ptr = ptr;
54 if (pstart)
56 fp->_IO_write_ptr = pstart;
57 fp->_IO_write_end = end;
58 fp->_IO_read_end = pstart;
60 else
62 fp->_IO_write_ptr = ptr;
63 fp->_IO_write_end = ptr;
64 fp->_IO_read_end = end;
66 /* A null _allocate_buffer function flags the strfile as being static. */
67 sf->_s._allocate_buffer = (_IO_alloc_type) 0;
70 void
71 _IO_str_init_static (sf, ptr, size, pstart)
72 _IO_strfile *sf;
73 char *ptr;
74 int size;
75 char *pstart;
77 return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
80 void
81 _IO_str_init_readonly (sf, ptr, size)
82 _IO_strfile *sf;
83 const char *ptr;
84 int size;
86 _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
87 sf->_sbf._f._IO_file_flags |= _IO_NO_WRITES;
90 int
91 _IO_str_overflow (fp, c)
92 _IO_FILE *fp;
93 int c;
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))
101 fp->_flags |= _IO_CURRENTLY_PUTTING;
102 fp->_IO_write_ptr = fp->_IO_read_ptr;
103 fp->_IO_read_ptr = fp->_IO_read_end;
105 pos = fp->_IO_write_ptr - fp->_IO_write_base;
106 if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only))
108 if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
109 return EOF;
110 else
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)
122 /* __ferror(fp) = 1; */
123 return EOF;
125 if (old_buf)
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;
132 memset (new_buf + old_blen, '\0', new_size - old_blen);
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);
140 fp->_IO_write_base = new_buf;
141 fp->_IO_write_end = fp->_IO_buf_end;
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;
151 libc_hidden_def (_IO_str_overflow)
154 _IO_str_underflow (fp)
155 _IO_FILE *fp;
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))
161 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
162 fp->_IO_read_ptr = fp->_IO_write_ptr;
163 fp->_IO_write_ptr = fp->_IO_write_end;
165 if (fp->_IO_read_ptr < fp->_IO_read_end)
166 return *((unsigned char *) fp->_IO_read_ptr);
167 else
168 return EOF;
170 libc_hidden_def (_IO_str_underflow)
172 /* The size of the valid part of the buffer. */
174 _IO_ssize_t
175 _IO_str_count (fp)
176 _IO_FILE *fp;
178 return ((fp->_IO_write_ptr > fp->_IO_read_end
179 ? fp->_IO_write_ptr : fp->_IO_read_end)
180 - fp->_IO_read_base);
184 static int
185 enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
187 if ((_IO_ssize_t) offset <= _IO_blen (fp))
188 return 0;
190 _IO_ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
192 /* Try to enlarge the buffer. */
193 if (fp->_flags & _IO_USER_BUF)
194 /* User-provided buffer. */
195 return 1;
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;
204 if (oldbuf != NULL)
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;
213 _IO_setb (fp, newbuf, newbuf + newsize, 1);
215 if (reading)
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);
222 fp->_IO_read_base = newbuf;
223 fp->_IO_read_end = fp->_IO_buf_end;
225 else
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);
232 fp->_IO_write_base = newbuf;
233 fp->_IO_write_end = fp->_IO_buf_end;
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);
244 return 0;
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;
255 _IO_off64_t new_pos;
257 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
258 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
260 if (mode == 0)
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;
269 else
271 _IO_ssize_t cur_size = _IO_str_count(fp);
272 new_pos = EOF;
274 /* Move the get pointer, if requested. */
275 if (mode & _IOS_INPUT)
277 switch (dir)
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;
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;
298 /* Move the put pointer, if requested. */
299 if (mode & _IOS_OUTPUT)
301 switch (dir)
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;
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;
321 return new_pos;
323 libc_hidden_def (_IO_str_seekoff)
326 _IO_str_pbackfail (fp, c)
327 _IO_FILE *fp;
328 int c;
330 if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
331 return EOF;
332 return _IO_default_pbackfail (fp, c);
334 libc_hidden_def (_IO_str_pbackfail)
336 void
337 _IO_str_finish (fp, dummy)
338 _IO_FILE *fp;
339 int dummy;
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;
345 _IO_default_finish (fp, 0);
348 const struct _IO_jump_t _IO_str_jumps =
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)