1 /* 2 * Copyright (c) 2002 Tim J. Robbins 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /* 27 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #include "lint.h" 32 #include "mse_int.h" 33 #include <errno.h> 34 #include <limits.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <time.h> 38 #include <wchar.h> 39 #include <alloca.h> 40 41 /* 42 * Convert date and time to a wide-character string. 43 * 44 * This is the wide-character counterpart of strftime(). So that we do not 45 * have to duplicate the code of strftime(), we convert the format string to 46 * multibyte, call strftime(), then convert the result back into wide 47 * characters. 48 * 49 * This technique loses in the presence of stateful multibyte encoding if any 50 * of the conversions in the format string change conversion state. When 51 * stateful encoding is implemented, we will need to reset the state between 52 * format specifications in the format string. 53 * 54 * Note carefully that prior to xpg5, the format was char *, not wchar_t. 55 */ 56 57 /* 58 * Hmmm this is probably a bit backwards. As we are converting to single 59 * byte formats, perhaps we should not be doing a redundant conversion. 60 * Something to look at for the future. 61 */ 62 63 size_t 64 __wcsftime_xpg5(wchar_t *wcs, size_t maxsize, const wchar_t *format, 65 const struct tm *timeptr) 66 { 67 static const mbstate_t initial = { 0 }; 68 mbstate_t mbs; 69 char *dst, *sformat; 70 const char *dstp; 71 const wchar_t *formatp; 72 size_t n, sflen; 73 int sverrno; 74 75 sformat = dst = NULL; 76 77 /* 78 * Convert the supplied format string to a multibyte representation 79 * for strftime(), which only handles single-byte characters. 80 */ 81 mbs = initial; 82 formatp = format; 83 sflen = wcsrtombs(NULL, &formatp, 0, &mbs); 84 if (sflen == (size_t)-1) 85 goto error; 86 if ((sformat = malloc(sflen + 1)) == NULL) 87 goto error; 88 mbs = initial; 89 (void) wcsrtombs(sformat, &formatp, sflen + 1, &mbs); 90 91 /* 92 * Allocate memory for longest multibyte sequence that will fit 93 * into the caller's buffer and call strftime() to fill it. 94 * Then, copy and convert the result back into wide characters in 95 * the caller's buffer. 96 */ 97 if (LONG_MAX / MB_CUR_MAX <= maxsize) { 98 /* maxsize is prepostorously large - avoid int. overflow. */ 99 errno = EINVAL; 100 goto error; 101 } 102 if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL) 103 goto error; 104 if (strftime(dst, maxsize, sformat, timeptr) == 0) 105 goto error; 106 dstp = dst; 107 mbs = initial; 108 n = mbsrtowcs(wcs, &dstp, maxsize, &mbs); 109 if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL) 110 goto error; 111 112 free(sformat); 113 free(dst); 114 return (n); 115 116 error: 117 sverrno = errno; 118 free(sformat); 119 free(dst); 120 errno = sverrno; 121 return (0); 122 } 123 124 size_t 125 wcsftime(wchar_t *wcs, size_t maxsize, const char *format, 126 const struct tm *timeptr) 127 { 128 int len; 129 wchar_t *wfmt; 130 131 /* Convert the format (mb string) to wide char array */ 132 len = strlen(format) + 1; 133 wfmt = alloca(sizeof (wchar_t) * len); 134 if (mbstowcs(wfmt, format, len) == (size_t)-1) { 135 return (0); 136 } 137 return (__wcsftime_xpg5(wcs, maxsize, wfmt, timeptr)); 138 } 139