Back to index

glibc  2.9
wcsnrtombs.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-2000, 2002, 2003, 2005 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <assert.h>
00021 #include <dlfcn.h>
00022 #include <errno.h>
00023 #include <gconv.h>
00024 #include <wchar.h>
00025 #include <wcsmbsload.h>
00026 
00027 #include <sysdep.h>
00028 
00029 #ifndef EILSEQ
00030 # define EILSEQ EINVAL
00031 #endif
00032 
00033 
00034 /* This is the private state used if PS is NULL.  */
00035 static mbstate_t state;
00036 
00037 /* This is a non-standard function but it is very useful in the
00038    implementation of stdio because we have to deal with unterminated
00039    buffers.  At most NWC wide character will be converted.  */
00040 size_t
00041 __wcsnrtombs (dst, src, nwc, len, ps)
00042      char *dst;
00043      const wchar_t **src;
00044      size_t nwc;
00045      size_t len;
00046      mbstate_t *ps;
00047 {
00048   struct __gconv_step_data data;
00049   const wchar_t *srcend;
00050   int status;
00051   size_t result;
00052   struct __gconv_step *tomb;
00053   const struct gconv_fcts *fcts;
00054 
00055   /* Tell where we want the result.  */
00056   data.__invocation_counter = 0;
00057   data.__internal_use = 1;
00058   data.__flags = __GCONV_IS_LAST;
00059   data.__statep = ps ?: &state;
00060   data.__trans = NULL;
00061 
00062   if (nwc == 0)
00063     return 0;
00064   srcend = *src + __wcsnlen (*src, nwc - 1) + 1;
00065 
00066   /* Get the conversion functions.  */
00067   fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
00068 
00069   /* Get the structure with the function pointers.  */
00070   tomb = fcts->tomb;
00071   __gconv_fct fct = tomb->__fct;
00072 #ifdef PTR_DEMANGLE
00073   if (tomb->__shlib_handle != NULL)
00074     PTR_DEMANGLE (fct);
00075 #endif
00076 
00077   /* We have to handle DST == NULL special.  */
00078   if (dst == NULL)
00079     {
00080       unsigned char buf[256];             /* Just an arbitrary value.  */
00081       const unsigned char *inbuf = (const unsigned char *) *src;
00082       size_t dummy;
00083 
00084       result = 0;
00085       data.__outbufend = buf + sizeof (buf);
00086 
00087       do
00088        {
00089          data.__outbuf = buf;
00090 
00091          status = DL_CALL_FCT (fct, (tomb, &data, &inbuf,
00092                                   (const unsigned char *) srcend, NULL,
00093                                   &dummy, 0, 1));
00094 
00095          /* Count the number of bytes.  */
00096          result += data.__outbuf - buf;
00097        }
00098       while (status == __GCONV_FULL_OUTPUT);
00099 
00100       if ((status == __GCONV_OK || status == __GCONV_EMPTY_INPUT)
00101          && data.__outbuf[-1] == '\0')
00102        /* Don't count the NUL character in.  */
00103        --result;
00104     }
00105   else
00106     {
00107       /* This code is based on the safe assumption that all internal
00108         multi-byte encodings use the NUL byte only to mark the end
00109         of the string.  */
00110       size_t dummy;
00111 
00112       data.__outbuf = (unsigned char *) dst;
00113       data.__outbufend = (unsigned char *) dst + len;
00114 
00115       status = DL_CALL_FCT (fct, (tomb, &data, (const unsigned char **) src,
00116                               (const unsigned char *) srcend, NULL,
00117                               &dummy, 0, 1));
00118 
00119       /* Count the number of bytes.  */
00120       result = data.__outbuf - (unsigned char *) dst;
00121 
00122       /* We have to determine whether the last character converted
00123         is the NUL character.  */
00124       if ((status == __GCONV_OK || status == __GCONV_EMPTY_INPUT)
00125          && data.__outbuf[-1] == '\0')
00126        {
00127          assert (data.__outbuf != (unsigned char *) dst);
00128          assert (__mbsinit (data.__statep));
00129          *src = NULL;
00130          --result;
00131        }
00132     }
00133 
00134   /* There must not be any problems with the conversion but illegal input
00135      characters.  */
00136   assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
00137          || status == __GCONV_ILLEGAL_INPUT
00138          || status == __GCONV_INCOMPLETE_INPUT
00139          || status == __GCONV_FULL_OUTPUT);
00140 
00141   if (status != __GCONV_OK && status != __GCONV_FULL_OUTPUT
00142       && status != __GCONV_EMPTY_INPUT)
00143     {
00144       result = (size_t) -1;
00145       __set_errno (EILSEQ);
00146     }
00147 
00148   return result;
00149 }
00150 weak_alias (__wcsnrtombs, wcsnrtombs)