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 11 #include <stdlib.h> 12 13 SkRTConfRegistry::SkRTConfRegistry(): fConfs(100) { 14 15 FILE *fp = sk_fopen(configFileLocation(), kRead_SkFILE_Flag); 16 17 if (!fp) { 18 return; 19 } 20 21 char line[1024]; 22 23 while (!sk_feof(fp)) { 24 25 if (!sk_fgets(line, sizeof(line), fp)) { 26 break; 27 } 28 29 char *commentptr = strchr(line, '#'); 30 if (commentptr == line) { 31 continue; 32 } 33 if (commentptr) { 34 *commentptr = '\0'; 35 } 36 37 char sep[] = " \t\r\n"; 38 39 char *keyptr = strtok(line, sep); 40 if (!keyptr) { 41 continue; 42 } 43 44 char *valptr = strtok(nullptr, sep); 45 if (!valptr) { 46 continue; 47 } 48 49 SkString *key = new SkString(keyptr); 50 SkString *val = new SkString(valptr); 51 52 fConfigFileKeys.append(1, &key); 53 fConfigFileValues.append(1, &val); 54 } 55 sk_fclose(fp); 56 } 57 58 SkRTConfRegistry::~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++) { 67 delete fConfigFileKeys[i]; 68 delete fConfigFileValues[i]; 69 } 70 } 71 72 const 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. 78 void SkRTConfRegistry::possiblyDumpFile() const { 79 const char *path = configFileLocation(); 80 FILE *fp = sk_fopen(path, kRead_SkFILE_Flag); 81 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. 93 void SkRTConfRegistry::validate() const { 94 for (int i = 0 ; i < fConfigFileKeys.count() ; i++) { 95 if (!fConfs.find(fConfigFileKeys[i]->c_str())) { 96 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 101 void SkRTConfRegistry::printAll(const char *fname) const { 102 SkWStream *o; 103 104 if (fname) { 105 o = new SkFILEWStream(fname); 106 } else { 107 o = new SkDebugWStream(); 108 } 109 110 ConfMap::Iter iter(fConfs); 111 SkTDArray<SkRTConfBase *> *confArray; 112 113 while (iter.next(&confArray)) { 114 if (confArray->getAt(0)->isDefault()) { 115 o->writeText("# "); 116 } 117 confArray->getAt(0)->print(o); 118 o->newline(); 119 } 120 121 delete o; 122 } 123 124 bool 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 135 void SkRTConfRegistry::printNonDefault(const char *fname) const { 136 SkWStream *o; 137 138 if (fname) { 139 o = new SkFILEWStream(fname); 140 } else { 141 o = new SkDebugWStream(); 142 } 143 ConfMap::Iter iter(fConfs); 144 SkTDArray<SkRTConfBase *> *confArray; 145 146 while (iter.next(&confArray)) { 147 if (!confArray->getAt(0)->isDefault()) { 148 confArray->getAt(0)->print(o); 149 o->newline(); 150 } 151 } 152 153 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. 160 void 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 175 template <typename T> T doParse(const char *, bool *success ) { 176 SkDebugf("WARNING: Invoked non-specialized doParse function...\n"); 177 if (success) { 178 *success = false; 179 } 180 return (T) 0; 181 } 182 183 template<> 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 199 template<> const char * doParse<const char *>(const char * s, bool *success) { 200 if (success) { 201 *success = true; 202 } 203 return s; 204 } 205 206 template<> int doParse<int>(const char * s, bool *success) { 207 if (success) { 208 *success = true; 209 } 210 return atoi(s); 211 } 212 213 template<> unsigned int doParse<unsigned int>(const char * s, bool *success) { 214 if (success) { 215 *success = true; 216 } 217 return (unsigned int) atoi(s); 218 } 219 220 template<> float doParse<float>(const char * s, bool *success) { 221 if (success) { 222 *success = true; 223 } 224 return (float) atof(s); 225 } 226 227 template<> double doParse<double>(const char * s, bool *success) { 228 if (success) { 229 *success = true; 230 } 231 return atof(s); 232 } 233 234 static 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 242 template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) { 243 const char *str = nullptr; 244 245 for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) { 246 if (fConfigFileKeys[i]->equals(name)) { 247 str = fConfigFileValues[i]->c_str(); 248 break; 249 } 250 } 251 252 SkString environment_variable("skia."); 253 environment_variable.append(name); 254 255 const char *environment_value = getenv(environment_variable.c_str()); 256 if (environment_value) { 257 str = environment_value; 258 } else { 259 // apparently my shell doesn't let me have environment variables that 260 // have periods in them, so also let the user substitute underscores. 261 SkAutoTMalloc<char> underscore_name(SkStrDup(environment_variable.c_str())); 262 str_replace(underscore_name.get(), '.', '_'); 263 environment_value = getenv(underscore_name.get()); 264 if (environment_value) { 265 str = environment_value; 266 } 267 } 268 269 if (!str) { 270 return false; 271 } 272 273 bool success; 274 T new_value = doParse<T>(str, &success); 275 if (success) { 276 *value = new_value; 277 } else { 278 SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n", 279 str, name); 280 } 281 return success; 282 } 283 284 // need to explicitly instantiate the parsing function for every config type we might have... 285 286 template bool SkRTConfRegistry::parse(const char *name, bool *value); 287 template bool SkRTConfRegistry::parse(const char *name, int *value); 288 template bool SkRTConfRegistry::parse(const char *name, unsigned int *value); 289 template bool SkRTConfRegistry::parse(const char *name, float *value); 290 template bool SkRTConfRegistry::parse(const char *name, double *value); 291 template bool SkRTConfRegistry::parse(const char *name, const char **value); 292 293 template <typename T> void SkRTConfRegistry::set(const char *name, 294 T value, 295 bool warnIfNotFound) { 296 SkTDArray<SkRTConfBase *> *confArray; 297 if (!fConfs.find(name, &confArray)) { 298 if (warnIfNotFound) { 299 SkDebugf("WARNING: Attempting to set configuration value \"%s\"," 300 " but I've never heard of that.\n", name); 301 } 302 return; 303 } 304 SkASSERT(confArray != nullptr); 305 for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) { 306 // static_cast here is okay because there's only one kind of child class. 307 SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase); 308 309 if (concrete) { 310 concrete->set(value); 311 } 312 } 313 } 314 315 template void SkRTConfRegistry::set(const char *name, bool value, bool); 316 template void SkRTConfRegistry::set(const char *name, int value, bool); 317 template void SkRTConfRegistry::set(const char *name, unsigned int value, bool); 318 template void SkRTConfRegistry::set(const char *name, float value, bool); 319 template void SkRTConfRegistry::set(const char *name, double value, bool); 320 template void SkRTConfRegistry::set(const char *name, char * value, bool); 321 322 SkRTConfRegistry &skRTConfRegistry() { 323 static SkRTConfRegistry r; 324 return r; 325 } 326