fmemopen.c raw

   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  }
 128