Mon Jun 24 19:57:01 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / libio / strops.c
1 /* 
2 Copyright (C) 1993 Free Software Foundation
3
4 This file is part of the GNU IO Library.  This library is free
5 software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this library; see the file COPYING.  If not, write to the Free
17 Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 As a special exception, if you link this library with files
20 compiled with a GNU compiler to produce an executable, this does not cause
21 the resulting executable to be covered by the GNU General Public License.
22 This exception does not however invalidate any other reasons why
23 the executable file might be covered by the GNU General Public License. */
24
25 #include "strfile.h"
26 #include "libioP.h"
27 #include <string.h>
28
29 #define LEN(fp) (((_IO_strfile*)(fp))->_s._len)
30
31 #ifdef TODO
32 /* An "unbounded buffer" is when a buffer is supplied, but with no
33    specified length.  An example is the buffer argument to sprintf.
34    */
35 #endif
36
37 void
38 DEFUN(_IO_str_init_static, (fp, ptr, size, pstart),
39       _IO_FILE *fp AND char *ptr AND int size AND char *pstart)
40 {
41   if (size == 0)
42     size = strlen(ptr);
43   else if (size < 0)
44     {
45       /* If size is negative 'the characters are assumed to
46          continue indefinitely.'  This is kind of messy ... */
47 #if 1
48       int s;
49       size = 512;
50       /* Try increasing powers of 2, as long as we don't wrap around.
51          This can lose in pathological cases (ptr near the end
52          of the address space).  A better solution might be to
53          adjust the size on underflow/overflow.  FIXME. */
54       for ( ; s = 2*size, s > 0 && ptr + s > ptr && s < 0x4000000L; )
55         size = s;
56       size = s;
57 #else
58       /* The following semi-portable kludge assumes that
59          sizeof(unsigned long) == sizeof(char*). Hence,
60          (unsigned long)(-1) should be the largest possible address. */
61       unsigned long highest = (unsigned long)(-1);
62       /* Pointers are signed on some brain-damaged systems, in
63          which case we divide by two to get the maximum signed address. */
64       if  ((char*)highest < ptr)
65         highest >>= 1;
66       size = (char*)highest - ptr;
67 #endif
68     }
69   _IO_setb(fp, ptr, ptr+size, 0);
70
71   fp->_IO_write_base = ptr;
72   fp->_IO_read_base = ptr;
73   fp->_IO_read_ptr = ptr;
74   if (pstart)
75     {
76       fp->_IO_write_ptr = pstart;
77       fp->_IO_write_end = ptr+size;
78       fp->_IO_read_end = pstart;
79     }
80   else
81     {
82       fp->_IO_write_ptr = ptr;
83       fp->_IO_write_end = ptr;
84       fp->_IO_read_end = ptr+size;
85     }
86   LEN(fp) = size;
87   /* A null _allocate_buffer function flags the strfile as being static. */
88   (((_IO_strfile*)(fp))->_s._allocate_buffer) =  (_IO_alloc_type)0;
89 }
90
91 void
92 DEFUN(_IO_str_init_readonly, (fp, ptr, size),
93       _IO_FILE *fp AND const char *ptr AND int size)
94 {
95   _IO_str_init_static (fp, (char*)ptr, size, NULL);
96   fp->_IO_file_flags |= _IO_NO_WRITES;
97 }
98
99 int
100 DEFUN(_IO_str_overflow, (fp, c),
101       register _IO_FILE* fp AND int c)
102 {
103   int flush_only = c == EOF;
104   _IO_size_t pos = fp->_IO_write_ptr - fp->_IO_write_base;
105   _IO_size_t get_pos = fp->_IO_read_ptr - fp->_IO_read_base;
106   if (fp->_flags & _IO_NO_WRITES)
107       return flush_only ? 0 : EOF;
108   if (pos > LEN(fp)) LEN(fp) = pos;
109   if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
110     {
111       pos = get_pos;
112       fp->_flags |= _IO_CURRENTLY_PUTTING;
113       get_pos = LEN(fp);
114     }
115   if (pos >= _IO_blen(fp) + flush_only)
116     {
117       if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
118         {
119 #ifdef TODO
120           if (indefinite size)
121             {
122               fp->_IO_buf_end += 512;
123             }
124           else
125 #endif
126           return EOF;
127         }
128       else
129         {
130           char *new_buf;
131           _IO_size_t new_size = 2 * _IO_blen(fp);
132           new_buf
133             = (char*)(*((_IO_strfile*)fp)->_s._allocate_buffer)(new_size);
134           if (new_buf == NULL)
135             {
136               /*          __ferror(fp) = 1; */
137               return EOF;
138             }
139           memcpy(new_buf, fp->_IO_buf_base, _IO_blen(fp));
140 #if 0
141           if (lenp == &LEN(fp)) /* use '\0'-filling */
142               memset(new_buf + pos, 0, blen() - pos);
143 #endif
144           if (fp->_IO_buf_base)
145             {
146               (*((_IO_strfile*)fp)->_s._free_buffer)(fp->_IO_buf_base);
147               /* Make sure _IO_setb won't try to delete _IO_buf_base. */
148               fp->_IO_buf_base = NULL;
149             }
150           _IO_setb(fp, new_buf, new_buf + new_size, 1);
151           fp->_IO_write_base = new_buf;
152         }
153       fp->_IO_write_end = fp->_IO_buf_end;
154     }
155
156   fp->_IO_write_ptr = fp->_IO_buf_base + pos;
157
158   fp->_IO_read_base = fp->_IO_buf_base;
159   fp->_IO_read_ptr = fp->_IO_buf_base + get_pos;
160   fp->_IO_read_end = fp->_IO_buf_base + LEN(fp);
161
162   if (!flush_only)
163     *fp->_IO_write_ptr++ = (unsigned char) c;
164   return c;
165 }
166
167 int
168 DEFUN(_IO_str_underflow, (fp),
169       register _IO_FILE* fp)
170 {
171   _IO_size_t ppos = fp->_IO_write_ptr - fp->_IO_write_base;
172   if (ppos > LEN(fp)) LEN(fp) = ppos;
173   if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
174     {
175       fp->_flags &= ~_IO_CURRENTLY_PUTTING;
176       fp->_IO_write_ptr = fp->_IO_write_end;
177     }
178   fp->_IO_read_end = fp->_IO_read_base + LEN(fp);
179   if (fp->_IO_read_ptr < fp->_IO_read_end)
180     return *fp->_IO_read_ptr;
181   else
182     return EOF;
183 }
184
185 _IO_ssize_t
186 DEFUN(_IO_str_count, (fp),
187       register _IO_FILE *fp)
188 {
189   _IO_ssize_t put_len = fp->_IO_write_ptr - fp->_IO_write_base;
190   if (put_len < LEN(fp))
191     put_len = LEN(fp);
192   return put_len;
193 }     
194
195 _IO_pos_t
196 DEFUN(_IO_str_seekoff, (fp, offset, dir, mode),
197       register _IO_FILE *fp AND _IO_off_t offset AND int dir AND int mode)
198 {
199   _IO_ssize_t cur_size = _IO_str_count(fp);
200   _IO_pos_t new_pos = EOF;
201
202   /* Move the get pointer, if requested. */
203   if (mode & _IOS_INPUT)
204     {
205       switch (dir)
206         {
207         case _IO_seek_end:
208           offset += cur_size;
209           break;
210         case _IO_seek_cur:
211           offset += fp->_IO_read_ptr - fp->_IO_read_base;
212           break;
213         default: /* case _IO_seek_set: */
214           break;
215         }
216       if (offset < 0 || (_IO_size_t)offset > cur_size)
217         return EOF;
218       fp->_IO_read_ptr = fp->_IO_read_base + offset;
219       fp->_IO_read_end = fp->_IO_read_base + cur_size;
220       new_pos = offset;
221     }
222
223   /* Move the put pointer, if requested. */
224   if (mode & _IOS_OUTPUT)
225     {
226       switch (dir)
227         {
228         case _IO_seek_end:
229           offset += cur_size;
230           break;
231         case _IO_seek_cur:
232           offset += fp->_IO_write_ptr - fp->_IO_write_base;
233           break;
234         default: /* case _IO_seek_set: */
235           break;
236         }
237       if (offset < 0 || (_IO_size_t)offset > cur_size)
238         return EOF;
239       LEN(fp) = cur_size;
240       fp->_IO_write_ptr = fp->_IO_write_base + offset;
241       new_pos = offset;
242     }
243   return new_pos;
244 }
245
246 int
247 DEFUN(_IO_str_pbackfail, (fp, c),
248       register _IO_FILE *fp AND int c)
249 {
250   if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
251     return EOF;
252   return _IO_default_pbackfail(fp, c);
253 }
254
255 void
256 DEFUN (_IO_str_finish, (fp),
257       register _IO_FILE* fp)
258 {
259   if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
260     (((_IO_strfile*)fp)->_s._free_buffer)(fp->_IO_buf_base);
261   fp->_IO_buf_base = NULL;
262
263   _IO_default_finish(fp);
264 }
265
266 struct _IO_jump_t _IO_str_jumps = {
267   JUMP_INIT_DUMMY,
268   JUMP_INIT(finish, _IO_str_finish),
269   JUMP_INIT(overflow, _IO_str_overflow),
270   JUMP_INIT(underflow, _IO_str_underflow),
271   JUMP_INIT(uflow, _IO_default_uflow),
272   JUMP_INIT(pbackfail, _IO_str_pbackfail),
273   JUMP_INIT(xsputn, _IO_default_xsputn),
274   JUMP_INIT(xsgetn, _IO_default_xsgetn),
275   JUMP_INIT(seekoff, _IO_str_seekoff),
276   JUMP_INIT(seekpos, _IO_default_seekpos),
277   JUMP_INIT(setbuf, _IO_default_setbuf),
278   JUMP_INIT(sync, _IO_default_sync),
279   JUMP_INIT(doallocate, _IO_default_doallocate),
280   JUMP_INIT(read, _IO_default_read),
281   JUMP_INIT(write, _IO_default_write),
282   JUMP_INIT(seek, _IO_default_seek),
283   JUMP_INIT(close, _IO_default_close),
284   JUMP_INIT(stat, _IO_default_stat)
285 };