xref: /openbsd/lib/libc/stdio/fmemopen.c (revision ac593df8)
1*ac593df8Smillert /*	$OpenBSD: fmemopen.c,v 1.4 2020/08/14 12:00:33 millert Exp $	*/
203222a19Smpi 
31b5be6a0Smpi /*
41b5be6a0Smpi  * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
51b5be6a0Smpi  * Copyright (c) 2009 Ted Unangst
61b5be6a0Smpi  *
71b5be6a0Smpi  * Permission to use, copy, modify, and distribute this software for any
81b5be6a0Smpi  * purpose with or without fee is hereby granted, provided that the above
91b5be6a0Smpi  * copyright notice and this permission notice appear in all copies.
101b5be6a0Smpi  *
111b5be6a0Smpi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
121b5be6a0Smpi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
131b5be6a0Smpi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
141b5be6a0Smpi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
151b5be6a0Smpi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
161b5be6a0Smpi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
171b5be6a0Smpi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
181b5be6a0Smpi  */
191b5be6a0Smpi 
201b5be6a0Smpi #include <errno.h>
211b5be6a0Smpi #include <fcntl.h>
221b5be6a0Smpi #include <stdio.h>
231b5be6a0Smpi #include <stdlib.h>
2403222a19Smpi #include <string.h>
251b5be6a0Smpi #include "local.h"
261b5be6a0Smpi 
271b5be6a0Smpi struct state {
281b5be6a0Smpi 	char		*string;	/* actual stream */
291b5be6a0Smpi 	size_t		 pos;		/* current position */
301b5be6a0Smpi 	size_t		 size;		/* allocated size */
311b5be6a0Smpi 	size_t		 len;		/* length of the data */
3203222a19Smpi 	int		 update;	/* open for update */
331b5be6a0Smpi };
341b5be6a0Smpi 
351b5be6a0Smpi static int
361b5be6a0Smpi fmemopen_read(void *v, char *b, int l)
371b5be6a0Smpi {
381b5be6a0Smpi 	struct state	*st = v;
391b5be6a0Smpi 	int		 i;
401b5be6a0Smpi 
411b5be6a0Smpi 	for (i = 0; i < l && i + st->pos < st->len; i++)
421b5be6a0Smpi 		b[i] = st->string[st->pos + i];
431b5be6a0Smpi 	st->pos += i;
441b5be6a0Smpi 
451b5be6a0Smpi 	return (i);
461b5be6a0Smpi }
471b5be6a0Smpi 
481b5be6a0Smpi static int
491b5be6a0Smpi fmemopen_write(void *v, const char *b, int l)
501b5be6a0Smpi {
511b5be6a0Smpi 	struct state	*st = v;
521b5be6a0Smpi 	int		i;
531b5be6a0Smpi 
541b5be6a0Smpi 	for (i = 0; i < l && i + st->pos < st->size; i++)
551b5be6a0Smpi 		st->string[st->pos + i] = b[i];
561b5be6a0Smpi 	st->pos += i;
571b5be6a0Smpi 
581b5be6a0Smpi 	if (st->pos >= st->len) {
591b5be6a0Smpi 		st->len = st->pos;
601b5be6a0Smpi 
6103222a19Smpi 		if (st->len < st->size)
621b5be6a0Smpi 			st->string[st->len] = '\0';
6303222a19Smpi 		else if (!st->update)
6403222a19Smpi 			st->string[st->size - 1] = '\0';
651b5be6a0Smpi 	}
661b5be6a0Smpi 
671b5be6a0Smpi 	return (i);
681b5be6a0Smpi }
691b5be6a0Smpi 
701b5be6a0Smpi static fpos_t
7103222a19Smpi fmemopen_seek(void *v, fpos_t off, int whence)
721b5be6a0Smpi {
731b5be6a0Smpi 	struct state	*st = v;
7403222a19Smpi 	ssize_t		 base = 0;
751b5be6a0Smpi 
761b5be6a0Smpi 	switch (whence) {
771b5be6a0Smpi 	case SEEK_SET:
781b5be6a0Smpi 		break;
791b5be6a0Smpi 	case SEEK_CUR:
8003222a19Smpi 		base = st->pos;
811b5be6a0Smpi 		break;
821b5be6a0Smpi 	case SEEK_END:
8303222a19Smpi 		base = st->len;
841b5be6a0Smpi 		break;
8503222a19Smpi 	}
8603222a19Smpi 
8703222a19Smpi 	if (off > st->size - base || off < -base) {
8803222a19Smpi 		errno = EOVERFLOW;
891b5be6a0Smpi 		return (-1);
901b5be6a0Smpi 	}
911b5be6a0Smpi 
9203222a19Smpi 	st->pos = base + off;
931b5be6a0Smpi 
9403222a19Smpi 	return (st->pos);
951b5be6a0Smpi }
961b5be6a0Smpi 
971b5be6a0Smpi static int
981b5be6a0Smpi fmemopen_close(void *v)
991b5be6a0Smpi {
1001b5be6a0Smpi 	free(v);
1011b5be6a0Smpi 
1021b5be6a0Smpi 	return (0);
1031b5be6a0Smpi }
1041b5be6a0Smpi 
1051b5be6a0Smpi static int
1061b5be6a0Smpi fmemopen_close_free(void *v)
1071b5be6a0Smpi {
1081b5be6a0Smpi 	struct state	*st = v;
1091b5be6a0Smpi 
1101b5be6a0Smpi 	free(st->string);
1111b5be6a0Smpi 	free(st);
1121b5be6a0Smpi 
1131b5be6a0Smpi 	return (0);
1141b5be6a0Smpi }
1151b5be6a0Smpi 
1161b5be6a0Smpi FILE *
1171b5be6a0Smpi fmemopen(void *buf, size_t size, const char *mode)
1181b5be6a0Smpi {
1191b5be6a0Smpi 	struct state	*st;
1201b5be6a0Smpi 	FILE		*fp;
1211b5be6a0Smpi 	int		 flags, oflags;
1221b5be6a0Smpi 
1231b5be6a0Smpi 	if (size == 0) {
1241b5be6a0Smpi 		errno = EINVAL;
1251b5be6a0Smpi 		return (NULL);
1261b5be6a0Smpi 	}
1271b5be6a0Smpi 
1281b5be6a0Smpi 	if ((flags = __sflags(mode, &oflags)) == 0) {
1291b5be6a0Smpi 		errno = EINVAL;
1301b5be6a0Smpi 		return (NULL);
1311b5be6a0Smpi 	}
1321b5be6a0Smpi 
1331b5be6a0Smpi 	if (buf == NULL && ((oflags & O_RDWR) == 0)) {
1341b5be6a0Smpi 		errno = EINVAL;
1351b5be6a0Smpi 		return (NULL);
1361b5be6a0Smpi 	}
1371b5be6a0Smpi 
1381b5be6a0Smpi 	if ((st = malloc(sizeof(*st))) == NULL)
1391b5be6a0Smpi 		return (NULL);
1401b5be6a0Smpi 
1411b5be6a0Smpi 	if ((fp = __sfp()) == NULL) {
1421b5be6a0Smpi 		free(st);
1431b5be6a0Smpi 		return (NULL);
1441b5be6a0Smpi 	}
1451b5be6a0Smpi 
1461b5be6a0Smpi 	st->pos = 0;
147*ac593df8Smillert 	st->len = (oflags & O_TRUNC) ? 0 : size;
1481b5be6a0Smpi 	st->size = size;
14903222a19Smpi 	st->update = oflags & O_RDWR;
1501b5be6a0Smpi 
1511b5be6a0Smpi 	if (buf == NULL) {
1521b5be6a0Smpi 		if ((st->string = malloc(size)) == NULL) {
1531b5be6a0Smpi 			free(st);
1541b5be6a0Smpi 			fp->_flags = 0;
1551b5be6a0Smpi 			return (NULL);
1561b5be6a0Smpi 		}
1571b5be6a0Smpi 		*st->string = '\0';
1581b5be6a0Smpi 	} else {
1591b5be6a0Smpi 		st->string = (char *)buf;
1601b5be6a0Smpi 
1611b5be6a0Smpi 		if (oflags & O_TRUNC)
1621b5be6a0Smpi 			*st->string = '\0';
1631b5be6a0Smpi 
1641b5be6a0Smpi 		if (oflags & O_APPEND) {
1651b5be6a0Smpi 			char	*p;
1661b5be6a0Smpi 
1671b5be6a0Smpi 			if ((p = memchr(st->string, '\0', size)) != NULL)
1681b5be6a0Smpi 				st->pos = st->len = (p - st->string);
1691b5be6a0Smpi 			else
1701b5be6a0Smpi 				st->pos = st->len = size;
1711b5be6a0Smpi 		}
1721b5be6a0Smpi 	}
1731b5be6a0Smpi 
1741b5be6a0Smpi 	fp->_flags = (short)flags;
1751b5be6a0Smpi 	fp->_file = -1;
1761b5be6a0Smpi 	fp->_cookie = (void *)st;
1771b5be6a0Smpi 	fp->_read = (flags & __SWR) ? NULL : fmemopen_read;
1781b5be6a0Smpi 	fp->_write = (flags & __SRD) ? NULL : fmemopen_write;
1791b5be6a0Smpi 	fp->_seek = fmemopen_seek;
1801b5be6a0Smpi 	fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close;
1811b5be6a0Smpi 
1821b5be6a0Smpi 	return (fp);
1831b5be6a0Smpi }
1849b9d2a55Sguenther DEF_WEAK(fmemopen);
185