xref: /dflybsd-src/lib/libc/locale/wcsftime.c (revision 761342f8d271d0bbb43bdda8a5b9c253b013e34f)
193d5af20SJoerg Sonnenberger /*-
293d5af20SJoerg Sonnenberger  * Copyright (c) 2002 Tim J. Robbins
393d5af20SJoerg Sonnenberger  * All rights reserved.
493d5af20SJoerg Sonnenberger  *
593d5af20SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
693d5af20SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
793d5af20SJoerg Sonnenberger  * are met:
893d5af20SJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
993d5af20SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
1093d5af20SJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
1193d5af20SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
1293d5af20SJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
1393d5af20SJoerg Sonnenberger  *
1493d5af20SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1593d5af20SJoerg Sonnenberger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1693d5af20SJoerg Sonnenberger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1793d5af20SJoerg Sonnenberger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1893d5af20SJoerg Sonnenberger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1993d5af20SJoerg Sonnenberger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2093d5af20SJoerg Sonnenberger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2193d5af20SJoerg Sonnenberger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2293d5af20SJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2393d5af20SJoerg Sonnenberger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2493d5af20SJoerg Sonnenberger  * SUCH DAMAGE.
2593d5af20SJoerg Sonnenberger  *
2693d5af20SJoerg Sonnenberger  * $FreeBSD: src/lib/libc/locale/wcsftime.c,v 1.4 2004/04/07 09:47:56 tjr Exp $
2793d5af20SJoerg Sonnenberger  * $DragonFly: src/lib/libc/locale/wcsftime.c,v 1.1 2005/08/10 13:42:28 joerg Exp $
2893d5af20SJoerg Sonnenberger  */
2993d5af20SJoerg Sonnenberger 
3093d5af20SJoerg Sonnenberger #include <errno.h>
3193d5af20SJoerg Sonnenberger #include <limits.h>
3293d5af20SJoerg Sonnenberger #include <stdlib.h>
3393d5af20SJoerg Sonnenberger #include <time.h>
3493d5af20SJoerg Sonnenberger #include <wchar.h>
3593d5af20SJoerg Sonnenberger 
3693d5af20SJoerg Sonnenberger /*
3793d5af20SJoerg Sonnenberger  * Convert date and time to a wide-character string.
3893d5af20SJoerg Sonnenberger  *
3993d5af20SJoerg Sonnenberger  * This is the wide-character counterpart of strftime(). So that we do not
4093d5af20SJoerg Sonnenberger  * have to duplicate the code of strftime(), we convert the format string to
4193d5af20SJoerg Sonnenberger  * multibyte, call strftime(), then convert the result back into wide
4293d5af20SJoerg Sonnenberger  * characters.
4393d5af20SJoerg Sonnenberger  *
4493d5af20SJoerg Sonnenberger  * This technique loses in the presence of stateful multibyte encoding if any
4593d5af20SJoerg Sonnenberger  * of the conversions in the format string change conversion state. When
4693d5af20SJoerg Sonnenberger  * stateful encoding is implemented, we will need to reset the state between
4793d5af20SJoerg Sonnenberger  * format specifications in the format string.
4893d5af20SJoerg Sonnenberger  */
4993d5af20SJoerg Sonnenberger size_t
5093d5af20SJoerg Sonnenberger wcsftime(wchar_t * __restrict wcs, size_t maxsize,
5193d5af20SJoerg Sonnenberger     const wchar_t * __restrict format, const struct tm * __restrict timeptr)
5293d5af20SJoerg Sonnenberger {
5393d5af20SJoerg Sonnenberger 	static const mbstate_t initial;
5493d5af20SJoerg Sonnenberger 	mbstate_t mbs;
5593d5af20SJoerg Sonnenberger 	char *dst, *dstp, *sformat;
56*761342f8SSascha Wildner 	const wchar_t *formatp;
5793d5af20SJoerg Sonnenberger 	size_t n, sflen;
5893d5af20SJoerg Sonnenberger 	int sverrno;
5993d5af20SJoerg Sonnenberger 
6093d5af20SJoerg Sonnenberger 	sformat = dst = NULL;
6193d5af20SJoerg Sonnenberger 
6293d5af20SJoerg Sonnenberger 	/*
6393d5af20SJoerg Sonnenberger 	 * Convert the supplied format string to a multibyte representation
6493d5af20SJoerg Sonnenberger 	 * for strftime(), which only handles single-byte characters.
6593d5af20SJoerg Sonnenberger 	 */
6693d5af20SJoerg Sonnenberger 	mbs = initial;
67*761342f8SSascha Wildner 	formatp = format;
68*761342f8SSascha Wildner 	sflen = wcsrtombs(NULL, &formatp, 0, &mbs);
6993d5af20SJoerg Sonnenberger 	if (sflen == (size_t)-1)
7093d5af20SJoerg Sonnenberger 		goto error;
7193d5af20SJoerg Sonnenberger 	if ((sformat = malloc(sflen + 1)) == NULL)
7293d5af20SJoerg Sonnenberger 		goto error;
7393d5af20SJoerg Sonnenberger 	mbs = initial;
74*761342f8SSascha Wildner 	wcsrtombs(sformat, &formatp, sflen + 1, &mbs);
7593d5af20SJoerg Sonnenberger 
7693d5af20SJoerg Sonnenberger 	/*
7793d5af20SJoerg Sonnenberger 	 * Allocate memory for longest multibyte sequence that will fit
7893d5af20SJoerg Sonnenberger 	 * into the caller's buffer and call strftime() to fill it.
7993d5af20SJoerg Sonnenberger 	 * Then, copy and convert the result back into wide characters in
8093d5af20SJoerg Sonnenberger 	 * the caller's buffer.
8193d5af20SJoerg Sonnenberger 	 */
8293d5af20SJoerg Sonnenberger 	if (SIZE_T_MAX / MB_CUR_MAX <= maxsize) {
8393d5af20SJoerg Sonnenberger 		/* maxsize is prepostorously large - avoid int. overflow. */
8493d5af20SJoerg Sonnenberger 		errno = EINVAL;
8593d5af20SJoerg Sonnenberger 		goto error;
8693d5af20SJoerg Sonnenberger 	}
8793d5af20SJoerg Sonnenberger 	if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
8893d5af20SJoerg Sonnenberger 		goto error;
8993d5af20SJoerg Sonnenberger 	if (strftime(dst, maxsize, sformat, timeptr) == 0)
9093d5af20SJoerg Sonnenberger 		goto error;
9193d5af20SJoerg Sonnenberger 	dstp = dst;
9293d5af20SJoerg Sonnenberger 	mbs = initial;
9393d5af20SJoerg Sonnenberger 	n = mbsrtowcs(wcs, (const char **)&dstp, maxsize, &mbs);
9493d5af20SJoerg Sonnenberger 	if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
9593d5af20SJoerg Sonnenberger 		goto error;
9693d5af20SJoerg Sonnenberger 
9793d5af20SJoerg Sonnenberger 	free(sformat);
9893d5af20SJoerg Sonnenberger 	free(dst);
9993d5af20SJoerg Sonnenberger 	return (n);
10093d5af20SJoerg Sonnenberger 
10193d5af20SJoerg Sonnenberger error:
10293d5af20SJoerg Sonnenberger 	sverrno = errno;
10393d5af20SJoerg Sonnenberger 	free(sformat);
10493d5af20SJoerg Sonnenberger 	free(dst);
10593d5af20SJoerg Sonnenberger 	errno = sverrno;
10693d5af20SJoerg Sonnenberger 	return (0);
10793d5af20SJoerg Sonnenberger }
108