]>
Commit | Line | Data |
---|---|---|
30de3b18 RM |
1 | /* Copyright (C) 1996 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
07a4742f | 3 | Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996. |
30de3b18 RM |
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 | |
17 | not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
19 | ||
07a4742f | 20 | #include <errno.h> |
30de3b18 RM |
21 | #include <wchar.h> |
22 | ||
07a4742f RM |
23 | #ifndef EILSEQ |
24 | #define EILSEQ EINVAL | |
25 | #endif | |
26 | ||
30de3b18 | 27 | |
6dbe2837 RM |
28 | static mbstate_t internal; |
29 | ||
30de3b18 | 30 | size_t |
23396375 | 31 | __mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) |
30de3b18 | 32 | { |
07a4742f | 33 | size_t used = 0; |
30de3b18 | 34 | |
6dbe2837 RM |
35 | if (ps == NULL) |
36 | ps = &internal; | |
37 | ||
30de3b18 RM |
38 | if (s == NULL) |
39 | { | |
07a4742f | 40 | /* See first paragraph of description in 7.16.6.3.2. */ |
30de3b18 RM |
41 | pwc = NULL; |
42 | s = ""; | |
43 | n = 1; | |
44 | } | |
45 | ||
07a4742f RM |
46 | if (n > 0) |
47 | { | |
48 | if (ps->count == 0) | |
49 | { | |
50 | unsigned char byte = (unsigned char) *s++; | |
51 | ++used; | |
30de3b18 | 52 | |
07a4742f RM |
53 | /* We must look for a possible first byte of a UTF8 sequence. */ |
54 | if (byte < 0x80) | |
55 | { | |
56 | /* One byte sequence. */ | |
57 | if (pwc != NULL) | |
58 | *pwc = (wchar_t) byte; | |
59 | return byte ? used : 0; | |
60 | } | |
30de3b18 | 61 | |
07a4742f RM |
62 | if ((byte & 0xc0) == 0x80 || (byte & 0xfe) == 0xfe) |
63 | { | |
64 | /* Oh, oh. An encoding error. */ | |
c4029823 | 65 | __set_errno (EILSEQ); |
07a4742f RM |
66 | return (size_t) -1; |
67 | } | |
30de3b18 | 68 | |
07a4742f RM |
69 | if ((byte & 0xe0) == 0xc0) |
70 | { | |
71 | /* We expect two bytes. */ | |
72 | ps->count = 1; | |
73 | ps->value = byte & 0x1f; | |
74 | } | |
75 | else if ((byte & 0xf0) == 0xe0) | |
76 | { | |
77 | /* We expect three bytes. */ | |
78 | ps->count = 2; | |
79 | ps->value = byte & 0x0f; | |
80 | } | |
81 | else if ((byte & 0xf8) == 0xf0) | |
82 | { | |
83 | /* We expect four bytes. */ | |
84 | ps->count = 3; | |
85 | ps->value = byte & 0x07; | |
86 | } | |
87 | else if ((byte & 0xfc) == 0xf8) | |
88 | { | |
89 | /* We expect five bytes. */ | |
90 | ps->count = 4; | |
91 | ps->value = byte & 0x03; | |
92 | } | |
93 | else | |
94 | { | |
95 | /* We expect six bytes. */ | |
96 | ps->count = 5; | |
97 | ps->value = byte & 0x01; | |
98 | } | |
99 | } | |
100 | ||
101 | /* We know we have to handle a multibyte character and there are | |
102 | some more bytes to read. */ | |
103 | while (used < n) | |
104 | { | |
105 | /* The second to sixths byte must be of the form 10xxxxxx. */ | |
106 | unsigned char byte = (unsigned char) *s++; | |
107 | ++used; | |
108 | ||
109 | if ((byte & 0xc0) != 0x80) | |
110 | { | |
111 | /* Oh, oh. An encoding error. */ | |
c4029823 | 112 | __set_errno (EILSEQ); |
07a4742f RM |
113 | return (size_t) -1; |
114 | } | |
115 | ||
116 | ps->value <<= 6; | |
117 | ps->value |= byte & 0x3f; | |
118 | ||
119 | if (--ps->count == 0) | |
120 | { | |
121 | /* The character is finished. */ | |
122 | if (pwc != NULL) | |
123 | *pwc = (wchar_t) ps->value; | |
124 | return ps->value ? used : 0; | |
125 | } | |
126 | } | |
30de3b18 RM |
127 | } |
128 | ||
07a4742f | 129 | return (size_t) -2; |
30de3b18 | 130 | } |
23396375 | 131 | weak_alias (__mbrtowc, mbrtowc) |