source: trunk/libs/newlib/src/newlib/libc/stdio/fopencookie.c @ 567

Last change on this file since 567 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 6.8 KB
Line 
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/*
7FUNCTION
8<<fopencookie>>---open a stream with custom callbacks
9
10INDEX
11        fopencookie
12
13SYNOPSIS
14        #include <stdio.h>
15        FILE *fopencookie(const void *<[cookie]>, const char *<[mode]>,
16                          cookie_io_functions_t <[functions]>);
17
18DESCRIPTION
19<<fopencookie>> creates a <<FILE>> stream where I/O is performed using
20custom callbacks.  The callbacks are registered via the structure:
21
22        typedef ssize_t (*cookie_read_function_t)(void *_cookie, char *_buf,
23                                                  size_t _n);
24        typedef ssize_t (*cookie_write_function_t)(void *_cookie,
25                                                   const char *_buf, size_t _n);
26        typedef int (*cookie_seek_function_t)(void *_cookie, off_t *_off,
27                                              int _whence);
28        typedef int (*cookie_close_function_t)(void *_cookie);
29
30.       typedef struct
31.       {
32.               cookie_read_function_t  *read;
33.               cookie_write_function_t *write;
34.               cookie_seek_function_t  *seek;
35.               cookie_close_function_t *close;
36.       } cookie_io_functions_t;
37
38The stream is opened with <[mode]> treated as in <<fopen>>.  The
39callbacks <[functions.read]> and <[functions.write]> may only be NULL
40when <[mode]> does not require them.
41
42<[functions.read]> should return -1 on failure, or else the number of
43bytes read (0 on EOF).  It is similar to <<read>>, except that
44<[cookie]> will be passed as the first argument.
45
46<[functions.write]> should return -1 on failure, or else the number of
47bytes written.  It is similar to <<write>>, except that <[cookie]>
48will be passed as the first argument.
49
50<[functions.seek]> should return -1 on failure, and 0 on success, with
51*<[_off]> set to the current file position.  It is a cross between
52<<lseek>> and <<fseek>>, with the <[_whence]> argument interpreted in
53the same manner.  A NULL <[functions.seek]> makes the stream behave
54similarly to a pipe in relation to stdio functions that require
55positioning.
56
57<[functions.close]> should return -1 on failure, or 0 on success.  It
58is similar to <<close>>, except that <[cookie]> will be passed as the
59first argument.  A NULL <[functions.close]> merely flushes all data
60then lets <<fclose>> succeed.  A failed close will still invalidate
61the stream.
62
63Read and write I/O functions are allowed to change the underlying
64buffer on fully buffered or line buffered streams by calling
65<<setvbuf>>.  They are also not required to completely fill or empty
66the buffer.  They are not, however, allowed to change streams from
67unbuffered to buffered or to change the state of the line buffering
68flag.  They must also be prepared to have read or write calls occur on
69buffers other than the one most recently specified.
70
71RETURNS
72The return value is an open FILE pointer on success.  On error,
73<<NULL>> is returned, and <<errno>> will be set to EINVAL if a
74function pointer is missing or <[mode]> is invalid, ENOMEM if the
75stream cannot be created, or EMFILE if too many streams are already
76open.
77
78PORTABILITY
79This function is a newlib extension, copying the prototype from Linux.
80It is not portable.  See also the <<funopen>> interface from BSD.
81
82Supporting OS subroutines required: <<sbrk>>.
83*/
84
85#define _GNU_SOURCE
86#include <stdio.h>
87#include <errno.h>
88#include <sys/lock.h>
89#include "local.h"
90
91typedef struct fccookie {
92  void *cookie;
93  FILE *fp;
94  cookie_read_function_t *readfn;
95  cookie_write_function_t *writefn;
96  cookie_seek_function_t *seekfn;
97  cookie_close_function_t *closefn;
98} fccookie;
99
100static _READ_WRITE_RETURN_TYPE
101fcreader (struct _reent *ptr,
102       void *cookie,
103       char *buf,
104       _READ_WRITE_BUFSIZE_TYPE n)
105{
106  int result;
107  fccookie *c = (fccookie *) cookie;
108  errno = 0;
109  if ((result = c->readfn (c->cookie, buf, n)) < 0 && errno)
110    ptr->_errno = errno;
111  return result;
112}
113
114static _READ_WRITE_RETURN_TYPE
115fcwriter (struct _reent *ptr,
116       void *cookie,
117       const char *buf,
118       _READ_WRITE_BUFSIZE_TYPE n)
119{
120  int result;
121  fccookie *c = (fccookie *) cookie;
122  if (c->fp->_flags & __SAPP && c->fp->_seek)
123    {
124#ifdef __LARGE64_FILES
125      c->fp->_seek64 (ptr, cookie, 0, SEEK_END);
126#else
127      c->fp->_seek (ptr, cookie, 0, SEEK_END);
128#endif
129    }
130  errno = 0;
131  if ((result = c->writefn (c->cookie, buf, n)) < 0 && errno)
132    ptr->_errno = errno;
133  return result;
134}
135
136static _fpos_t
137fcseeker (struct _reent *ptr,
138       void *cookie,
139       _fpos_t pos,
140       int whence)
141{
142  fccookie *c = (fccookie *) cookie;
143#ifndef __LARGE64_FILES
144  off_t offset = (off_t) pos;
145#else /* __LARGE64_FILES */
146  _off64_t offset = (_off64_t) pos;
147#endif /* __LARGE64_FILES */
148
149  errno = 0;
150  if (c->seekfn (c->cookie, &offset, whence) < 0 && errno)
151    ptr->_errno = errno;
152#ifdef __LARGE64_FILES
153  else if ((_fpos_t)offset != offset)
154    {
155      ptr->_errno = EOVERFLOW;
156      offset = -1;
157    }
158#endif /* __LARGE64_FILES */
159  return (_fpos_t) offset;
160}
161
162#ifdef __LARGE64_FILES
163static _fpos64_t
164fcseeker64 (struct _reent *ptr,
165       void *cookie,
166       _fpos64_t pos,
167       int whence)
168{
169  _off64_t offset;
170  fccookie *c = (fccookie *) cookie;
171  errno = 0;
172  if (c->seekfn (c->cookie, &offset, whence) < 0 && errno)
173    ptr->_errno = errno;
174  return (_fpos64_t) offset;
175}
176#endif /* __LARGE64_FILES */
177
178static int
179fccloser (struct _reent *ptr,
180       void *cookie)
181{
182  int result = 0;
183  fccookie *c = (fccookie *) cookie;
184  if (c->closefn)
185    {
186      errno = 0;
187      if ((result = c->closefn (c->cookie)) < 0 && errno)
188        ptr->_errno = errno;
189    }
190  _free_r (ptr, c);
191  return result;
192}
193
194FILE *
195_fopencookie_r (struct _reent *ptr,
196       void *cookie,
197       const char *mode,
198       cookie_io_functions_t functions)
199{
200  FILE *fp;
201  fccookie *c;
202  int flags;
203  int dummy;
204
205  if ((flags = __sflags (ptr, mode, &dummy)) == 0)
206    return NULL;
207  if (((flags & (__SRD | __SRW)) && !functions.read)
208      || ((flags & (__SWR | __SRW)) && !functions.write))
209    {
210      ptr->_errno = EINVAL;
211      return NULL;
212    }
213  if ((fp = __sfp (ptr)) == NULL)
214    return NULL;
215  if ((c = (fccookie *) _malloc_r (ptr, sizeof *c)) == NULL)
216    {
217      _newlib_sfp_lock_start ();
218      fp->_flags = 0;           /* release */
219#ifndef __SINGLE_THREAD__
220      __lock_close_recursive (fp->_lock);
221#endif
222      _newlib_sfp_lock_end ();
223      return NULL;
224    }
225
226  _newlib_flockfile_start (fp);
227  fp->_file = -1;
228  fp->_flags = flags;
229  c->cookie = cookie;
230  c->fp = fp;
231  fp->_cookie = c;
232  c->readfn = functions.read;
233  fp->_read = fcreader;
234  c->writefn = functions.write;
235  fp->_write = fcwriter;
236  c->seekfn = functions.seek;
237  fp->_seek = functions.seek ? fcseeker : NULL;
238#ifdef __LARGE64_FILES
239  fp->_seek64 = functions.seek ? fcseeker64 : NULL;
240  fp->_flags |= __SL64;
241#endif
242  c->closefn = functions.close;
243  fp->_close = fccloser;
244  _newlib_flockfile_end (fp);
245  return fp;
246}
247
248#ifndef _REENT_ONLY
249FILE *
250fopencookie (void *cookie,
251       const char *mode,
252       cookie_io_functions_t functions)
253{
254  return _fopencookie_r (_REENT, cookie, mode, functions);
255}
256#endif /* !_REENT_ONLY */
Note: See TracBrowser for help on using the repository browser.