diff options
Diffstat (limited to 'wcsmbs/wmemrtowcs.c')
-rw-r--r-- | wcsmbs/wmemrtowcs.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/wcsmbs/wmemrtowcs.c b/wcsmbs/wmemrtowcs.c new file mode 100644 index 0000000000..1686229b8f --- /dev/null +++ b/wcsmbs/wmemrtowcs.c @@ -0,0 +1,134 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@gnu.org>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <wchar.h> + +#ifndef EILSEQ +#define EILSEQ EINVAL +#endif + + +/* We don't need the state really because we don't have shift states + to maintain between calls to this function. */ +static mbstate_t internal; + +/* This is a non-standard function but it is very useful in the + implementation of stdio because we have to deal with unterminated + buffers. At most NMC bytes will be converted. */ +size_t +__wmemrtowcs (dst, src, nmc, len, ps) + wchar_t *dst; + const char **src; + size_t nmc; + size_t len; + mbstate_t *ps; +{ + size_t written = 0; + const char *run = *src; + const char *last = run + nmc; + + if (ps == NULL) + ps = &internal; + + if (dst == NULL) + /* The LEN parameter has to be ignored if we don't actually write + anything. */ + len = ~0; + + /* Copy all words. */ + while (written < len && run < last) + { + wchar_t value; + size_t count; + unsigned char byte = *run++; + + /* We expect a start of a new multibyte character. */ + if (byte < 0x80) + { + /* One byte sequence. */ + count = 0; + value = byte; + } + else if ((byte & 0xe0) == 0xc0) + { + count = 1; + value = byte & 0x1f; + } + else if ((byte & 0xf0) == 0xe0) + { + /* We expect three bytes. */ + count = 2; + value = byte & 0x0f; + } + else if ((byte & 0xf8) == 0xf0) + { + /* We expect four bytes. */ + count = 3; + value = byte & 0x07; + } + else if ((byte & 0xfc) == 0xf8) + { + /* We expect five bytes. */ + count = 4; + value = byte & 0x03; + } + else if ((byte & 0xfe) == 0xfc) + { + /* We expect six bytes. */ + count = 5; + value = byte & 0x01; + } + else + { + /* This is an illegal encoding. */ + __set_errno (EILSEQ); + return (size_t) -1; + } + + /* Read the possible remaining bytes. */ + while (count-- > 0) + { + byte = *run++; + + if ((byte & 0xc0) != 0x80) + { + /* This is an illegal encoding. */ + __set_errno (EILSEQ); + return (size_t) -1; + } + + value <<= 6; + value |= byte & 0x3f; + } + + /* Store value is required. */ + if (dst != NULL) + *dst++ = value; + + /* Increment counter of produced words. */ + ++written; + } + + /* Store address of next byte to process. */ + *src = run; + + return written; +} +weak_alias (__wmemrtowcs, wmemrtowcs) |