2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
11 SkRTConfRegistry::SkRTConfRegistry(): fConfs(100) {
13 SkFILE *fp = sk_fopen(configFileLocation(), kRead_SkFILE_Flag);
21 while (!sk_feof(fp)) {
23 if (!sk_fgets(line, sizeof(line), fp)) {
27 char *commentptr = strchr(line, '#');
28 if (commentptr == line) {
31 if (NULL != commentptr) {
35 char sep[] = " \t\r\n";
37 char *keyptr = strtok(line, sep);
42 char *valptr = strtok(NULL, sep);
47 SkString* key = SkNEW_ARGS(SkString,(keyptr));
48 SkString* val = SkNEW_ARGS(SkString,(valptr));
50 fConfigFileKeys.append(1, &key);
51 fConfigFileValues.append(1, &val);
56 SkRTConfRegistry::~SkRTConfRegistry() {
57 ConfMap::Iter iter(fConfs);
58 SkTDArray<SkRTConfBase *> *confArray;
60 while (iter.next(&confArray)) {
64 for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
65 SkDELETE(fConfigFileKeys[i]);
66 SkDELETE(fConfigFileValues[i]);
70 const char *SkRTConfRegistry::configFileLocation() const {
71 return "skia.conf"; // for now -- should probably do something fancier like home directories or whatever.
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);
82 size_t configFileSize = sk_fgetsize(fp);
83 if (configFileSize == 0) {
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());
99 void SkRTConfRegistry::printAll(const char *fname) const {
103 o = new SkFILEWStream(fname);
105 o = new SkDebugWStream();
108 ConfMap::Iter iter(fConfs);
109 SkTDArray<SkRTConfBase *> *confArray;
111 while (iter.next(&confArray)) {
112 if (confArray->getAt(0)->isDefault()) {
115 confArray->getAt(0)->print(o);
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()) {
133 void SkRTConfRegistry::printNonDefault(const char *fname) const {
137 o = new SkFILEWStream(fname);
139 o = new SkDebugWStream();
141 ConfMap::Iter iter(fConfs);
142 SkTDArray<SkRTConfBase *> *confArray;
144 while (iter.next(&confArray)) {
145 if (!confArray->getAt(0)->isDefault()) {
146 confArray->getAt(0)->print(o);
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());
164 confArray->append(1, &conf);
167 confArray = new SkTDArray<SkRTConfBase *>;
168 confArray->append(1, &conf);
169 fConfs.set(conf->getName(),confArray);
173 template <typename T> T doParse(const char *, bool *success ) {
174 SkDebugf("WARNING: Invoked non-specialized doParse function...\n");
181 template<> bool doParse<bool>(const char *s, bool *success) {
185 if (!strcmp(s,"1") || !strcmp(s,"true")) {
188 if (!strcmp(s,"0") || !strcmp(s,"false")) {
197 template<> const char * doParse<const char *>(const char * s, bool *success) {
204 template<> int doParse<int>(const char * s, bool *success) {
211 template<> unsigned int doParse<unsigned int>(const char * s, bool *success) {
215 return (unsigned int) atoi(s);
218 template<> float doParse<float>(const char * s, bool *success) {
222 return (float) atof(s);
225 template<> double doParse<double>(const char * s, bool *success) {
232 static inline void str_replace(char *s, char search, char replace) {
233 for (char *ptr = s ; *ptr ; ptr++) {
234 if (*ptr == search) {
240 template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) {
241 const char *str = NULL;
243 for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) {
244 if (fConfigFileKeys[i]->equals(name)) {
245 str = fConfigFileValues[i]->c_str();
250 SkString environment_variable("skia.");
251 environment_variable.append(name);
253 const char *environment_value = getenv(environment_variable.c_str());
254 if (environment_value) {
255 str = environment_value;
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;
272 T new_value = doParse<T>(str, &success);
276 SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n",
282 // need to explicitly instantiate the parsing function for every config type we might have...
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);
291 template <typename T> void SkRTConfRegistry::set(const char *name,
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);
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);
308 concrete->set(value);
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);
320 SkRTConfRegistry &skRTConfRegistry() {
321 static SkRTConfRegistry r;
326 #ifdef SK_SUPPORT_UNITTEST
328 #ifdef SK_BUILD_FOR_WIN32
329 static void sk_setenv(const char* key, const char* value) {
330 _putenv_s(key, value);
333 static void sk_setenv(const char* key, const char* value) {
334 setenv(key, value, 1);
338 void SkRTConfRegistry::UnitTest() {
339 SkRTConfRegistry registryWithoutContents(true);
341 sk_setenv("skia_nonexistent_item", "132");
343 registryWithoutContents.parse("nonexistent.item", &result);
344 SkASSERT(result == 132);
347 SkRTConfRegistry::SkRTConfRegistry(bool)