Use spaces for indentation, not tabs.
[gnulib.git] / lib / unistr / u8-strmblen.c
1 /* Look at first character in UTF-8 string.
2    Copyright (C) 1999-2000, 2002, 2006-2007 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2002.
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 int
24 u8_strmblen (const uint8_t *s)
25 {
26   /* Keep in sync with unistr.h and utf8-ucs4.c.  */
27   uint8_t c = *s;
28
29   if (c < 0x80)
30     return (c != 0 ? 1 : 0);
31   if (c >= 0xc2)
32     {
33       if (c < 0xe0)
34         {
35 #if CONFIG_UNICODE_SAFETY
36           if ((s[1] ^ 0x80) < 0x40)
37 #else
38           if (s[1] != 0)
39 #endif
40             return 2;
41         }
42       else if (c < 0xf0)
43         {
44 #if CONFIG_UNICODE_SAFETY
45           if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
46               && (c >= 0xe1 || s[1] >= 0xa0)
47               && (c != 0xed || s[1] < 0xa0))
48 #else
49           if (s[1] != 0 && s[2] != 0)
50 #endif
51             return 3;
52         }
53       else if (c < 0xf8)
54         {
55 #if CONFIG_UNICODE_SAFETY
56           if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
57               && (s[3] ^ 0x80) < 0x40
58               && (c >= 0xf1 || s[1] >= 0x90)
59 #if 1
60               && (c < 0xf4 || (c == 0xf4 && s[1] < 0x90))
61 #endif
62              )
63 #else
64           if (s[1] != 0 && s[2] != 0 && s[3] != 0)
65 #endif
66             return 4;
67         }
68 #if 0
69       else if (c < 0xfc)
70         {
71 #if CONFIG_UNICODE_SAFETY
72           if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
73               && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
74               && (c >= 0xf9 || s[1] >= 0x88))
75 #else
76           if (s[1] != 0 && s[2] != 0 && s[3] != 0 && s[4] != 0)
77 #endif
78             return 5;
79         }
80       else if (c < 0xfe)
81         {
82 #if CONFIG_UNICODE_SAFETY
83           if ((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
84               && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
85               && (s[5] ^ 0x80) < 0x40
86               && (c >= 0xfd || s[1] >= 0x84))
87 #else
88           if (s[1] != 0 && s[2] != 0 && s[3] != 0 && s[4] != 0 && s[5] != 0)
89 #endif
90             return 6;
91         }
92 #endif
93     }
94   /* invalid or incomplete multibyte character */
95   return -1;
96 }