Home | History | Annotate | Download | only in utils
      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 "SkParse.h"
     10 
     11 #include <stdlib.h>
     12 
     13 static inline bool is_between(int c, int min, int max)
     14 {
     15     return (unsigned)(c - min) <= (unsigned)(max - min);
     16 }
     17 
     18 static inline bool is_ws(int c)
     19 {
     20     return is_between(c, 1, 32);
     21 }
     22 
     23 static inline bool is_digit(int c)
     24 {
     25     return is_between(c, '0', '9');
     26 }
     27 
     28 static inline bool is_sep(int c)
     29 {
     30     return is_ws(c) || c == ',' || c == ';';
     31 }
     32 
     33 static 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 
     45 static inline bool is_hex(int c)
     46 {
     47     return to_hex(c) >= 0;
     48 }
     49 
     50 static const char* skip_ws(const char str[])
     51 {
     52     SkASSERT(str);
     53     while (is_ws(*str))
     54         str++;
     55     return str;
     56 }
     57 
     58 static const char* skip_sep(const char str[])
     59 {
     60     SkASSERT(str);
     61     while (is_sep(*str))
     62         str++;
     63     return str;
     64 }
     65 
     66 int 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);
     77 skipLeading:
     78         do {
     79             if ((c = *str++) == '\0')
     80                 goto goHome;
     81         } while (is_sep(c));
     82     } while (true);
     83 goHome:
     84     return count;
     85 }
     86 
     87 int 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);
     98 skipLeading:
     99         do {
    100             if ((c = *str++) == '\0')
    101                 goto goHome;
    102         } while (c == separator);
    103     } while (true);
    104 goHome:
    105     return count;
    106 }
    107 
    108 const 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 
    137 const 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 
    163 const 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 
    202 const 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 
    217 const 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 
    238 static 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 
    246 bool 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 
    264 int 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 
    290 #ifdef SK_SUPPORT_UNITTEST
    291 void SkParse::UnitTest()
    292 {
    293     // !!! additional parse tests go here
    294     SkParse::TestColor();
    295 }
    296 #endif
    297