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 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 56 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. 62 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. 77 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 85 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 108 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. 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 148 template <typename T> T doParse(const char *, bool *success ) { 149 SkDebugf("WARNING: Invoked non-specialized doParse function...\n"); 150 if (success) { 151 *success = false; 152 } 153 return (T) 0; 154 } 155 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 172 template<> const char * doParse<const char *>(const char * s, bool *success) { 173 if (success) { 174 *success = true; 175 } 176 return s; 177 } 178 179 template<> int doParse<int>(const char * s, bool *success) { 180 if (success) { 181 *success = true; 182 } 183 return atoi(s); 184 } 185 186 template<> unsigned int doParse<unsigned int>(const char * s, bool *success) { 187 if (success) { 188 *success = true; 189 } 190 return (unsigned int) atoi(s); 191 } 192 193 template<> float doParse<float>(const char * s, bool *success) { 194 if (success) { 195 *success = true; 196 } 197 return (float) atof(s); 198 } 199 200 template<> double doParse<double>(const char * s, bool *success) { 201 if (success) { 202 *success = true; 203 } 204 return atof(s); 205 } 206 207 static inline void str_replace(char *s, char search, char replace) { 208 for (char *ptr = s ; *ptr ; ptr++) { 209 if (*ptr == search) { 210 *ptr = replace; 211 } 212 } 213 } 214 215 template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) { 216 SkString *str = NULL; 217 218 for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) { 219 if (fConfigFileKeys[i]->equals(name)) { 220 str = fConfigFileValues[i]; 221 break; 222 } 223 } 224 225 SkString environment_variable("skia."); 226 environment_variable.append(name); 227 228 const char *environment_value = getenv(environment_variable.c_str()); 229 if (environment_value) { 230 str->set(environment_value); 231 } else { 232 // apparently my shell doesn't let me have environment variables that 233 // have periods in them, so also let the user substitute underscores. 234 SkString underscore_environment_variable("skia_"); 235 char *underscore_name = SkStrDup(name); 236 str_replace(underscore_name,'.','_'); 237 underscore_environment_variable.append(underscore_name); 238 sk_free(underscore_name); 239 environment_value = getenv(underscore_environment_variable.c_str()); 240 if (environment_value) { 241 str->set(environment_value); 242 } 243 } 244 245 if (!str) { 246 return false; 247 } 248 249 bool success; 250 T new_value = doParse<T>(str->c_str(),&success); 251 if (success) { 252 *value = new_value; 253 } else { 254 SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n", str->c_str(), name); 255 } 256 return success; 257 } 258 259 // need to explicitly instantiate the parsing function for every config type we might have... 260 261 template bool SkRTConfRegistry::parse(const char *name, bool *value); 262 template bool SkRTConfRegistry::parse(const char *name, int *value); 263 template bool SkRTConfRegistry::parse(const char *name, unsigned int *value); 264 template bool SkRTConfRegistry::parse(const char *name, float *value); 265 template bool SkRTConfRegistry::parse(const char *name, double *value); 266 template bool SkRTConfRegistry::parse(const char *name, const char **value); 267 268 template <typename T> void SkRTConfRegistry::set(const char *name, T value) { 269 270 SkTDArray<SkRTConfBase *> *confArray; 271 if (!fConfs.find(name, &confArray)) { 272 SkDebugf("WARNING: Attempting to set configuration value \"%s\", but I've never heard of that.\n", name); 273 return; 274 } 275 276 for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) { 277 // static_cast here is okay because there's only one kind of child class. 278 SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase); 279 280 if (concrete) { 281 concrete->set(value); 282 } 283 } 284 } 285 286 template void SkRTConfRegistry::set(const char *name, bool value); 287 template void SkRTConfRegistry::set(const char *name, int value); 288 template void SkRTConfRegistry::set(const char *name, unsigned int value); 289 template void SkRTConfRegistry::set(const char *name, float value); 290 template void SkRTConfRegistry::set(const char *name, double value); 291 template void SkRTConfRegistry::set(const char *name, char * value); 292 293 SkRTConfRegistry &skRTConfRegistry() { 294 static SkRTConfRegistry r; 295 return r; 296 } 297