|  | /* | 
|  | * Copyright 2006 The Android Open Source Project | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include "include/utils/SkParse.h" | 
|  |  | 
|  | #include <stdlib.h> | 
|  |  | 
|  | static inline bool is_between(int c, int min, int max) | 
|  | { | 
|  | return (unsigned)(c - min) <= (unsigned)(max - min); | 
|  | } | 
|  |  | 
|  | static inline bool is_ws(int c) | 
|  | { | 
|  | return is_between(c, 1, 32); | 
|  | } | 
|  |  | 
|  | static inline bool is_digit(int c) | 
|  | { | 
|  | return is_between(c, '0', '9'); | 
|  | } | 
|  |  | 
|  | static inline bool is_sep(int c) | 
|  | { | 
|  | return is_ws(c) || c == ',' || c == ';'; | 
|  | } | 
|  |  | 
|  | static int to_hex(int c) | 
|  | { | 
|  | if (is_digit(c)) | 
|  | return c - '0'; | 
|  |  | 
|  | c |= 0x20;  // make us lower-case | 
|  | if (is_between(c, 'a', 'f')) | 
|  | return c + 10 - 'a'; | 
|  | else | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static inline bool is_hex(int c) | 
|  | { | 
|  | return to_hex(c) >= 0; | 
|  | } | 
|  |  | 
|  | static const char* skip_ws(const char str[]) | 
|  | { | 
|  | SkASSERT(str); | 
|  | while (is_ws(*str)) | 
|  | str++; | 
|  | return str; | 
|  | } | 
|  |  | 
|  | static const char* skip_sep(const char str[]) | 
|  | { | 
|  | SkASSERT(str); | 
|  | while (is_sep(*str)) | 
|  | str++; | 
|  | return str; | 
|  | } | 
|  |  | 
|  | int SkParse::Count(const char str[]) | 
|  | { | 
|  | char c; | 
|  | int count = 0; | 
|  | goto skipLeading; | 
|  | do { | 
|  | count++; | 
|  | do { | 
|  | if ((c = *str++) == '\0') | 
|  | goto goHome; | 
|  | } while (is_sep(c) == false); | 
|  | skipLeading: | 
|  | do { | 
|  | if ((c = *str++) == '\0') | 
|  | goto goHome; | 
|  | } while (is_sep(c)); | 
|  | } while (true); | 
|  | goHome: | 
|  | return count; | 
|  | } | 
|  |  | 
|  | int SkParse::Count(const char str[], char separator) | 
|  | { | 
|  | char c; | 
|  | int count = 0; | 
|  | goto skipLeading; | 
|  | do { | 
|  | count++; | 
|  | do { | 
|  | if ((c = *str++) == '\0') | 
|  | goto goHome; | 
|  | } while (c != separator); | 
|  | skipLeading: | 
|  | do { | 
|  | if ((c = *str++) == '\0') | 
|  | goto goHome; | 
|  | } while (c == separator); | 
|  | } while (true); | 
|  | goHome: | 
|  | return count; | 
|  | } | 
|  |  | 
|  | const char* SkParse::FindHex(const char str[], uint32_t* value) | 
|  | { | 
|  | SkASSERT(str); | 
|  | str = skip_ws(str); | 
|  |  | 
|  | if (!is_hex(*str)) | 
|  | return nullptr; | 
|  |  | 
|  | uint32_t n = 0; | 
|  | int max_digits = 8; | 
|  | int digit; | 
|  |  | 
|  | while ((digit = to_hex(*str)) >= 0) | 
|  | { | 
|  | if (--max_digits < 0) | 
|  | return nullptr; | 
|  | n = (n << 4) | digit; | 
|  | str += 1; | 
|  | } | 
|  |  | 
|  | if (*str == 0 || is_ws(*str)) | 
|  | { | 
|  | if (value) | 
|  | *value = n; | 
|  | return str; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | const char* SkParse::FindS32(const char str[], int32_t* value) | 
|  | { | 
|  | SkASSERT(str); | 
|  | str = skip_ws(str); | 
|  |  | 
|  | int sign = 0; | 
|  | if (*str == '-') | 
|  | { | 
|  | sign = -1; | 
|  | str += 1; | 
|  | } | 
|  |  | 
|  | if (!is_digit(*str)) | 
|  | return nullptr; | 
|  |  | 
|  | int n = 0; | 
|  | while (is_digit(*str)) | 
|  | { | 
|  | n = 10*n + *str - '0'; | 
|  | str += 1; | 
|  | } | 
|  | if (value) | 
|  | *value = (n ^ sign) - sign; | 
|  | return str; | 
|  | } | 
|  |  | 
|  | const char* SkParse::FindMSec(const char str[], SkMSec* value) | 
|  | { | 
|  | SkASSERT(str); | 
|  | str = skip_ws(str); | 
|  |  | 
|  | int sign = 0; | 
|  | if (*str == '-') | 
|  | { | 
|  | sign = -1; | 
|  | str += 1; | 
|  | } | 
|  |  | 
|  | if (!is_digit(*str)) | 
|  | return nullptr; | 
|  |  | 
|  | int n = 0; | 
|  | while (is_digit(*str)) | 
|  | { | 
|  | n = 10*n + *str - '0'; | 
|  | str += 1; | 
|  | } | 
|  | int remaining10s = 3; | 
|  | if (*str == '.') { | 
|  | str++; | 
|  | while (is_digit(*str)) | 
|  | { | 
|  | n = 10*n + *str - '0'; | 
|  | str += 1; | 
|  | if (--remaining10s == 0) | 
|  | break; | 
|  | } | 
|  | } | 
|  | while (--remaining10s >= 0) | 
|  | n *= 10; | 
|  | if (value) | 
|  | *value = (n ^ sign) - sign; | 
|  | return str; | 
|  | } | 
|  |  | 
|  | const char* SkParse::FindScalar(const char str[], SkScalar* value) { | 
|  | SkASSERT(str); | 
|  | str = skip_ws(str); | 
|  |  | 
|  | char* stop; | 
|  | float v = (float)strtod(str, &stop); | 
|  | if (str == stop) { | 
|  | return nullptr; | 
|  | } | 
|  | if (value) { | 
|  | *value = v; | 
|  | } | 
|  | return stop; | 
|  | } | 
|  |  | 
|  | const char* SkParse::FindScalars(const char str[], SkScalar value[], int count) | 
|  | { | 
|  | SkASSERT(count >= 0); | 
|  |  | 
|  | if (count > 0) | 
|  | { | 
|  | for (;;) | 
|  | { | 
|  | str = SkParse::FindScalar(str, value); | 
|  | if (--count == 0 || str == nullptr) | 
|  | break; | 
|  |  | 
|  | // keep going | 
|  | str = skip_sep(str); | 
|  | if (value) | 
|  | value += 1; | 
|  | } | 
|  | } | 
|  | return str; | 
|  | } | 
|  |  | 
|  | static bool lookup_str(const char str[], const char** table, int count) | 
|  | { | 
|  | while (--count >= 0) | 
|  | if (!strcmp(str, table[count])) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SkParse::FindBool(const char str[], bool* value) | 
|  | { | 
|  | static const char* gYes[] = { "yes", "1", "true" }; | 
|  | static const char* gNo[] = { "no", "0", "false" }; | 
|  |  | 
|  | if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes))) | 
|  | { | 
|  | if (value) *value = true; | 
|  | return true; | 
|  | } | 
|  | else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo))) | 
|  | { | 
|  | if (value) *value = false; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int SkParse::FindList(const char target[], const char list[]) | 
|  | { | 
|  | size_t  len = strlen(target); | 
|  | int     index = 0; | 
|  |  | 
|  | for (;;) | 
|  | { | 
|  | const char* end = strchr(list, ','); | 
|  | size_t      entryLen; | 
|  |  | 
|  | if (end == nullptr) // last entry | 
|  | entryLen = strlen(list); | 
|  | else | 
|  | entryLen = end - list; | 
|  |  | 
|  | if (entryLen == len && memcmp(target, list, len) == 0) | 
|  | return index; | 
|  | if (end == nullptr) | 
|  | break; | 
|  |  | 
|  | list = end + 1; // skip the ',' | 
|  | index += 1; | 
|  | } | 
|  | return -1; | 
|  | } |