Update copyright notices with scripts/update-copyrights.
[jlayton/glibc.git] / libio / strops.c
1 /* Copyright (C) 1993-2013 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 };