blob: b5a108e2cb3629d37055c23a83839471be3353fb [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkParse.h"
11
bungeman60e0fee2015-08-26 05:15:46 -070012#include <stdlib.h>
13
reed@android.com8a1c16f2008-12-17 15:59:43 +000014static inline bool is_between(int c, int min, int max)
15{
16 return (unsigned)(c - min) <= (unsigned)(max - min);
17}
18
19static inline bool is_ws(int c)
20{
21 return is_between(c, 1, 32);
22}
23
24static inline bool is_digit(int c)
25{
26 return is_between(c, '0', '9');
27}
28
29static inline bool is_sep(int c)
30{
31 return is_ws(c) || c == ',' || c == ';';
32}
33
34static int to_hex(int c)
35{
36 if (is_digit(c))
37 return c - '0';
38
39 c |= 0x20; // make us lower-case
40 if (is_between(c, 'a', 'f'))
41 return c + 10 - 'a';
42 else
43 return -1;
44}
45
46static inline bool is_hex(int c)
47{
48 return to_hex(c) >= 0;
49}
50
51static const char* skip_ws(const char str[])
52{
53 SkASSERT(str);
54 while (is_ws(*str))
55 str++;
56 return str;
57}
58
59static const char* skip_sep(const char str[])
60{
61 SkASSERT(str);
62 while (is_sep(*str))
63 str++;
64 return str;
65}
66
rmistry@google.comd6176b02012-08-23 18:14:13 +000067int SkParse::Count(const char str[])
reed@android.com8a1c16f2008-12-17 15:59:43 +000068{
69 char c;
70 int count = 0;
71 goto skipLeading;
72 do {
73 count++;
74 do {
75 if ((c = *str++) == '\0')
76 goto goHome;
77 } while (is_sep(c) == false);
78skipLeading:
79 do {
80 if ((c = *str++) == '\0')
81 goto goHome;
82 } while (is_sep(c));
83 } while (true);
84goHome:
85 return count;
86}
87
rmistry@google.comd6176b02012-08-23 18:14:13 +000088int SkParse::Count(const char str[], char separator)
reed@android.com8a1c16f2008-12-17 15:59:43 +000089{
90 char c;
91 int count = 0;
92 goto skipLeading;
93 do {
94 count++;
95 do {
96 if ((c = *str++) == '\0')
97 goto goHome;
98 } while (c != separator);
99skipLeading:
100 do {
101 if ((c = *str++) == '\0')
102 goto goHome;
103 } while (c == separator);
104 } while (true);
105goHome:
106 return count;
107}
108
109const char* SkParse::FindHex(const char str[], uint32_t* value)
110{
111 SkASSERT(str);
112 str = skip_ws(str);
113
114 if (!is_hex(*str))
halcanary96fcdcc2015-08-27 07:41:13 -0700115 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116
117 uint32_t n = 0;
118 int max_digits = 8;
119 int digit;
120
121 while ((digit = to_hex(*str)) >= 0)
122 {
123 if (--max_digits < 0)
halcanary96fcdcc2015-08-27 07:41:13 -0700124 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 n = (n << 4) | digit;
126 str += 1;
127 }
128
129 if (*str == 0 || is_ws(*str))
130 {
131 if (value)
132 *value = n;
133 return str;
134 }
halcanary96fcdcc2015-08-27 07:41:13 -0700135 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136}
137
138const char* SkParse::FindS32(const char str[], int32_t* value)
139{
140 SkASSERT(str);
141 str = skip_ws(str);
142
143 int sign = 0;
144 if (*str == '-')
145 {
146 sign = -1;
147 str += 1;
148 }
149
150 if (!is_digit(*str))
halcanary96fcdcc2015-08-27 07:41:13 -0700151 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152
153 int n = 0;
154 while (is_digit(*str))
155 {
156 n = 10*n + *str - '0';
157 str += 1;
158 }
159 if (value)
160 *value = (n ^ sign) - sign;
161 return str;
162}
163
164const char* SkParse::FindMSec(const char str[], SkMSec* value)
165{
166 SkASSERT(str);
167 str = skip_ws(str);
168
169 int sign = 0;
170 if (*str == '-')
171 {
172 sign = -1;
173 str += 1;
174 }
175
176 if (!is_digit(*str))
halcanary96fcdcc2015-08-27 07:41:13 -0700177 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
179 int n = 0;
180 while (is_digit(*str))
181 {
182 n = 10*n + *str - '0';
183 str += 1;
184 }
185 int remaining10s = 3;
186 if (*str == '.') {
187 str++;
188 while (is_digit(*str))
189 {
190 n = 10*n + *str - '0';
191 str += 1;
192 if (--remaining10s == 0)
193 break;
194 }
195 }
196 while (--remaining10s >= 0)
197 n *= 10;
198 if (value)
199 *value = (n ^ sign) - sign;
200 return str;
201}
202
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000203const char* SkParse::FindScalar(const char str[], SkScalar* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 SkASSERT(str);
205 str = skip_ws(str);
reed@google.com8f4d2302013-12-17 16:44:46 +0000206
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000207 char* stop;
reed@android.come191b162009-12-18 21:33:39 +0000208 float v = (float)strtod(str, &stop);
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000209 if (str == stop) {
halcanary96fcdcc2015-08-27 07:41:13 -0700210 return nullptr;
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000211 }
212 if (value) {
213 *value = v;
214 }
215 return stop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216}
217
218const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
219{
220 SkASSERT(count >= 0);
221
222 if (count > 0)
223 {
224 for (;;)
225 {
226 str = SkParse::FindScalar(str, value);
halcanary96fcdcc2015-08-27 07:41:13 -0700227 if (--count == 0 || str == nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 break;
229
230 // keep going
231 str = skip_sep(str);
232 if (value)
233 value += 1;
234 }
235 }
236 return str;
237}
238
239static bool lookup_str(const char str[], const char** table, int count)
240{
241 while (--count >= 0)
242 if (!strcmp(str, table[count]))
243 return true;
244 return false;
245}
246
247bool SkParse::FindBool(const char str[], bool* value)
248{
249 static const char* gYes[] = { "yes", "1", "true" };
250 static const char* gNo[] = { "no", "0", "false" };
251
252 if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
253 {
254 if (value) *value = true;
255 return true;
256 }
257 else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
258 {
259 if (value) *value = false;
260 return true;
261 }
262 return false;
263}
264
265int SkParse::FindList(const char target[], const char list[])
266{
267 size_t len = strlen(target);
268 int index = 0;
269
270 for (;;)
271 {
272 const char* end = strchr(list, ',');
273 size_t entryLen;
274
halcanary96fcdcc2015-08-27 07:41:13 -0700275 if (end == nullptr) // last entry
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 entryLen = strlen(list);
277 else
278 entryLen = end - list;
279
280 if (entryLen == len && memcmp(target, list, len) == 0)
281 return index;
halcanary96fcdcc2015-08-27 07:41:13 -0700282 if (end == nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 break;
284
285 list = end + 1; // skip the ','
286 index += 1;
287 }
288 return -1;
289}
290
291#ifdef SK_SUPPORT_UNITTEST
rmistry@google.comd6176b02012-08-23 18:14:13 +0000292void SkParse::UnitTest()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293{
294 // !!! additional parse tests go here
295 SkParse::TestColor();
296}
297#endif