more robust config parser

This commit is contained in:
tqchen 2015-03-07 08:52:56 -08:00
parent bae1a08c9b
commit d202d8b977

View File

@ -24,14 +24,14 @@ class ConfigReaderBase {
* \return current parameter name * \return current parameter name
*/ */
inline const char *name(void) const { inline const char *name(void) const {
return s_name; return s_name.c_str();
} }
/*! /*!
* \brief get current value, called after Next returns true * \brief get current value, called after Next returns true
* \return current parameter value * \return current parameter value
*/ */
inline const char *val(void) const { inline const char *val(void) const {
return s_val; return s_val.c_str();
} }
/*! /*!
* \brief move iterator to next position * \brief move iterator to next position
@ -39,10 +39,10 @@ class ConfigReaderBase {
*/ */
inline bool Next(void) { inline bool Next(void) {
while (!this->IsEnd()) { while (!this->IsEnd()) {
GetNextToken(s_name); GetNextToken(&s_name);
if (s_name[0] == '=') return false; if (s_name == "=") return false;
if (GetNextToken( s_buf ) || s_buf[0] != '=') return false; if (GetNextToken(&s_buf) || s_buf != "=") return false;
if (GetNextToken( s_val ) || s_val[0] == '=') return false; if (GetNextToken(&s_val) || s_val == "=") return false;
return true; return true;
} }
return false; return false;
@ -63,7 +63,7 @@ class ConfigReaderBase {
private: private:
char ch_buf; char ch_buf;
char s_name[100000], s_val[100000], s_buf[100000]; std::string s_name, s_val, s_buf;
inline void SkipLine(void) { inline void SkipLine(void) {
do { do {
@ -71,76 +71,72 @@ class ConfigReaderBase {
} while (ch_buf != EOF && ch_buf != '\n' && ch_buf != '\r'); } while (ch_buf != EOF && ch_buf != '\n' && ch_buf != '\r');
} }
inline void ParseStr(char tok[]) { inline void ParseStr(std::string *tok) {
int i = 0;
while ((ch_buf = this->GetChar()) != EOF) { while ((ch_buf = this->GetChar()) != EOF) {
switch (ch_buf) { switch (ch_buf) {
case '\\': tok[i++] = this->GetChar(); break; case '\\': *tok += this->GetChar(); break;
case '\"': tok[i++] = '\0'; return; case '\"': return;
case '\r': case '\r':
case '\n': Error("ConfigReader: unterminated string"); case '\n': Error("ConfigReader: unterminated string");
default: tok[i++] = ch_buf; default: *tok += ch_buf;
} }
} }
Error("ConfigReader: unterminated string"); Error("ConfigReader: unterminated string");
} }
inline void ParseStrML(char tok[]) { inline void ParseStrML(std::string *tok) {
int i = 0;
while ((ch_buf = this->GetChar()) != EOF) { while ((ch_buf = this->GetChar()) != EOF) {
switch (ch_buf) { switch (ch_buf) {
case '\\': tok[i++] = this->GetChar(); break; case '\\': *tok += this->GetChar(); break;
case '\'': tok[i++] = '\0'; return; case '\'': return;
default: tok[i++] = ch_buf; default: *tok += ch_buf;
} }
} }
Error("unterminated string"); Error("unterminated string");
} }
// return newline // return newline
inline bool GetNextToken(char tok[]) { inline bool GetNextToken(std::string *tok) {
int i = 0; tok->clear();
bool new_line = false; bool new_line = false;
while (ch_buf != EOF) { while (ch_buf != EOF) {
switch (ch_buf) { switch (ch_buf) {
case '#' : SkipLine(); new_line = true; break; case '#' : SkipLine(); new_line = true; break;
case '\"': case '\"':
if (i == 0) { if (tok->length() == 0) {
ParseStr(tok); ch_buf = this->GetChar(); return new_line; ParseStr(tok); ch_buf = this->GetChar(); return new_line;
} else { } else {
Error("ConfigReader: token followed directly by string"); Error("ConfigReader: token followed directly by string");
} }
case '\'': case '\'':
if (i == 0) { if (tok->length() == 0) {
ParseStrML( tok ); ch_buf = this->GetChar(); return new_line; ParseStrML(tok); ch_buf = this->GetChar(); return new_line;
} else { } else {
Error("ConfigReader: token followed directly by string"); Error("ConfigReader: token followed directly by string");
} }
case '=': case '=':
if (i == 0) { if (tok->length() == 0) {
ch_buf = this->GetChar(); ch_buf = this->GetChar();
tok[0] = '='; *tok = '=';
tok[1] = '\0';
} else {
tok[i] = '\0';
} }
return new_line; return new_line;
case '\r': case '\r':
case '\n': case '\n':
if (i == 0) new_line = true; if (tok->length() == 0) new_line = true;
case '\t': case '\t':
case ' ' : case ' ' :
ch_buf = this->GetChar(); ch_buf = this->GetChar();
if (i > 0) { if (tok->length() != 0) return new_line;
tok[i] = '\0';
return new_line;
}
break; break;
default: default:
tok[i++] = ch_buf; *tok += ch_buf;
ch_buf = this->GetChar(); ch_buf = this->GetChar();
break; break;
} }
} }
return true; if (tok->length() == 0) {
return true;
} else {
return false;
}
} }
}; };
/*! /*!