open_memstream.c 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #include "stdio_impl.h"
  2. struct cookie {
  3. char **bufp;
  4. size_t *sizep;
  5. size_t pos;
  6. char *buf;
  7. size_t len;
  8. size_t space;
  9. };
  10. static off_t ms_seek(FILE *f, off_t off, int whence)
  11. {
  12. ssize_t base;
  13. struct cookie *c = f->cookie;
  14. if (whence>2U) {
  15. fail:
  16. errno = EINVAL;
  17. return -1;
  18. }
  19. base = (size_t [3]){0, c->pos, c->len}[whence];
  20. if (off < -base || off > SSIZE_MAX-base) goto fail;
  21. return c->pos = base+off;
  22. }
  23. static size_t ms_write(FILE *f, const unsigned char *buf, size_t len)
  24. {
  25. struct cookie *c = f->cookie;
  26. size_t len2 = f->wpos - f->wbase;
  27. char *newbuf;
  28. if (len2) {
  29. f->wpos = f->wbase;
  30. if (ms_write(f, f->wbase, len2) < len2) return 0;
  31. }
  32. if (len + c->pos >= c->space) {
  33. len2 = 2*c->space+1 | c->pos+len+1;
  34. newbuf = realloc(c->buf, len2);
  35. if (!newbuf) return 0;
  36. *c->bufp = c->buf = newbuf;
  37. memset(c->buf + c->space, 0, len2 - c->space);
  38. c->space = len2;
  39. }
  40. memcpy(c->buf+c->pos, buf, len);
  41. c->pos += len;
  42. if (c->pos >= c->len) c->len = c->pos;
  43. *c->sizep = c->pos;
  44. return len;
  45. }
  46. static int ms_close(FILE *f)
  47. {
  48. return 0;
  49. }
  50. FILE *open_memstream(char **bufp, size_t *sizep)
  51. {
  52. FILE *f;
  53. struct cookie *c;
  54. if (!(f=malloc(sizeof *f + sizeof *c + BUFSIZ))) return 0;
  55. memset(f, 0, sizeof *f + sizeof *c);
  56. f->cookie = c = (void *)(f+1);
  57. c->bufp = bufp;
  58. c->sizep = sizep;
  59. c->pos = c->len = c->space = 0;
  60. c->buf = 0;
  61. f->flags = F_NORD;
  62. f->fd = -1;
  63. f->buf = (void *)(c+1);
  64. f->buf_size = BUFSIZ;
  65. f->lbf = EOF;
  66. f->write = ms_write;
  67. f->seek = ms_seek;
  68. f->close = ms_close;
  69. if (!libc.threaded) {
  70. f->lock = -1;
  71. f->next = libc.ofl_head;
  72. if (libc.ofl_head) libc.ofl_head->prev = f;
  73. libc.ofl_head = f;
  74. }
  75. return f;
  76. }