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