Back to home page

Enduro/X

 
 

    


0001 /*
0002  * POSIX 2008 fmemopen(3) implemented in terms of BSD funopen(3)
0003  */
0004 
0005 /*
0006  * Copyright (c) 2013 Taylor R. Campbell
0007  * All rights reserved.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
0022  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0023  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0024  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0026  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0027  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0028  * SUCH DAMAGE.
0029  */
0030 
0031 #define _BSD_SOURCE
0032 #define _NETBSD_SOURCE
0033 
0034 #include <errno.h>
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <string.h>
0038 
0039 struct fmem_cookie {
0040   void *fmc_buffer;
0041   size_t fmc_index;
0042   size_t fmc_limit;
0043 };
0044 
0045 static int
0046 fmem_read(void *cookie, char *buffer, int n)
0047 {
0048   struct fmem_cookie *const fmc = cookie;
0049 
0050   if (n < 0) {                  /* paranoia */
0051     errno = EINVAL;
0052     return -1;
0053   }
0054 
0055   if (n > (fmc->fmc_limit - fmc->fmc_index))
0056     n = (fmc->fmc_limit - fmc->fmc_index);
0057 
0058   (void)memcpy(buffer, (char *)fmc->fmc_buffer + fmc->fmc_index, n);
0059   fmc->fmc_index += n;
0060   return n;
0061 }
0062 
0063 static int
0064 fmem_write(void *cookie, const char *buffer, int n)
0065 {
0066   struct fmem_cookie *const fmc = cookie;
0067 
0068   if (n < 0) {                  /* paranoia */
0069     errno = EINVAL;
0070     return -1;
0071   }
0072 
0073   if (n > (fmc->fmc_limit - fmc->fmc_index))
0074     n = (fmc->fmc_limit - fmc->fmc_index);
0075 
0076   (void)memcpy((char *)fmc->fmc_buffer + fmc->fmc_index, buffer, n);
0077   fmc->fmc_index += n;
0078   return n;
0079 }
0080 
0081 static fpos_t
0082 fmem_seek(void *cookie, fpos_t offset, int cmd)
0083 {
0084   struct fmem_cookie *const fmc = cookie;
0085 
0086   switch (cmd) {
0087   case SEEK_SET:
0088     if ((offset < 0) || (fmc->fmc_limit < offset))
0089       goto einval;
0090     fmc->fmc_index = offset;
0091     return 0;
0092 
0093   case SEEK_CUR:
0094     if (offset < 0) {
0095       /* Assume two's-complement arithmetic.  */
0096       if ((offset == ~(fpos_t)0) || (-offset > fmc->fmc_index))
0097         goto einval;
0098     } else {
0099       if (offset > (fmc->fmc_limit - fmc->fmc_index))
0100         goto einval;
0101     }
0102     fmc->fmc_index += offset;
0103     return 0;
0104 
0105   case SEEK_END:
0106       /* Assume two's-complement arithmetic.  */
0107     if ((offset >= 0) || (offset == ~(fpos_t)0) || (fmc->fmc_limit < -offset))
0108       goto einval;
0109     fmc->fmc_index = (fmc->fmc_limit + offset);
0110     return 0;
0111 
0112   default:
0113     goto einval;
0114   }
0115 
0116 einval:
0117   errno = EINVAL;
0118   return -1;
0119 }
0120 
0121 static int
0122 fmem_close(void *cookie)
0123 {
0124   struct fmem_cookie *const fmc = cookie;
0125 
0126   free(fmc);
0127 
0128   return 0;
0129 }
0130 
0131 FILE *
0132 fmemopen(void *buffer, size_t len, const char *mode)
0133 {
0134   struct fmem_cookie *fmc;
0135   FILE *file;
0136 
0137   fmc = malloc(sizeof(*fmc));
0138   if (fmc == NULL)
0139     goto fail0;
0140 
0141   (void)memset(fmc, 0, sizeof(*fmc));
0142   fmc->fmc_buffer = buffer;
0143   fmc->fmc_index = 0;
0144   fmc->fmc_limit = len;
0145 
0146   file = funopen(fmc, &fmem_read, &fmem_write, &fmem_seek, &fmem_close);
0147   if (file == NULL)
0148     goto fail1;
0149 
0150   return file;
0151 
0152 fail1:
0153   free(fmc);
0154 fail0:
0155   return NULL;
0156 }