summaryrefslogtreecommitdiff
path: root/sysutils/mcelog/files/memstream.c
blob: 20cbf29b472c07508e4adf08ad699ec2ae38b556 (plain) (blame)
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);
}