diff options
Diffstat (limited to 'CommonLibs/Configuration.cpp')
-rw-r--r-- | CommonLibs/Configuration.cpp | 872 |
1 files changed, 774 insertions, 98 deletions
diff --git a/CommonLibs/Configuration.cpp b/CommonLibs/Configuration.cpp index 5dcc277..bda6865 100644 --- a/CommonLibs/Configuration.cpp +++ b/CommonLibs/Configuration.cpp @@ -32,6 +32,12 @@ #include <iostream> #include <string.h> +#ifdef DEBUG_CONFIG +#define debugLogEarly gLogEarly +#else +#define debugLogEarly +#endif + using namespace std; @@ -57,7 +63,7 @@ float ConfigurationRecord::floatNumber() const } -ConfigurationTable::ConfigurationTable(const char* filename, const char *wCmdName) +ConfigurationTable::ConfigurationTable(const char* filename, const char *wCmdName, ConfigurationKeyMap wSchema) { gLogEarly(LOG_INFO, "opening configuration table from path %s", filename); // Connect to the database. @@ -78,35 +84,440 @@ ConfigurationTable::ConfigurationTable(const char* filename, const char *wCmdNam if (!sqlite3_command(mDB,createConfigTable)) { gLogEarly(LOG_EMERG, "cannot create configuration table in database at %s, error message: %s", filename, sqlite3_errmsg(mDB)); } + + // Build CommonLibs schema + ConfigurationKey *tmp; + tmp = new ConfigurationKey("Log.Alarms.Max","20", + "alarms", + ConfigurationKey::CUSTOMER, + ConfigurationKey::VALRANGE, + "10:20",// educated guess + false, + "Maximum number of alarms to remember inside the application." + ); + mSchema[tmp->getName()] = *tmp; + free(tmp); + + tmp = new ConfigurationKey("Log.File","", + "", + ConfigurationKey::DEVELOPER, + ConfigurationKey::FILEPATH_OPT,// audited + "", + false, + "Path to use for textfile based logging. " + "By default, this feature is disabled. " + "To enable, specify an absolute path to the file you wish to use, eg: /tmp/my-debug.log. " + "To disable again, execute \"unconfig Log.File\"." + ); + mSchema[tmp->getName()] = *tmp; + free(tmp); + + tmp = new ConfigurationKey("Log.Level","NOTICE", + "", + ConfigurationKey::CUSTOMER, + ConfigurationKey::CHOICE, + "EMERG|EMERGENCY - report serious faults associated with service failure or hardware damage," + "ALERT|ALERT - report likely service disruption caused by misconfiguration or poor connectivity," + "CRIT|CRITICAL - report anomalous events that are likely to degrade service," + "ERR|ERROR - report internal errors of the software that may result in degradation of service in unusual circumstances," + "WARNING|WARNING - report anomalous events that may indicate a degradation of normal service," + "NOTICE|NOTICE - report anomalous events that probably do not affect service but may be of interest to network operators," + "INFO|INFORMATION - report normal events," + "DEBUG|DEBUG - only for use by developers and will degrade system performance", + false, + "Default logging level when no other level is defined for a file." + ); + mSchema[tmp->getName()] = *tmp; + free(tmp); + + // Add application specific schema + mSchema.insert(wSchema.begin(), wSchema.end()); + + // Init the cross checking callback to something predictable + mCrossCheck = NULL; } +string ConfigurationTable::getDefaultSQL(const std::string& program, const std::string& version) +{ + stringstream ss; + ConfigurationKeyMap::iterator mp; + + ss << "--" << endl; + ss << "-- This file was generated using: " << program << " --gensql" << endl; + ss << "-- binary version: " << version << endl; + ss << "--" << endl; + ss << "-- Future changes should not be put in this file directly but" << endl; + ss << "-- rather in the program's ConfigurationKey schema." << endl; + ss << "--" << endl; + ss << "PRAGMA foreign_keys=OFF;" << endl; + ss << "BEGIN TRANSACTION;" << endl; + ss << "CREATE TABLE CONFIG ( KEYSTRING TEXT UNIQUE NOT NULL, VALUESTRING TEXT, STATIC INTEGER DEFAULT 0, OPTIONAL INTEGER DEFAULT 0, COMMENTS TEXT DEFAULT '');" << endl; + + mp = mSchema.begin(); + while (mp != mSchema.end()) { + ss << "INSERT INTO \"CONFIG\" VALUES("; + // name + ss << "'" << mp->first << "',"; + // default + ss << "'" << mp->second.getDefaultValue() << "',"; + // static + if (mp->second.isStatic()) { + ss << "1"; + } else { + ss << "0"; + } + ss << ","; + // optional + ss << "0,"; + // description + ss << "'"; + if (mp->second.getType() == ConfigurationKey::BOOLEAN) { + ss << "1=enabled, 0=disabled - "; + } + ss << mp->second.getDescription(); + if (mp->second.isStatic()) { + ss << " Static."; + } + ss << "'"; + ss << ");" << endl; + mp++; + } + + ss << "COMMIT;" << endl; + ss << endl; + return ss.str(); +} -bool ConfigurationTable::defines(const string& key) +string ConfigurationTable::getTeX(const std::string& program, const std::string& version) { - assert(mDB); - ScopedLock lock(mLock); + stringstream ss; + ConfigurationKeyMap::iterator mp; + + ss << "% START AUTO-GENERATED CONTENT" << endl; + ss << "% -- these sections were generated using: " << program << " --gentex" << endl; + ss << "% -- binary version: " << version << endl; + + ss << "\\subsection{Customer Site Parameters}" << endl; + ss << "These parameters must be changed to fit your site." << endl; + ss << "\\begin{itemize}" << endl; + mp = mSchema.begin(); + while (mp != mSchema.end()) { + if (mp->second.getVisibility() == ConfigurationKey::CUSTOMERSITE) { + ss << " \\item "; + // name + ss << mp->first << " -- "; + // description + ss << mp->second.getDescription(); + ss << endl; + } + mp++; + } + ss << "\\end{itemize}" << endl; + ss << endl; + + ss << "\\subsection{Customer Tuneable Parameters}" << endl; + ss << "These parameters can be changed to optimize your site." << endl; + ss << "\\begin{itemize}" << endl; + mp = mSchema.begin(); + while (mp != mSchema.end()) { + if (mp->second.getVisibility() != ConfigurationKey::CUSTOMERSITE && + ( + mp->second.getVisibility() == ConfigurationKey::CUSTOMER || + mp->second.getVisibility() == ConfigurationKey::CUSTOMERTUNE || + mp->second.getVisibility() == ConfigurationKey::CUSTOMERWARN + )) { + ss << " \\item "; + // name + ss << mp->first << " -- "; + // description + ss << mp->second.getDescription(); + ss << endl; + } + mp++; + } + ss << "\\end{itemize}" << endl; + ss << endl; + + ss << "\\subsection{Developer/Factory Parameters}" << endl; + ss << "These parameters should only be changed by when developing new code." << endl; + ss << "\\begin{itemize}" << endl; + mp = mSchema.begin(); + while (mp != mSchema.end()) { + if (mp->second.getVisibility() == ConfigurationKey::FACTORY || + mp->second.getVisibility() == ConfigurationKey::DEVELOPER) { + ss << " \\item "; + // name + ss << mp->first << " -- "; + // description + ss << mp->second.getDescription(); + ss << endl; + } + mp++; + } + ss << "\\end{itemize}" << endl; + ss << "% END AUTO-GENERATED CONTENT" << endl; + ss << endl; - // Check the cache. - checkCacheAge(); - ConfigurationMap::const_iterator where = mCache.find(key); - if (where!=mCache.end()) return where->second.defined(); + string tmp = Utils::replaceAll(ss.str(), "^", "\\^"); + return Utils::replaceAll(tmp, "_", "\\_"); +} - // Check the database. - char *value = NULL; - sqlite3_single_lookup(mDB,"CONFIG","KEYSTRING",key.c_str(),"VALUESTRING",value); +bool ConfigurationTable::defines(const string& key) +{ + try { + ScopedLock lock(mLock); + return lookup(key).defined(); + } catch (ConfigurationTableKeyNotFound) { + debugLogEarly(LOG_ALERT, "configuration parameter %s not found", key.c_str()); + return false; + } +} - // Cache the result. - if (value) { - mCache[key] = ConfigurationRecord(value); - free(value); - return true; +bool ConfigurationTable::keyDefinedInSchema(const std::string& name) +{ + return mSchema.find(name) == mSchema.end() ? false : true; +} + +bool ConfigurationTable::isValidValue(const std::string& name, const std::string& val) { + bool ret = false; + + ConfigurationKey key = mSchema[name]; + + switch (key.getType()) { + case ConfigurationKey::BOOLEAN: { + if (val == "1" || val == "0") { + ret = true; + } + break; + } + + case ConfigurationKey::CHOICE_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::CHOICE: { + int startPos = -1; + uint endPos = 0; + + std::string tmp = key.getValidValues(); + + do { + startPos++; + if ((endPos = tmp.find('|', startPos)) != std::string::npos) { + if (val == tmp.substr(startPos, endPos-startPos)) { + ret = true; + break; + } + } else { + if (val == tmp.substr(startPos, tmp.find(',', startPos)-startPos)) { + ret = true; + break; + } + } + + } while ((startPos = tmp.find(',', startPos)) != (int)std::string::npos); + break; + } + + case ConfigurationKey::CIDR_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::CIDR: { + uint delimiter; + std::string ip; + int cidr = -1; + + delimiter = val.find('/'); + if (delimiter != std::string::npos) { + ip = val.substr(0, delimiter); + std::stringstream(val.substr(delimiter+1)) >> cidr; + if (ConfigurationKey::isValidIP(ip) && 0 <= cidr && cidr <= 32) { + ret = true; + } + } + break; + } + + case ConfigurationKey::FILEPATH_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::FILEPATH: { + regex_t r; + const char* expression = "^[a-zA-Z0-9/_.-]+$"; + int result = regcomp(&r, expression, REG_EXTENDED); + if (result) { + char msg[256]; + regerror(result,&r,msg,255); + break;//abort(); + } + if (regexec(&r, val.c_str(), 0, NULL, 0)==0) { + ret = true; + } + regfree(&r); + break; + } + + case ConfigurationKey::IPADDRESS_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::IPADDRESS: { + ret = ConfigurationKey::isValidIP(val); + break; + } + + case ConfigurationKey::IPANDPORT: { + uint delimiter; + std::string ip; + int port = -1; + + delimiter = val.find(':'); + if (delimiter != std::string::npos) { + ip = val.substr(0, delimiter); + std::stringstream(val.substr(delimiter+1)) >> port; + if (ConfigurationKey::isValidIP(ip) && 1 <= port && port <= 65535) { + ret = true; + } + } + break; + } + + case ConfigurationKey::MIPADDRESS_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::MIPADDRESS: { + int startPos = -1; + uint endPos = 0; + + do { + startPos++; + endPos = val.find(' ', startPos); + if (ConfigurationKey::isValidIP(val.substr(startPos, endPos-startPos))) { + ret = true; + } else { + ret = false; + break; + } + + } while ((startPos = endPos) != (int)std::string::npos); + break; + } + + case ConfigurationKey::PORT_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::PORT: { + int intVal; + + std::stringstream(val) >> intVal; + + if (1 <= intVal && intVal <= 65535) { + ret = true; + } + break; + } + + case ConfigurationKey::REGEX_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::REGEX: { + regex_t r; + const char* expression = val.c_str(); + int result = regcomp(&r, expression, REG_EXTENDED); + if (result) { + char msg[256]; + regerror(result,&r,msg,255); + } else { + ret = true; + } + regfree(&r); + break; + } + + case ConfigurationKey::STRING_OPT: { + if (val.length() == 0) { + ret = true; + break; + } + } + case ConfigurationKey::STRING: { + regex_t r; + const char* expression = key.getValidValues().c_str(); + int result = regcomp(&r, expression, REG_EXTENDED); + if (result) { + char msg[256]; + regerror(result,&r,msg,255); + break;//abort(); + } + if (regexec(&r, val.c_str(), 0, NULL, 0)==0) { + ret = true; + } + regfree(&r); + break; + } + + case ConfigurationKey::VALRANGE: { + regex_t r; + int result; + if (key.getValidValues().find('.') != std::string::npos) { + result = regcomp(&r, "^[0-9.-]+$", REG_EXTENDED); + } else { + result = regcomp(&r, "^[0-9-]+$", REG_EXTENDED); + } + if (result) { + char msg[256]; + regerror(result,&r,msg,255); + break;//abort(); + } + if (regexec(&r, val.c_str(), 0, NULL, 0)!=0) { + ret = false; + } else if (key.getValidValues().find('.') != std::string::npos) { + ret = ConfigurationKey::isInValRange<float>(key, val, false); + } else { + ret = ConfigurationKey::isInValRange<int>(key, val, true); + } + + regfree(&r); + break; + } } - - mCache[key] = ConfigurationRecord(false); - return false; + + return ret; } +ConfigurationKeyMap ConfigurationTable::getSimilarKeys(const std::string& snippet) { + ConfigurationKeyMap tmp; + + ConfigurationKeyMap::const_iterator mp = mSchema.begin(); + while (mp != mSchema.end()) { + if (mp->first.find(snippet) != std::string::npos) { + tmp[mp->first] = mp->second; + } + mp++; + } + + return tmp; +} const ConfigurationRecord& ConfigurationTable::lookup(const string& key) { @@ -129,15 +540,18 @@ const ConfigurationRecord& ConfigurationTable::lookup(const string& key) sqlite3_single_lookup(mDB,"CONFIG", "KEYSTRING",key.c_str(),"VALUESTRING",value); - // Nothing defined? - if (!value) { - // Cache the failure. + // value found, cache the result + if (value) { + mCache[key] = ConfigurationRecord(value); + // key definition found, cache the default + } else if (keyDefinedInSchema(key)) { + mCache[key] = ConfigurationRecord(mSchema[key].getDefaultValue()); + // total miss, cache the error + } else { mCache[key] = ConfigurationRecord(false); throw ConfigurationTableKeyNotFound(key); } - // Cache the result. - mCache[key] = ConfigurationRecord(value); free(value); // Leave mLock locked. The caller holds it still. @@ -146,22 +560,13 @@ const ConfigurationRecord& ConfigurationTable::lookup(const string& key) -bool ConfigurationTable::isStatic(const string& key) const -{ - assert(mDB); - unsigned stat; - bool success = sqlite3_single_lookup(mDB,"CONFIG","KEYSTRING",key.c_str(),"STATIC",stat); - if (success) return (bool)stat; - return false; -} - -bool ConfigurationTable::isRequired(const string& key) const +bool ConfigurationTable::isStatic(const string& key) { - assert(mDB); - unsigned optional; - bool success = sqlite3_single_lookup(mDB,"CONFIG","KEYSTRING",key.c_str(),"OPTIONAL",optional); - if (success) return !((bool)optional); - return false; + if (keyDefinedInSchema(key)) { + return mSchema[key].isStatic(); + } else { + return false; + } } @@ -175,30 +580,20 @@ string ConfigurationTable::getStr(const string& key) return lookup(key).value(); } catch (ConfigurationTableKeyNotFound) { // Raise an alert and re-throw the exception. - gLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); + debugLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); throw ConfigurationTableKeyNotFound(key); } } -string ConfigurationTable::getStr(const string& key, const char* defaultValue) -{ - try { - ScopedLock lock(mLock); - return lookup(key).value(); - } catch (ConfigurationTableKeyNotFound) { - gLogEarly(LOG_NOTICE, "deinfing missing parameter %s with value %s", key.c_str(),defaultValue); - set(key,defaultValue); - return string(defaultValue); - } -} - bool ConfigurationTable::getBool(const string& key) { try { return getNum(key) != 0; } catch (ConfigurationTableKeyNotFound) { - return false; + // Raise an alert and re-throw the exception. + debugLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); + throw ConfigurationTableKeyNotFound(key); } } @@ -211,32 +606,24 @@ long ConfigurationTable::getNum(const string& key) return lookup(key).number(); } catch (ConfigurationTableKeyNotFound) { // Raise an alert and re-throw the exception. - gLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); + debugLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); throw ConfigurationTableKeyNotFound(key); } } -long ConfigurationTable::getNum(const string& key, long defaultValue) +float ConfigurationTable::getFloat(const string& key) { try { ScopedLock lock(mLock); - return lookup(key).number(); + return lookup(key).floatNumber(); } catch (ConfigurationTableKeyNotFound) { - gLogEarly(LOG_NOTICE, "deinfing missing parameter %s with value %ld", key.c_str(),defaultValue); - set(key,defaultValue); - return defaultValue; + // Raise an alert and re-throw the exception. + debugLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); + throw ConfigurationTableKeyNotFound(key); } } - -float ConfigurationTable::getFloat(const string& key) -{ - // We need the lock because rec is a reference into the cache. - ScopedLock lock(mLock); - return lookup(key).floatNumber(); -} - std::vector<string> ConfigurationTable::getVectorOfStrings(const string& key) { // Look up the string. @@ -247,7 +634,7 @@ std::vector<string> ConfigurationTable::getVectorOfStrings(const string& key) line = strdup(rec.value().c_str()); } catch (ConfigurationTableKeyNotFound) { // Raise an alert and re-throw the exception. - gLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); + debugLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); throw ConfigurationTableKeyNotFound(key); } @@ -268,17 +655,6 @@ std::vector<string> ConfigurationTable::getVectorOfStrings(const string& key) } -std::vector<string> ConfigurationTable::getVectorOfStrings(const string& key, const char* defaultValue){ - try { - return getVectorOfStrings(key); - } catch (ConfigurationTableKeyNotFound) { - set(key,defaultValue); - return getVectorOfStrings(key); - } -} - - - std::vector<unsigned> ConfigurationTable::getVector(const string& key) { // Look up the string. @@ -289,7 +665,7 @@ std::vector<unsigned> ConfigurationTable::getVector(const string& key) line = strdup(rec.value().c_str()); } catch (ConfigurationTableKeyNotFound) { // Raise an alert and re-throw the exception. - gLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); + debugLogEarly(LOG_ALERT, "configuration parameter %s has no defined value", key.c_str()); throw ConfigurationTableKeyNotFound(key); } @@ -310,25 +686,9 @@ std::vector<unsigned> ConfigurationTable::getVector(const string& key) } -bool ConfigurationTable::unset(const string& key) -{ - assert(mDB); - if (!defines(key)) return true; - if (isRequired(key)) return false; - - ScopedLock lock(mLock); - // Clear the cache entry and the database. - ConfigurationMap::iterator where = mCache.find(key); - if (where!=mCache.end()) mCache.erase(where); - // Don't delete it; just set VALUESTRING to NULL. - string cmd = "UPDATE CONFIG SET VALUESTRING=NULL WHERE KEYSTRING=='"+key+"'"; - return sqlite3_command(mDB,cmd.c_str()); -} - bool ConfigurationTable::remove(const string& key) { assert(mDB); - if (isRequired(key)) return false; ScopedLock lock(mLock); // Clear the cache entry and the database. @@ -352,14 +712,43 @@ void ConfigurationTable::find(const string& pat, ostream& os) const while (src==SQLITE_ROW) { const char* value = (const char*)sqlite3_column_text(stmt,1); os << sqlite3_column_text(stmt,0) << " "; - if (value) os << value << endl; - else os << "(null)" << endl; + int len = 0; + if (value) { + len = strlen(value); + } + if (len && value) os << value << endl; + else os << "(disabled)" << endl; src = sqlite3_run_query(mDB,stmt); } sqlite3_finalize(stmt); } +ConfigurationRecordMap ConfigurationTable::getAllPairs() const +{ + ConfigurationRecordMap tmp; + + // Prepare the statement. + string cmd = "SELECT KEYSTRING,VALUESTRING FROM CONFIG"; + sqlite3_stmt *stmt; + if (sqlite3_prepare_statement(mDB,&stmt,cmd.c_str())) return tmp; + // Read the result. + int src = sqlite3_run_query(mDB,stmt); + while (src==SQLITE_ROW) { + const char* key = (const char*)sqlite3_column_text(stmt,0); + const char* value = (const char*)sqlite3_column_text(stmt,1); + if (key && value) { + tmp[string(key)] = ConfigurationRecord(value); + } else if (key && !value) { + tmp[string(key)] = ConfigurationRecord(false); + } + src = sqlite3_run_query(mDB,stmt); + } + sqlite3_finalize(stmt); + + return tmp; +} + bool ConfigurationTable::set(const string& key, const string& value) { assert(mDB); @@ -428,6 +817,21 @@ void ConfigurationTable::setUpdateHook(void(*func)(void *,int ,char const *,char } +void ConfigurationTable::setCrossCheckHook(vector<string> (*wCrossCheck)(const string&)) +{ + mCrossCheck = wCrossCheck; +} + + +vector<string> ConfigurationTable::crossCheck(const string& key) { + vector<string> ret; + + if (mCrossCheck != NULL) { + ret = mCrossCheck(key); + } + + return ret; +} void HashString::computeHash() { @@ -474,5 +878,277 @@ void SimpleKeyValue::addItems(const char* pairs_orig) } +bool ConfigurationKey::isValidIP(const std::string& ip) { + struct sockaddr_in sa; + return inet_pton(AF_INET, ip.c_str(), &(sa.sin_addr)) != 0; +} + + +void ConfigurationKey::getMinMaxStepping(const ConfigurationKey &key, std::string &min, std::string &max, std::string &stepping) { + uint delimiter; + int startPos; + uint endPos; + + std::string tmp = key.getValidValues(); + stepping = "1"; + + // grab steps if they're defined + startPos = tmp.find('('); + if (startPos != (int)std::string::npos) { + endPos = tmp.find(')'); + stepping = tmp.substr(startPos+1, endPos-startPos-1); + tmp = tmp.substr(0, startPos); + } + startPos = 0; + + delimiter = tmp.find(':', startPos); + min = tmp.substr(startPos, delimiter-startPos); + max = tmp.substr(delimiter+1, tmp.find(',', delimiter)-delimiter-1); +} + + +template<class T> bool ConfigurationKey::isInValRange(const ConfigurationKey &key, const std::string& val, const bool isInteger) { + bool ret = false; + + T convVal; + T min; + T max; + T steps; + std::string strMin; + std::string strMax; + std::string strSteps; + + std::stringstream(val) >> convVal; + + ConfigurationKey::getMinMaxStepping(key, strMin, strMax, strSteps); + std::stringstream(strMin) >> min; + std::stringstream(strMax) >> max; + std::stringstream(strSteps) >> steps; + + // TODO : only ranges checked, steps not enforced + if (isInteger) { + if (val.find('.') == std::string::npos && min <= convVal && convVal <= max) { + ret = true; + } + } else { + if (min <= convVal && convVal <= max) { + ret = true; + } + } + + return ret; +} + +const std::string ConfigurationKey::getARFCNsString() { + stringstream ss; + int i; + float downlink; + float uplink; + + // 128:251 GSM850 + downlink = 869.2; + uplink = 824.2; + for (i = 128; i <= 251; i++) { + ss << i << "|GSM850 #" << i << " : " << downlink << " MHz downlink / " << uplink << " MHz uplink,"; + downlink += 0.2; + uplink += 0.2; + } + + // 1:124 PGSM900 + downlink = 935.2; + uplink = 890.2; + for (i = 1; i <= 124; i++) { + ss << i << "|PGSM900 #" << i << " : " << downlink << " MHz downlink / " << uplink << " MHz uplink,"; + downlink += 0.2; + uplink += 0.2; + } + + // 512:885 DCS1800 + downlink = 1805.2; + uplink = 1710.2; + for (i = 512; i <= 885; i++) { + ss << i << "|DCS1800 #" << i << " : " << downlink << " MHz downlink / " << uplink << " MHz uplink,"; + downlink += 0.2; + uplink += 0.2; + } + + // 512:810 PCS1900 + downlink = 1930.2; + uplink = 1850.2; + for (i = 512; i <= 810; i++) { + ss << i << "|PCS1900 #" << i << " : " << downlink << " MHz downlink / " << uplink << " MHz uplink,"; + downlink += 0.2; + uplink += 0.2; + } + + ss << endl; + + return ss.str(); +} + +const std::string ConfigurationKey::visibilityLevelToString(const ConfigurationKey::VisibilityLevel& visibility) { + std::string ret = "UNKNOWN ERROR"; + + switch (visibility) { + case ConfigurationKey::CUSTOMER: + ret = "customer - can be freely changed by the customer without any detriment to their system"; + break; + case ConfigurationKey::CUSTOMERSITE: + ret = "customer site - these values are different for each BTS and should not be left default"; + break; + case ConfigurationKey::CUSTOMERTUNE: + ret = "customer tune - should only be changed to tune an installation to better suit the physical environment or MS usage pattern"; + break; + case ConfigurationKey::CUSTOMERWARN: + ret = "customer warn - a warning will be presented and confirmation required before changing this sensitive setting"; + break; + case ConfigurationKey::DEVELOPER: + ret = "developer - should only be changed by developers to debug/optimize the implementation"; + break; + case ConfigurationKey::FACTORY: + ret = "factory - set once at the factory, should never be changed"; + break; + } + + return ret; +} + +const std::string ConfigurationKey::typeToString(const ConfigurationKey::Type& type) { + std::string ret = "UNKNOWN ERROR"; + + switch (type) { + case BOOLEAN: + ret = "boolean"; + break; + case CHOICE_OPT: + ret = "multiple choice (optional)"; + break; + case CHOICE: + ret = "multiple choice"; + break; + case CIDR_OPT: + ret = "CIDR notation (optional)"; + break; + case CIDR: + ret = "CIDR notation"; + break; + case FILEPATH_OPT: + ret = "file path (optional)"; + break; + case FILEPATH: + ret = "file path"; + break; + case IPADDRESS_OPT: + ret = "IP address (optional)"; + break; + case IPADDRESS: + ret = "IP address"; + break; + case IPANDPORT: + ret = "IP address and port"; + break; + case MIPADDRESS_OPT: + ret = "space-separated list of IP addresses (optional)"; + break; + case MIPADDRESS: + ret = "space-separated list of IP addresses"; + break; + case PORT_OPT: + ret = "IP port (optional)"; + break; + case PORT: + ret = "IP port"; + break; + case REGEX_OPT: + ret = "regular expression (optional)"; + break; + case REGEX: + ret = "regular expression"; + break; + case STRING_OPT: + ret = "string (optional)"; + break; + case STRING: + ret = "string"; + break; + case VALRANGE: + ret = "value range"; + break; + } + + return ret; +} + +void ConfigurationKey::printKey(const ConfigurationKey &key, const std::string& currentValue, ostream& os) { + os << key.getName() << " "; + if (!currentValue.length()) { + os << "(disabled)"; + } else { + os << currentValue; + } + if (currentValue.compare(key.getDefaultValue()) == 0) { + os << " [default]"; + } + os << endl; +} + +void ConfigurationKey::printDescription(const ConfigurationKey &key, ostream& os) { + std::string tmp; + + os << " - description: " << key.getDescription() << std::endl; + if (key.getUnits().length()) { + os << " - units: " << key.getUnits() << std::endl; + } + os << " - type: " << ConfigurationKey::typeToString(key.getType()) << std::endl; + if (key.getDefaultValue().length()) { + os << " - default value: " << key.getDefaultValue() << std::endl; + } + os << " - visibility level: " << ConfigurationKey::visibilityLevelToString(key.getVisibility()) << std::endl; + os << " - static: " << key.isStatic() << std::endl; + + tmp = key.getValidValues(); + if (key.getType() == ConfigurationKey::VALRANGE) { + int startPos = tmp.find('('); + uint delimiter = 0; + if (startPos != (int)std::string::npos) { + tmp = tmp.substr(0, startPos); + } + startPos = -1; + + do { + startPos++; + delimiter = tmp.find(':', startPos); + os << " - valid values: " << "from " << tmp.substr(startPos, delimiter-startPos) << " to " + << tmp.substr(delimiter+1, tmp.find(',', delimiter)-delimiter-1) << std::endl; + + } while ((startPos = tmp.find(',', startPos)) != (int)std::string::npos); + + } else if (key.getType() == ConfigurationKey::CHOICE) { + int startPos = -1; + uint endPos = 0; + + do { + startPos++; + if ((endPos = tmp.find('|', startPos)) != std::string::npos) { + os << " - valid values: " << tmp.substr(startPos, endPos-startPos); + os << " = " << tmp.substr(endPos+1, tmp.find(',', endPos)-endPos-1) << std::endl; + } else { + os << " - valid values: " << tmp.substr(startPos, tmp.find(',', startPos)-startPos) << std::endl; + } + + } while ((startPos = tmp.find(',', startPos)) != (int)std::string::npos); + + } else if (key.getType() == ConfigurationKey::BOOLEAN) { + os << " - valid values: 0 = disabled" << std::endl; + os << " - valid values: 1 = enabled" << std::endl; + + } else if (key.getType() == ConfigurationKey::STRING) { + os << " - valid val regex: " << tmp << std::endl; + + } else if (key.getValidValues().length()) { + os << " - raw valid values: " << tmp << std::endl; + } +} + // vim: ts=4 sw=4 |