Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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