1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
/* Use funopen(3) to provide open_memstream(3) like functionality. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
struct memstream {
char **cp;
size_t *lenp;
size_t offset;
};
FILE *
open_memstream(char **cp, size_t *lenp);
static void
memstream_grow(struct memstream *ms, size_t newsize)
{
char *buf;
if (newsize > *ms->lenp) {
buf = realloc(*ms->cp, newsize + 1);
if (buf != NULL) {
#ifdef DEBUG
fprintf(stderr, "MS: %p growing from %zd to %zd\n",
ms, *ms->lenp, newsize);
#endif
memset(buf + *ms->lenp + 1, 0, newsize - *ms->lenp);
*ms->cp = buf;
*ms->lenp = newsize;
}
}
}
static int
memstream_read(void *cookie, char *buf, int len)
{
struct memstream *ms;
int tocopy;
ms = cookie;
memstream_grow(ms, ms->offset + len);
tocopy = *ms->lenp - ms->offset;
if (len < tocopy)
tocopy = len;
memcpy(buf, *ms->cp + ms->offset, tocopy);
ms->offset += tocopy;
#ifdef DEBUG
fprintf(stderr, "MS: read(%p, %d) = %d\n", ms, len, tocopy);
#endif
return (tocopy);
}
static int
memstream_write(void *cookie, const char *buf, int len)
{
struct memstream *ms;
int tocopy;
ms = cookie;
memstream_grow(ms, ms->offset + len);
tocopy = *ms->lenp - ms->offset;
if (len < tocopy)
tocopy = len;
memcpy(*ms->cp + ms->offset, buf, tocopy);
ms->offset += tocopy;
#ifdef DEBUG
fprintf(stderr, "MS: write(%p, %d) = %d\n", ms, len, tocopy);
#endif
return (tocopy);
}
static fpos_t
memstream_seek(void *cookie, fpos_t pos, int whence)
{
struct memstream *ms;
#ifdef DEBUG
size_t old;
#endif
ms = cookie;
#ifdef DEBUG
old = ms->offset;
#endif
switch (whence) {
case SEEK_SET:
ms->offset = pos;
break;
case SEEK_CUR:
ms->offset += pos;
break;
case SEEK_END:
ms->offset = *ms->lenp + pos;
break;
}
#ifdef DEBUG
fprintf(stderr, "MS: seek(%p, %zd, %d) %zd -> %zd\n", ms, pos, whence,
old, ms->offset);
#endif
return (ms->offset);
}
static int
memstream_close(void *cookie)
{
free(cookie);
return (0);
}
FILE *
open_memstream(char **cp, size_t *lenp)
{
struct memstream *ms;
int save_errno;
FILE *fp;
*cp = NULL;
*lenp = 0;
ms = malloc(sizeof(*ms));
ms->cp = cp;
ms->lenp = lenp;
ms->offset = 0;
fp = funopen(ms, memstream_read, memstream_write, memstream_seek,
memstream_close);
if (fp == NULL) {
save_errno = errno;
free(ms);
errno = save_errno;
}
return (fp);
}
|