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