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 13SkRTConfRegistry::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 58SkRTConfRegistry::~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 72const 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(); 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. 93void 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 101void 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 124bool 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 135void 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. 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 175template <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 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) { 207 if (success) { 208 *success = true; 209 } 210 return atoi(s); 211} 212 213template<> 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 220template<> float doParse<float>(const char * s, bool *success) { 221 if (success) { 222 *success = true; 223 } 224 return (float) atof(s); 225} 226 227template<> double doParse<double>(const char * s, bool *success) { 228 if (success) { 229 *success = true; 230 } 231 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) { 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 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 293template <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 315template 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); 321 322SkRTConfRegistry &skRTConfRegistry() { 323 static SkRTConfRegistry r; 324 return r; 325} 326