Move to u8-mbtouc-aux.c.
[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 Library General Public License as published
7    by the Free Software Foundation; either version 2, or (at your option)
8    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    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 this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18    USA.  */
19
20 #include <config.h>
21
22 /* Specification.  */
23 #include "unistr.h"
24
25 #if !HAVE_INLINE
26
27 int
28 u8_mbtouc (ucs4_t *puc, const uint8_t *s, size_t n)
29 {
30   uint8_t c = *s;
31
32   if (c < 0x80)
33     {
34       *puc = c;
35       return 1;
36     }
37   else if (c >= 0xc2)
38     {
39       if (c < 0xe0)
40         {
41           if (n >= 2)
42             {
43               if ((s[1] ^ 0x80) < 0x40)
44                 {
45                   *puc = ((unsigned int) (c & 0x1f) << 6)
46                          | (unsigned int) (s[1] ^ 0x80);
47                   return 2;
48                 }
49               /* invalid multibyte character */
50             }
51           else
52             {
53               /* incomplete multibyte character */
54               *puc = 0xfffd;
55               return n;
56             }
57         }
58       else if (c < 0xf0)
59         {
60           if (n >= 3)
61             {
62               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
63                   && (c >= 0xe1 || s[1] >= 0xa0)
64                   && (c != 0xed || s[1] < 0xa0))
65                 {
66                   *puc = ((unsigned int) (c & 0x0f) << 12)
67                          | ((unsigned int) (s[1] ^ 0x80) << 6)
68                          | (unsigned int) (s[2] ^ 0x80);
69                   return 3;
70                 }
71               /* invalid multibyte character */
72             }
73           else
74             {
75               /* incomplete multibyte character */
76               *puc = 0xfffd;
77               return n;
78             }
79         }
80       else if (c < 0xf8)
81         {
82           if (n >= 4)
83             {
84               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
85                   && (s[3] ^ 0x80) < 0x40
86                   && (c >= 0xf1 || s[1] >= 0x90)
87 #if 1
88                   && (c < 0xf4 || (c == 0xf4 && s[1] < 0x90))
89 #endif
90                  )
91                 {
92                   *puc = ((unsigned int) (c & 0x07) << 18)
93                          | ((unsigned int) (s[1] ^ 0x80) << 12)
94                          | ((unsigned int) (s[2] ^ 0x80) << 6)
95                          | (unsigned int) (s[3] ^ 0x80);
96                   return 4;
97                 }
98               /* invalid multibyte character */
99             }
100           else
101             {
102               /* incomplete multibyte character */
103               *puc = 0xfffd;
104               return n;
105             }
106         }
107 #if 0
108       else if (c < 0xfc)
109         {
110           if (n >= 5)
111             {
112               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
113                   && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
114                   && (c >= 0xf9 || s[1] >= 0x88))
115                 {
116                   *puc = ((unsigned int) (c & 0x03) << 24)
117                          | ((unsigned int) (s[1] ^ 0x80) << 18)
118                          | ((unsigned int) (s[2] ^ 0x80) << 12)
119                          | ((unsigned int) (s[3] ^ 0x80) << 6)
120                          | (unsigned int) (s[4] ^ 0x80);
121                   return 5;
122                 }
123               /* invalid multibyte character */
124             }
125           else
126             {
127               /* incomplete multibyte character */
128               *puc = 0xfffd;
129               return n;
130             }
131         }
132       else if (c < 0xfe)
133         {
134           if (n >= 6)
135             {
136               if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
137                   && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
138                   && (s[5] ^ 0x80) < 0x40
139                   && (c >= 0xfd || s[1] >= 0x84))
140                 {
141                   *puc = ((unsigned int) (c & 0x01) << 30)
142                          | ((unsigned int) (s[1] ^ 0x80) << 24)
143                          | ((unsigned int) (s[2] ^ 0x80) << 18)
144                          | ((unsigned int) (s[3] ^ 0x80) << 12)
145                          | ((unsigned int) (s[4] ^ 0x80) << 6)
146                          | (unsigned int) (s[5] ^ 0x80);
147                   return 6;
148                 }
149               /* invalid multibyte character */
150             }
151           else
152             {
153               /* incomplete multibyte character */
154               *puc = 0xfffd;
155               return n;
156             }
157         }
158 #endif
159     }
160   /* invalid multibyte character */
161   *puc = 0xfffd;
162   return 1;
163 }
164
165 #endif