#include #include #include #include #include #include struct strdata { char **ptr; size_t lim; size_t cur; size_t max; }; static ssize_t fixptr(struct strdata *d, size_t len) { char *ptr = *d->ptr; len++; /* for NUL */ if (ptr != NULL && d->lim - d->cur > len) return 0; char *nptr = realloc(ptr, d->lim + len); if (nptr == NULL) return -1; *d->ptr = nptr; d->lim += len; return 0; } static ssize_t strwrite(void *p, const void *buf, size_t len) { struct strdata *d = p; if (fixptr(d, len) == -1) return -1; memcpy(*d->ptr + d->cur, buf, len); d->cur += len; (*d->ptr)[d->cur] = '\0'; d->max = MAX(d->cur, d->max); return len; } static ssize_t strread(void *p, void *buf, size_t len) { struct strdata *d = p; if (len > d->max - d->cur) len = d->max - d->cur; memcpy(buf, *d->ptr + d->cur, len); d->cur += len; return len; } static off_t strseek(void *p, off_t pos, int whence) { struct strdata *d = p; off_t len; switch (whence) { case SEEK_END: len = pos + d->max; break; case SEEK_CUR: len = pos + d->cur; break; case SEEK_SET: len = pos; break; default: errno = EINVAL; return -1; } if (len < 0) { errno = EINVAL; return -1; } if (fixptr(d, (size_t)len) == -1) return -1; d->cur = (size_t)len; d->max = MAX(d->cur, d->max); return d->cur; } static int fstrclose(void *p) { free(p); } FILE * fstropen(char **str) { struct strdata *d = calloc(1, sizeof(*d)); if (d == NULL) return NULL; *str = NULL; d->ptr = str; return funopen2(d, strread, strwrite, strseek, NULL, fstrclose); } #ifdef TEST int main(int argc, char *argv[]) { char *str; FILE *fp = fstropen(&str); if (fp == NULL) err(EXIT_FAILURE, "Can't open stream"); for (int i = 1; i < argc; i++) fprintf(fp, "%d: %s\n", i, argv[i]); fflush(fp); printf("str=%s", str); if (fseek(fp, 0, SEEK_SET) == -1) err(EXIT_FAILURE, "seek"); size_t size = strlen(str) + 1; char *buf = malloc(size); size_t len = fread(buf, 1, size, fp); if (len != size - 1) errx(EXIT_FAILURE, "%zu != %zu", len, size - 1); buf[len] = '\0'; printf("buf=%s", buf); fclose(fp); return EXIT_SUCCESS; } #endif