blob: f6e2a438e85bc15bc5e857090a0eeaeeb1c008b1 [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
12static inline bool is_between(int c, int min, int max)
13{
14 return (unsigned)(c - min) <= (unsigned)(max - min);
15}
16
17static inline bool is_ws(int c)
18{
19 return is_between(c, 1, 32);
20}
21
22static inline bool is_digit(int c)
23{
24 return is_between(c, '0', '9');
25}
26
27static inline bool is_sep(int c)
28{
29 return is_ws(c) || c == ',' || c == ';';
30}
31
32static int to_hex(int c)
33{
34 if (is_digit(c))
35 return c - '0';
36
37 c |= 0x20; // make us lower-case
38 if (is_between(c, 'a', 'f'))
39 return c + 10 - 'a';
40 else
41 return -1;
42}
43
44static inline bool is_hex(int c)
45{
46 return to_hex(c) >= 0;
47}
48
49static const char* skip_ws(const char str[])
50{
51 SkASSERT(str);
52 while (is_ws(*str))
53 str++;
54 return str;
55}
56
57static const char* skip_sep(const char str[])
58{
59 SkASSERT(str);
60 while (is_sep(*str))
61 str++;
62 return str;
63}
64
rmistry@google.comd6176b02012-08-23 18:14:13 +000065int SkParse::Count(const char str[])
reed@android.com8a1c16f2008-12-17 15:59:43 +000066{
67 char c;
68 int count = 0;
69 goto skipLeading;
70 do {
71 count++;
72 do {
73 if ((c = *str++) == '\0')
74 goto goHome;
75 } while (is_sep(c) == false);
76skipLeading:
77 do {
78 if ((c = *str++) == '\0')
79 goto goHome;
80 } while (is_sep(c));
81 } while (true);
82goHome:
83 return count;
84}
85
rmistry@google.comd6176b02012-08-23 18:14:13 +000086int SkParse::Count(const char str[], char separator)
reed@android.com8a1c16f2008-12-17 15:59:43 +000087{
88 char c;
89 int count = 0;
90 goto skipLeading;
91 do {
92 count++;
93 do {
94 if ((c = *str++) == '\0')
95 goto goHome;
96 } while (c != separator);
97skipLeading:
98 do {
99 if ((c = *str++) == '\0')
100 goto goHome;
101 } while (c == separator);
102 } while (true);
103goHome:
104 return count;
105}
106
107const char* SkParse::FindHex(const char str[], uint32_t* value)
108{
109 SkASSERT(str);
110 str = skip_ws(str);
111
112 if (!is_hex(*str))
113 return NULL;
114
115 uint32_t n = 0;
116 int max_digits = 8;
117 int digit;
118
119 while ((digit = to_hex(*str)) >= 0)
120 {
121 if (--max_digits < 0)
122 return NULL;
123 n = (n << 4) | digit;
124 str += 1;
125 }
126
127 if (*str == 0 || is_ws(*str))
128 {
129 if (value)
130 *value = n;
131 return str;
132 }
epoger@google.com17b78942011-08-26 14:40:38 +0000133 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134}
135
136const char* SkParse::FindS32(const char str[], int32_t* value)
137{
138 SkASSERT(str);
139 str = skip_ws(str);
140
141 int sign = 0;
142 if (*str == '-')
143 {
144 sign = -1;
145 str += 1;
146 }
147
148 if (!is_digit(*str))
149 return NULL;
150
151 int n = 0;
152 while (is_digit(*str))
153 {
154 n = 10*n + *str - '0';
155 str += 1;
156 }
157 if (value)
158 *value = (n ^ sign) - sign;
159 return str;
160}
161
162const char* SkParse::FindMSec(const char str[], SkMSec* value)
163{
164 SkASSERT(str);
165 str = skip_ws(str);
166
167 int sign = 0;
168 if (*str == '-')
169 {
170 sign = -1;
171 str += 1;
172 }
173
174 if (!is_digit(*str))
175 return NULL;
176
177 int n = 0;
178 while (is_digit(*str))
179 {
180 n = 10*n + *str - '0';
181 str += 1;
182 }
183 int remaining10s = 3;
184 if (*str == '.') {
185 str++;
186 while (is_digit(*str))
187 {
188 n = 10*n + *str - '0';
189 str += 1;
190 if (--remaining10s == 0)
191 break;
192 }
193 }
194 while (--remaining10s >= 0)
195 n *= 10;
196 if (value)
197 *value = (n ^ sign) - sign;
198 return str;
199}
200
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000201const char* SkParse::FindScalar(const char str[], SkScalar* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 SkASSERT(str);
203 str = skip_ws(str);
reed@google.com8f4d2302013-12-17 16:44:46 +0000204
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000205 char* stop;
reed@android.come191b162009-12-18 21:33:39 +0000206 float v = (float)strtod(str, &stop);
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000207 if (str == stop) {
208 return NULL;
209 }
210 if (value) {
211 *value = v;
212 }
213 return stop;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214}
215
216const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
217{
218 SkASSERT(count >= 0);
219
220 if (count > 0)
221 {
222 for (;;)
223 {
224 str = SkParse::FindScalar(str, value);
225 if (--count == 0 || str == NULL)
226 break;
227
228 // keep going
229 str = skip_sep(str);
230 if (value)
231 value += 1;
232 }
233 }
234 return str;
235}
236
237static bool lookup_str(const char str[], const char** table, int count)
238{
239 while (--count >= 0)
240 if (!strcmp(str, table[count]))
241 return true;
242 return false;
243}
244
245bool SkParse::FindBool(const char str[], bool* value)
246{
247 static const char* gYes[] = { "yes", "1", "true" };
248 static const char* gNo[] = { "no", "0", "false" };
249
250 if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
251 {
252 if (value) *value = true;
253 return true;
254 }
255 else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
256 {
257 if (value) *value = false;
258 return true;
259 }
260 return false;
261}
262
263int SkParse::FindList(const char target[], const char list[])
264{
265 size_t len = strlen(target);
266 int index = 0;
267
268 for (;;)
269 {
270 const char* end = strchr(list, ',');
271 size_t entryLen;
272
273 if (end == NULL) // last entry
274 entryLen = strlen(list);
275 else
276 entryLen = end - list;
277
278 if (entryLen == len && memcmp(target, list, len) == 0)
279 return index;
280 if (end == NULL)
281 break;
282
283 list = end + 1; // skip the ','
284 index += 1;
285 }
286 return -1;
287}
288
289#ifdef SK_SUPPORT_UNITTEST
rmistry@google.comd6176b02012-08-23 18:14:13 +0000290void SkParse::UnitTest()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291{
292 // !!! additional parse tests go here
293 SkParse::TestColor();
294}
295#endif