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