2N/A/* Convert string to wide string.
2N/A Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
2N/A Written by Bruno Haible <bruno@clisp.org>, 2008.
2N/A
2N/A This program is free software: you can redistribute it and/or modify
2N/A it under the terms of the GNU General Public License as published by
2N/A the Free Software Foundation; either version 3 of the License, or
2N/A (at your option) any later version.
2N/A
2N/A This program is distributed in the hope that it will be useful,
2N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A GNU General Public License for more details.
2N/A
2N/A You should have received a copy of the GNU General Public License
2N/A along with this program. If not, see <http://www.gnu.org/licenses/>. */
2N/A
2N/A#include <config.h>
2N/A
2N/A/* Specification. */
2N/A#include <wchar.h>
2N/A
2N/A#include <errno.h>
2N/A#include <limits.h>
2N/A#include <stdlib.h>
2N/A
2N/A#include "strnlen1.h"
2N/A
2N/A
2N/Aextern mbstate_t _gl_mbsrtowcs_state;
2N/A
2N/Asize_t
2N/Ambsrtowcs (wchar_t *dest, const char **srcp, size_t len, mbstate_t *ps)
2N/A{
2N/A if (ps == NULL)
2N/A ps = &_gl_mbsrtowcs_state;
2N/A {
2N/A const char *src = *srcp;
2N/A
2N/A if (dest != NULL)
2N/A {
2N/A wchar_t *destptr = dest;
2N/A
2N/A for (; len > 0; destptr++, len--)
2N/A {
2N/A size_t src_avail;
2N/A size_t ret;
2N/A
2N/A /* An optimized variant of
2N/A src_avail = strnlen1 (src, MB_LEN_MAX); */
2N/A if (src[0] == '\0')
2N/A src_avail = 1;
2N/A else if (src[1] == '\0')
2N/A src_avail = 2;
2N/A else if (src[2] == '\0')
2N/A src_avail = 3;
2N/A else if (MB_LEN_MAX <= 4 || src[3] == '\0')
2N/A src_avail = 4;
2N/A else
2N/A src_avail = 4 + strnlen1 (src + 4, MB_LEN_MAX - 4);
2N/A
2N/A /* Parse the next multibyte character. */
2N/A ret = mbrtowc (destptr, src, src_avail, ps);
2N/A
2N/A if (ret == (size_t)(-2))
2N/A /* Encountered a multibyte character that extends past a '\0' byte
2N/A or that is longer than MB_LEN_MAX bytes. Cannot happen. */
2N/A abort ();
2N/A
2N/A if (ret == (size_t)(-1))
2N/A goto bad_input;
2N/A if (ret == 0)
2N/A {
2N/A src = NULL;
2N/A /* Here mbsinit (ps). */
2N/A break;
2N/A }
2N/A src += ret;
2N/A }
2N/A
2N/A *srcp = src;
2N/A return destptr - dest;
2N/A }
2N/A else
2N/A {
2N/A /* Ignore dest and len, don't store *srcp at the end, and
2N/A don't clobber *ps. */
2N/A mbstate_t state = *ps;
2N/A size_t totalcount = 0;
2N/A
2N/A for (;; totalcount++)
2N/A {
2N/A size_t src_avail;
2N/A size_t ret;
2N/A
2N/A /* An optimized variant of
2N/A src_avail = strnlen1 (src, MB_LEN_MAX); */
2N/A if (src[0] == '\0')
2N/A src_avail = 1;
2N/A else if (src[1] == '\0')
2N/A src_avail = 2;
2N/A else if (src[2] == '\0')
2N/A src_avail = 3;
2N/A else if (MB_LEN_MAX <= 4 || src[3] == '\0')
2N/A src_avail = 4;
2N/A else
2N/A src_avail = 4 + strnlen1 (src + 4, MB_LEN_MAX - 4);
2N/A
2N/A /* Parse the next multibyte character. */
2N/A ret = mbrtowc (NULL, src, src_avail, &state);
2N/A
2N/A if (ret == (size_t)(-2))
2N/A /* Encountered a multibyte character that extends past a '\0' byte
2N/A or that is longer than MB_LEN_MAX bytes. Cannot happen. */
2N/A abort ();
2N/A
2N/A if (ret == (size_t)(-1))
2N/A goto bad_input2;
2N/A if (ret == 0)
2N/A {
2N/A /* Here mbsinit (&state). */
2N/A break;
2N/A }
2N/A src += ret;
2N/A }
2N/A
2N/A return totalcount;
2N/A }
2N/A
2N/A bad_input:
2N/A *srcp = src;
2N/A bad_input2:
2N/A errno = EILSEQ;
2N/A return (size_t)(-1);
2N/A }
2N/A}