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 * s,bool * success)148 template <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
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 return atoi(s);
181 }
182
doParse(const char * s,bool * success)183 template<> unsigned int doParse<unsigned int>(const char * s, bool *success) {
184 return (unsigned int) atoi(s);
185 }
186
doParse(const char * s,bool * success)187 template<> float doParse<float>(const char * s, bool *success) {
188 return (float) atof(s);
189 }
190
doParse(const char * s,bool * success)191 template<> double doParse<double>(const char * s, bool *success) {
192 return atof(s);
193 }
194
str_replace(char * s,char search,char replace)195 static 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
parse(const char * name,T * value)203 template<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
248 template bool SkRTConfRegistry::parse(const char *name, bool *value);
249 template bool SkRTConfRegistry::parse(const char *name, int *value);
250 template bool SkRTConfRegistry::parse(const char *name, unsigned int *value);
251 template bool SkRTConfRegistry::parse(const char *name, float *value);
252 template bool SkRTConfRegistry::parse(const char *name, double *value);
253 template bool SkRTConfRegistry::parse(const char *name, const char **value);
254
set(const char * name,T value)255 template <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++) {
264 // static_cast here is okay because there's only one kind of child class.
265 SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase);
266
267 if (concrete) {
268 concrete->set(value);
269 }
270 }
271 }
272
273 template void SkRTConfRegistry::set(const char *name, bool value);
274 template void SkRTConfRegistry::set(const char *name, int value);
275 template void SkRTConfRegistry::set(const char *name, unsigned int value);
276 template void SkRTConfRegistry::set(const char *name, float value);
277 template void SkRTConfRegistry::set(const char *name, double value);
278 template void SkRTConfRegistry::set(const char *name, char * value);
279
skRTConfRegistry()280 SkRTConfRegistry &skRTConfRegistry() {
281 static SkRTConfRegistry r;
282 return r;
283 }
284