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