Blame gnulib/lib/mbsrtowcs-impl.h

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