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 *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 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 return atoi(s); 181 } 182 183 template<> unsigned int doParse<unsigned int>(const char * s, bool *success) { 184 return (unsigned int) atoi(s); 185 } 186 187 template<> float doParse<float>(const char * s, bool *success) { 188 return (float) atof(s); 189 } 190 191 template<> double doParse<double>(const char * s, bool *success) { 192 return atof(s); 193 } 194 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 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 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 280 SkRTConfRegistry &skRTConfRegistry() { 281 static SkRTConfRegistry r; 282 return r; 283 } 284