Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6536 serge 1
/* Copyright (C) 2007 Eric Blake
2
 * Permission to use, copy, modify, and distribute this software
3
 * is freely granted, provided that this notice is preserved.
4
 */
5
 
6
/*
7
FUNCTION
8
<>, <>, <>---open a stream with custom callbacks
9
 
10
INDEX
11
	funopen
12
INDEX
13
	fropen
14
INDEX
15
	fwopen
16
 
17
ANSI_SYNOPSIS
18
	#include 
19
	FILE *funopen(const void *<[cookie]>,
20
	              int (*<[readfn]>) (void *cookie, char *buf, int n),
21
	              int (*<[writefn]>) (void *cookie, const char *buf, int n),
22
	              fpos_t (*<[seekfn]>) (void *cookie, fpos_t off, int whence),
23
	              int (*<[closefn]>) (void *cookie));
24
	FILE *fropen(const void *<[cookie]>,
25
	             int (*<[readfn]>) (void *cookie, char *buf, int n));
26
	FILE *fwopen(const void *<[cookie]>,
27
	             int (*<[writefn]>) (void *cookie, const char *buf, int n));
28
 
29
DESCRIPTION
30
<> creates a <> stream where I/O is performed using
31
custom callbacks.  At least one of <[readfn]> and <[writefn]> must be
32
provided, which determines whether the stream behaves with mode <"r">,
33
<"w">, or <"r+">.
34
 
35
<[readfn]> should return -1 on failure, or else the number of bytes
36
read (0 on EOF).  It is similar to <>, except that  rather
37
than  bounds a transaction size, and <[cookie]> will be passed
38
as the first argument.  A NULL <[readfn]> makes attempts to read the
39
stream fail.
40
 
41
<[writefn]> should return -1 on failure, or else the number of bytes
42
written.  It is similar to <>, except that  rather than
43
 bounds a transaction size, and <[cookie]> will be passed as
44
the first argument.  A NULL <[writefn]> makes attempts to write the
45
stream fail.
46
 
47
<[seekfn]> should return (fpos_t)-1 on failure, or else the current
48
file position.  It is similar to <>, except that <[cookie]>
49
will be passed as the first argument.  A NULL <[seekfn]> makes the
50
stream behave similarly to a pipe in relation to stdio functions that
51
require positioning.  This implementation assumes fpos_t and off_t are
52
the same type.
53
 
54
<[closefn]> should return -1 on failure, or 0 on success.  It is
55
similar to <>, except that <[cookie]> will be passed as the
56
first argument.  A NULL <[closefn]> merely flushes all data then lets
57
<> succeed.  A failed close will still invalidate the stream.
58
 
59
Read and write I/O functions are allowed to change the underlying
60
buffer on fully buffered or line buffered streams by calling
61
<>.  They are also not required to completely fill or empty
62
the buffer.  They are not, however, allowed to change streams from
63
unbuffered to buffered or to change the state of the line buffering
64
flag.  They must also be prepared to have read or write calls occur on
65
buffers other than the one most recently specified.
66
 
67
The functions <> and <> are convenience macros around
68
<> that only use the specified callback.
69
 
70
RETURNS
71
The return value is an open FILE pointer on success.  On error,
72
<> is returned, and <> will be set to EINVAL if a
73
function pointer is missing, ENOMEM if the stream cannot be created,
74
or EMFILE if too many streams are already open.
75
 
76
PORTABILITY
77
This function is a newlib extension, copying the prototype from BSD.
78
It is not portable.  See also the <> interface from Linux.
79
 
80
Supporting OS subroutines required: <>.
81
*/
82
 
83
#include 
84
#include 
85
#include 
86
#include "local.h"
87
 
88
typedef int (*funread)(void *_cookie, char *_buf, _READ_WRITE_BUFSIZE_TYPE _n);
89
typedef int (*funwrite)(void *_cookie, const char *_buf,
90
			_READ_WRITE_BUFSIZE_TYPE _n);
91
#ifdef __LARGE64_FILES
92
typedef _fpos64_t (*funseek)(void *_cookie, _fpos64_t _off, int _whence);
93
#else
94
typedef fpos_t (*funseek)(void *_cookie, fpos_t _off, int _whence);
95
#endif
96
typedef int (*funclose)(void *_cookie);
97
 
98
typedef struct funcookie {
99
  void *cookie;
100
  funread readfn;
101
  funwrite writefn;
102
  funseek seekfn;
103
  funclose closefn;
104
} funcookie;
105
 
106
static _READ_WRITE_RETURN_TYPE
107
_DEFUN(funreader, (ptr, cookie, buf, n),
108
       struct _reent *ptr _AND
109
       void *cookie _AND
110
       char *buf _AND
111
       _READ_WRITE_BUFSIZE_TYPE n)
112
{
113
  int result;
114
  funcookie *c = (funcookie *) cookie;
115
  errno = 0;
116
  if ((result = c->readfn (c->cookie, buf, n)) < 0 && errno)
117
    ptr->_errno = errno;
118
  return result;
119
}
120
 
121
static _READ_WRITE_RETURN_TYPE
122
_DEFUN(funwriter, (ptr, cookie, buf, n),
123
       struct _reent *ptr _AND
124
       void *cookie _AND
125
       const char *buf _AND
126
       _READ_WRITE_BUFSIZE_TYPE n)
