blob: 2dfa47efc71015c12864d3ae585dd681dd027075 [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
bungeman60e0fee2015-08-26 05:15:46 -070011#include <stdlib.h>
12
humper@google.com7af56be2013-01-14 18:49:19 +000013SkRTConfRegistry::SkRTConfRegistry(): fConfs(100) {
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000014
halcanaryd76be9c2015-11-20 13:47:49 -080015 FILE *fp = sk_fopen(configFileLocation(), kRead_SkFILE_Flag);
humper@google.com7af56be2013-01-14 18:49:19 +000016
17 if (!fp) {
18 return;
19 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000020
humper@google.com18a48c32013-01-14 19:42:08 +000021 char line[1024];
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000022
humper@google.com7af56be2013-01-14 18:49:19 +000023 while (!sk_feof(fp)) {
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000024
humper@google.com18a48c32013-01-14 19:42:08 +000025 if (!sk_fgets(line, sizeof(line), fp)) {
26 break;
27 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000028
humper@google.com7af56be2013-01-14 18:49:19 +000029 char *commentptr = strchr(line, '#');
30 if (commentptr == line) {
31 continue;
32 }
bsalomon49f085d2014-09-05 13:34:00 -070033 if (commentptr) {
humper@google.com18a48c32013-01-14 19:42:08 +000034 *commentptr = '\0';
humper@google.com7af56be2013-01-14 18:49:19 +000035 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000036
humper@google.com18a48c32013-01-14 19:42:08 +000037 char sep[] = " \t\r\n";
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000038
humper@google.com7af56be2013-01-14 18:49:19 +000039 char *keyptr = strtok(line, sep);
40 if (!keyptr) {
41 continue;
42 }
43
halcanary96fcdcc2015-08-27 07:41:13 -070044 char *valptr = strtok(nullptr, sep);
humper@google.com7af56be2013-01-14 18:49:19 +000045 if (!valptr) {
46 continue;
47 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +000048
halcanary385fe4d2015-08-26 13:07:48 -070049 SkString *key = new SkString(keyptr);
50 SkString *val = new SkString(valptr);
humper@google.com7af56be2013-01-14 18:49:19 +000051
52 fConfigFileKeys.append(1, &key);
53 fConfigFileValues.append(1, &val);
54 }
55 sk_fclose(fp);
56}
57
commit-bot@chromium.orgbf6a6d42014-01-31 17:32:03 +000058SkRTConfRegistry::~SkRTConfRegistry() {
59 ConfMap::Iter iter(fConfs);
60 SkTDArray<SkRTConfBase *> *confArray;
61
62 while (iter.next(&confArray)) {
63 delete confArray;
64 }
65
66 for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
halcanary385fe4d2015-08-26 13:07:48 -070067 delete fConfigFileKeys[i];
68 delete fConfigFileValues[i];
commit-bot@chromium.orgbf6a6d42014-01-31 17:32:03 +000069 }
70}
71
humper@google.com7af56be2013-01-14 18:49:19 +000072const char *SkRTConfRegistry::configFileLocation() const {
73 return "skia.conf"; // for now -- should probably do something fancier like home directories or whatever.
74}
75
76// dump all known runtime config options to the file with their default values.
77// to trigger this, make a config file of zero size.
78void SkRTConfRegistry::possiblyDumpFile() const {
79 const char *path = configFileLocation();
halcanaryd76be9c2015-11-20 13:47:49 -080080 FILE *fp = sk_fopen(path, kRead_SkFILE_Flag);
humper@google.com7af56be2013-01-14 18:49:19 +000081 if (!fp) {
82 return;
83 }
84 size_t configFileSize = sk_fgetsize(fp);
85 if (configFileSize == 0) {
86 printAll(path);
87 }
88 sk_fclose(fp);
89}
90
91// Run through every provided configuration option and print a warning if the user hasn't
92// declared a correponding configuration object somewhere.
93void SkRTConfRegistry::validate() const {
94 for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
humper@google.com2b71c432013-05-20 17:14:40 +000095 if (!fConfs.find(fConfigFileKeys[i]->c_str())) {
humper@google.com7af56be2013-01-14 18:49:19 +000096 SkDebugf("WARNING: You have config value %s in your configuration file, but I've never heard of that.\n", fConfigFileKeys[i]->c_str());
97 }
98 }
99}
100
101void SkRTConfRegistry::printAll(const char *fname) const {
102 SkWStream *o;
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000103
bsalomon49f085d2014-09-05 13:34:00 -0700104 if (fname) {
humper@google.com7af56be2013-01-14 18:49:19 +0000105 o = new SkFILEWStream(fname);
106 } else {
107 o = new SkDebugWStream();
108 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000109
humper@google.com7af56be2013-01-14 18:49:19 +0000110 ConfMap::Iter iter(fConfs);
111 SkTDArray<SkRTConfBase *> *confArray;
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000112
humper@google.com7af56be2013-01-14 18:49:19 +0000113 while (iter.next(&confArray)) {
114 if (confArray->getAt(0)->isDefault()) {
115 o->writeText("# ");
116 }
117 confArray->getAt(0)->print(o);
118 o->newline();
119 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000120
humper@google.com7af56be2013-01-14 18:49:19 +0000121 delete o;
122}
123
halcanary@google.com2d1adf22014-01-10 15:00:45 +0000124bool SkRTConfRegistry::hasNonDefault() const {
125 ConfMap::Iter iter(fConfs);
126 SkTDArray<SkRTConfBase *> *confArray;
127 while (iter.next(&confArray)) {
128 if (!confArray->getAt(0)->isDefault()) {
129 return true;
130 }
131 }
132 return false;
133}
134
humper@google.com7af56be2013-01-14 18:49:19 +0000135void SkRTConfRegistry::printNonDefault(const char *fname) const {
136 SkWStream *o;
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000137
bsalomon49f085d2014-09-05 13:34:00 -0700138 if (fname) {
humper@google.com7af56be2013-01-14 18:49:19 +0000139 o = new SkFILEWStream(fname);
140 } else {
141 o = new SkDebugWStream();
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000142 }
humper@google.com7af56be2013-01-14 18:49:19 +0000143 ConfMap::Iter iter(fConfs);
144 SkTDArray<SkRTConfBase *> *confArray;
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000145
humper@google.com7af56be2013-01-14 18:49:19 +0000146 while (iter.next(&confArray)) {
147 if (!confArray->getAt(0)->isDefault()) {
148 confArray->getAt(0)->print(o);
149 o->newline();
150 }
151 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000152
humper@google.com7af56be2013-01-14 18:49:19 +0000153 delete o;
154}
155
156// register a configuration variable after its value has been set by the parser.
157// we maintain a vector of these things instead of just a single one because the
158// user might set the value after initialization time and we need to have
159// all the pointers lying around, not just one.
160void SkRTConfRegistry::registerConf(SkRTConfBase *conf) {
161 SkTDArray<SkRTConfBase *> *confArray;
162 if (fConfs.find(conf->getName(), &confArray)) {
163 if (!conf->equals(confArray->getAt(0))) {
164 SkDebugf("WARNING: Skia config \"%s\" was registered more than once in incompatible ways.\n", conf->getName());
165 } else {
166 confArray->append(1, &conf);
167 }
168 } else {
169 confArray = new SkTDArray<SkRTConfBase *>;
170 confArray->append(1, &conf);
171 fConfs.set(conf->getName(),confArray);
172 }
173}
174
sugoi@google.com8563d302013-03-04 21:03:17 +0000175template <typename T> T doParse(const char *, bool *success ) {
humper@google.com7af56be2013-01-14 18:49:19 +0000176 SkDebugf("WARNING: Invoked non-specialized doParse function...\n");
177 if (success) {
178 *success = false;
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000179 }
humper@google.com7af56be2013-01-14 18:49:19 +0000180 return (T) 0;
181}
182
183template<> bool doParse<bool>(const char *s, bool *success) {
184 if (success) {
185 *success = true;
186 }
187 if (!strcmp(s,"1") || !strcmp(s,"true")) {
188 return true;
189 }
190 if (!strcmp(s,"0") || !strcmp(s,"false")) {
191 return false;
192 }
193 if (success) {
194 *success = false;
195 }
196 return false;
197}
198
199template<> const char * doParse<const char *>(const char * s, bool *success) {
200 if (success) {
201 *success = true;
202 }
203 return s;
204}
205
206template<> int doParse<int>(const char * s, bool *success) {
sugoi@google.com8563d302013-03-04 21:03:17 +0000207 if (success) {
208 *success = true;
209 }
humper@google.com7af56be2013-01-14 18:49:19 +0000210 return atoi(s);
211}
212
213template<> unsigned int doParse<unsigned int>(const char * s, bool *success) {
sugoi@google.com8563d302013-03-04 21:03:17 +0000214 if (success) {
215 *success = true;
216 }
humper@google.com7af56be2013-01-14 18:49:19 +0000217 return (unsigned int) atoi(s);
218}
219
220template<> float doParse<float>(const char * s, bool *success) {
sugoi@google.com8563d302013-03-04 21:03:17 +0000221 if (success) {
222 *success = true;
223 }
humper@google.com7af56be2013-01-14 18:49:19 +0000224 return (float) atof(s);
225}
226
227template<> double doParse<double>(const char * s, bool *success) {
sugoi@google.com8563d302013-03-04 21:03:17 +0000228 if (success) {
229 *success = true;
230 }
humper@google.com7af56be2013-01-14 18:49:19 +0000231 return atof(s);
232}
233
234static inline void str_replace(char *s, char search, char replace) {
235 for (char *ptr = s ; *ptr ; ptr++) {
236 if (*ptr == search) {
237 *ptr = replace;
238 }
239 }
240}
241
242template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) {
halcanary96fcdcc2015-08-27 07:41:13 -0700243 const char *str = nullptr;
humper@google.com7af56be2013-01-14 18:49:19 +0000244
humper@google.com91673aa2013-07-24 21:44:40 +0000245 for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) {
humper@google.com7af56be2013-01-14 18:49:19 +0000246 if (fConfigFileKeys[i]->equals(name)) {
halcanary@google.com7a2269e2013-11-06 14:18:46 +0000247 str = fConfigFileValues[i]->c_str();
humper@google.com91673aa2013-07-24 21:44:40 +0000248 break;
humper@google.com7af56be2013-01-14 18:49:19 +0000249 }
250 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000251
humper@google.com7af56be2013-01-14 18:49:19 +0000252 SkString environment_variable("skia.");
253 environment_variable.append(name);
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000254
humper@google.com7af56be2013-01-14 18:49:19 +0000255 const char *environment_value = getenv(environment_variable.c_str());
256 if (environment_value) {
halcanary@google.com7a2269e2013-11-06 14:18:46 +0000257 str = environment_value;
humper@google.com7af56be2013-01-14 18:49:19 +0000258 } else {
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000259 // apparently my shell doesn't let me have environment variables that
humper@google.com7af56be2013-01-14 18:49:19 +0000260 // have periods in them, so also let the user substitute underscores.
halcanary@google.com7a2269e2013-11-06 14:18:46 +0000261 SkAutoTMalloc<char> underscore_name(SkStrDup(environment_variable.c_str()));
262 str_replace(underscore_name.get(), '.', '_');
263 environment_value = getenv(underscore_name.get());
humper@google.com7af56be2013-01-14 18:49:19 +0000264 if (environment_value) {
halcanary@google.com7a2269e2013-11-06 14:18:46 +0000265 str = environment_value;
humper@google.com7af56be2013-01-14 18:49:19 +0000266 }
267 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000268
humper@google.com7af56be2013-01-14 18:49:19 +0000269 if (!str) {
270 return false;
271 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000272
humper@google.com7af56be2013-01-14 18:49:19 +0000273 bool success;
halcanary@google.com7a2269e2013-11-06 14:18:46 +0000274 T new_value = doParse<T>(str, &success);
humper@google.com7af56be2013-01-14 18:49:19 +0000275 if (success) {
276 *value = new_value;
277 } else {
halcanary@google.com7a2269e2013-11-06 14:18:46 +0000278 SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n",
279 str, name);
humper@google.com7af56be2013-01-14 18:49:19 +0000280 }
281 return success;
282}
283
284// need to explicitly instantiate the parsing function for every config type we might have...
285
286template bool SkRTConfRegistry::parse(const char *name, bool *value);
287template bool SkRTConfRegistry::parse(const char *name, int *value);
288template bool SkRTConfRegistry::parse(const char *name, unsigned int *value);
289template bool SkRTConfRegistry::parse(const char *name, float *value);
290template bool SkRTConfRegistry::parse(const char *name, double *value);
291template bool SkRTConfRegistry::parse(const char *name, const char **value);
292
halcanary@google.com1f0121a2013-11-06 15:07:44 +0000293template <typename T> void SkRTConfRegistry::set(const char *name,
294 T value,
295 bool warnIfNotFound) {
humper@google.com7af56be2013-01-14 18:49:19 +0000296 SkTDArray<SkRTConfBase *> *confArray;
297 if (!fConfs.find(name, &confArray)) {
halcanary@google.com1f0121a2013-11-06 15:07:44 +0000298 if (warnIfNotFound) {
299 SkDebugf("WARNING: Attempting to set configuration value \"%s\","
300 " but I've never heard of that.\n", name);
301 }
humper@google.com7af56be2013-01-14 18:49:19 +0000302 return;
303 }
halcanary96fcdcc2015-08-27 07:41:13 -0700304 SkASSERT(confArray != nullptr);
humper@google.com7af56be2013-01-14 18:49:19 +0000305 for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) {
humper@google.com6d29eda2013-01-14 19:20:28 +0000306 // static_cast here is okay because there's only one kind of child class.
humper@google.com810ae482013-01-14 20:11:00 +0000307 SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase);
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000308
humper@google.com7af56be2013-01-14 18:49:19 +0000309 if (concrete) {
310 concrete->set(value);
311 }
312 }
313}
314
halcanary@google.com1f0121a2013-11-06 15:07:44 +0000315template void SkRTConfRegistry::set(const char *name, bool value, bool);
316template void SkRTConfRegistry::set(const char *name, int value, bool);
317template void SkRTConfRegistry::set(const char *name, unsigned int value, bool);
318template void SkRTConfRegistry::set(const char *name, float value, bool);
319template void SkRTConfRegistry::set(const char *name, double value, bool);
320template void SkRTConfRegistry::set(const char *name, char * value, bool);
humper@google.com7af56be2013-01-14 18:49:19 +0000321
humper@google.com7af56be2013-01-14 18:49:19 +0000322SkRTConfRegistry &skRTConfRegistry() {
323 static SkRTConfRegistry r;
324 return r;
325}