14297a3b0SGarrett D'Amore /* 2*6b5e5868SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 34297a3b0SGarrett D'Amore * Copyright (c) 2002 Tim J. Robbins 44297a3b0SGarrett D'Amore * All rights reserved. 54297a3b0SGarrett D'Amore * 64297a3b0SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 74297a3b0SGarrett D'Amore * modification, are permitted provided that the following conditions 84297a3b0SGarrett D'Amore * are met: 94297a3b0SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 104297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 114297a3b0SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 124297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 134297a3b0SGarrett D'Amore * documentation and/or other materials provided with the distribution. 144297a3b0SGarrett D'Amore * 154297a3b0SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 164297a3b0SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 174297a3b0SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 184297a3b0SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 194297a3b0SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 204297a3b0SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 214297a3b0SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 224297a3b0SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 234297a3b0SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 244297a3b0SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 254297a3b0SGarrett D'Amore * SUCH DAMAGE. 264297a3b0SGarrett D'Amore */ 274297a3b0SGarrett D'Amore 284297a3b0SGarrett D'Amore #include "lint.h" 294297a3b0SGarrett D'Amore #include "mse_int.h" 304297a3b0SGarrett D'Amore #include <errno.h> 314297a3b0SGarrett D'Amore #include <limits.h> 324297a3b0SGarrett D'Amore #include <stdlib.h> 334297a3b0SGarrett D'Amore #include <string.h> 344297a3b0SGarrett D'Amore #include <time.h> 354297a3b0SGarrett D'Amore #include <wchar.h> 364297a3b0SGarrett D'Amore #include <alloca.h> 374297a3b0SGarrett D'Amore 384297a3b0SGarrett D'Amore /* 394297a3b0SGarrett D'Amore * Convert date and time to a wide-character string. 404297a3b0SGarrett D'Amore * 414297a3b0SGarrett D'Amore * This is the wide-character counterpart of strftime(). So that we do not 424297a3b0SGarrett D'Amore * have to duplicate the code of strftime(), we convert the format string to 434297a3b0SGarrett D'Amore * multibyte, call strftime(), then convert the result back into wide 444297a3b0SGarrett D'Amore * characters. 454297a3b0SGarrett D'Amore * 464297a3b0SGarrett D'Amore * This technique loses in the presence of stateful multibyte encoding if any 474297a3b0SGarrett D'Amore * of the conversions in the format string change conversion state. When 484297a3b0SGarrett D'Amore * stateful encoding is implemented, we will need to reset the state between 494297a3b0SGarrett D'Amore * format specifications in the format string. 504297a3b0SGarrett D'Amore * 514297a3b0SGarrett D'Amore * Note carefully that prior to xpg5, the format was char *, not wchar_t. 524297a3b0SGarrett D'Amore */ 534297a3b0SGarrett D'Amore 544297a3b0SGarrett D'Amore /* 554297a3b0SGarrett D'Amore * Hmmm this is probably a bit backwards. As we are converting to single 564297a3b0SGarrett D'Amore * byte formats, perhaps we should not be doing a redundant conversion. 574297a3b0SGarrett D'Amore * Something to look at for the future. 584297a3b0SGarrett D'Amore */ 594297a3b0SGarrett D'Amore 604297a3b0SGarrett D'Amore size_t 614297a3b0SGarrett D'Amore __wcsftime_xpg5(wchar_t *wcs, size_t maxsize, const wchar_t *format, 624297a3b0SGarrett D'Amore const struct tm *timeptr) 634297a3b0SGarrett D'Amore { 644297a3b0SGarrett D'Amore static const mbstate_t initial = { 0 }; 654297a3b0SGarrett D'Amore mbstate_t mbs; 664297a3b0SGarrett D'Amore char *dst, *sformat; 674297a3b0SGarrett D'Amore const char *dstp; 684297a3b0SGarrett D'Amore const wchar_t *formatp; 694297a3b0SGarrett D'Amore size_t n, sflen; 704297a3b0SGarrett D'Amore int sverrno; 714297a3b0SGarrett D'Amore 724297a3b0SGarrett D'Amore sformat = dst = NULL; 734297a3b0SGarrett D'Amore 744297a3b0SGarrett D'Amore /* 754297a3b0SGarrett D'Amore * Convert the supplied format string to a multibyte representation 764297a3b0SGarrett D'Amore * for strftime(), which only handles single-byte characters. 774297a3b0SGarrett D'Amore */ 784297a3b0SGarrett D'Amore mbs = initial; 794297a3b0SGarrett D'Amore formatp = format; 804297a3b0SGarrett D'Amore sflen = wcsrtombs(NULL, &formatp, 0, &mbs); 814297a3b0SGarrett D'Amore if (sflen == (size_t)-1) 824297a3b0SGarrett D'Amore goto error; 834297a3b0SGarrett D'Amore if ((sformat = malloc(sflen + 1)) == NULL) 844297a3b0SGarrett D'Amore goto error; 854297a3b0SGarrett D'Amore mbs = initial; 864297a3b0SGarrett D'Amore (void) wcsrtombs(sformat, &formatp, sflen + 1, &mbs); 874297a3b0SGarrett D'Amore 884297a3b0SGarrett D'Amore /* 894297a3b0SGarrett D'Amore * Allocate memory for longest multibyte sequence that will fit 904297a3b0SGarrett D'Amore * into the caller's buffer and call strftime() to fill it. 914297a3b0SGarrett D'Amore * Then, copy and convert the result back into wide characters in 924297a3b0SGarrett D'Amore * the caller's buffer. 934297a3b0SGarrett D'Amore */ 944297a3b0SGarrett D'Amore if (LONG_MAX / MB_CUR_MAX <= maxsize) { 954297a3b0SGarrett D'Amore /* maxsize is prepostorously large - avoid int. overflow. */ 964297a3b0SGarrett D'Amore errno = EINVAL; 974297a3b0SGarrett D'Amore goto error; 984297a3b0SGarrett D'Amore } 994297a3b0SGarrett D'Amore if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL) 1004297a3b0SGarrett D'Amore goto error; 1014297a3b0SGarrett D'Amore if (strftime(dst, maxsize, sformat, timeptr) == 0) 1024297a3b0SGarrett D'Amore goto error; 1034297a3b0SGarrett D'Amore dstp = dst; 1044297a3b0SGarrett D'Amore mbs = initial; 1054297a3b0SGarrett D'Amore n = mbsrtowcs(wcs, &dstp, maxsize, &mbs); 1064297a3b0SGarrett D'Amore if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL) 1074297a3b0SGarrett D'Amore goto error; 1084297a3b0SGarrett D'Amore 1094297a3b0SGarrett D'Amore free(sformat); 1104297a3b0SGarrett D'Amore free(dst); 1114297a3b0SGarrett D'Amore return (n); 1124297a3b0SGarrett D'Amore 1134297a3b0SGarrett D'Amore error: 1144297a3b0SGarrett D'Amore sverrno = errno; 1154297a3b0SGarrett D'Amore free(sformat); 1164297a3b0SGarrett D'Amore free(dst); 1174297a3b0SGarrett D'Amore errno = sverrno; 1184297a3b0SGarrett D'Amore return (0); 1194297a3b0SGarrett D'Amore } 1204297a3b0SGarrett D'Amore 1214297a3b0SGarrett D'Amore size_t 1224297a3b0SGarrett D'Amore wcsftime(wchar_t *wcs, size_t maxsize, const char *format, 1234297a3b0SGarrett D'Amore const struct tm *timeptr) 1244297a3b0SGarrett D'Amore { 1254297a3b0SGarrett D'Amore int len; 1264297a3b0SGarrett D'Amore wchar_t *wfmt; 127*6b5e5868SGarrett D'Amore size_t rv; 1284297a3b0SGarrett D'Amore 1294297a3b0SGarrett D'Amore /* Convert the format (mb string) to wide char array */ 1304297a3b0SGarrett D'Amore len = strlen(format) + 1; 131*6b5e5868SGarrett D'Amore wfmt = malloc(sizeof (wchar_t) * len); 1324297a3b0SGarrett D'Amore if (mbstowcs(wfmt, format, len) == (size_t)-1) { 133*6b5e5868SGarrett D'Amore free(wfmt); 1344297a3b0SGarrett D'Amore return (0); 1354297a3b0SGarrett D'Amore } 136*6b5e5868SGarrett D'Amore rv = __wcsftime_xpg5(wcs, maxsize, wfmt, timeptr); 137*6b5e5868SGarrett D'Amore free(wfmt); 138*6b5e5868SGarrett D'Amore return (rv); 1394297a3b0SGarrett D'Amore } 140