Subject: lib/29826: libc missing wcsftime()
To: None <lib-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: J.T. Conklin <jtc@acorntoolworks.com>
List: netbsd-bugs
Date: 03/29/2005 17:06:01
>Number:         29826
>Category:       lib
>Synopsis:       libc missing wcsftime()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Mar 29 17:06:01 +0000 2005
>Originator:     J.T. Conklin
>Release:        NetBSD 2.0.1
>Organization:
J.T. Conklin
>Environment:
	
	
System: NetBSD orac 2.0.1 NetBSD 2.0.1 (ORAC) #2: Sun Mar 13 22:46:10 PST 2005 jtc@orac:/home/jtc/netbsd/NetBSD-2.0/src/sys/arch/i386/compile/ORAC i386
Architecture: i386
Machine: i386
>Description:
libc is missing wcsftime() --- the wide character version of
strftime().

This is the only function that is actually required for the C++
library to support wide strings (However, libstdc++'s configure script
still thinks it needs the wide character versions of *printf.  I'll be
submitting a PR on that shortly).

This enclosed patch adapts Tim Robbins' implementation from FreeBSD. 
It converts the wide string to multi-byte strings, calls strftime(),
and then converts the results back to a wide character array.  This
may not be the most elegant implementation, but it's consistant with
what we do with wcstod(), etc.

>How-To-Repeat:
	
>Fix:
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	PATCH
#	wcsftime.c
#
echo x - PATCH
sed 's/^X//' >PATCH << 'END-of-PATCH'
XIndex: include/wchar.h
X===================================================================
XRCS file: /cvsroot/src/include/wchar.h,v
Xretrieving revision 1.21
Xdiff -c -r1.21 wchar.h
X*** include/wchar.h	3 Feb 2005 04:39:32 -0000	1.21
X***************
X*** 93,98 ****
X--- 93,100 ----
X  #undef	_BSD_SIZE_T_
X  #endif
X  
X+ struct tm;
X+ 
X  __BEGIN_DECLS
X  wint_t	btowc(int);
X  size_t	mbrlen(const char * __restrict, size_t, mbstate_t * __restrict);
X***************
X*** 108,113 ****
X--- 110,117 ----
X  int	wcscoll(const wchar_t *, const wchar_t *);
X  wchar_t	*wcscpy(wchar_t * __restrict, const wchar_t * __restrict);
X  size_t	wcscspn(const wchar_t *, const wchar_t *);
X+ size_t	wcsftime(wchar_t * __restrict, size_t, const wchar_t * __restrict,
X+ 	    const struct tm * __restrict);
X  size_t	wcslen(const wchar_t *);
X  wchar_t	*wcsncat(wchar_t * __restrict, const wchar_t * __restrict, size_t);
X  int	wcsncmp(const wchar_t *, const wchar_t *, size_t);
XIndex: lib/libc/locale/Makefile.inc
X===================================================================
XRCS file: /cvsroot/src/lib/libc/locale/Makefile.inc,v
Xretrieving revision 1.45
Xdiff -c -r1.45 Makefile.inc
X*** lib/libc/locale/Makefile.inc	11 Mar 2003 09:21:23 -0000	1.45
X***************
X*** 6,12 ****
X  
X  SRCS+=	_def_messages.c _def_monetary.c _def_numeric.c _def_time.c \
X  	ctypeio.c localeconv.c nl_langinfo.c setlocale.c setlocale1.c \
X! 	setlocale32.c __mb_cur_max.c wcscoll.c wcstod.c \
X  	wcstol.c wcstoll.c wcstoimax.c wcstoul.c wcstoull.c wcstoumax.c \
X  	wcsxfrm.c aliasname.c
X  MAN+=	nl_langinfo.3 setlocale.3
X--- 6,12 ----
X  
X  SRCS+=	_def_messages.c _def_monetary.c _def_numeric.c _def_time.c \
X  	ctypeio.c localeconv.c nl_langinfo.c setlocale.c setlocale1.c \
X! 	setlocale32.c __mb_cur_max.c wcscoll.c wcsftime.c wcstod.c \
X  	wcstol.c wcstoll.c wcstoimax.c wcstoul.c wcstoull.c wcstoumax.c \
X  	wcsxfrm.c aliasname.c
X  MAN+=	nl_langinfo.3 setlocale.3
END-of-PATCH
echo x - wcsftime.c
sed 's/^X//' >wcsftime.c << 'END-of-wcsftime.c'
X/*-
X * Copyright (c) 2002 Tim J. Robbins
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#include <sys/cdefs.h>
X#if defined(LIBC_SCCS) && !defined(lint)
X#if 0
X__FBSDID("$FreeBSD: src/lib/libc/locale/wcsftime.c,v 1.4 2004/04/07 09:47:56 tjr Exp $");
X#else
X__RCSID("$NetBSD: $");
X#endif
X#endif /* LIBC_SCCS and not lint */
X
X#include <errno.h>
X#include <limits.h>
X#include <stdlib.h>
X#include <time.h>
X#include <wchar.h>
X
X/*
X * Convert date and time to a wide-character string.
X *
X * This is the wide-character counterpart of strftime(). So that we do not
X * have to duplicate the code of strftime(), we convert the format string to
X * multibyte, call strftime(), then convert the result back into wide
X * characters.
X *
X * This technique loses in the presence of stateful multibyte encoding if any
X * of the conversions in the format string change conversion state. When
X * stateful encoding is implemented, we will need to reset the state between
X * format specifications in the format string.
X */
Xsize_t
Xwcsftime(wchar_t *wcs, size_t maxsize,
X    const wchar_t *format, const struct tm *timeptr)
X{
X	static const mbstate_t initial;
X	mbstate_t mbs;
X	char *dst, *dstp, *sformat;
X	size_t n, sflen;
X	int sverrno;
X
X	sformat = dst = NULL;
X
X	/*
X	 * Convert the supplied format string to a multibyte representation
X	 * for strftime(), which only handles single-byte characters.
X	 */
X	mbs = initial;
X	sflen = wcsrtombs(NULL, &format, 0, &mbs);
X	if (sflen == (size_t)-1)
X		goto error;
X	if ((sformat = malloc(sflen + 1)) == NULL)
X		goto error;
X	mbs = initial;
X	wcsrtombs(sformat, &format, sflen + 1, &mbs);
X
X	/*
X	 * Allocate memory for longest multibyte sequence that will fit
X	 * into the caller's buffer and call strftime() to fill it.
X	 * Then, copy and convert the result back into wide characters in
X	 * the caller's buffer.
X	 */
X	if (SIZE_T_MAX / MB_CUR_MAX <= maxsize) {
X		/* maxsize is prepostorously large - avoid int. overflow. */
X		errno = EINVAL;
X		goto error;
X	}
X	if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
X		goto error;
X	if (strftime(dst, maxsize, sformat, timeptr) == 0)
X		goto error;
X	dstp = dst;
X	mbs = initial;
X	n = mbsrtowcs(wcs, (const char **)&dstp, maxsize, &mbs);
X	if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
X		goto error;
X
X	free(sformat);
X	free(dst);
X	return (n);
X
Xerror:
X	sverrno = errno;
X	free(sformat);
X	free(dst);
X	errno = sverrno;
X	return (0);
X}
END-of-wcsftime.c
exit

>Unformatted: