You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

421 lines
9.2 KiB

// Module: Log4CPLUS
// File: property.cxx
// Created: 2/2002
// Author: Tad E. Smith
//
//
// Copyright 2002-2013 Tad E. Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <log4cplus/config.hxx>
#include <cstring>
#if defined (UNICODE)
# include <cwctype>
#else
# include <cctype>
#endif
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) \
|| defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) \
|| defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET)
# include <codecvt>
#endif
#include <locale>
#include <fstream>
#include <sstream>
#include <log4cplus/streams.h>
#include <log4cplus/fstreams.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/internal/internal.h>
#include <log4cplus/internal/env.h>
#include <log4cplus/helpers/loglog.h>
namespace log4cplus { namespace helpers {
const tchar Properties::PROPERTIES_COMMENT_CHAR = LOG4CPLUS_TEXT('#');
namespace
{
static
int
is_space (tchar ch)
{
#if defined (UNICODE)
return std::iswspace (ch);
#else
return std::isspace (static_cast<unsigned char>(ch));
#endif
}
static
void
trim_leading_ws (tstring & str)
{
tstring::iterator it = str.begin ();
for (; it != str.end (); ++it)
{
if (! is_space (*it))
break;
}
str.erase (str.begin (), it);
}
static
void
trim_trailing_ws (tstring & str)
{
tstring::reverse_iterator rit = str.rbegin ();
for (; rit != str.rend (); ++rit)
{
if (! is_space (*rit))
break;
}
str.erase (rit.base (), str.end ());
}
static
void
trim_ws (tstring & str)
{
trim_trailing_ws (str);
trim_leading_ws (str);
}
void
imbue_file_from_flags (tistream & file, unsigned flags)
{
switch (flags & (Properties::fEncodingMask << Properties::fEncodingShift))
{
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) && defined (UNICODE)
case Properties::fUTF8:
file.imbue (
std::locale (file.getloc (),
new std::codecvt_utf8<tchar, 0x10FFFF,
static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
break;
#endif
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) && defined (UNICODE)
case Properties::fUTF16:
file.imbue (
std::locale (file.getloc (),
new std::codecvt_utf16<tchar, 0x10FFFF,
static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
break;
#elif defined (UNICODE) && defined (WIN32)
case Properties::fUTF16:
file.imbue (
std::locale (file.getloc (),
// TODO: This should actually be a custom "null" facet
// that just copies the chars to wchar_t buffer.
new std::codecvt<wchar_t, char, std::mbstate_t>));
break;
#endif
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) && defined (UNICODE)
case Properties::fUTF32:
file.imbue (
std::locale (file.getloc (),
new std::codecvt_utf32<tchar, 0x10FFFF,
static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>));
break;
#endif
case Properties::fUnspecEncoding:;
default:
// Do nothing.
;
}
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
// Properties ctors and dtor
///////////////////////////////////////////////////////////////////////////////
Properties::Properties()
: flags (0)
{
}
Properties::Properties(tistream& input)
: flags (0)
{
init(input);
}
Properties::Properties(const tstring& inputFile, unsigned f)
: flags (f)
{
if (inputFile.empty ())
return;
tifstream file;
imbue_file_from_flags (file, flags);
file.open(LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(inputFile).c_str(),
std::ios::binary);
if (! file.good ())
helpers::getLogLog ().error (LOG4CPLUS_TEXT ("could not open file ")
+ inputFile);
init(file);
}
void
Properties::init(tistream& input)
{
if (! input)
return;
tstring buffer;
while (std::getline (input, buffer))
{
trim_leading_ws (buffer);
tstring::size_type const buffLen = buffer.size ();
if (buffLen == 0 || buffer[0] == PROPERTIES_COMMENT_CHAR)
continue;
// Check if we have a trailing \r because we are
// reading a properties file produced on Windows.
if (buffer[buffLen-1] == LOG4CPLUS_TEXT('\r'))
// Remove trailing 'Windows' \r.
buffer.resize (buffLen - 1);
tstring::size_type const idx = buffer.find('=');
if (idx != tstring::npos)
{
tstring key = buffer.substr(0, idx);
tstring value = buffer.substr(idx + 1);
trim_trailing_ws (key);
trim_ws (value);
setProperty(key, value);
}
else if (buffer.compare (0, 7, LOG4CPLUS_TEXT ("include")) == 0
&& buffer.size () >= 7 + 1 + 1
&& is_space (buffer[7]))
{
tstring included (buffer, 8) ;
trim_ws (included);
tifstream file;
imbue_file_from_flags (file, flags);
file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(included).c_str(),
std::ios::binary);
if (! file.good ())
helpers::getLogLog ().error (
LOG4CPLUS_TEXT ("could not open file ") + included);
init (file);
}
}
}
Properties::~Properties()
{
}
///////////////////////////////////////////////////////////////////////////////
// helpers::Properties public methods
///////////////////////////////////////////////////////////////////////////////
bool
Properties::exists(const log4cplus::tstring& key) const
{
return data.find(key) != data.end();
}
bool
Properties::exists(tchar const * key) const
{
return data.find(key) != data.end();
}
tstring const &
Properties::getProperty(const tstring& key) const
{
return get_property_worker (key);
}
log4cplus::tstring const &
Properties::getProperty(tchar const * key) const
{
return get_property_worker (key);
}
tstring
Properties::getProperty(const tstring& key, const tstring& defaultVal) const
{
StringMap::const_iterator it (data.find (key));
if (it == data.end ())
return defaultVal;
else
return it->second;
}
std::vector<tstring>
Properties::propertyNames() const
{
std::vector<tstring> tmp;
for (StringMap::const_iterator it=data.begin(); it!=data.end(); ++it)
tmp.push_back(it->first);
return tmp;
}
void
Properties::setProperty(const log4cplus::tstring& key,
const log4cplus::tstring& value)
{
data[key] = value;
}
bool
Properties::removeProperty(const log4cplus::tstring& key)
{
return data.erase(key) > 0;
}
Properties
Properties::getPropertySubset(const log4cplus::tstring& prefix) const
{
Properties ret;
std::size_t const prefix_len = prefix.size ();
std::vector<tstring> keys = propertyNames();
for (std::vector<tstring>::iterator it=keys.begin(); it!=keys.end(); ++it)
{
int result = it->compare (0, prefix_len, prefix);
if (result == 0)
ret.setProperty (it->substr (prefix_len), getProperty(*it));
}
return ret;
}
bool
Properties::getInt (int & val, log4cplus::tstring const & key) const
{
return get_type_val_worker (val, key);
}
bool
Properties::getUInt (unsigned & val, log4cplus::tstring const & key) const
{
return get_type_val_worker (val, key);
}
bool
Properties::getLong (long & val, log4cplus::tstring const & key) const
{
return get_type_val_worker (val, key);
}
bool
Properties::getULong (unsigned long & val, log4cplus::tstring const & key) const
{
return get_type_val_worker (val, key);
}
bool
Properties::getBool (bool & val, log4cplus::tstring const & key) const
{
if (! exists (key))
return false;
log4cplus::tstring const & prop_val = getProperty (key);
return internal::parse_bool (val, prop_val);
}
template <typename StringType>
log4cplus::tstring const &
Properties::get_property_worker (StringType const & key) const
{
StringMap::const_iterator it (data.find (key));
if (it == data.end ())
return log4cplus::internal::empty_str;
else
return it->second;
}
template <typename ValType>
bool
Properties::get_type_val_worker (ValType & val, log4cplus::tstring const & key)
const
{
if (! exists (key))
return false;
log4cplus::tstring const & prop_val = getProperty (key);
log4cplus::tistringstream iss (prop_val);
ValType tmp_val;
tchar ch;
iss >> tmp_val;
if (! iss)
return false;
iss >> ch;
if (iss)
return false;
val = tmp_val;
return true;
}
} } // namespace log4cplus { namespace helpers {