• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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