Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright 2013 Google Inc.
      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 #include "SkRTConf.h"
      9 #include "SkOSFile.h"
     10 
     11 SkRTConfRegistry::SkRTConfRegistry(): fConfs(100) {
     12 
     13     SkFILE *fp = sk_fopen(configFileLocation(), kRead_SkFILE_Flag);
     14 
     15     if (!fp) {
     16         return;
     17     }
     18 
     19     char line[1024];
     20 
     21     while (!sk_feof(fp)) {
     22 
     23         if (!sk_fgets(line, sizeof(line), fp)) {
     24             break;
     25         }
     26 
     27         char *commentptr = strchr(line, '#');
     28         if (commentptr == line) {
     29             continue;
     30         }
     31         if (NULL != commentptr) {
     32             *commentptr = '\0';
     33         }
     34 
     35         char sep[] = " \t\r\n";
     36 
     37         char *keyptr = strtok(line, sep);
     38         if (!keyptr) {
     39             continue;
     40         }
     41 
     42         char *valptr = strtok(NULL, sep);
     43         if (!valptr) {
     44             continue;
     45         }
     46 
     47         SkString* key = new SkString(keyptr);
     48         SkString* val = new SkString(valptr);
     49 
     50         fConfigFileKeys.append(1, &key);
     51         fConfigFileValues.append(1, &val);
     52     }
     53     sk_fclose(fp);
     54 }
     55 
     56 const char *SkRTConfRegistry::configFileLocation() const {
     57     return "skia.conf"; // for now -- should probably do something fancier like home directories or whatever.
     58 }
     59 
     60 // dump all known runtime config options to the file with their default values.
     61 // to trigger this, make a config file of zero size.
     62 void SkRTConfRegistry::possiblyDumpFile() const {
     63     const char *path = configFileLocation();
     64     SkFILE *fp = sk_fopen(path, kRead_SkFILE_Flag);
     65     if (!fp) {
     66         return;
     67     }
     68     size_t configFileSize = sk_fgetsize(fp);
     69     if (configFileSize == 0) {
     70         printAll(path);
     71     }
     72     sk_fclose(fp);
     73 }
     74 
     75 // Run through every provided configuration option and print a warning if the user hasn't
     76 // declared a correponding configuration object somewhere.
     77 void SkRTConfRegistry::validate() const {
     78     for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
     79         if (!fConfs.find(fConfigFileKeys[i]->c_str())) {
     80             SkDebugf("WARNING: You have config value %s in your configuration file, but I've never heard of that.\n", fConfigFileKeys[i]->c_str());
     81         }
     82     }
     83 }
     84 
     85 void SkRTConfRegistry::printAll(const char *fname) const {
     86     SkWStream *o;
     87 
     88     if (NULL != fname) {
     89         o = new SkFILEWStream(fname);
     90     } else {
     91         o = new SkDebugWStream();
     92     }
     93 
     94     ConfMap::Iter iter(fConfs);
     95     SkTDArray<SkRTConfBase *> *confArray;
     96 
     97     while (iter.next(&confArray)) {
     98         if (confArray->getAt(0)->isDefault()) {
     99             o->writeText("# ");
    100         }
    101         confArray->getAt(0)->print(o);
    102         o->newline();
    103     }
    104 
    105     delete o;
    106 }
    107 
    108 void SkRTConfRegistry::printNonDefault(const char *fname) const {
    109     SkWStream *o;
    110 
    111     if (NULL != fname) {
    112         o = new SkFILEWStream(fname);
    113     } else {
    114         o = new SkDebugWStream();
    115     }
    116     ConfMap::Iter iter(fConfs);
    117     SkTDArray<SkRTConfBase *> *confArray;
    118 
    119     while (iter.next(&confArray)) {
    120         if (!confArray->getAt(0)->isDefault()) {
    121             confArray->getAt(0)->print(o);
    122             o->newline();
    123         }
    124     }
    125 
    126     delete o;
    127 }
    128 
    129 // register a configuration variable after its value has been set by the parser.
    130 // we maintain a vector of these things instead of just a single one because the
    131 // user might set the value after initialization time and we need to have
    132 // all the pointers lying around, not just one.
    133 void SkRTConfRegistry::registerConf(SkRTConfBase *conf) {
    134     SkTDArray<SkRTConfBase *> *confArray;
    135     if (fConfs.find(conf->getName(), &confArray)) {
    136         if (!conf->equals(confArray->getAt(0))) {
    137             SkDebugf("WARNING: Skia config \"%s\" was registered more than once in incompatible ways.\n", conf->getName());
    138         } else {
    139             confArray->append(1, &conf);
    140         }
    141     } else {
    142         confArray = new SkTDArray<SkRTConfBase *>;
    143         confArray->append(1, &conf);
    144         fConfs.set(conf->getName(),confArray);
    145     }
    146 }
    147 
    148 template <typename T> T doParse(const char *, bool *success ) {
    149     SkDebugf("WARNING: Invoked non-specialized doParse function...\n");
    150     if (success) {
    151         *success = false;
    152     }
    153     return (T) 0;
    154 }
    155 
    156 template<> bool doParse<bool>(const char *s, bool *success) {
    157     if (success) {
    158         *success = true;
    159     }
    160     if (!strcmp(s,"1") || !strcmp(s,"true")) {
    161         return true;
    162     }
    163     if (!strcmp(s,"0") || !strcmp(s,"false")) {
    164         return false;
    165     }
    166     if (success) {
    167         *success = false;
    168     }
    169     return false;
    170 }
    171 
    172 template<> const char * doParse<const char *>(const char * s, bool *success) {
    173     if (success) {
    174         *success = true;
    175     }
    176     return s;
    177 }
    178 
    179 template<> int doParse<int>(const char * s, bool *success) {
    180     if (success) {
    181         *success = true;
    182     }
    183     return atoi(s);
    184 }
    185 
    186 template<> unsigned int doParse<unsigned int>(const char * s, bool *success) {
    187     if (success) {
    188         *success = true;
    189     }
    190     return (unsigned int) atoi(s);
    191 }
    192 
    193 template<> float doParse<float>(const char * s, bool *success) {
    194     if (success) {
    195         *success = true;
    196     }
    197     return (float) atof(s);
    198 }
    199 
    200 template<> double doParse<double>(const char * s, bool *success) {
    201     if (success) {
    202         *success = true;
    203     }
    204     return atof(s);
    205 }
    206 
    207 static inline void str_replace(char *s, char search, char replace) {
    208     for (char *ptr = s ; *ptr ; ptr++) {
    209         if (*ptr == search) {
    210             *ptr = replace;
    211         }
    212     }
    213 }
    214 
    215 template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) {
    216     SkString *str = NULL;
    217 
    218     for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) {
    219         if (fConfigFileKeys[i]->equals(name)) {
    220             str = fConfigFileValues[i];
    221             break;
    222         }
    223     }
    224 
    225     SkString environment_variable("skia.");
    226     environment_variable.append(name);
    227 
    228     const char *environment_value = getenv(environment_variable.c_str());
    229     if (environment_value) {
    230         str->set(environment_value);
    231     } else {
    232         // apparently my shell doesn't let me have environment variables that
    233         // have periods in them, so also let the user substitute underscores.
    234         SkString underscore_environment_variable("skia_");
    235         char *underscore_name = SkStrDup(name);
    236         str_replace(underscore_name,'.','_');
    237         underscore_environment_variable.append(underscore_name);
    238         sk_free(underscore_name);
    239         environment_value = getenv(underscore_environment_variable.c_str());
    240         if (environment_value) {
    241             str->set(environment_value);
    242         }
    243     }
    244 
    245     if (!str) {
    246         return false;
    247     }
    248 
    249     bool success;
    250     T new_value = doParse<T>(str->c_str(),&success);
    251     if (success) {
    252         *value = new_value;
    253     } else {
    254         SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n", str->c_str(), name);
    255     }
    256     return success;
    257 }
    258 
    259 // need to explicitly instantiate the parsing function for every config type we might have...
    260 
    261 template bool SkRTConfRegistry::parse(const char *name, bool *value);
    262 template bool SkRTConfRegistry::parse(const char *name, int *value);
    263 template bool SkRTConfRegistry::parse(const char *name, unsigned int *value);
    264 template bool SkRTConfRegistry::parse(const char *name, float *value);
    265 template bool SkRTConfRegistry::parse(const char *name, double *value);
    266 template bool SkRTConfRegistry::parse(const char *name, const char **value);
    267 
    268 template <typename T> void SkRTConfRegistry::set(const char *name, T value) {
    269 
    270     SkTDArray<SkRTConfBase *> *confArray;
    271     if (!fConfs.find(name, &confArray)) {
    272         SkDebugf("WARNING: Attempting to set configuration value \"%s\", but I've never heard of that.\n", name);
    273         return;
    274     }
    275 
    276     for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) {
    277         // static_cast here is okay because there's only one kind of child class.
    278         SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase);
    279 
    280         if (concrete) {
    281             concrete->set(value);
    282         }
    283     }
    284 }
    285 
    286 template void SkRTConfRegistry::set(const char *name, bool value);
    287 template void SkRTConfRegistry::set(const char *name, int value);
    288 template void SkRTConfRegistry::set(const char *name, unsigned int value);
    289 template void SkRTConfRegistry::set(const char *name, float value);
    290 template void SkRTConfRegistry::set(const char *name, double value);
    291 template void SkRTConfRegistry::set(const char *name, char * value);
    292 
    293 SkRTConfRegistry &skRTConfRegistry() {
    294     static SkRTConfRegistry r;
    295     return r;
    296 }
    297