From e1d8490f0654a3da0b900407d80d91d8d0da68c8 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 27 Sep 2009 01:55:44 +0200 Subject: Use libicu to support unicode properly; migrated ConfigManager to UnicodeString --- CMakeLists.txt | 3 +- FindICU.cmake | 99 ++++++++++++++++++++++ src/Client/CommandParser.cpp | 21 +++-- src/Common/ModuleManager.cpp | 6 +- src/Common/UserManager.cpp | 34 ++++---- src/Core/Application.cpp | 9 +- src/Core/CMakeLists.txt | 3 +- src/Core/ConfigEntry.cpp | 8 +- src/Core/ConfigEntry.h | 32 ++++--- src/Core/ConfigManager.cpp | 33 ++++---- src/Core/LogManager.cpp | 37 ++++---- src/Core/LogManager.h | 3 +- src/Core/Tokenizer.cpp | 50 +++++------ src/Core/Tokenizer.h | 8 +- src/Core/UnicodeString.cpp | 44 ++++++++++ src/Core/UnicodeString.h | 64 ++++++++++++++ src/Server/ConnectionManager.cpp | 30 +++---- src/modules/AuthProviderFile/AuthProviderFile.cpp | 12 +-- src/modules/FileLogger/Module.cpp | 12 +-- .../StorageBackendFile/StorageBackendFile.cpp | 6 +- .../UserConfigBackendHome.cpp | 18 ++-- .../UserConfigBackendKrb5.cpp | 24 +++--- .../UserDBBackendMysql/UserDBBackendMysql.cpp | 98 ++++++++++----------- 23 files changed, 442 insertions(+), 212 deletions(-) create mode 100644 FindICU.cmake create mode 100644 src/Core/UnicodeString.cpp create mode 100644 src/Core/UnicodeString.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d0d1ebb..9222e4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,10 @@ set(CMAKE_MODULE_PATH ${MAD_SOURCE_DIR}) find_package(Boost REQUIRED date_time filesystem regex signals system thread) find_package(Editline REQUIRED) +find_package(ICU REQUIRED) find_package(LibXml2 REQUIRED) find_package(Mhash REQUIRED) find_package(OpenSSL REQUIRED) - find_package(KRB5 COMPONENTS krb5 kadm-client) find_package(MySQL) @@ -35,6 +35,7 @@ set(INCLUDES ${Boost_INCLUDE_DIR} ${DL_INCLUDE_DIR} ${EDITLINE_INCLUDE_DIR} + ${ICU_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${MHASH_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} diff --git a/FindICU.cmake b/FindICU.cmake new file mode 100644 index 0000000..dfbf67d --- /dev/null +++ b/FindICU.cmake @@ -0,0 +1,99 @@ +FIND_PROGRAM(ICU_CONFIG NAMES icu-config) + +IF(ICU_CONFIG) + SET(ICU_FOUND 1) +ELSE(ICU_CONFIG) + SET(ICU_FOUND 0) +ENDIF(ICU_CONFIG) + +IF(ICU_FOUND) + EXECUTE_PROCESS( + COMMAND ${ICU_CONFIG} --cflags + OUTPUT_VARIABLE ICU_CONFIG_CFLAGS + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE ICU_CONFIG_RESULT + ) + + IF("${ICU_CONFIG_RESULT}" MATCHES "^0$") + STRING(REGEX REPLACE " +" ";" ICU_CONFIG_CFLAGS "${ICU_CONFIG_CFLAGS}") + + # Look for -I options. + SET(ICU_INCLUDE_DIRS) + FOREACH(flag ${ICU_CONFIG_CFLAGS}) + IF("${flag}" MATCHES "^-I") + STRING(REGEX REPLACE "^-I" "" DIR "${flag}") + FILE(TO_CMAKE_PATH "${DIR}" DIR) + SET(ICU_INCLUDE_DIRS ${ICU_INCLUDE_DIRS} "${DIR}") + ENDIF("${flag}" MATCHES "^-I") + ENDFOREACH(flag) + ELSE("${ICU_CONFIG_RESULT}" MATCHES "^0$") + MESSAGE("Error running ${ICU_CONFIG}: [${ICU_CONFIG_RESULT}]") + SET(ICU_FOUND 0) + ENDIF("${ICU_CONFIG_RESULT}" MATCHES "^0$") +ENDIF(ICU_FOUND) + +IF(ICU_FOUND) + EXECUTE_PROCESS( + COMMAND ${ICU_CONFIG} --ldflags + OUTPUT_VARIABLE ICU_CONFIG_LDFLAGS + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE ICU_CONFIG_RESULT + ) + + IF("${ICU_CONFIG_RESULT}" MATCHES "^0$") + STRING(REGEX REPLACE " +" ";" ICU_CONFIG_LDFLAGS "${ICU_CONFIG_LDFLAGS}") + + # Look for -L flags for directories and -l flags for library names. + SET(ICU_LIBRARY_DIRS) + SET(ICU_LIBRARY_NAMES) + FOREACH(flag ${ICU_CONFIG_LDFLAGS}) + IF("${flag}" MATCHES "^-L") + STRING(REGEX REPLACE "^-L" "" DIR "${flag}") + FILE(TO_CMAKE_PATH "${DIR}" DIR) + SET(ICU_LIBRARY_DIRS ${ICU_LIBRARY_DIRS} "${DIR}") + ELSEIF("${flag}" MATCHES "^-l") + STRING(REGEX REPLACE "^-l" "" NAME "${flag}") + SET(ICU_LIBRARY_NAMES ${ICU_LIBRARY_NAMES} "${NAME}") + ENDIF("${flag}" MATCHES "^-L") + ENDFOREACH(flag) + + # Search for each library needed using the directories given. + FOREACH(name ${ICU_LIBRARY_NAMES}) + # Look for this library. + FIND_LIBRARY(ICU_${name}_LIBRARY + NAMES ${name} + PATHS ${ICU_LIBRARY_DIRS} + NO_DEFAULT_PATH + ) + FIND_LIBRARY(ICU_${name}_LIBRARY NAMES ${name}) + MARK_AS_ADVANCED(ICU_${name}_LIBRARY) + + # If any library is not found then the whole package is not found. + IF(NOT ICU_${name}_LIBRARY) + SET(ICU_FOUND 0) + ENDIF(NOT ICU_${name}_LIBRARY) + + # Build an ordered list of all the libraries needed. + SET(ICU_LIBRARIES ${ICU_LIBRARIES} "${ICU_${name}_LIBRARY}") + ENDFOREACH(name) + ELSE("${ICU_CONFIG_RESULT}" MATCHES "^0$") + MESSAGE("Error running ${ICU_CONFIG}: [${ICU_CONFIG_RESULT}]") + SET(ICU_FOUND 0) + ENDIF("${ICU_CONFIG_RESULT}" MATCHES "^0$") +ENDIF(ICU_FOUND) + +# Report the results. +IF(ICU_FOUND) + MESSAGE(STATUS "Found ICU headers: ${ICU_INCLUDE_DIRS}") + MESSAGE(STATUS "Found ICU libs: ${ICU_LIBRARIES}") +ELSE(ICU_FOUND) + SET(ICU_DIR_MESSAGE + "ICU was not found.") + IF(NOT ICU_FIND_QUIETLY) + MESSAGE(STATUS "${ICU_DIR_MESSAGE}") + ELSE(NOT ICU_FIND_QUIETLY) + IF(ICU_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "${ICU_DIR_MESSAGE}") + ENDIF(ICU_FIND_REQUIRED) + ENDIF(NOT ICU_FIND_QUIETLY) +ENDIF(ICU_FOUND) diff --git a/src/Client/CommandParser.cpp b/src/Client/CommandParser.cpp index 3f1850c..a271860 100644 --- a/src/Client/CommandParser.cpp +++ b/src/Client/CommandParser.cpp @@ -213,19 +213,26 @@ void CommandParser::exitCommand(const std::vector &/*args*/) { } bool CommandParser::parse(const std::string &cmd) { - std::vector splitCmd; + std::vector splitCmd; - Core::Tokenizer::tokenize(cmd, splitCmd); + Core::Tokenizer::tokenize(cmd.c_str(), splitCmd); if(splitCmd.empty()) return true; - const Command* command = findCommand(splitCmd[0]); + const Command* command = findCommand(splitCmd[0].extract()); - if(command) - command->function(this, splitCmd); - else - std::cerr << "Unknown command '" << splitCmd[0] << "'." << std::endl; + if(command) { + std::vector strings; + + for(std::vector::iterator it = splitCmd.begin(); it != splitCmd.end(); ++it) + strings.push_back(it->extract()); + + command->function(this, strings); + } + else { + std::cerr << "Unknown command '" << splitCmd[0].extract() << "'." << std::endl; + } return true; } diff --git a/src/Common/ModuleManager.cpp b/src/Common/ModuleManager.cpp index 78a6459..053d395 100644 --- a/src/Common/ModuleManager.cpp +++ b/src/Common/ModuleManager.cpp @@ -62,9 +62,9 @@ bool ModuleManager::handleConfigEntry(const Core::ConfigEntry &entry, bool handl if(handled) return false; - if(entry[0].getKey().matches("LoadModule") && entry[1].empty()) { - if(!loadModule(entry[0][0].c_str())) - application->logf(Core::Logger::LOG_ERROR, "Can't load module '%s'.", entry[0][0].c_str()); + if(entry[0].getKey().matches("LoadModule") && entry[1].isEmpty()) { + if(!loadModule(entry[0][0].extract())) + application->logf(Core::Logger::LOG_ERROR, "Can't load module '%s'.", entry[0][0].extract().c_str()); return true; } diff --git a/src/Common/UserManager.cpp b/src/Common/UserManager.cpp index f112894..f14dbcc 100644 --- a/src/Common/UserManager.cpp +++ b/src/Common/UserManager.cpp @@ -39,11 +39,11 @@ UserManager::~UserManager() { bool UserManager::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handled*/) { if(entry[0].getKey().matches("UserManager")) { if(entry[1].getKey().matches("MinUid")) { - if(entry[2].empty()) { + if(entry[2].isEmpty()) { char *endptr; - unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); - if(entry[1][0].empty() || *endptr) { - application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MinUid '%s'", entry[1][0].c_str()); + unsigned long val = std::strtoul(entry[1][0].extract().c_str(), &endptr, 10); + if(entry[1][0].isEmpty() || *endptr) { + application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MinUid '%s'", entry[1][0].extract().c_str()); } else { minUid = val; @@ -51,11 +51,11 @@ bool UserManager::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handl } } else if(entry[1].getKey().matches("MaxUid")) { - if(entry[2].empty()) { + if(entry[2].isEmpty()) { char *endptr; - unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); - if(entry[1][0].empty() || *endptr) { - application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MaxUid '%s'", entry[1][0].c_str()); + unsigned long val = std::strtoul(entry[1][0].extract().c_str(), &endptr, 10); + if(entry[1][0].isEmpty() || *endptr) { + application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MaxUid '%s'", entry[1][0].extract().c_str()); } else { maxUid = val; @@ -63,11 +63,11 @@ bool UserManager::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handl } } else if(entry[1].getKey().matches("MinGid")) { - if(entry[2].empty()) { + if(entry[2].isEmpty()) { char *endptr; - unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); - if(entry[1][0].empty() || *endptr) { - application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MinGid '%s'", entry[1][0].c_str()); + unsigned long val = std::strtoul(entry[1][0].extract().c_str(), &endptr, 10); + if(entry[1][0].isEmpty() || *endptr) { + application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MinGid '%s'", entry[1][0].extract().c_str()); } else { minGid = val; @@ -75,18 +75,18 @@ bool UserManager::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handl } } else if(entry[1].getKey().matches("MaxGid")) { - if(entry[2].empty()) { + if(entry[2].isEmpty()) { char *endptr; - unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 10); - if(entry[1][0].empty() || *endptr) { - application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MaxGid '%s'", entry[1][0].c_str()); + unsigned long val = std::strtoul(entry[1][0].extract().c_str(), &endptr, 10); + if(entry[1][0].isEmpty() || *endptr) { + application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: MaxGid '%s'", entry[1][0].extract().c_str()); } else { maxGid = val; } } } - else if(!entry[1].empty()) + else if(!entry[1].isEmpty()) return false; return true; diff --git a/src/Core/Application.cpp b/src/Core/Application.cpp index d75cbaf..666f2cb 100644 --- a/src/Core/Application.cpp +++ b/src/Core/Application.cpp @@ -22,6 +22,7 @@ #include "LogManager.h" #include "ThreadManager.h" +#include #include #ifndef va_copy @@ -31,7 +32,13 @@ namespace Mad { namespace Core { -Application::Application() : configManager(new ConfigManager(this)), logManager(new LogManager(this)), threadManager(new ThreadManager(this)) {} +Application::Application() { + std::setlocale(LC_ALL, ""); + + configManager = new ConfigManager(this); + logManager = new LogManager(this); + threadManager = new ThreadManager(this); +} Application::~Application() { delete threadManager; diff --git a/src/Core/CMakeLists.txt b/src/Core/CMakeLists.txt index 50e62c8..9828f61 100644 --- a/src/Core/CMakeLists.txt +++ b/src/Core/CMakeLists.txt @@ -21,5 +21,6 @@ mad_library(Core Signals.h ThreadManager.cpp ThreadManager.h Tokenizer.cpp Tokenizer.h + UnicodeString.cpp UnicodeString.h ) -target_link_libraries(Core ${Boost_LIBRARIES}) +target_link_libraries(Core ${Boost_LIBRARIES} ${ICU_LIBRARIES}) diff --git a/src/Core/ConfigEntry.cpp b/src/Core/ConfigEntry.cpp index d260fa1..b587043 100644 --- a/src/Core/ConfigEntry.cpp +++ b/src/Core/ConfigEntry.cpp @@ -22,7 +22,7 @@ namespace Mad { namespace Core { -ConfigEntry::String& ConfigEntry::Entry::operator[] (size_t i) { +ConfigEntry::String& ConfigEntry::Entry::operator[] (std::size_t i) { try { return value.at(i); } @@ -32,7 +32,7 @@ ConfigEntry::String& ConfigEntry::Entry::operator[] (size_t i) { } } -const ConfigEntry::String& ConfigEntry::Entry::operator[] (size_t i) const { +const ConfigEntry::String& ConfigEntry::Entry::operator[] (std::size_t i) const { try { return value.at(i); } @@ -41,7 +41,7 @@ const ConfigEntry::String& ConfigEntry::Entry::operator[] (size_t i) const { } } -ConfigEntry::Entry& ConfigEntry::operator[] (size_t i) { +ConfigEntry::Entry& ConfigEntry::operator[] (std::size_t i) { try { return entries.at(i); } @@ -51,7 +51,7 @@ ConfigEntry::Entry& ConfigEntry::operator[] (size_t i) { } } -const ConfigEntry::Entry& ConfigEntry::operator[] (size_t i) const { +const ConfigEntry::Entry& ConfigEntry::operator[] (std::size_t i) const { try { return entries.at(i); } diff --git a/src/Core/ConfigEntry.h b/src/Core/ConfigEntry.h index fcd8dd4..d4cacc9 100644 --- a/src/Core/ConfigEntry.h +++ b/src/Core/ConfigEntry.h @@ -22,25 +22,23 @@ #include "export.h" +#include "UnicodeString.h" + #include -#include -#include #include -#include - namespace Mad { namespace Core { class MAD_CORE_EXPORT ConfigEntry { public: - class String : public std::string { + class String : public UnicodeString { public: String() {} - String(const std::string &str) : std::string(str) {} + String(const UnicodeString &str) : UnicodeString(str) {} - bool matches(const std::string &str) const { - return (boost::algorithm::to_lower_copy(static_cast(*this)) == boost::algorithm::to_lower_copy(str)); + bool matches(const UnicodeString &str) const { + return (str.caseCompare(*this, 0) == 0); } }; @@ -53,7 +51,7 @@ class MAD_CORE_EXPORT ConfigEntry { public: Entry() {} - Entry(const std::vector &args) { + Entry(const std::vector &args) { if(args.empty()) return; @@ -62,17 +60,17 @@ class MAD_CORE_EXPORT ConfigEntry { value.assign(args.begin()+1, args.end()); } - bool empty() const { - return key.empty(); + bool isEmpty() const { + return key.isEmpty(); } String &getKey() {return key;} const String &getKey() const {return key;} - size_t getSize() const {return value.size();} + std::size_t getSize() const {return value.size();} - String& operator[] (size_t i); - const String& operator[] (size_t i) const; + String& operator[] (std::size_t i); + const String& operator[] (std::size_t i) const; }; private: @@ -80,10 +78,10 @@ class MAD_CORE_EXPORT ConfigEntry { Entry zero, constZero; public: - size_t getSize() const {return entries.size();} + std::size_t getSize() const {return entries.size();} - Entry& operator[] (size_t i); - const Entry& operator[] (size_t i) const; + Entry& operator[] (std::size_t i); + const Entry& operator[] (std::size_t i) const; void push(const Entry &entry) { entries.push_back(entry); diff --git a/src/Core/ConfigManager.cpp b/src/Core/ConfigManager.cpp index bd20cc5..51d8647 100644 --- a/src/Core/ConfigManager.cpp +++ b/src/Core/ConfigManager.cpp @@ -46,7 +46,7 @@ void ConfigManager::handleConfigEntry(const ConfigEntry &entry) { } if(!handled) - application->logf(Logger::LOG_WARNING, "Invalid config option '%s'.", entry[entry.getSize()-1].getKey().c_str()); + application->logf(Logger::LOG_WARNING, "Invalid config option '%s'.", entry[entry.getSize()-1].getKey().extract().c_str()); } bool ConfigManager::loadFile(const std::string &filename) { @@ -55,30 +55,33 @@ bool ConfigManager::loadFile(const std::string &filename) { std::ifstream file(filename.c_str()); ConfigEntry entry; - std::string line, input; - char delim; - std::vector splitLine, lastConfigLine; + UnicodeString line, input; + UChar delim; + std::vector splitLine, lastConfigLine; if(!file.good()) return false; - while(!(file.eof() && line.empty() && input.empty())) { - while(input.empty() && !file.eof()) - std::getline(file, input); + while(!(file.eof() && line.isEmpty() && input.isEmpty())) { + while(input.isEmpty() && !file.eof()) { + std::string tmp; + std::getline(file, tmp); + input = tmp.c_str(); + } - if(input.empty()) + if(input.isEmpty()) break; - size_t pos = input.find_first_of("#{}"); - if(pos == std::string::npos) { + boost::int32_t pos = input.findFirstOf("#{}"); + if(pos < 0) { line += input; delim = '\n'; - input.clear(); + input.remove(); } else { line += input.substr(0, pos); delim = input[pos]; - input = input.substr(pos+1); + input.remove(0, pos+1); } if(!Tokenizer::tokenize(line, splitLine)) { @@ -87,8 +90,6 @@ bool ConfigManager::loadFile(const std::string &filename) { } if(!splitLine.empty()) { - pos = line.find_first_of(" \t"); - entry.push(splitLine); handleConfigEntry(entry); entry.pop(); @@ -98,7 +99,7 @@ bool ConfigManager::loadFile(const std::string &filename) { switch(delim) { case '#': - input.clear(); + input.remove(); break; case '{': entry.push(lastConfigLine); @@ -107,7 +108,7 @@ bool ConfigManager::loadFile(const std::string &filename) { entry.pop(); } - line.clear(); + line.remove(); } // TODO Depth check diff --git a/src/Core/LogManager.cpp b/src/Core/LogManager.cpp index af3e0ba..4a4cc0d 100644 --- a/src/Core/LogManager.cpp +++ b/src/Core/LogManager.cpp @@ -42,23 +42,28 @@ void LogManager::ConsoleLogger::logMessageDirect(MessageCategory /*category*/, M } -LogManager::MessageLevel LogManager::parseLevel(const std::string &str) throw (Exception) { - if(str.empty()) +LogManager::MessageLevel LogManager::parseLevel(const UnicodeString &str) throw (Exception) { + static const UnicodeString DEBUG_LEVEL("debug"); + static const UnicodeString VERBOSE_LEVEL("verbose"); + static const UnicodeString DEFAULT_LEVEL("default"); + static const UnicodeString WARNING_LEVEL("warning"); + static const UnicodeString ERROR_LEVEL("error"); + static const UnicodeString CRITICAL_LEVEL("critical"); + + if(str.isEmpty()) return Logger::LOG_DEFAULT; - std::string lowerStr = boost::algorithm::to_lower_copy(str); - - if(lowerStr == "debug") + if(str.caseCompare(DEBUG_LEVEL, 0) == 0) return Logger::LOG_DEBUG; - else if(lowerStr == "verbose") + else if(str.caseCompare(VERBOSE_LEVEL, 0) == 0) return Logger::LOG_VERBOSE; - else if(lowerStr == "default") + else if(str.caseCompare(DEFAULT_LEVEL, 0) == 0) return Logger::LOG_DEFAULT; - else if(lowerStr == "warning") + else if(str.caseCompare(WARNING_LEVEL, 0) == 0) return Logger::LOG_WARNING; - else if(lowerStr == "error") + else if(str.caseCompare(ERROR_LEVEL, 0) == 0) return Logger::LOG_ERROR; - else if(lowerStr == "critical") + else if(str.caseCompare(CRITICAL_LEVEL, 0) == 0) return Logger::LOG_CRITICAL; else throw Exception(Exception::INVALID_INPUT); @@ -77,29 +82,29 @@ LogManager::~LogManager() { bool LogManager::handleConfigEntry(const ConfigEntry &entry, bool handled) { if(entry[0].getKey().matches("Log")) { if(entry[0][0].matches("Console")) { - if(entry[1].empty()) { + if(entry[1].isEmpty()) { registerLogger(consoleLogger); return true; } else if(entry[1].getKey().matches("Level")) { - if(entry[2].empty()) { + if(entry[2].isEmpty()) { try { - if(boost::algorithm::to_lower_copy(static_cast(entry[1][0])) == "remote") + if(entry[1][0].matches("remote")) consoleLogger->setRemoteLevel(parseLevel(entry[1][1])); else consoleLogger->setLevel(parseLevel(entry[1][0])); } catch(Core::Exception e) { - application->logf(Logger::LOG_WARNING, "Unknown log level '%s'.", entry[1][0].c_str()); + application->logf(Logger::LOG_WARNING, "Unknown log level '%s'.", entry[1][0].extract().c_str()); } return true; } } } - else if(entry[1].empty()) { + else if(entry[1].isEmpty()) { if(!handled) { - application->logf(Logger::LOG_WARNING, "Unknown logger '%s'.", entry[0][0].c_str()); + application->logf(Logger::LOG_WARNING, "Unknown logger '%s'.", entry[0][0].extract().c_str()); return true; } } diff --git a/src/Core/LogManager.h b/src/Core/LogManager.h index c569238..9b47a7e 100644 --- a/src/Core/LogManager.h +++ b/src/Core/LogManager.h @@ -25,6 +25,7 @@ #include "Configurable.h" #include "Exception.h" #include "Logger.h" +#include "UnicodeString.h" #include #include @@ -99,7 +100,7 @@ class MAD_CORE_EXPORT LogManager : public Configurable { virtual void configFinished(); public: - static MessageLevel parseLevel(const std::string &str) throw (Exception); + static MessageLevel parseLevel(const UnicodeString &str) throw (Exception); void log(MessageCategory category, MessageLevel level, boost::posix_time::ptime timestamp, const std::string &message, const std::string &source = std::string()); diff --git a/src/Core/Tokenizer.cpp b/src/Core/Tokenizer.cpp index 4043b39..93c853a 100644 --- a/src/Core/Tokenizer.cpp +++ b/src/Core/Tokenizer.cpp @@ -18,30 +18,32 @@ */ #include "Tokenizer.h" +#include +#include namespace Mad { namespace Core { -const std::string Tokenizer::delimiters = " \t\n\"'\\"; +const UnicodeString Tokenizer::delimiters(" \t\n\"'\\"); -std::vector Tokenizer::split(const std::string &str) { - std::vector ret; +std::vector Tokenizer::split(const UnicodeString &str) { + std::vector ret; - for(size_t s = 0; s < str.length();) { - size_t index = str.find_first_of(delimiters, s); - size_t length = (index == std::string::npos) ? std::string::npos : index-s; + for(boost::int32_t s = 0; s < str.length();) { + boost::int32_t index = str.findFirstOf(delimiters, s); + boost::int32_t length = (index < 0) ? -1 : index-s; ret.push_back(str.substr(s, length)); - if(index != std::string::npos) { - size_t index2 = str.find_first_not_of(delimiters, index); + if(index >= 0) { + boost::int32_t index2 = str.findFirstNotOf(delimiters, index); - length = (index2 == std::string::npos) ? std::string::npos : index2-index; + length = (index2 < 0) ? -1 : index2-index; ret.push_back(str.substr(index, length)); - if(index2 != std::string::npos) + if(index2 >= 0) s = index2; else break; @@ -53,48 +55,48 @@ std::vector Tokenizer::split(const std::string &str) { return ret; } -bool Tokenizer::tokenize(const std::string &str, std::vector &out) { - std::vector splitString = split(str); +bool Tokenizer::tokenize(const UnicodeString &str, std::vector &out) { + std::vector splitString = split(str); bool singleQuotes = false, doubleQuotes = false, escape = false; - std::string token; + UnicodeString token; bool forceToken = false; out.clear(); - for(std::vector::iterator s = splitString.begin(); s != splitString.end(); ++s) { + for(std::vector::iterator s = splitString.begin(); s != splitString.end(); ++s) { token += *s; escape = false; if(++s == splitString.end()) break; - for(std::string::iterator c = s->begin(); c != s->end(); ++c) { - if(*c == '\n' && escape) { + for(icu::StringCharacterIterator c(*s); c.hasNext(); c.next()) { + if(c.current() == '\n' && escape) { escape = false; if(doubleQuotes) continue; } - if(escape || (singleQuotes && *c != '\'')) { - token += *c; + if(escape || (singleQuotes && c.current() != '\'')) { + token += c.current(); escape = false; continue; } - switch(*c) { + switch(c.current()) { case ' ': case '\t': case '\n': if(doubleQuotes) { - token += *c; + token += c.current(); } else { - if(!token.empty() || forceToken) { + if(!token.isEmpty() || forceToken) { out.push_back(token); - token.clear(); + token.remove(); forceToken = false; } } @@ -107,7 +109,7 @@ bool Tokenizer::tokenize(const std::string &str, std::vector &out) case '\'': if(doubleQuotes) { - token += *c; + token += c.current(); } else { singleQuotes = !singleQuotes; @@ -121,7 +123,7 @@ bool Tokenizer::tokenize(const std::string &str, std::vector &out) } } - if(!token.empty() || forceToken) + if(!token.isEmpty() || forceToken) out.push_back(token); return !(singleQuotes || doubleQuotes || escape); diff --git a/src/Core/Tokenizer.h b/src/Core/Tokenizer.h index 637aa05..f65d44c 100644 --- a/src/Core/Tokenizer.h +++ b/src/Core/Tokenizer.h @@ -22,7 +22,7 @@ #include "export.h" -#include +#include "UnicodeString.h" #include namespace Mad { @@ -30,14 +30,14 @@ namespace Core { class MAD_CORE_EXPORT Tokenizer { private: - static const std::string delimiters; + static const UnicodeString delimiters; Tokenizer(); - static std::vector split(const std::string &str); + static std::vector split(const UnicodeString &str); public: - static bool tokenize(const std::string &str, std::vector &out); + static bool tokenize(const UnicodeString &str, std::vector &out); }; } diff --git a/src/Core/UnicodeString.cpp b/src/Core/UnicodeString.cpp new file mode 100644 index 0000000..ccace47 --- /dev/null +++ b/src/Core/UnicodeString.cpp @@ -0,0 +1,44 @@ +/* + * UnicodeString.cpp + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#include "UnicodeString.h" + +namespace Mad { +namespace Core { + +boost::int32_t UnicodeString::findFirstOf(const UnicodeString &chars, boost::int32_t start) const { + for(boost::int32_t i = start; i < length(); ++i) { + if(chars.indexOf(charAt(i)) >= 0) + return i; + } + + return -1; +} + +boost::int32_t UnicodeString::findFirstNotOf(const UnicodeString &chars, boost::int32_t start) const { + for(boost::int32_t i = start; i < length(); ++i) { + if(chars.indexOf(charAt(i)) < 0) + return i; + } + + return -1; +} + +} +} diff --git a/src/Core/UnicodeString.h b/src/Core/UnicodeString.h new file mode 100644 index 0000000..aed53b6 --- /dev/null +++ b/src/Core/UnicodeString.h @@ -0,0 +1,64 @@ +/* + * UnicodeString.h + * + * Copyright (C) 2009 Matthias Schiffer + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see . + */ + +#ifndef MAD_CORE_UNICODESTRING_H_ +#define MAD_CORE_UNICODESTRING_H_ + +#include "export.h" + +#include +#include +#include + +#define U_USING_ICU_NAMESPACE 0 +#include + +namespace Mad { +namespace Core { + +class MAD_CORE_EXPORT UnicodeString : public icu::UnicodeString { + public: + UnicodeString() {} + UnicodeString(const icu::UnicodeString &str) : icu::UnicodeString(str) {} + UnicodeString(const char *str) : icu::UnicodeString(str) {} + + UnicodeString substr(boost::int32_t start, boost::int32_t length = -1) const { + if(length < 0) + return icu::UnicodeString(*this, start); + else + return icu::UnicodeString(*this, start, length); + } + + boost::int32_t findFirstOf(const UnicodeString &chars, boost::int32_t start = 0) const; + boost::int32_t findFirstNotOf(const UnicodeString &chars, boost::int32_t start = 0) const; + + std::string extract() const { + boost::uint32_t len = (boost::uint32_t)icu::UnicodeString::extract(0, length(), (char*)0, 0u); + + boost::scoped_array buf(new char[len]); + icu::UnicodeString::extract(0, length(), buf.get(), len); + + return std::string(buf.get(), len); + } +}; + +} +} + +#endif /* MAD_CORE_UNICODESTRING_H_ */ diff --git a/src/Server/ConnectionManager.cpp b/src/Server/ConnectionManager.cpp index 1ffd3f1..5836b32 100644 --- a/src/Server/ConnectionManager.cpp +++ b/src/Server/ConnectionManager.cpp @@ -118,45 +118,45 @@ bool ConnectionManager::handleConfigEntry(const Core::ConfigEntry &entry, bool h if(handled) return false; - if(entry[0].getKey().matches("Listen") && entry[1].empty()) { + if(entry[0].getKey().matches("Listen") && entry[1].isEmpty()) { try { - listenerAddresses.push_back(parseAddress(entry[0][0])); + listenerAddresses.push_back(parseAddress(entry[0][0].extract())); } catch(Core::Exception &e) { - application->logf(Core::Logger::LOG_WARNING, "ConnectionManager: Invalid listen address '%s'", entry[0][0].c_str()); + application->logf(Core::Logger::LOG_WARNING, "ConnectionManager: Invalid listen address '%s'", entry[0][0].extract().c_str()); } return true; } - else if(entry[0].getKey().matches("X509TrustFile") && entry[1].empty()) { - x509TrustFile = entry[0][0]; + else if(entry[0].getKey().matches("X509TrustFile") && entry[1].isEmpty()) { + x509TrustFile = entry[0][0].extract(); return true; } - else if(entry[0].getKey().matches("X509CrlFile") && entry[1].empty()) { - x509CrlFile = entry[0][0]; + else if(entry[0].getKey().matches("X509CrlFile") && entry[1].isEmpty()) { + x509CrlFile = entry[0][0].extract(); return true; } - else if(entry[0].getKey().matches("X509CertFile") && entry[1].empty()) { - x509CertFile = entry[0][0]; + else if(entry[0].getKey().matches("X509CertFile") && entry[1].isEmpty()) { + x509CertFile = entry[0][0].extract(); return true; } - else if(entry[0].getKey().matches("X509KeyFile") && entry[1].empty()) { - x509KeyFile = entry[0][0]; + else if(entry[0].getKey().matches("X509KeyFile") && entry[1].isEmpty()) { + x509KeyFile = entry[0][0].extract(); return true; } else if(entry[0].getKey().matches("Daemon")) { if(entry[0].getSize() == 1) { - if(entry[1].empty()) { - daemonInfo.insert(std::make_pair(entry[0][0], Common::HostInfo(entry[0][0]))); + if(entry[1].isEmpty()) { + daemonInfo.insert(std::make_pair(entry[0][0].extract(), Common::HostInfo(entry[0][0].extract()))); return true; } - else if(entry[1].getKey().matches("IpAddress") && entry[2].empty()) { - daemonInfo[entry[0][0]].setIP(entry[1][0]); + else if(entry[1].getKey().matches("IpAddress") && entry[2].isEmpty()) { + daemonInfo[entry[0][0].extract()].setIP(entry[1][0].extract()); return true; } diff --git a/src/modules/AuthProviderFile/AuthProviderFile.cpp b/src/modules/AuthProviderFile/AuthProviderFile.cpp index 1756747..b1e1e52 100644 --- a/src/modules/AuthProviderFile/AuthProviderFile.cpp +++ b/src/modules/AuthProviderFile/AuthProviderFile.cpp @@ -89,23 +89,23 @@ bool AuthProviderFile::handleConfigEntry(const Core::ConfigEntry &entry, bool /* if(!entry[0].getKey().matches("AuthProviderFile")) return false; - if(entry[1].empty()) + if(entry[1].isEmpty()) return true; if(entry[1].getKey().matches("Hash")) { - if(entry[2].empty()) { - filehash = entry[1][0]; + if(entry[2].isEmpty()) { + filehash = entry[1][0].extract(); if(!Common::Hash::isHashSupported(filehash)) application->logf(Core::Logger::LOG_WARNING, "AuthProviderFile: Unsupported hash '%s'", filehash.c_str()); } } else if(entry[1].getKey().matches("File")) { - if(entry[2].empty()) { - files.push_back(entry[1][0]); + if(entry[2].isEmpty()) { + files.push_back(entry[1][0].extract()); } } - else if(!entry[2].empty()) + else if(!entry[2].isEmpty()) return false; return true; diff --git a/src/modules/FileLogger/Module.cpp b/src/modules/FileLogger/Module.cpp index d000c8b..663389f 100644 --- a/src/modules/FileLogger/Module.cpp +++ b/src/modules/FileLogger/Module.cpp @@ -32,9 +32,9 @@ bool Module::handleConfigEntry(const Core::ConfigEntry &entry, bool handled) { if(entry[0].getKey().matches("Log")) { if(entry[0][0].matches("File")) { - if(entry[1].empty()) { - if(!entry[0][1].empty()) { - lastLogger.reset(new FileLogger(entry[0][1])); + if(entry[1].isEmpty()) { + if(!entry[0][1].isEmpty()) { + lastLogger.reset(new FileLogger(entry[0][1].extract())); loggers.insert(lastLogger); application->getLogManager()->registerLogger(lastLogger); @@ -47,15 +47,15 @@ bool Module::handleConfigEntry(const Core::ConfigEntry &entry, bool handled) { return true; } else if(entry[1].getKey().matches("Level")) { - if(entry[2].empty()) { + if(entry[2].isEmpty()) { try { - if(boost::algorithm::to_lower_copy(static_cast(entry[1][0])) == "remote") + if(entry[1][0].matches("remote")) lastLogger->setRemoteLevel(Core::LogManager::parseLevel(entry[1][1])); else lastLogger->setLevel(Core::LogManager::parseLevel(entry[1][0])); } catch(Core::Exception e) { - application->logf(Core::Logger::LOG_WARNING, "Unknown log level '%s'.", entry[1][0].c_str()); + application->logf(Core::Logger::LOG_WARNING, "Unknown log level '%s'.", entry[1][0].extract().c_str()); } return true; diff --git a/src/modules/StorageBackendFile/StorageBackendFile.cpp b/src/modules/StorageBackendFile/StorageBackendFile.cpp index 33c6b0f..aae7e03 100644 --- a/src/modules/StorageBackendFile/StorageBackendFile.cpp +++ b/src/modules/StorageBackendFile/StorageBackendFile.cpp @@ -35,12 +35,12 @@ bool StorageBackendFile::handleConfigEntry(const Core::ConfigEntry &entry, bool boost::lock_guard lock(mutex); if(entry[1].getKey().matches("Root")) { - if(!entry[2].empty()) + if(!entry[2].isEmpty()) return false; - storageRoot = entry[1][0]; + storageRoot = entry[1][0].extract(); } - else if(!entry[1].empty()) { + else if(!entry[1].isEmpty()) { return false; } diff --git a/src/modules/UserConfigBackendHome/UserConfigBackendHome.cpp b/src/modules/UserConfigBackendHome/UserConfigBackendHome.cpp index 9f724e5..d47e03b 100644 --- a/src/modules/UserConfigBackendHome/UserConfigBackendHome.cpp +++ b/src/modules/UserConfigBackendHome/UserConfigBackendHome.cpp @@ -34,23 +34,23 @@ namespace UserConfigBackendHome { bool UserConfigBackendHome::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handled*/) { if(entry[0].getKey().matches("UserManager")) { if(entry[1].getKey().matches("Skeleton")) { - if(entry[2].empty()) - skeleton = entry[1][0]; + if(entry[2].isEmpty()) + skeleton = entry[1][0].extract(); } else if(entry[1].getKey().matches("HomeDir")) { - if(entry[2].empty()) - homeDir = entry[1][0]; + if(entry[2].isEmpty()) + homeDir = entry[1][0].extract(); } else if(entry[1].getKey().matches("UserDirMode")) { - if(entry[2].empty()) { - if(entry[1][0].empty()) { + if(entry[2].isEmpty()) { + if(entry[1][0].isEmpty()) { dirMode = 0755; } else { char *endptr; - unsigned long val = std::strtoul(entry[1][0].c_str(), &endptr, 8); + unsigned long val = std::strtoul(entry[1][0].extract().c_str(), &endptr, 8); if(*endptr || val > 07777) { - application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: DirMode '%s'", entry[1][0].c_str()); + application->logf(Core::Logger::LOG_WARNING, "UserBackendHome: Invalid configuration: DirMode '%s'", entry[1][0].extract().c_str()); } else { dirMode = val; @@ -58,7 +58,7 @@ bool UserConfigBackendHome::handleConfigEntry(const Core::ConfigEntry &entry, bo } } } - else if(!entry[1].empty()) + else if(!entry[1].isEmpty()) return false; return true; diff --git a/src/modules/UserConfigBackendKrb5/UserConfigBackendKrb5.cpp b/src/modules/UserConfigBackendKrb5/UserConfigBackendKrb5.cpp index b10dbcf..475a689 100644 --- a/src/modules/UserConfigBackendKrb5/UserConfigBackendKrb5.cpp +++ b/src/modules/UserConfigBackendKrb5/UserConfigBackendKrb5.cpp @@ -92,7 +92,7 @@ bool UserConfigBackendKrb5::handleConfigEntry(const Core::ConfigEntry &entry, bo if(!entry[0].getKey().matches("UserManager")) return false; - if(entry[1].empty()) + if(entry[1].isEmpty()) return true; if(!entry[1].getKey().matches("Krb5")) @@ -101,26 +101,26 @@ bool UserConfigBackendKrb5::handleConfigEntry(const Core::ConfigEntry &entry, bo boost::lock_guard lock(mutex); if(entry[2].getKey().matches("Realm")) { - if(entry[3].empty()) - realm = entry[2][0]; + if(entry[3].isEmpty()) + realm = entry[2][0].extract(); } else if(entry[2].getKey().matches("Principal")) { - if(entry[3].empty()) - principal = entry[2][0]; + if(entry[3].isEmpty()) + principal = entry[2][0].extract(); } else if(entry[2].getKey().matches("Server")) { - if(entry[3].empty()) - server = entry[2][0]; + if(entry[3].isEmpty()) + server = entry[2][0].extract(); } else if(entry[2].getKey().matches("Password")) { - if(entry[3].empty()) - password = entry[2][0]; + if(entry[3].isEmpty()) + password = entry[2][0].extract(); } else if(entry[2].getKey().matches("Keytab")) { - if(entry[3].empty()) - keytab = entry[2][0]; + if(entry[3].isEmpty()) + keytab = entry[2][0].extract(); } - else if(!entry[2].empty()) + else if(!entry[2].isEmpty()) return false; return true; diff --git a/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp b/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp index e905541..7e7711a 100644 --- a/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp +++ b/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp @@ -40,34 +40,34 @@ bool UserDBBackendMysql::handleConfigEntry(const Core::ConfigEntry &entry, bool if(!entry[0].getKey().matches("UserManager")) return false; - if(entry[1].empty()) + if(entry[1].isEmpty()) return true; if(!entry[1].getKey().matches("Mysql")) return false; if(entry[2].getKey().matches("Host")) { - if(entry[3].empty()) - host = entry[2][0]; + if(entry[3].isEmpty()) + host = entry[2][0].extract(); } else if(entry[2].getKey().matches("Username")) { - if(entry[3].empty()) - username = entry[2][0]; + if(entry[3].isEmpty()) + username = entry[2][0].extract(); } else if(entry[2].getKey().matches("Password")) { - if(entry[3].empty()) - passwd = entry[2][0]; + if(entry[3].isEmpty()) + passwd = entry[2][0].extract(); } else if(entry[2].getKey().matches("Database")) { - if(entry[3].empty()) - db = entry[2][0]; + if(entry[3].isEmpty()) + db = entry[2][0].extract(); } else if(entry[2].getKey().matches("Port")) { - if(entry[3].empty()) { + if(entry[3].isEmpty()) { char *endptr; long val; - val = strtol(entry[2][0].c_str(), &endptr, 10); + val = strtol(entry[2][0].extract().c_str(), &endptr, 10); if(endptr != 0 || val < 0 || val > 65535) application->log(Core::Logger::LOG_WARNING, "UserDBBackendMysql: Invalid port"); @@ -76,82 +76,82 @@ bool UserDBBackendMysql::handleConfigEntry(const Core::ConfigEntry &entry, bool } } else if(entry[2].getKey().matches("UnixSocket")) { - if(entry[3].empty()) - unixSocket = entry[2][0]; + if(entry[3].isEmpty()) + unixSocket = entry[2][0].extract(); } else if(entry[2].getKey().matches("Queries")) { if(entry[3].getKey().matches("ListUsers")) { - if(entry[4].empty()) - queryListUsers = entry[3][0]; + if(entry[4].isEmpty()) + queryListUsers = entry[3][0].extract(); } else if(entry[3].getKey().matches("ListGroups")) { - if(entry[4].empty()) - queryListGroups = entry[3][0]; + if(entry[4].isEmpty()) + queryListGroups = entry[3][0].extract(); } else if(entry[3].getKey().matches("ListUserGroups")) { - if(entry[4].empty()) - queryListUserGroups = entry[3][0]; + if(entry[4].isEmpty()) + queryListUserGroups = entry[3][0].extract(); } else if(entry[3].getKey().matches("ListGroupUsers")) { - if(entry[4].empty()) - queryListGroupUsers = entry[3][0]; + if(entry[4].isEmpty()) + queryListGroupUsers = entry[3][0].extract(); } else if(entry[3].getKey().matches("UserById")) { - if(entry[4].empty()) - queryUserById = entry[3][0]; + if(entry[4].isEmpty()) + queryUserById = entry[3][0].extract(); } else if(entry[3].getKey().matches("UserByName")) { - if(entry[4].empty()) - queryUserByName = entry[3][0]; + if(entry[4].isEmpty()) + queryUserByName = entry[3][0].extract(); } else if(entry[3].getKey().matches("GroupById")) { - if(entry[4].empty()) - queryGroupById = entry[3][0]; + if(entry[4].isEmpty()) + queryGroupById = entry[3][0].extract(); } else if(entry[3].getKey().matches("GroupByName")) { - if(entry[4].empty()) - queryGroupByName = entry[3][0]; + if(entry[4].isEmpty()) + queryGroupByName = entry[3][0].extract(); } else if(entry[3].getKey().matches("UserGroupTable")) { - if(entry[4].empty()) - queryUserGroupTable = entry[3][0]; + if(entry[4].isEmpty()) + queryUserGroupTable = entry[3][0].extract(); } else if(entry[3].getKey().matches("AddUser")) { - if(entry[4].empty()) - queryAddUser = entry[3][0]; + if(entry[4].isEmpty()) + queryAddUser = entry[3][0].extract(); } else if(entry[3].getKey().matches("UpdateUser")) { - if(entry[4].empty()) - queryUpdateUser = entry[3][0]; + if(entry[4].isEmpty()) + queryUpdateUser = entry[3][0].extract(); } else if(entry[3].getKey().matches("DeleteUser")) { - if(entry[4].empty()) - queryDeleteUser = entry[3][0]; + if(entry[4].isEmpty()) + queryDeleteUser = entry[3][0].extract(); } else if(entry[3].getKey().matches("AddGroup")) { - if(entry[4].empty()) - queryAddGroup = entry[3][0]; + if(entry[4].isEmpty()) + queryAddGroup = entry[3][0].extract(); } else if(entry[3].getKey().matches("UpdateGroup")) { - if(entry[4].empty()) - queryUpdateGroup = entry[3][0]; + if(entry[4].isEmpty()) + queryUpdateGroup = entry[3][0].extract(); } else if(entry[3].getKey().matches("DeleteGroup")) { - if(entry[4].empty()) - queryDeleteGroup = entry[3][0]; + if(entry[4].isEmpty()) + queryDeleteGroup = entry[3][0].extract(); } else if(entry[3].getKey().matches("AddUserToGroup")) { - if(entry[4].empty()) - queryAddUserToGroup = entry[3][0]; + if(entry[4].isEmpty()) + queryAddUserToGroup = entry[3][0].extract(); } else if(entry[3].getKey().matches("DeleteUserFromGroup")) { - if(entry[4].empty()) - queryDeleteUserFromGroup = entry[3][0]; + if(entry[4].isEmpty()) + queryDeleteUserFromGroup = entry[3][0].extract(); } - else if(!entry[3].empty()) + else if(!entry[3].isEmpty()) return false; } - else if(!entry[2].empty()) + else if(!entry[2].isEmpty()) return false; return true; -- cgit v1.2.3