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