1
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
9
10 #include "SkParse.h"
11
is_between(int c,int min,int max)12 static inline bool is_between(int c, int min, int max)
13 {
14 return (unsigned)(c - min) <= (unsigned)(max - min);
15 }
16
is_ws(int c)17 static inline bool is_ws(int c)
18 {
19 return is_between(c, 1, 32);
20 }
21
is_digit(int c)22 static inline bool is_digit(int c)
23 {
24 return is_between(c, '0', '9');
25 }
26
is_sep(int c)27 static inline bool is_sep(int c)
28 {
29 return is_ws(c) || c == ',' || c == ';';
30 }
31
to_hex(int c)32 static 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
is_hex(int c)44 static inline bool is_hex(int c)
45 {
46 return to_hex(c) >= 0;
47 }
48
skip_ws(const char str[])49 static const char* skip_ws(const char str[])
50 {
51 SkASSERT(str);
52 while (is_ws(*str))
53 str++;
54 return str;
55 }
56
skip_sep(const char str[])57 static const char* skip_sep(const char str[])
58 {
59 SkASSERT(str);
60 while (is_sep(*str))
61 str++;
62 return str;
63 }
64
Count(const char str[])65 int SkParse::Count(const char str[])
66 {
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);
76 skipLeading:
77 do {
78 if ((c = *str++) == '\0')
79 goto goHome;
80 } while (is_sep(c));
81 } while (true);
82 goHome:
83 return count;
84 }
85
Count(const char str[],char separator)86 int SkParse::Count(const char str[], char separator)
87 {
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);
97 skipLeading:
98 do {
99 if ((c = *str++) == '\0')
100 goto goHome;
101 } while (c == separator);
102 } while (true);
103 goHome:
104 return count;
105 }
106
FindHex(const char str[],uint32_t * value)107 const 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 }
133 return NULL;
134 }
135
FindS32(const char str[],int32_t * value)136 const 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
FindMSec(const char str[],SkMSec * value)162 const 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
FindScalar(const char str[],SkScalar * value)201 const char* SkParse::FindScalar(const char str[], SkScalar* value) {
202 SkASSERT(str);
203 str = skip_ws(str);
204
205 char* stop;
206 float v = (float)strtod(str, &stop);
207 if (str == stop) {
208 return NULL;
209 }
210 if (value) {
211 *value = v;
212 }
213 return stop;
214 }
215
FindScalars(const char str[],SkScalar value[],int count)216 const 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
lookup_str(const char str[],const char ** table,int count)237 static 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
FindBool(const char str[],bool * value)245 bool 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
FindList(const char target[],const char list[])263 int 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
UnitTest()290 void SkParse::UnitTest()
291 {
292 // !!! additional parse tests go here
293 SkParse::TestColor();
294 }
295 #endif
296