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