193d5af20SJoerg Sonnenberger /*-
293d5af20SJoerg Sonnenberger * Copyright (c) 2002 Tim J. Robbins
393d5af20SJoerg Sonnenberger * All rights reserved.
493d5af20SJoerg Sonnenberger *
5*0d5acd74SJohn Marino * Copyright (c) 2011 The FreeBSD Foundation
6*0d5acd74SJohn Marino * All rights reserved.
7*0d5acd74SJohn Marino * Portions of this software were developed by David Chisnall
8*0d5acd74SJohn Marino * under sponsorship from the FreeBSD Foundation.
9*0d5acd74SJohn Marino *
1093d5af20SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
1193d5af20SJoerg Sonnenberger * modification, are permitted provided that the following conditions
1293d5af20SJoerg Sonnenberger * are met:
1393d5af20SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
1493d5af20SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer.
1593d5af20SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
1693d5af20SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
1793d5af20SJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
1893d5af20SJoerg Sonnenberger *
1993d5af20SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2093d5af20SJoerg Sonnenberger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2193d5af20SJoerg Sonnenberger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2293d5af20SJoerg Sonnenberger * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2393d5af20SJoerg Sonnenberger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2493d5af20SJoerg Sonnenberger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2593d5af20SJoerg Sonnenberger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2693d5af20SJoerg Sonnenberger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2793d5af20SJoerg Sonnenberger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2893d5af20SJoerg Sonnenberger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2993d5af20SJoerg Sonnenberger * SUCH DAMAGE.
3093d5af20SJoerg Sonnenberger *
31*0d5acd74SJohn Marino * $FreeBSD: head/lib/libc/locale/wcsftime.c 227753 2011-11-20 14:45:42Z theraven $
3293d5af20SJoerg Sonnenberger */
3393d5af20SJoerg Sonnenberger
34*0d5acd74SJohn Marino
3593d5af20SJoerg Sonnenberger #include <errno.h>
3693d5af20SJoerg Sonnenberger #include <limits.h>
3793d5af20SJoerg Sonnenberger #include <stdlib.h>
3893d5af20SJoerg Sonnenberger #include <time.h>
3993d5af20SJoerg Sonnenberger #include <wchar.h>
40*0d5acd74SJohn Marino #include "xlocale_private.h"
4193d5af20SJoerg Sonnenberger
4293d5af20SJoerg Sonnenberger /*
4393d5af20SJoerg Sonnenberger * Convert date and time to a wide-character string.
4493d5af20SJoerg Sonnenberger *
4593d5af20SJoerg Sonnenberger * This is the wide-character counterpart of strftime(). So that we do not
4693d5af20SJoerg Sonnenberger * have to duplicate the code of strftime(), we convert the format string to
4793d5af20SJoerg Sonnenberger * multibyte, call strftime(), then convert the result back into wide
4893d5af20SJoerg Sonnenberger * characters.
4993d5af20SJoerg Sonnenberger *
5093d5af20SJoerg Sonnenberger * This technique loses in the presence of stateful multibyte encoding if any
5193d5af20SJoerg Sonnenberger * of the conversions in the format string change conversion state. When
5293d5af20SJoerg Sonnenberger * stateful encoding is implemented, we will need to reset the state between
5393d5af20SJoerg Sonnenberger * format specifications in the format string.
5493d5af20SJoerg Sonnenberger */
5593d5af20SJoerg Sonnenberger size_t
wcsftime_l(wchar_t * __restrict wcs,size_t maxsize,const wchar_t * __restrict format,const struct tm * __restrict timeptr,locale_t locale)56*0d5acd74SJohn Marino wcsftime_l(wchar_t * __restrict wcs, size_t maxsize,
57*0d5acd74SJohn Marino const wchar_t * __restrict format, const struct tm * __restrict timeptr,
58*0d5acd74SJohn Marino locale_t locale)
5993d5af20SJoerg Sonnenberger {
6093d5af20SJoerg Sonnenberger static const mbstate_t initial;
6193d5af20SJoerg Sonnenberger mbstate_t mbs;
62*0d5acd74SJohn Marino char *dst, *sformat;
63*0d5acd74SJohn Marino const char *dstp;
64761342f8SSascha Wildner const wchar_t *formatp;
6593d5af20SJoerg Sonnenberger size_t n, sflen;
6693d5af20SJoerg Sonnenberger int sverrno;
67*0d5acd74SJohn Marino FIX_LOCALE(locale);
6893d5af20SJoerg Sonnenberger
6993d5af20SJoerg Sonnenberger sformat = dst = NULL;
7093d5af20SJoerg Sonnenberger
7193d5af20SJoerg Sonnenberger /*
7293d5af20SJoerg Sonnenberger * Convert the supplied format string to a multibyte representation
7393d5af20SJoerg Sonnenberger * for strftime(), which only handles single-byte characters.
7493d5af20SJoerg Sonnenberger */
7593d5af20SJoerg Sonnenberger mbs = initial;
76761342f8SSascha Wildner formatp = format;
77*0d5acd74SJohn Marino sflen = wcsrtombs_l(NULL, &formatp, 0, &mbs, locale);
7893d5af20SJoerg Sonnenberger if (sflen == (size_t)-1)
7993d5af20SJoerg Sonnenberger goto error;
8093d5af20SJoerg Sonnenberger if ((sformat = malloc(sflen + 1)) == NULL)
8193d5af20SJoerg Sonnenberger goto error;
8293d5af20SJoerg Sonnenberger mbs = initial;
83*0d5acd74SJohn Marino wcsrtombs_l(sformat, &formatp, sflen + 1, &mbs, locale);
8493d5af20SJoerg Sonnenberger
8593d5af20SJoerg Sonnenberger /*
8693d5af20SJoerg Sonnenberger * Allocate memory for longest multibyte sequence that will fit
8793d5af20SJoerg Sonnenberger * into the caller's buffer and call strftime() to fill it.
8893d5af20SJoerg Sonnenberger * Then, copy and convert the result back into wide characters in
8993d5af20SJoerg Sonnenberger * the caller's buffer.
9093d5af20SJoerg Sonnenberger */
9193d5af20SJoerg Sonnenberger if (SIZE_T_MAX / MB_CUR_MAX <= maxsize) {
9293d5af20SJoerg Sonnenberger /* maxsize is prepostorously large - avoid int. overflow. */
9393d5af20SJoerg Sonnenberger errno = EINVAL;
9493d5af20SJoerg Sonnenberger goto error;
9593d5af20SJoerg Sonnenberger }
9693d5af20SJoerg Sonnenberger if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
9793d5af20SJoerg Sonnenberger goto error;
98*0d5acd74SJohn Marino if (strftime_l(dst, maxsize, sformat, timeptr, locale) == 0)
9993d5af20SJoerg Sonnenberger goto error;
10093d5af20SJoerg Sonnenberger dstp = dst;
10193d5af20SJoerg Sonnenberger mbs = initial;
102*0d5acd74SJohn Marino n = mbsrtowcs_l(wcs, &dstp, maxsize, &mbs, locale);
10393d5af20SJoerg Sonnenberger if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
10493d5af20SJoerg Sonnenberger goto error;
10593d5af20SJoerg Sonnenberger
10693d5af20SJoerg Sonnenberger free(sformat);
10793d5af20SJoerg Sonnenberger free(dst);
10893d5af20SJoerg Sonnenberger return (n);
10993d5af20SJoerg Sonnenberger
11093d5af20SJoerg Sonnenberger error:
11193d5af20SJoerg Sonnenberger sverrno = errno;
11293d5af20SJoerg Sonnenberger free(sformat);
11393d5af20SJoerg Sonnenberger free(dst);
11493d5af20SJoerg Sonnenberger errno = sverrno;
11593d5af20SJoerg Sonnenberger return (0);
11693d5af20SJoerg Sonnenberger }
117*0d5acd74SJohn Marino size_t
wcsftime(wchar_t * __restrict wcs,size_t maxsize,const wchar_t * __restrict format,const struct tm * __restrict timeptr)118*0d5acd74SJohn Marino wcsftime(wchar_t * __restrict wcs, size_t maxsize,
119*0d5acd74SJohn Marino const wchar_t * __restrict format, const struct tm * __restrict timeptr)
120*0d5acd74SJohn Marino {
121*0d5acd74SJohn Marino return wcsftime_l(wcs, maxsize, format, timeptr, __get_locale());
122*0d5acd74SJohn Marino }
123