fmemopen.c 2.5 KB

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