Use _IO_FILE_complete, not _IO_file_plus.
[kopensolaris-gnu/glibc.git] / wcsmbs / wcsrtombs.c
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <wchar.h>
22
23 #ifndef EILSEQ
24 #define EILSEQ EINVAL
25 #endif
26
27
28 static const wchar_t encoding_mask[] =
29 {
30   ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
31 };
32
33 static const unsigned char encoding_byte[] =
34 {
35   0xc0, 0xe0, 0xf0, 0xf8, 0xfc
36 };
37
38 /* We don't need the state really because we don't have shift states
39    to maintain between calls to this function.  */
40 static mbstate_t internal;
41
42 size_t
43 __wcsrtombs (dst, src, len, ps)
44      char *dst;
45      const wchar_t **src;
46      size_t len;
47      mbstate_t *ps;
48 {
49   size_t written = 0;
50   const wchar_t *run = *src;
51
52   if (ps == NULL)
53     ps = &internal;
54
55   if (dst == NULL)
56     /* The LEN parameter has to be ignored if we don't actually write
57        anything.  */
58     len = ~0;
59
60   while (written < len)
61     {
62       wchar_t wc = *run++;
63
64       if (wc < 0 || wc > 0x7fffffff)
65         {
66           /* This is no correct ISO 10646 character.  */
67           __set_errno (EILSEQ);
68           return (size_t) -1;
69         }
70
71       if (wc == L'\0')
72         {
73           /* Found the end.  */
74           if (dst != NULL)
75             *dst = '\0';
76           *src = NULL;
77           return written;
78         }
79       else if (wc < 0x80)
80         {
81           /* It's an one byte sequence.  */
82           if (dst != NULL)
83             *dst++ = (char) wc;
84           ++written;
85         }
86       else
87         {
88           size_t step;
89
90           for (step = 2; step < 6; ++step)
91             if ((wc & encoding_mask[step - 2]) == 0)
92               break;
93
94           if (written + step >= len)
95             /* Too long.  */
96             break;
97
98           if (dst != NULL)
99             {
100               size_t cnt = step;
101
102               dst[0] = encoding_byte[cnt - 2];
103
104               --cnt;
105               do
106                 {
107                   dst[cnt] = 0x80 | (wc & 0x3f);
108                   wc >>= 6;
109                 }
110               while (--cnt > 0);
111               dst[0] |= wc;
112
113               dst += step;
114             }
115
116           written += step;
117         }
118     }
119
120   /* Store position of first unprocessed word.  */
121   *src = run;
122
123   return written;
124 }
125 weak_alias (__wcsrtombs, wcsrtombs)