1/* Copyright (C) 1993,95,97,99,2000,2002 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, write to the Free
16   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17   02111-1307 USA.
18
19   As a special exception, if you link the code in this file with
20   files compiled with a GNU compiler to produce an executable,
21   that does not cause the resulting executable to be covered by
22   the GNU Lesser General Public License.  This exception does not
23   however invalidate any other reasons why the executable file
24   might be covered by the GNU Lesser General Public License.
25   This exception applies to code released by its copyright holders
26   in files containing the exception.  */
27
28#include <libioP.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <shlib-compat.h>
32
33/* Prototyped for local functions.  */
34static _IO_ssize_t _IO_cookie_read (register _IO_FILE* fp, void* buf,
35				    _IO_ssize_t size);
36static _IO_ssize_t _IO_cookie_write (register _IO_FILE* fp,
37				     const void* buf, _IO_ssize_t size);
38static _IO_off64_t _IO_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir);
39static int _IO_cookie_close (_IO_FILE* fp);
40
41static _IO_ssize_t
42_IO_cookie_read (fp, buf, size)
43     _IO_FILE *fp;
44     void *buf;
45     _IO_ssize_t size;
46{
47  struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
48
49  if (cfile->__io_functions.read == NULL)
50    return -1;
51
52  return cfile->__io_functions.read (cfile->__cookie, buf, size);
53}
54
55static _IO_ssize_t
56_IO_cookie_write (fp, buf, size)
57     _IO_FILE *fp;
58     const void *buf;
59     _IO_ssize_t size;
60{
61  struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
62
63  if (cfile->__io_functions.write == NULL)
64    return -1;
65
66  return cfile->__io_functions.write (cfile->__cookie, buf, size);
67}
68
69static _IO_off64_t
70_IO_cookie_seek (fp, offset, dir)
71     _IO_FILE *fp;
72     _IO_off64_t offset;
73     int dir;
74{
75  struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
76
77  return ((cfile->__io_functions.seek == NULL
78	   || (cfile->__io_functions.seek (cfile->__cookie, &offset, dir)
79	       == -1)
80	   || offset == (_IO_off64_t) -1)
81	  ? _IO_pos_BAD : offset);
82}
83
84static int
85_IO_cookie_close (fp)
86     _IO_FILE *fp;
87{
88  struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
89
90  if (cfile->__io_functions.close == NULL)
91    return 0;
92
93  return cfile->__io_functions.close (cfile->__cookie);
94}
95
96
97static struct _IO_jump_t _IO_cookie_jumps = {
98  JUMP_INIT_DUMMY,
99  JUMP_INIT(finish, INTUSE(_IO_file_finish)),
100  JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),
101  JUMP_INIT(underflow, INTUSE(_IO_file_underflow)),
102  JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
103  JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
104  JUMP_INIT(xsputn, INTUSE(_IO_file_xsputn)),
105  JUMP_INIT(xsgetn, INTUSE(_IO_default_xsgetn)),
106  JUMP_INIT(seekoff, INTUSE(_IO_file_seekoff)),
107  JUMP_INIT(seekpos, _IO_default_seekpos),
108  JUMP_INIT(setbuf, INTUSE(_IO_file_setbuf)),
109  JUMP_INIT(sync, INTUSE(_IO_file_sync)),
110  JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
111  JUMP_INIT(read, _IO_cookie_read),
112  JUMP_INIT(write, _IO_cookie_write),
113  JUMP_INIT(seek, _IO_cookie_seek),
114  JUMP_INIT(close, _IO_cookie_close),
115  JUMP_INIT(stat, _IO_default_stat),
116  JUMP_INIT(showmanyc, _IO_default_showmanyc),
117  JUMP_INIT(imbue, _IO_default_imbue),
118};
119
120
121void
122_IO_cookie_init (struct _IO_cookie_file *cfile, int read_write,
123		 void *cookie, _IO_cookie_io_functions_t io_functions)
124{
125  INTUSE(_IO_init) (&cfile->__fp.file, 0);
126  _IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps;
127
128  cfile->__cookie = cookie;
129  cfile->__io_functions = io_functions;
130
131  INTUSE(_IO_file_init) (&cfile->__fp);
132
133  cfile->__fp.file._IO_file_flags =
134    _IO_mask_flags (&cfile->__fp.file, read_write,
135		    _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
136
137  /* We use a negative number different from -1 for _fileno to mark that
138     this special stream is not associated with a real file, but still has
139     to be treated as such.  */
140  cfile->__fp.file._fileno = -2;
141}
142
143
144_IO_FILE *
145_IO_fopencookie (cookie, mode, io_functions)
146     void *cookie;
147     const char *mode;
148     _IO_cookie_io_functions_t io_functions;
149{
150  int read_write;
151  struct locked_FILE
152  {
153    struct _IO_cookie_file cfile;
154#ifdef _IO_MTSAFE_IO
155    _IO_lock_t lock;
156#endif
157  } *new_f;
158
159  switch (*mode++)
160    {
161    case 'r':
162      read_write = _IO_NO_WRITES;
163      break;
164    case 'w':
165      read_write = _IO_NO_READS;
166      break;
167    case 'a':
168      read_write = _IO_NO_READS|_IO_IS_APPENDING;
169      break;
170    default:
171      return NULL;
172  }
173  if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
174    read_write &= _IO_IS_APPENDING;
175
176  new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
177  if (new_f == NULL)
178    return NULL;
179#ifdef _IO_MTSAFE_IO
180  new_f->cfile.__fp.file._lock = &new_f->lock;
181#endif
182
183  _IO_cookie_init (&new_f->cfile, read_write, cookie, io_functions);
184
185  return (_IO_FILE *) &new_f->cfile.__fp;
186}
187
188versioned_symbol (libc, _IO_fopencookie, fopencookie, GLIBC_2_2);
189
190#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
191
192static _IO_off64_t _IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset,
193					int dir);
194_IO_FILE * _IO_old_fopencookie (void *cookie, const char *mode,
195				_IO_cookie_io_functions_t io_functions);
196
197static _IO_off64_t
198_IO_old_cookie_seek (fp, offset, dir)
199     _IO_FILE *fp;
200     _IO_off64_t offset;
201     int dir;
202{
203  struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
204  int (*seek) (_IO_FILE *, _IO_off_t, int);
205  int ret;
206
207  seek = (int (*)(_IO_FILE *, _IO_off_t, int)) cfile->__io_functions.seek;
208  if (seek == NULL)
209    return _IO_pos_BAD;
210
211  ret = seek (cfile->__cookie, offset, dir);
212
213  return (ret == -1) ? _IO_pos_BAD : ret;
214}
215
216static struct _IO_jump_t _IO_old_cookie_jumps = {
217  JUMP_INIT_DUMMY,
218  JUMP_INIT(finish, INTUSE(_IO_file_finish)),
219  JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),
220  JUMP_INIT(underflow, INTUSE(_IO_file_underflow)),
221  JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),
222  JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),
223  JUMP_INIT(xsputn, INTUSE(_IO_file_xsputn)),
224  JUMP_INIT(xsgetn, INTUSE(_IO_default_xsgetn)),
225  JUMP_INIT(seekoff, INTUSE(_IO_file_seekoff)),
226  JUMP_INIT(seekpos, _IO_default_seekpos),
227  JUMP_INIT(setbuf, INTUSE(_IO_file_setbuf)),
228  JUMP_INIT(sync, INTUSE(_IO_file_sync)),
229  JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),
230  JUMP_INIT(read, _IO_cookie_read),
231  JUMP_INIT(write, _IO_cookie_write),
232  JUMP_INIT(seek, _IO_old_cookie_seek),
233  JUMP_INIT(close, _IO_cookie_close),
234  JUMP_INIT(stat, _IO_default_stat),
235  JUMP_INIT(showmanyc, _IO_default_showmanyc),
236  JUMP_INIT(imbue, _IO_default_imbue),
237};
238
239_IO_FILE *
240_IO_old_fopencookie (cookie, mode, io_functions)
241     void *cookie;
242     const char *mode;
243     _IO_cookie_io_functions_t io_functions;
244{
245  _IO_FILE *ret;
246
247  ret = _IO_fopencookie (cookie, mode, io_functions);
248  if (ret != NULL)
249    _IO_JUMPS ((struct _IO_FILE_plus *) ret) = &_IO_old_cookie_jumps;
250
251  return ret;
252}
253
254compat_symbol (libc, _IO_old_fopencookie, fopencookie, GLIBC_2_0);
255
256#endif
257