github.com/afumu/libc@v0.0.6/musl/src/stdio/fopencookie.c (about)

     1  #define _GNU_SOURCE
     2  #include "stdio_impl.h"
     3  #include <stdlib.h>
     4  #include <sys/ioctl.h>
     5  #include <fcntl.h>
     6  #include <errno.h>
     7  #include <string.h>
     8  
     9  struct fcookie {
    10  	void *cookie;
    11  	cookie_io_functions_t iofuncs;
    12  };
    13  
    14  struct cookie_FILE {
    15  	FILE f;
    16  	struct fcookie fc;
    17  	unsigned char buf[UNGET+BUFSIZ];
    18  };
    19  
    20  static size_t cookieread(FILE *f, unsigned char *buf, size_t len)
    21  {
    22  	struct fcookie *fc = f->cookie;
    23  	ssize_t ret = -1;
    24  	size_t remain = len, readlen = 0;
    25  	size_t len2 = len - !!f->buf_size;
    26  
    27  	if (!fc->iofuncs.read) goto bail;
    28  
    29  	if (len2) {
    30  		ret = fc->iofuncs.read(fc->cookie, (char *) buf, len2);
    31  		if (ret <= 0) goto bail;
    32  
    33  		readlen += ret;
    34  		remain -= ret;
    35  	}
    36  
    37  	if (!f->buf_size || remain > !!f->buf_size) return readlen;
    38  
    39  	f->rpos = f->buf;
    40  	ret = fc->iofuncs.read(fc->cookie, (char *) f->rpos, f->buf_size);
    41  	if (ret <= 0) goto bail;
    42  	f->rend = f->rpos + ret;
    43  
    44  	buf[readlen++] = *f->rpos++;
    45  
    46  	return readlen;
    47  
    48  bail:
    49  	f->flags |= ret == 0 ? F_EOF : F_ERR;
    50  	f->rpos = f->rend = f->buf;
    51  	return readlen;
    52  }
    53  
    54  static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len)
    55  {
    56  	struct fcookie *fc = f->cookie;
    57  	ssize_t ret;
    58  	size_t len2 = f->wpos - f->wbase;
    59  	if (!fc->iofuncs.write) return len;
    60  	if (len2) {
    61  		f->wpos = f->wbase;
    62  		if (cookiewrite(f, f->wpos, len2) < len2) return 0;
    63  	}
    64  	ret = fc->iofuncs.write(fc->cookie, (const char *) buf, len);
    65  	if (ret < 0) {
    66  		f->wpos = f->wbase = f->wend = 0;
    67  		f->flags |= F_ERR;
    68  		return 0;
    69  	}
    70  	return ret;
    71  }
    72  
    73  static off_t cookieseek(FILE *f, off_t off, int whence)
    74  {
    75  	struct fcookie *fc = f->cookie;
    76  	int res;
    77  	if (whence > 2U) {
    78  		errno = EINVAL;
    79  		return -1;
    80  	}
    81  	if (!fc->iofuncs.seek) {
    82  		errno = ENOTSUP;
    83  		return -1;
    84  	}
    85  	res = fc->iofuncs.seek(fc->cookie, &off, whence);
    86  	if (res < 0)
    87  		return res;
    88  	return off;
    89  }
    90  
    91  static int cookieclose(FILE *f)
    92  {
    93  	struct fcookie *fc = f->cookie;
    94  	if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie);
    95  	return 0;
    96  }
    97  
    98  FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs)
    99  {
   100  	struct cookie_FILE *f;
   101  
   102  	/* Check for valid initial mode character */
   103  	if (!strchr("rwa", *mode)) {
   104  		errno = EINVAL;
   105  		return 0;
   106  	}
   107  
   108  	/* Allocate FILE+fcookie+buffer or fail */
   109  	if (!(f=malloc(sizeof *f))) return 0;
   110  
   111  	/* Zero-fill only the struct, not the buffer */
   112  	memset(&f->f, 0, sizeof f->f);
   113  
   114  	/* Impose mode restrictions */
   115  	if (!strchr(mode, '+')) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD;
   116  
   117  	/* Set up our fcookie */
   118  	f->fc.cookie = cookie;
   119  	f->fc.iofuncs = iofuncs;
   120  
   121  	f->f.fd = -1;
   122  	f->f.cookie = &f->fc;
   123  	f->f.buf = f->buf + UNGET;
   124  	f->f.buf_size = sizeof f->buf - UNGET;
   125  	f->f.lbf = EOF;
   126  
   127  	/* Initialize op ptrs. No problem if some are unneeded. */
   128  	f->f.read = cookieread;
   129  	f->f.write = cookiewrite;
   130  	f->f.seek = cookieseek;
   131  	f->f.close = cookieclose;
   132  
   133  	/* Add new FILE to open file list */
   134  	return __ofl_add(&f->f);
   135  }