diff options
author | Bruno Haible <bruno@clisp.org> | 2008-12-22 00:42:11 +0100 |
---|---|---|
committer | Bruno Haible <bruno@clisp.org> | 2008-12-22 00:42:11 +0100 |
commit | a35b7df64eb0863e3d0759691e4d041354d7030f (patch) | |
tree | 4a922f0e8fd98429691be332a6dd4257d79937ab /lib/wcsnrtombs.c | |
parent | 0ce087b81f8a3f8a5aed8fbd0a7b1f38c1d7c2fd (diff) | |
download | gnulib-a35b7df64eb0863e3d0759691e4d041354d7030f.tar.gz |
New module 'wcsnrtombs'.
Diffstat (limited to 'lib/wcsnrtombs.c')
-rw-r--r-- | lib/wcsnrtombs.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/lib/wcsnrtombs.c b/lib/wcsnrtombs.c new file mode 100644 index 0000000000..742b857910 --- /dev/null +++ b/lib/wcsnrtombs.c @@ -0,0 +1,104 @@ +/* Convert wide string to string. + Copyright (C) 2008 Free Software Foundation, Inc. + Written by Bruno Haible <bruno@clisp.org>, 2008. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <wchar.h> + +# include <errno.h> +# include <stdlib.h> +# include <string.h> + + +extern mbstate_t _gl_wcsrtombs_state; + +size_t +wcsnrtombs (char *dest, const wchar_t **srcp, size_t srclen, size_t len, mbstate_t *ps) +{ + if (ps == NULL) + ps = &_gl_wcsrtombs_state; + { + const wchar_t *src = *srcp; + size_t cur_max = MB_CUR_MAX; + char buf[64]; + + if (!(cur_max <= sizeof (buf))) + abort (); + + if (dest != NULL) + { + char *destptr = dest; + + for (; srclen > 0 && len > 0; src++, srclen--) + { + wchar_t wc = *src; + size_t ret = wcrtomb (len >= cur_max ? destptr : buf, wc, ps); + + if (ret == (size_t)(-1)) + goto bad_input; + if (!(ret <= cur_max)) + abort (); + if (len < ret) + break; + if (len < cur_max) + memcpy (destptr, buf, ret); + if (wc == 0) + { + src = NULL; + /* Here mbsinit (ps). */ + break; + } + destptr += ret; + len -= ret; + } + *srcp = src; + return destptr - dest; + } + else + { + /* Ignore dest and len, don't store *srcp at the end, and + don't clobber *ps. */ + mbstate_t state = *ps; + size_t totalcount = 0; + + for (; srclen > 0; src++, srclen--) + { + wchar_t wc = *src; + size_t ret = wcrtomb (buf, wc, &state); + + if (ret == (size_t)(-1)) + goto bad_input2; + if (wc == 0) + { + /* Here mbsinit (&state). */ + break; + } + totalcount += ret; + } + return totalcount; + } + + bad_input: + *srcp = src; + bad_input2: + errno = EILSEQ; + return (size_t)(-1); + } +} + +#endif |