Edit

IABSD.fr/src/lib/libc/stdio/open_wmemstream.c

Branch :

  • Show log

    Commit

  • Author : claudio
    Date : 2023-07-11 12:14:16
    Hash : eafe0233
    Message : No need to initialize the first element of st->string since it was just calloc(3)-ed a few lines above. OK tb@

  • lib/libc/stdio/open_wmemstream.c
  • /*	$OpenBSD: open_wmemstream.c,v 1.10 2023/07/11 12:14:16 claudio Exp $	*/
    
    /*
     * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    #include <wchar.h>
    #include "local.h"
    
    #define	MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
    
    struct state {
    	wchar_t		 *string;	/* actual stream */
    	wchar_t		**pbuf;		/* point to the stream */
    	size_t		 *psize;	/* point to min(pos, len) */
    	size_t		  pos;		/* current position */
    	size_t		  size;		/* number of allocated wchar_t */
    	size_t		  len;		/* length of the data */
    	mbstate_t	  mbs;		/* conversion state of the stream */
    };
    
    static int
    wmemstream_write(void *v, const char *b, int l)
    {
    	struct state	*st = v;
    	wchar_t		*p;
    	size_t		 nmc, len, end;
    
    	end = (st->pos + l);
    
    	if (end >= st->size) {
    		/* 1.6 is (very) close to the golden ratio. */
    		size_t	sz = st->size * 8 / 5;
    
    		if (sz < end + 1)
    			sz = end + 1;
    		p = recallocarray(st->string, st->size, sz, sizeof(wchar_t));
    		if (!p)
    			return (-1);
    		*st->pbuf = st->string = p;
    		st->size = sz;
    	}
    
    	nmc = (st->size - st->pos) * sizeof(wchar_t);
    	len = mbsnrtowcs(st->string + st->pos, &b, nmc, l, &st->mbs);
    	if (len == (size_t)-1)
    		return (-1);
    	st->pos += len;
    
    	if (st->pos > st->len) {
    		st->len = st->pos;
    		st->string[st->len] = L'\0';
    	}
    
    	*st->psize = st->pos;
    
    	return (len);
    }
    
    static fpos_t
    wmemstream_seek(void *v, fpos_t off, int whence)
    {
    	struct state	*st = v;
    	ssize_t		 base = 0;
    
    	switch (whence) {
    	case SEEK_SET:
    		break;
    	case SEEK_CUR:
    		base = st->pos;
    		break;
    	case SEEK_END:
    		base = st->len;
    		break;
    	}
    
    	if (off > (SIZE_MAX / sizeof(wchar_t)) - base || off < -base) {
    		errno = EOVERFLOW;
    		return (-1);
    	}
    
    	/*
    	 * XXX Clearing mbs here invalidates shift state for state-
    	 * dependent encodings, but they are not (yet) supported.
    	 */
    	bzero(&st->mbs, sizeof(st->mbs));
    
    	st->pos = base + off;
    	*st->psize = MINIMUM(st->pos, st->len);
    
    	return (st->pos);
    }
    
    static int
    wmemstream_close(void *v)
    {
    	struct state	*st = v;
    
    	free(st);
    
    	return (0);
    }
    
    FILE *
    open_wmemstream(wchar_t **pbuf, size_t *psize)
    {
    	struct state	*st;
    	FILE		*fp;
    
    	if (pbuf == NULL || psize == NULL) {
    		errno = EINVAL;
    		return (NULL);
    	}
    
    	if ((st = malloc(sizeof(*st))) == NULL)
    		return (NULL);
    
    	if ((fp = __sfp()) == NULL) {
    		free(st);
    		return (NULL);
    	}
    
    	st->size = BUFSIZ * sizeof(wchar_t);
    	if ((st->string = calloc(1, st->size)) == NULL) {
    		free(st);
    		fp->_flags = 0;
    		return (NULL);
    	}
    
    	st->pos = 0;
    	st->len = 0;
    	st->pbuf = pbuf;
    	st->psize = psize;
    	bzero(&st->mbs, sizeof(st->mbs));
    
    	*pbuf = st->string;
    	*psize = st->len;
    
    	fp->_flags = __SWR;
    	fp->_file = -1;
    	fp->_cookie = st;
    	fp->_read = NULL;
    	fp->_write = wmemstream_write;
    	fp->_seek = wmemstream_seek;
    	fp->_close = wmemstream_close;
    	_SET_ORIENTATION(fp, 1);
    
    	return (fp);
    }