|
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 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 = SkNEW_ARGS(SkString,(keyptr)); |
|
48 SkString* val = SkNEW_ARGS(SkString,(valptr)); |
|
49 |
|
50 fConfigFileKeys.append(1, &key); |
|
51 fConfigFileValues.append(1, &val); |
|
52 } |
|
53 sk_fclose(fp); |
|
54 } |
|
55 |
|
56 SkRTConfRegistry::~SkRTConfRegistry() { |
|
57 ConfMap::Iter iter(fConfs); |
|
58 SkTDArray<SkRTConfBase *> *confArray; |
|
59 |
|
60 while (iter.next(&confArray)) { |
|
61 delete confArray; |
|
62 } |
|
63 |
|
64 for (int i = 0 ; i < fConfigFileKeys.count() ; i++) { |
|
65 SkDELETE(fConfigFileKeys[i]); |
|
66 SkDELETE(fConfigFileValues[i]); |
|
67 } |
|
68 } |
|
69 |
|
70 const char *SkRTConfRegistry::configFileLocation() const { |
|
71 return "skia.conf"; // for now -- should probably do something fancier like home directories or whatever. |
|
72 } |
|
73 |
|
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); |
|
79 if (!fp) { |
|
80 return; |
|
81 } |
|
82 size_t configFileSize = sk_fgetsize(fp); |
|
83 if (configFileSize == 0) { |
|
84 printAll(path); |
|
85 } |
|
86 sk_fclose(fp); |
|
87 } |
|
88 |
|
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()); |
|
95 } |
|
96 } |
|
97 } |
|
98 |
|
99 void SkRTConfRegistry::printAll(const char *fname) const { |
|
100 SkWStream *o; |
|
101 |
|
102 if (NULL != fname) { |
|
103 o = new SkFILEWStream(fname); |
|
104 } else { |
|
105 o = new SkDebugWStream(); |
|
106 } |
|
107 |
|
108 ConfMap::Iter iter(fConfs); |
|
109 SkTDArray<SkRTConfBase *> *confArray; |
|
110 |
|
111 while (iter.next(&confArray)) { |
|
112 if (confArray->getAt(0)->isDefault()) { |
|
113 o->writeText("# "); |
|
114 } |
|
115 confArray->getAt(0)->print(o); |
|
116 o->newline(); |
|
117 } |
|
118 |
|
119 delete o; |
|
120 } |
|
121 |
|
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()) { |
|
127 return true; |
|
128 } |
|
129 } |
|
130 return false; |
|
131 } |
|
132 |
|
133 void SkRTConfRegistry::printNonDefault(const char *fname) const { |
|
134 SkWStream *o; |
|
135 |
|
136 if (NULL != fname) { |
|
137 o = new SkFILEWStream(fname); |
|
138 } else { |
|
139 o = new SkDebugWStream(); |
|
140 } |
|
141 ConfMap::Iter iter(fConfs); |
|
142 SkTDArray<SkRTConfBase *> *confArray; |
|
143 |
|
144 while (iter.next(&confArray)) { |
|
145 if (!confArray->getAt(0)->isDefault()) { |
|
146 confArray->getAt(0)->print(o); |
|
147 o->newline(); |
|
148 } |
|
149 } |
|
150 |
|
151 delete o; |
|
152 } |
|
153 |
|
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()); |
|
163 } else { |
|
164 confArray->append(1, &conf); |
|
165 } |
|
166 } else { |
|
167 confArray = new SkTDArray<SkRTConfBase *>; |
|
168 confArray->append(1, &conf); |
|
169 fConfs.set(conf->getName(),confArray); |
|
170 } |
|
171 } |
|
172 |
|
173 template <typename T> T doParse(const char *, bool *success ) { |
|
174 SkDebugf("WARNING: Invoked non-specialized doParse function...\n"); |
|
175 if (success) { |
|
176 *success = false; |
|
177 } |
|
178 return (T) 0; |
|
179 } |
|
180 |
|
181 template<> bool doParse<bool>(const char *s, bool *success) { |
|
182 if (success) { |
|
183 *success = true; |
|
184 } |
|
185 if (!strcmp(s,"1") || !strcmp(s,"true")) { |
|
186 return true; |
|
187 } |
|
188 if (!strcmp(s,"0") || !strcmp(s,"false")) { |
|
189 return false; |
|
190 } |
|
191 if (success) { |
|
192 *success = false; |
|
193 } |
|
194 return false; |
|
195 } |
|
196 |
|
197 template<> const char * doParse<const char *>(const char * s, bool *success) { |
|
198 if (success) { |
|
199 *success = true; |
|
200 } |
|
201 return s; |
|
202 } |
|
203 |
|
204 template<> int doParse<int>(const char * s, bool *success) { |
|
205 if (success) { |
|
206 *success = true; |
|
207 } |
|
208 return atoi(s); |
|
209 } |
|
210 |
|
211 template<> unsigned int doParse<unsigned int>(const char * s, bool *success) { |
|
212 if (success) { |
|
213 *success = true; |
|
214 } |
|
215 return (unsigned int) atoi(s); |
|
216 } |
|
217 |
|
218 template<> float doParse<float>(const char * s, bool *success) { |
|
219 if (success) { |
|
220 *success = true; |
|
221 } |
|
222 return (float) atof(s); |
|
223 } |
|
224 |
|
225 template<> double doParse<double>(const char * s, bool *success) { |
|
226 if (success) { |
|
227 *success = true; |
|
228 } |
|
229 return atof(s); |
|
230 } |
|
231 |
|
232 static inline void str_replace(char *s, char search, char replace) { |
|
233 for (char *ptr = s ; *ptr ; ptr++) { |
|
234 if (*ptr == search) { |
|
235 *ptr = replace; |
|
236 } |
|
237 } |
|
238 } |
|
239 |
|
240 template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) { |
|
241 const char *str = NULL; |
|
242 |
|
243 for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) { |
|
244 if (fConfigFileKeys[i]->equals(name)) { |
|
245 str = fConfigFileValues[i]->c_str(); |
|
246 break; |
|
247 } |
|
248 } |
|
249 |
|
250 SkString environment_variable("skia."); |
|
251 environment_variable.append(name); |
|
252 |
|
253 const char *environment_value = getenv(environment_variable.c_str()); |
|
254 if (environment_value) { |
|
255 str = environment_value; |
|
256 } else { |
|
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; |
|
264 } |
|
265 } |
|
266 |
|
267 if (!str) { |
|
268 return false; |
|
269 } |
|
270 |
|
271 bool success; |
|
272 T new_value = doParse<T>(str, &success); |
|
273 if (success) { |
|
274 *value = new_value; |
|
275 } else { |
|
276 SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n", |
|
277 str, name); |
|
278 } |
|
279 return success; |
|
280 } |
|
281 |
|
282 // need to explicitly instantiate the parsing function for every config type we might have... |
|
283 |
|
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); |
|
290 |
|
291 template <typename T> void SkRTConfRegistry::set(const char *name, |
|
292 T value, |
|
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); |
|
299 } |
|
300 return; |
|
301 } |
|
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); |
|
306 |
|
307 if (concrete) { |
|
308 concrete->set(value); |
|
309 } |
|
310 } |
|
311 } |
|
312 |
|
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); |
|
319 |
|
320 SkRTConfRegistry &skRTConfRegistry() { |
|
321 static SkRTConfRegistry r; |
|
322 return r; |
|
323 } |
|
324 |
|
325 |
|
326 #ifdef SK_SUPPORT_UNITTEST |
|
327 |
|
328 #ifdef SK_BUILD_FOR_WIN32 |
|
329 static void sk_setenv(const char* key, const char* value) { |
|
330 _putenv_s(key, value); |
|
331 } |
|
332 #else |
|
333 static void sk_setenv(const char* key, const char* value) { |
|
334 setenv(key, value, 1); |
|
335 } |
|
336 #endif |
|
337 |
|
338 void SkRTConfRegistry::UnitTest() { |
|
339 SkRTConfRegistry registryWithoutContents(true); |
|
340 |
|
341 sk_setenv("skia_nonexistent_item", "132"); |
|
342 int result = 0; |
|
343 registryWithoutContents.parse("nonexistent.item", &result); |
|
344 SkASSERT(result == 132); |
|
345 } |
|
346 |
|
347 SkRTConfRegistry::SkRTConfRegistry(bool) |
|
348 : fConfs(100) { |
|
349 } |
|
350 #endif |