127
{
128
  int result;
129
  funcookie *c = (funcookie *) cookie;
130
  errno = 0;
131
  if ((result = c->writefn (c->cookie, buf, n)) < 0 && errno)
132
    ptr->_errno = errno;
133
  return result;
134
}
135
 
136
static _fpos_t
137
_DEFUN(funseeker, (ptr, cookie, off, whence),
138
       struct _reent *ptr _AND
139
       void *cookie _AND
140
       _fpos_t off _AND
141
       int whence)
142
{
143
  funcookie *c = (funcookie *) cookie;
144
#ifndef __LARGE64_FILES
145
  fpos_t result;
146
  errno = 0;
147
  if ((result = c->seekfn (c->cookie, (fpos_t) off, whence)) < 0 && errno)
148
    ptr->_errno = errno;
149
#else /* __LARGE64_FILES */
150
  _fpos64_t result;
151
  errno = 0;
152
  if ((result = c->seekfn (c->cookie, (_fpos64_t) off, whence)) < 0 && errno)
153
    ptr->_errno = errno;
154
  else if ((_fpos_t)result != result)
155
    {
156
      ptr->_errno = EOVERFLOW;
157
      result = -1;
158
    }
159
#endif /* __LARGE64_FILES */
160
  return result;
161
}
162
 
163
#ifdef __LARGE64_FILES
164
static _fpos64_t
165
_DEFUN(funseeker64, (ptr, cookie, off, whence),
166
       struct _reent *ptr _AND
167
       void *cookie _AND
168
       _fpos64_t off _AND
169
       int whence)
170
{
171
  _fpos64_t result;
172
  funcookie *c = (funcookie *) cookie;
173
  errno = 0;
174
  if ((result = c->seekfn (c->cookie, off, whence)) < 0 && errno)
175
    ptr->_errno = errno;
176
  return result;
177
}
178
#endif /* __LARGE64_FILES */
179
 
180
static int
181
_DEFUN(funcloser, (ptr, cookie),
182
       struct _reent *ptr _AND
183
       void *cookie)
184
{
185
  int result = 0;
186
  funcookie *c = (funcookie *) cookie;
187
  if (c->closefn)
188
    {
189
      errno = 0;
190
      if ((result = c->closefn (c->cookie)) < 0 && errno)
191
	ptr->_errno = errno;
192
    }
193
  _free_r (ptr, c);
194
  return result;
195
}
196
 
197
FILE *
198
_DEFUN(_funopen_r, (ptr, cookie, readfn, writefn, seekfn, closefn),
199
       struct _reent *ptr _AND
200
       const void *cookie _AND
201
       funread readfn _AND
202
       funwrite writefn _AND
203
       funseek seekfn _AND
204
       funclose closefn)
205
{
206
  FILE *fp;
207
  funcookie *c;
208
 
209
  if (!readfn && !writefn)
210
    {
211
      ptr->_errno = EINVAL;
212
      return NULL;
213
    }
214
  if ((fp = __sfp (ptr)) == NULL)
215
    return NULL;
216
  if ((c = (funcookie *) _malloc_r (ptr, sizeof *c)) == NULL)
217
    {
218
      _newlib_sfp_lock_start ();
219
      fp->_flags = 0;		/* release */
220
#ifndef __SINGLE_THREAD__
221
      __lock_close_recursive (fp->_lock);
222
#endif
223
      _newlib_sfp_lock_end ();
224
      return NULL;
225
    }
226
 
227
  _newlib_flockfile_start (fp);
228
  fp->_file = -1;
229
  c->cookie = (void *) cookie; /* cast away const */
230
  fp->_cookie = c;
231
  if (readfn)
232
    {
233
      c->readfn = readfn;
234
      fp->_read = funreader;
235
      if (writefn)
236
	{
237
	  fp->_flags = __SRW;
238
	  c->writefn = writefn;
239
	  fp->_write = funwriter;
240
	}
241
      else
242
	{
243
	  fp->_flags = __SRD;
244
	  c->writefn = NULL;
245
	  fp->_write = NULL;
246
	}
247
    }
248
  else
249
    {
250
      fp->_flags = __SWR;
251
      c->writefn = writefn;
252
      fp->_write = funwriter;
253
      c->readfn = NULL;
254
      fp->_read = NULL;
255
    }
256
  c->seekfn = seekfn;
257
  fp->_seek = seekfn ? funseeker : NULL;
258
#ifdef __LARGE64_FILES
259
  fp->_seek64 = seekfn ? funseeker64 : NULL;
260
  fp->_flags |= __SL64;
261
#endif
262
  c->closefn = closefn;
263
  fp->_close = funcloser;
264
  _newlib_flockfile_end (fp);
265
  return fp;
266
}
267
 
268
#ifndef _REENT_ONLY
269
FILE *
270
_DEFUN(funopen, (cookie, readfn, writefn, seekfn, closefn),
271
       const void *cookie _AND
272
       funread readfn _AND
273
       funwrite writefn _AND
274
       funseek seekfn _AND
275
       funclose closefn)
276
{
277
  return _funopen_r (_REENT, cookie, readfn, writefn, seekfn, closefn);
278
}
279
#endif /* !_REENT_ONLY */