blob: 38bc64ce766a8b6b9770107254b123060a0bbbf2 [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
humper@google.com18a48c32013-01-14 19:42:08 +000019 char line[1024];
humper@google.com7af56be2013-01-14 18:49:19 +000020
21 while (!sk_feof(fp)) {
humper@google.com7af56be2013-01-14 18:49:19 +000022
humper@google.com18a48c32013-01-14 19:42:08 +000023 if (!sk_fgets(line, sizeof(line), fp)) {
24 break;
25 }
humper@google.com7af56be2013-01-14 18:49:19 +000026
27 char *commentptr = strchr(line, '#');
28 if (commentptr == line) {
29 continue;
30 }
31 if (NULL != commentptr) {
humper@google.com18a48c32013-01-14 19:42:08 +000032 *commentptr = '\0';
humper@google.com7af56be2013-01-14 18:49:19 +000033 }
34
humper@google.com18a48c32013-01-14 19:42:08 +000035 char sep[] = " \t\r\n";
humper@google.com7af56be2013-01-14 18:49:19 +000036
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
56const 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.
62void 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.
77void SkRTConfRegistry::validate() const {
78 for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
79 if (fConfs.find(fConfigFileKeys[i]->c_str()) == -1) {
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
85void 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
108void 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.
133void 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
148template <typename T> T doParse(const char *s, bool *success ) {
149 SkDebugf("WARNING: Invoked non-specialized doParse function...\n");
150 if (success) {
151 *success = false;
152 }
153 return (T) 0;
154}
155
156template<> 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
172template<> const char * doParse<const char *>(const char * s, bool *success) {
173 if (success) {
174 *success = true;
175 }
176 return s;
177}
178
179template<> int doParse<int>(const char * s, bool *success) {
180 return atoi(s);
181}
182
183template<> unsigned int doParse<unsigned int>(const char * s, bool *success) {
184 return (unsigned int) atoi(s);
185}
186
187template<> float doParse<float>(const char * s, bool *success) {
188 return (float) atof(s);
189}
190
191template<> double doParse<double>(const char * s, bool *success) {
192 return atof(s);
193}
194
195static inline void str_replace(char *s, char search, char replace) {
196 for (char *ptr = s ; *ptr ; ptr++) {
197 if (*ptr == search) {
198 *ptr = replace;
199 }
200 }
201}
202
203template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) {
204 SkString *str = NULL;
205
206 for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
207 if (fConfigFileKeys[i]->equals(name)) {
208 str = fConfigFileValues[i];
209 }
210 }
211
212 SkString environment_variable("skia.");
213 environment_variable.append(name);
214
215 const char *environment_value = getenv(environment_variable.c_str());
216 if (environment_value) {
217 str->set(environment_value);
218 } else {
219 // apparently my shell doesn't let me have environment variables that
220 // have periods in them, so also let the user substitute underscores.
221 SkString underscore_environment_variable("skia_");
222 char *underscore_name = SkStrDup(name);
223 str_replace(underscore_name,'.','_');
224 underscore_environment_variable.append(underscore_name);
225 sk_free(underscore_name);
226 environment_value = getenv(underscore_environment_variable.c_str());
227 if (environment_value) {
228 str->set(environment_value);
229 }
230 }
231
232 if (!str) {
233 return false;
234 }
235
236 bool success;
237 T new_value = doParse<T>(str->c_str(),&success);
238 if (success) {
239 *value = new_value;
240 } else {
241 SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n", str->c_str(), name);
242 }
243 return success;
244}
245
246// need to explicitly instantiate the parsing function for every config type we might have...
247
248template bool SkRTConfRegistry::parse(const char *name, bool *value);
249template bool SkRTConfRegistry::parse(const char *name, int *value);
250template bool SkRTConfRegistry::parse(const char *name, unsigned int *value);
251template bool SkRTConfRegistry::parse(const char *name, float *value);
252template bool SkRTConfRegistry::parse(const char *name, double *value);
253template bool SkRTConfRegistry::parse(const char *name, const char **value);
254
255template <typename T> void SkRTConfRegistry::set(const char *name, T value) {
256
257 SkTDArray<SkRTConfBase *> *confArray;
258 if (!fConfs.find(name, &confArray)) {
259 SkDebugf("WARNING: Attempting to set configuration value \"%s\", but I've never heard of that.\n", name);
260 return;
261 }
262
263 for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) {
humper@google.com6d29eda2013-01-14 19:20:28 +0000264 // static_cast here is okay because there's only one kind of child class.
265 SkRTConf<bool> *concrete = static_cast<SkRTConf<bool> *>(*confBase);
humper@google.com7af56be2013-01-14 18:49:19 +0000266
267 if (concrete) {
268 concrete->set(value);
269 }
270 }
271}
272
273template void SkRTConfRegistry::set(const char *name, bool value);
274template void SkRTConfRegistry::set(const char *name, int value);
275template void SkRTConfRegistry::set(const char *name, unsigned int value);
276template void SkRTConfRegistry::set(const char *name, float value);
277template void SkRTConfRegistry::set(const char *name, double value);
278template void SkRTConfRegistry::set(const char *name, char * value);
279
280template<> void SkRTConf<bool>::doPrint(char *s) const {
281 char tmp[30];
282 sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false");
283 sprintf(s, "%-30.30s", tmp);
284}
285
286template<> void SkRTConf<int>::doPrint(char *s) const {
287 char tmp[30];
288 sprintf(tmp, "%d # [%d]", fValue, fDefault);
289 sprintf(s, "%-30.30s", tmp);
290}
291
292template<> void SkRTConf<unsigned int>::doPrint(char *s) const {
293 char tmp[30];
294 sprintf(tmp, "%u # [%u]", fValue, fDefault);
295 sprintf(s, "%-30.30s", tmp);
296}
297
298template<> void SkRTConf<float>::doPrint(char *s) const {
299 char tmp[30];
300 sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
301 sprintf(s, "%-30.30s", tmp);
302}
303
304template<> void SkRTConf<double>::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<const char *>::doPrint(char *s) const {
311 char tmp[30];
312 sprintf(tmp, "%s # [%s]", fValue, fDefault);
313 sprintf(s, "%-30.30s", tmp);
314}
315
316SkRTConfRegistry &skRTConfRegistry() {
317 static SkRTConfRegistry r;
318 return r;
319}