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