blob: ae5a75d1d0a8673b181f2af6e1e307f51d1c0714 [file] [log] [blame]
/***************************************************************************
propreties.cpp - class Properties
-------------------
begin : 06/17/2003
copyright : (C) 2003 by Michael CATANZARITI
email : mcatan@free.fr
***************************************************************************/
/***************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* *
* This software is published under the terms of the Apache Software *
* License version 1.1, a copy of which has been included with this *
* distribution in the LICENSE.txt file. *
***************************************************************************/
#include <log4cxx/helpers/properties.h>
using namespace log4cxx;
using namespace log4cxx::helpers;
class PropertyParser
{
public:
void parse(istream& in, Properties& properties)
{
StringBuffer key, element;
LexemType lexemType = BEGIN;
TCHAR c;
bool finished = false;
if (!get(in, c))
{
return;
}
while (!finished)
{
switch(lexemType)
{
case BEGIN:
switch(c)
{
case _T(' '):
case _T('\t'):
case _T('\n'):
case _T('\r'):
if (!get(in, c))
finished = true;
break;
case _T('#'):
case _T('!'):
lexemType = COMMENT;
if (!get(in, c))
finished = true;
break;
default:
lexemType = KEY;
break;
}
break;
case KEY:
switch(c)
{
case _T('\\'):
lexemType = KEY_ESCAPE;
if (!get(in, c))
finished = true;
break;
case _T('\t'):
case _T(' '):
case _T(':'):
case _T('='):
lexemType = DELIMITER;
if (!get(in, c))
finished = true;
break;
case _T('\n'):
case _T('\r'):
// key associated with an empty string element
properties.setProperty(key.str(), _T(""));
key.str(_T(""));
lexemType = BEGIN;
if (!get(in, c))
finished = true;
break;
default:
key << c;
if (!get(in, c))
finished = true;
break;
}
break;
case KEY_ESCAPE:
switch(c)
{
case _T('\t'):
case _T(' '):
case _T(':'):
case _T('='):
case _T('\\'):
key << c;
lexemType = KEY;
if (!get(in, c))
finished = true;
break;
case _T('\n'):
lexemType = KEY_CONTINUE;
if (!get(in, c))
finished = true;
break;
case _T('\r'):
lexemType = KEY_CONTINUE2;
if (!get(in, c))
finished = true;
break;
}
break;
case KEY_CONTINUE:
switch(c)
{
case _T(' '):
case _T('\t'):
if (!get(in, c))
finished = true;
break;
default:
lexemType = KEY;
break;
}
break;
case KEY_CONTINUE2:
switch(c)
{
case _T('\n'):
if (!get(in, c))
finished = true;
lexemType = KEY_CONTINUE;
break;
default:
lexemType = KEY_CONTINUE;
break;
}
break;
case DELIMITER:
switch(c)
{
case _T('\t'):
case _T(' '):
case _T(':'):
case _T('='):
if (!get(in, c))
finished = true;
break;
default:
lexemType = ELEMENT;
break;
}
break;
case ELEMENT:
switch(c)
{
case _T('\\'):
lexemType = ELEMENT_ESCAPE;
if (!get(in, c))
finished = true;
break;
case _T('\n'):
case _T('\r'):
// key associated with an empty string element
properties.setProperty(key.str(), element.str());
key.str(_T(""));
element.str(_T(""));
lexemType = BEGIN;
if (!get(in, c))
finished = true;
break;
default:
element << c;
if (!get(in, c))
finished = true;
break;
}
break;
case ELEMENT_ESCAPE:
switch(c)
{
case _T('t'):
case _T(' '):
case _T('n'):
case _T('r'):
case _T('\''):
case _T('\\'):
case _T('\"'):
case _T(':'):
default:
element << c;
lexemType = ELEMENT;
if (!get(in, c))
finished = true;
break;
case _T('\n'):
lexemType = ELEMENT_CONTINUE;
if (!get(in, c))
finished = true;
break;
case _T('\r'):
lexemType = ELEMENT_CONTINUE2;
if (!get(in, c))
finished = true;
break;
}
break;
case ELEMENT_CONTINUE:
switch(c)
{
case _T(' '):
case _T('\t'):
if (!get(in, c))
finished = true;
break;
default:
lexemType = ELEMENT;
break;
}
break;
case ELEMENT_CONTINUE2:
switch(c)
{
case _T('\n'):
if (!get(in, c))
finished = true;
lexemType = ELEMENT_CONTINUE;
break;
default:
lexemType = ELEMENT_CONTINUE;
break;
}
break;
case COMMENT:
if (c == _T('\n') || c == _T('\r'))
{
lexemType = BEGIN;
}
if (!get(in, c))
finished = true;
break;
}
}
if (!key.str().empty())
{
properties.setProperty(key.str(), element.str());
}
}
protected:
bool get(istream& in, TCHAR& c)
{
in.get(c);
if (in.eof())
{
return false;
}
if (in.bad())
{
throw IOException();
}
return true;
}
typedef enum
{
BEGIN,
KEY,
KEY_ESCAPE,
KEY_CONTINUE,
KEY_CONTINUE2,
DELIMITER,
ELEMENT,
ELEMENT_ESCAPE,
ELEMENT_CONTINUE,
ELEMENT_CONTINUE2,
COMMENT
}
LexemType;
};
String Properties::setProperty(const String& key, const String& value)
{
String oldValue = properties[key];
properties[key] = value;
//tcout << _T("setting property key=") << key << _T(", value=") << value << std::endl;
return oldValue;
}
String Properties::getProperty(const String& key) const
{
std::map<String, String>::const_iterator it = properties.find(key);
return (it != properties.end()) ? it->second : String();
}
void Properties::load(istream& inStream)
{
properties.clear();
PropertyParser parser;
parser.parse(inStream, *this);
}
std::vector<String> Properties::propertyNames() const
{
std::vector<String> names;
names.reserve(properties.size());
std::map<String, String>::const_iterator it;
for (it = properties.begin(); it != properties.end(); it++)
{
const String& key = it->first;
names.push_back(key);
}
return names;
}