|
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 |
|
12 static inline bool is_between(int c, int min, int max) |
|
13 { |
|
14 return (unsigned)(c - min) <= (unsigned)(max - min); |
|
15 } |
|
16 |
|
17 static inline bool is_ws(int c) |
|
18 { |
|
19 return is_between(c, 1, 32); |
|
20 } |
|
21 |
|
22 static inline bool is_digit(int c) |
|
23 { |
|
24 return is_between(c, '0', '9'); |
|
25 } |
|
26 |
|
27 static inline bool is_sep(int c) |
|
28 { |
|
29 return is_ws(c) || c == ',' || c == ';'; |
|
30 } |
|
31 |
|
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 |
|
44 static inline bool is_hex(int c) |
|
45 { |
|
46 return to_hex(c) >= 0; |
|
47 } |
|
48 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
290 void SkParse::UnitTest() |
|
291 { |
|
292 // !!! additional parse tests go here |
|
293 SkParse::TestColor(); |
|
294 } |
|
295 #endif |