| /* | |
| * Copyright 2013 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "SkRTConf.h" | |
| #include "SkOSFile.h" | |
| #include <stdlib.h> | |
| SkRTConfRegistry::SkRTConfRegistry(): fConfs(100) { | |
| FILE *fp = sk_fopen(configFileLocation(), kRead_SkFILE_Flag); | |
| if (!fp) { | |
| return; | |
| } | |
| char line[1024]; | |
| while (!sk_feof(fp)) { | |
| if (!sk_fgets(line, sizeof(line), fp)) { | |
| break; | |
| } | |
| char *commentptr = strchr(line, '#'); | |
| if (commentptr == line) { | |
| continue; | |
| } | |
| if (commentptr) { | |
| *commentptr = '\0'; | |
| } | |
| char sep[] = " \t\r\n"; | |
| char *keyptr = strtok(line, sep); | |
| if (!keyptr) { | |
| continue; | |
| } | |
| char *valptr = strtok(nullptr, sep); | |
| if (!valptr) { | |
| continue; | |
| } | |
| SkString *key = new SkString(keyptr); | |
| SkString *val = new SkString(valptr); | |
| fConfigFileKeys.append(1, &key); | |
| fConfigFileValues.append(1, &val); | |
| } | |
| sk_fclose(fp); | |
| } | |
| SkRTConfRegistry::~SkRTConfRegistry() { | |
| ConfMap::Iter iter(fConfs); | |
| SkTDArray<SkRTConfBase *> *confArray; | |
| while (iter.next(&confArray)) { | |
| delete confArray; | |
| } | |
| for (int i = 0 ; i < fConfigFileKeys.count() ; i++) { | |
| delete fConfigFileKeys[i]; | |
| delete fConfigFileValues[i]; | |
| } | |
| } | |
| const char *SkRTConfRegistry::configFileLocation() const { | |
| return "skia.conf"; // for now -- should probably do something fancier like home directories or whatever. | |
| } | |
| // dump all known runtime config options to the file with their default values. | |
| // to trigger this, make a config file of zero size. | |
| void SkRTConfRegistry::possiblyDumpFile() const { | |
| const char *path = configFileLocation(); | |
| FILE *fp = sk_fopen(path, kRead_SkFILE_Flag); | |
| if (!fp) { | |
| return; | |
| } | |
| size_t configFileSize = sk_fgetsize(fp); | |
| if (configFileSize == 0) { | |
| printAll(path); | |
| } | |
| sk_fclose(fp); | |
| } | |
| // Run through every provided configuration option and print a warning if the user hasn't | |
| // declared a correponding configuration object somewhere. | |
| void SkRTConfRegistry::validate() const { | |
| for (int i = 0 ; i < fConfigFileKeys.count() ; i++) { | |
| if (!fConfs.find(fConfigFileKeys[i]->c_str())) { | |
| SkDebugf("WARNING: You have config value %s in your configuration file, but I've never heard of that.\n", fConfigFileKeys[i]->c_str()); | |
| } | |
| } | |
| } | |
| void SkRTConfRegistry::printAll(const char *fname) const { | |
| SkWStream *o; | |
| if (fname) { | |
| o = new SkFILEWStream(fname); | |
| } else { | |
| o = new SkDebugWStream(); | |
| } | |
| ConfMap::Iter iter(fConfs); | |
| SkTDArray<SkRTConfBase *> *confArray; | |
| while (iter.next(&confArray)) { | |
| if (confArray->getAt(0)->isDefault()) { | |
| o->writeText("# "); | |
| } | |
| confArray->getAt(0)->print(o); | |
| o->newline(); | |
| } | |
| delete o; | |
| } | |
| bool SkRTConfRegistry::hasNonDefault() const { | |
| ConfMap::Iter iter(fConfs); | |
| SkTDArray<SkRTConfBase *> *confArray; | |
| while (iter.next(&confArray)) { | |
| if (!confArray->getAt(0)->isDefault()) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| void SkRTConfRegistry::printNonDefault(const char *fname) const { | |
| SkWStream *o; | |
| if (fname) { | |
| o = new SkFILEWStream(fname); | |
| } else { | |
| o = new SkDebugWStream(); | |
| } | |
| ConfMap::Iter iter(fConfs); | |
| SkTDArray<SkRTConfBase *> *confArray; | |
| while (iter.next(&confArray)) { | |
| if (!confArray->getAt(0)->isDefault()) { | |
| confArray->getAt(0)->print(o); | |
| o->newline(); | |
| } | |
| } | |
| delete o; | |
| } | |
| // register a configuration variable after its value has been set by the parser. | |
| // we maintain a vector of these things instead of just a single one because the | |
| // user might set the value after initialization time and we need to have | |
| // all the pointers lying around, not just one. | |
| void SkRTConfRegistry::registerConf(SkRTConfBase *conf) { | |
| SkTDArray<SkRTConfBase *> *confArray; | |
| if (fConfs.find(conf->getName(), &confArray)) { | |
| if (!conf->equals(confArray->getAt(0))) { | |
| SkDebugf("WARNING: Skia config \"%s\" was registered more than once in incompatible ways.\n", conf->getName()); | |
| } else { | |
| confArray->append(1, &conf); | |
| } | |
| } else { | |
| confArray = new SkTDArray<SkRTConfBase *>; | |
| confArray->append(1, &conf); | |
| fConfs.set(conf->getName(),confArray); | |
| } | |
| } | |
| template <typename T> T doParse(const char *, bool *success ) { | |
| SkDebugf("WARNING: Invoked non-specialized doParse function...\n"); | |
| if (success) { | |
| *success = false; | |
| } | |
| return (T) 0; | |
| } | |
| template<> bool doParse<bool>(const char *s, bool *success) { | |
| if (success) { | |
| *success = true; | |
| } | |
| if (!strcmp(s,"1") || !strcmp(s,"true")) { | |
| return true; | |
| } | |
| if (!strcmp(s,"0") || !strcmp(s,"false")) { | |
| return false; | |
| } | |
| if (success) { | |
| *success = false; | |
| } | |
| return false; | |
| } | |
| template<> const char * doParse<const char *>(const char * s, bool *success) { | |
| if (success) { | |
| *success = true; | |
| } | |
| return s; | |
| } | |
| template<> int doParse<int>(const char * s, bool *success) { | |
| if (success) { | |
| *success = true; | |
| } | |
| return atoi(s); | |
| } | |
| template<> unsigned int doParse<unsigned int>(const char * s, bool *success) { | |
| if (success) { | |
| *success = true; | |
| } | |
| return (unsigned int) atoi(s); | |
| } | |
| template<> float doParse<float>(const char * s, bool *success) { | |
| if (success) { | |
| *success = true; | |
| } | |
| return (float) atof(s); | |
| } | |
| template<> double doParse<double>(const char * s, bool *success) { | |
| if (success) { | |
| *success = true; | |
| } | |
| return atof(s); | |
| } | |
| static inline void str_replace(char *s, char search, char replace) { | |
| for (char *ptr = s ; *ptr ; ptr++) { | |
| if (*ptr == search) { | |
| *ptr = replace; | |
| } | |
| } | |
| } | |
| template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) { | |
| const char *str = nullptr; | |
| for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) { | |
| if (fConfigFileKeys[i]->equals(name)) { | |
| str = fConfigFileValues[i]->c_str(); | |
| break; | |
| } | |
| } | |
| SkString environment_variable("skia."); | |
| environment_variable.append(name); | |
| const char *environment_value = getenv(environment_variable.c_str()); | |
| if (environment_value) { | |
| str = environment_value; | |
| } else { | |
| // apparently my shell doesn't let me have environment variables that | |
| // have periods in them, so also let the user substitute underscores. | |
| SkAutoTMalloc<char> underscore_name(SkStrDup(environment_variable.c_str())); | |
| str_replace(underscore_name.get(), '.', '_'); | |
| environment_value = getenv(underscore_name.get()); | |
| if (environment_value) { | |
| str = environment_value; | |
| } | |
| } | |
| if (!str) { | |
| return false; | |
| } | |
| bool success; | |
| T new_value = doParse<T>(str, &success); | |
| if (success) { | |
| *value = new_value; | |
| } else { | |
| SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n", | |
| str, name); | |
| } | |
| return success; | |
| } | |
| // need to explicitly instantiate the parsing function for every config type we might have... | |
| template bool SkRTConfRegistry::parse(const char *name, bool *value); | |
| template bool SkRTConfRegistry::parse(const char *name, int *value); | |
| template bool SkRTConfRegistry::parse(const char *name, unsigned int *value); | |
| template bool SkRTConfRegistry::parse(const char *name, float *value); | |
| template bool SkRTConfRegistry::parse(const char *name, double *value); | |
| template bool SkRTConfRegistry::parse(const char *name, const char **value); | |
| template <typename T> void SkRTConfRegistry::set(const char *name, | |
| T value, | |
| bool warnIfNotFound) { | |
| SkTDArray<SkRTConfBase *> *confArray; | |
| if (!fConfs.find(name, &confArray)) { | |
| if (warnIfNotFound) { | |
| SkDebugf("WARNING: Attempting to set configuration value \"%s\"," | |
| " but I've never heard of that.\n", name); | |
| } | |
| return; | |
| } | |
| SkASSERT(confArray != nullptr); | |
| for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) { | |
| // static_cast here is okay because there's only one kind of child class. | |
| SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase); | |
| if (concrete) { | |
| concrete->set(value); | |
| } | |
| } | |
| } | |
| template void SkRTConfRegistry::set(const char *name, bool value, bool); | |
| template void SkRTConfRegistry::set(const char *name, int value, bool); | |
| template void SkRTConfRegistry::set(const char *name, unsigned int value, bool); | |
| template void SkRTConfRegistry::set(const char *name, float value, bool); | |
| template void SkRTConfRegistry::set(const char *name, double value, bool); | |
| template void SkRTConfRegistry::set(const char *name, char * value, bool); | |
| SkRTConfRegistry &skRTConfRegistry() { | |
| static SkRTConfRegistry r; | |
| return r; | |
| } |