GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/stdio/open_memstream.c Lines: 0 64 0.0 %
Date: 2017-11-13 Branches: 0 33 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: open_memstream.c,v 1.7 2017/03/17 14:53:08 deraadt Exp $	*/
2
3
/*
4
 * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <errno.h>
20
#include <fcntl.h>
21
#include <stdint.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include "local.h"
26
27
#define	MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
28
29
struct state {
30
	char		 *string;	/* actual stream */
31
	char		**pbuf;		/* point to the stream */
32
	size_t		 *psize;	/* point to min(pos, len) */
33
	size_t		  pos;		/* current position */
34
	size_t		  size;		/* number of allocated char */
35
	size_t		  len;		/* length of the data */
36
};
37
38
static int
39
memstream_write(void *v, const char *b, int l)
40
{
41
	struct state	*st = v;
42
	char		*p;
43
	size_t		 i, end;
44
45
	end = (st->pos + l);
46
47
	if (end >= st->size) {
48
		/* 1.6 is (very) close to the golden ratio. */
49
		size_t	sz = st->size * 8 / 5;
50
51
		if (sz < end + 1)
52
			sz = end + 1;
53
		p = recallocarray(st->string, st->size, sz, 1);
54
		if (!p)
55
			return (-1);
56
		bzero(p + st->size, sz - st->size);
57
		*st->pbuf = st->string = p;
58
		st->size = sz;
59
	}
60
61
	for (i = 0; i < l; i++)
62
		st->string[st->pos + i] = b[i];
63
	st->pos += l;
64
65
	if (st->pos > st->len) {
66
		st->len = st->pos;
67
		st->string[st->len] = '\0';
68
	}
69
70
	*st->psize = st->pos;
71
72
	return (i);
73
}
74
75
static fpos_t
76
memstream_seek(void *v, fpos_t off, int whence)
77
{
78
	struct state	*st = v;
79
	ssize_t		 base = 0;
80
81
	switch (whence) {
82
	case SEEK_SET:
83
		break;
84
	case SEEK_CUR:
85
		base = st->pos;
86
		break;
87
	case SEEK_END:
88
		base = st->len;
89
		break;
90
	}
91
92
	if (off > SIZE_MAX - base || off < -base) {
93
		errno = EOVERFLOW;
94
		return (-1);
95
	}
96
97
	st->pos = base + off;
98
	*st->psize = MINIMUM(st->pos, st->len);
99
100
	return (st->pos);
101
}
102
103
static int
104
memstream_close(void *v)
105
{
106
	struct state	*st = v;
107
108
	free(st);
109
110
	return (0);
111
}
112
113
FILE *
114
open_memstream(char **pbuf, size_t *psize)
115
{
116
	struct state	*st;
117
	FILE		*fp;
118
119
	if (pbuf == NULL || psize == NULL) {
120
		errno = EINVAL;
121
		return (NULL);
122
	}
123
124
	if ((st = malloc(sizeof(*st))) == NULL)
125
		return (NULL);
126
127
	if ((fp = __sfp()) == NULL) {
128
		free(st);
129
		return (NULL);
130
	}
131
132
	st->size = BUFSIZ;
133
	if ((st->string = calloc(1, st->size)) == NULL) {
134
		free(st);
135
		fp->_flags = 0;
136
		return (NULL);
137
	}
138
139
	*st->string = '\0';
140
	st->pos = 0;
141
	st->len = 0;
142
	st->pbuf = pbuf;
143
	st->psize = psize;
144
145
	*pbuf = st->string;
146
	*psize = st->len;
147
148
	fp->_flags = __SWR;
149
	fp->_file = -1;
150
	fp->_cookie = st;
151
	fp->_read = NULL;
152
	fp->_write = memstream_write;
153
	fp->_seek = memstream_seek;
154
	fp->_close = memstream_close;
155
	_SET_ORIENTATION(fp, -1);
156
157
	return (fp);
158
}
159
DEF_WEAK(open_memstream);