Change copyright notice from LGPLv2.0+ to LGPLv3+.
[gnulib.git] / lib / unistr / u8-mbtouc.c
1 /* Look at first character in UTF-8 string.
2    Copyright (C) 1999-2002, 2006-2007 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2001.
4
5    This program is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Lesser General Public License as published
7    by the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include <config.h>
19
20 /* Specification.  */
21 #include "unistr.h"
22
23 #if !HAVE_INLINE
24
25 int
26 u8_mbtouc (ucs4_t *puc, const uint8_t *s, size_t n)
27 {
28   uint8_t c = *s;
29
30   if (c < 0x80)
31     {
32       *puc = c;
33       return 1;
34     }
35   else if (c >= 0xc2)
36     {
37       if (c < 0xe0)
38         {
39           if (n >= 2)
40             {
41               if ((s[1] ^ 0x80) < 0x40)
42                 {
43                   *puc = ((unsigned int) (c & 0x1f) << 6)
44                          | (unsigned int) (s[1] ^ 0x80);
45                   return 2;
46                 }
47               /* invalid multibyte character */
48             }
49           else
50             {
51               /* incomplete multibyte character */
52               *puc = 0xfffd;
53               return n;
54             }
55         }
56       else if (c < 0xf0)
57         {
58           if (n >= 3)
59             {
60               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
61                   && (c >= 0xe1 || s[1] >= 0xa0)
62                   && (c != 0xed || s[1] < 0xa0))
63                 {
64                   *puc = ((unsigned int) (c & 0x0f) << 12)
65                          | ((unsigned int) (s[1] ^ 0x80) << 6)
66                          | (unsigned int) (s[2] ^ 0x80);
67                   return 3;
68                 }
69               /* invalid multibyte character */
70             }
71           else
72             {
73               /* incomplete multibyte character */
74               *puc = 0xfffd;
75               return n;
76             }
77         }
78       else if (c < 0xf8)
79         {
80           if (n >= 4)
81             {
82               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
83                   && (s[3] ^ 0x80) < 0x40
84                   && (c >= 0xf1 || s[1] >= 0x90)
85 #if 1
86                   && (c < 0xf4 || (c == 0xf4 && s[1] < 0x90))
87 #endif
88                  )
89                 {
90                   *puc = ((unsigned int) (c & 0x07) << 18)
91                          | ((unsigned int) (s[1] ^ 0x80) << 12)
92                          | ((unsigned int) (s[2] ^ 0x80) << 6)
93                          | (unsigned int) (s[3] ^ 0x80);
94                   return 4;
95                 }
96               /* invalid multibyte character */
97             }
98           else
99             {
100               /* incomplete multibyte character */
101               *puc = 0xfffd;
102               return n;
103             }
104         }
105 #if 0
106       else if (c < 0xfc)
107         {
108           if (n >= 5)
109             {
110               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
111                   && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
112                   && (c >= 0xf9 || s[1] >= 0x88))
113                 {
114                   *puc = ((unsigned int) (c & 0x03) << 24)
115                          | ((unsigned int) (s[1] ^ 0x80) << 18)
116                          | ((unsigned int) (s[2] ^ 0x80) << 12)
117                          | ((unsigned int) (s[3] ^ 0x80) << 6)
118                          | (unsigned int) (s[4] ^ 0x80);
119                   return 5;
120                 }
121               /* invalid multibyte character */
122             }
123           else
124             {
125               /* incomplete multibyte character */
126               *puc = 0xfffd;
127               return n;
128             }
129         }
130       else if (c < 0xfe)
131         {
132           if (n >= 6)
133             {
134               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
135                   && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
136                   && (s[5] ^ 0x80) < 0x40
137                   && (c >= 0xfd || s[1] >= 0x84))
138                 {
139                   *puc = ((unsigned int) (c & 0x01) << 30)
140                          | ((unsigned int) (s[1] ^ 0x80) << 24)
141                          | ((unsigned int) (s[2] ^ 0x80) << 18)
142                          | ((unsigned int) (s[3] ^ 0x80) << 12)
143                          | ((unsigned int) (s[4] ^ 0x80) << 6)
144                          | (unsigned int) (s[5] ^ 0x80);
145                   return 6;
146                 }
147               /* invalid multibyte character */
148             }
149           else
150             {
151               /* incomplete multibyte character */
152               *puc = 0xfffd;
153               return n;
154             }
155         }
156 #endif
157     }
158   /* invalid multibyte character */
159   *puc = 0xfffd;
160   return 1;
161 }
162
163 #endif