1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#include "include/utils/SkParse.h"
10
11#include <stdlib.h>
12
13static inline bool is_between(int c, int min, int max)
14{
15 return (unsigned)(c - min) <= (unsigned)(max - min);
16}
17
18static inline bool is_ws(int c)
19{
20 return is_between(c, 1, 32);
21}
22
23static inline bool is_digit(int c)
24{
25 return is_between(c, '0', '9');
26}
27
28static inline bool is_sep(int c)
29{
30 return is_ws(c) || c == ',' || c == ';';
31}
32
33static int to_hex(int c)
34{
35 if (is_digit(c))
36 return c - '0';
37
38 c |= 0x20; // make us lower-case
39 if (is_between(c, 'a', 'f'))
40 return c + 10 - 'a';
41 else
42 return -1;
43}
44
45static inline bool is_hex(int c)
46{
47 return to_hex(c) >= 0;
48}
49
50static const char* skip_ws(const char str[])
51{
52 SkASSERT(str);
53 while (is_ws(*str))
54 str++;
55 return str;
56}
57
58static const char* skip_sep(const char str[])
59{
60 SkASSERT(str);
61 while (is_sep(*str))
62 str++;
63 return str;
64}
65
66int SkParse::Count(const char str[])
67{
68 char c;
69 int count = 0;
70 goto skipLeading;
71 do {
72 count++;
73 do {
74 if ((c = *str++) == '\0')
75 goto goHome;
76 } while (is_sep(c) == false);
77skipLeading:
78 do {
79 if ((c = *str++) == '\0')
80 goto goHome;
81 } while (is_sep(c));
82 } while (true);
83goHome:
84 return count;
85}
86
87int SkParse::Count(const char str[], char separator)
88{
89 char c;
90 int count = 0;
91 goto skipLeading;
92 do {
93 count++;
94 do {
95 if ((c = *str++) == '\0')
96 goto goHome;
97 } while (c != separator);
98skipLeading:
99 do {
100 if ((c = *str++) == '\0')
101 goto goHome;
102 } while (c == separator);
103 } while (true);
104goHome:
105 return count;
106}
107
108const char* SkParse::FindHex(const char str[], uint32_t* value)
109{
110 SkASSERT(str);
111 str = skip_ws(str);
112
113 if (!is_hex(*str))
114 return nullptr;
115
116 uint32_t n = 0;
117 int max_digits = 8;
118 int digit;
119
120 while ((digit = to_hex(*str)) >= 0)
121 {
122 if (--max_digits < 0)
123 return nullptr;
124 n = (n << 4) | digit;
125 str += 1;
126 }
127
128 if (*str == 0 || is_ws(*str))
129 {
130 if (value)
131 *value = n;
132 return str;
133 }
134 return nullptr;
135}
136
137const char* SkParse::FindS32(const char str[], int32_t* value)
138{
139 SkASSERT(str);
140 str = skip_ws(str);
141
142 int sign = 0;
143 if (*str == '-')
144 {
145 sign = -1;
146 str += 1;
147 }
148
149 if (!is_digit(*str))
150 return nullptr;
151
152 int n = 0;
153 while (is_digit(*str))
154 {
155 n = 10*n + *str - '0';
156 str += 1;
157 }
158 if (value)
159 *value = (n ^ sign) - sign;
160 return str;
161}
162
163const char* SkParse::FindMSec(const char str[], SkMSec* value)
164{
165 SkASSERT(str);
166 str = skip_ws(str);
167
168 int sign = 0;
169 if (*str == '-')
170 {
171 sign = -1;
172 str += 1;
173 }
174
175 if (!is_digit(*str))
176 return nullptr;
177
178 int n = 0;
179 while (is_digit(*str))
180 {
181 n = 10*n + *str - '0';
182 str += 1;
183 }
184 int remaining10s = 3;
185 if (*str == '.') {
186 str++;
187 while (is_digit(*str))
188 {
189 n = 10*n + *str - '0';
190 str += 1;
191 if (--remaining10s == 0)
192 break;
193 }
194 }
195 while (--remaining10s >= 0)
196 n *= 10;
197 if (value)
198 *value = (n ^ sign) - sign;
199 return str;
200}
201
202const char* SkParse::FindScalar(const char str[], SkScalar* value) {
203 SkASSERT(str);
204 str = skip_ws(str);
205
206 char* stop;
207 float v = (float)strtod(str, &stop);
208 if (str == stop) {
209 return nullptr;
210 }
211 if (value) {
212 *value = v;
213 }
214 return stop;
215}
216
217const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
218{
219 SkASSERT(count >= 0);
220
221 if (count > 0)
222 {
223 for (;;)
224 {
225 str = SkParse::FindScalar(str, value);
226 if (--count == 0 || str == nullptr)
227 break;
228
229 // keep going
230 str = skip_sep(str);
231 if (value)
232 value += 1;
233 }
234 }
235 return str;
236}
237
238static bool lookup_str(const char str[], const char** table, int count)
239{
240 while (--count >= 0)
241 if (!strcmp(str, table[count]))
242 return true;
243 return false;
244}
245
246bool SkParse::FindBool(const char str[], bool* value)
247{
248 static const char* gYes[] = { "yes", "1", "true" };
249 static const char* gNo[] = { "no", "0", "false" };
250
251 if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
252 {
253 if (value) *value = true;
254 return true;
255 }
256 else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
257 {
258 if (value) *value = false;
259 return true;
260 }
261 return false;
262}
263
264int SkParse::FindList(const char target[], const char list[])
265{
266 size_t len = strlen(target);
267 int index = 0;
268
269 for (;;)
270 {
271 const char* end = strchr(list, ',');
272 size_t entryLen;
273
274 if (end == nullptr) // last entry
275 entryLen = strlen(list);
276 else
277 entryLen = end - list;
278
279 if (entryLen == len && memcmp(target, list, len) == 0)
280 return index;
281 if (end == nullptr)
282 break;
283
284 list = end + 1; // skip the ','
285 index += 1;
286 }
287 return -1;
288}
289