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