Index: src/utils/SkRTConf.cpp |
diff --git a/src/utils/SkRTConf.cpp b/src/utils/SkRTConf.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2dfa47efc71015c12864d3ae585dd681dd027075 |
--- /dev/null |
+++ b/src/utils/SkRTConf.cpp |
@@ -0,0 +1,325 @@ |
+/* |
+ * 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; |
+} |