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

     1  #include "stdio_impl.h"
     2  #include <errno.h>
     3  #include <string.h>
     4  #include <stdlib.h>
     5  #include <stddef.h>
     6  #include <inttypes.h>
     7  #include "libc.h"
     8  
     9  struct cookie {
    10  	size_t pos, len, size;
    11  	unsigned char *buf;
    12  	int mode;
    13  };
    14  
    15  struct mem_FILE {
    16  	FILE f;
    17  	struct cookie c;
    18  	unsigned char buf[UNGET+BUFSIZ], buf2[];
    19  };
    20  
    21  static off_t mseek(FILE *f, off_t off, int whence)
    22  {
    23  	ssize_t base;
    24  	struct cookie *c = f->cookie;
    25  	if (whence>2U) {
    26  fail:
    27  		errno = EINVAL;
    28  		return -1;
    29  	}
    30  	base = (size_t [3]){0, c->pos, c->len}[whence];
    31  	if (off < -base || off > (ssize_t)c->size-base) goto fail;
    32  	return c->pos = base+off;
    33  }
    34  
    35  static size_t mread(FILE *f, unsigned char *buf, size_t len)
    36  {
    37  	struct cookie *c = f->cookie;
    38  	size_t rem = c->len - c->pos;
    39  	if (c->pos > c->len) rem = 0;
    40  	if (len > rem) {
    41  		len = rem;
    42  		f->flags |= F_EOF;
    43  	}
    44  	memcpy(buf, c->buf+c->pos, len);
    45  	c->pos += len;
    46  	rem -= len;
    47  	if (rem > f->buf_size) rem = f->buf_size;
    48  	f->rpos = f->buf;
    49  	f->rend = f->buf + rem;
    50  	memcpy(f->rpos, c->buf+c->pos, rem);
    51  	c->pos += rem;
    52  	return len;
    53  }
    54  
    55  static size_t mwrite(FILE *f, const unsigned char *buf, size_t len)
    56  {
    57  	struct cookie *c = f->cookie;
    58  	size_t rem;
    59  	size_t len2 = f->wpos - f->wbase;
    60  	if (len2) {
    61  		f->wpos = f->wbase;
    62  		if (mwrite(f, f->wpos, len2) < len2) return 0;
    63  	}
    64  	if (c->mode == 'a') c->pos = c->len;
    65  	rem = c->size - c->pos;
    66  	if (len > rem) len = rem;
    67  	memcpy(c->buf+c->pos, buf, len);
    68  	c->pos += len;
    69  	if (c->pos > c->len) {
    70  		c->len = c->pos;
    71  		if (c->len < c->size) c->buf[c->len] = 0;
    72  		else if ((f->flags&F_NORD) && c->size) c->buf[c->size-1] = 0;
    73  	}
    74  	return len;
    75  }
    76  
    77  static int mclose(FILE *m)
    78  {
    79  	return 0;
    80  }
    81  
    82  FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode)
    83  {
    84  	struct mem_FILE *f;
    85  	int plus = !!strchr(mode, '+');
    86  	
    87  	if (!strchr("rwa", *mode)) {
    88  		errno = EINVAL;
    89  		return 0;
    90  	}
    91  
    92  	if (!buf && size > PTRDIFF_MAX) {
    93  		errno = ENOMEM;
    94  		return 0;
    95  	}
    96  
    97  	f = malloc(sizeof *f + (buf?0:size));
    98  	if (!f) return 0;
    99  	memset(f, 0, offsetof(struct mem_FILE, buf));
   100  	f->f.cookie = &f->c;
   101  	f->f.fd = -1;
   102  	f->f.lbf = EOF;
   103  	f->f.buf = f->buf + UNGET;
   104  	f->f.buf_size = sizeof f->buf - UNGET;
   105  	if (!buf) {
   106  		buf = f->buf2;
   107  		memset(buf, 0, size);
   108  	}
   109  
   110  	f->c.buf = buf;
   111  	f->c.size = size;
   112  	f->c.mode = *mode;
   113  	
   114  	if (!plus) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD;
   115  	if (*mode == 'r') f->c.len = size;
   116  	else if (*mode == 'a') f->c.len = f->c.pos = strnlen(buf, size);
   117  	else if (plus) *f->c.buf = 0;
   118  
   119  	f->f.read = mread;
   120  	f->f.write = mwrite;
   121  	f->f.seek = mseek;
   122  	f->f.close = mclose;
   123  
   124  	if (!libc.threaded) f->f.lock = -1;
   125  
   126  	return __ofl_add(&f->f);
   127  }