More carriage return issues. Strip now uses the ISO C isspace() routine.

This commit is contained in:
Harry Moffat 2008-09-17 20:03:31 +00:00
parent 7a4e9ee4e3
commit 86b9899e74
2 changed files with 416 additions and 354 deletions

View file

@ -18,6 +18,8 @@ using namespace std;
#include "xml.h"
#include <ctype.h>
#define XML_INDENT 4
namespace Cantera {
@ -85,213 +87,229 @@ namespace Cantera {
//////////////////// XML_Reader methods ///////////////////////
/// Get a single character from the input stream. If the character
/// is a new-line character, then increment the line count.
void XML_Reader::getchr(char& ch) {
m_s.get(ch);
if (ch == '\n') m_line++;
XML_Reader::XML_Reader(std::istream& input) :
m_s(input),
m_line(0)
{
}
//! Get a single character from the input stream.
/*!
* If the character
* is a new-line character, then increment the line count.
*/
void XML_Reader::getchr(char& ch) {
m_s.get(ch);
if (ch == '\n') {
m_line++;
}
}
// Returns string 'aline' stripped of leading and trailing white
// space.
// @todo why is this a class method?
string XML_Reader::strip(const string& aline) {
int len = static_cast<int>(aline.size());
int i, j, ll;
for (i = len-1; i >= 0; i--) {
ll = aline[i];
if (! isspace(ll)) break;
}
/// Returns string 'aline' stripped of leading and trailing white
/// space.
/// @todo why is this a class method?
string XML_Reader::strip(const string& aline) {
int len = static_cast<int>(aline.size());
int i, j;
for (i = len-1; i >= 0; i--)
if (aline[i] != ' ' && aline[i] != '\n') break;
for (j = 0; j < i; j++)
if (aline[j] != ' ' && aline[j] != '\n') break;
return aline.substr(j, i - j + 1);
for (j = 0; j < i; j++) {
ll = aline[j];
if (! isspace(ll)) break;
}
// if (aline[j] != ' ' && aline[j] != '\n') break;
return aline.substr(j, i - j + 1);
}
/// Looks for a substring within 'aline' enclosed in double
/// quotes, and returns this substring (without the quotes) if
/// found. If not, an empty string is returned.
/// @todo why is this a class method?
string XML_Reader::inquotes(const string& aline) {
int len = static_cast<int>(aline.size());
int i, j;
for (i = len-1; i >= 0; i--)
if (aline[i] == '"') break;
for (j = 0; j < i; j++)
if (aline[j] == '"') break;
if (j == i) return "";
else return aline.substr(j+1, i - j - 1);
/// Looks for a substring within 'aline' enclosed in double
/// quotes, and returns this substring (without the quotes) if
/// found. If not, an empty string is returned.
/// @todo why is this a class method?
string XML_Reader::inquotes(const string& aline) {
int len = static_cast<int>(aline.size());
int i, j;
for (i = len-1; i >= 0; i--)
if (aline[i] == '"') break;
for (j = 0; j < i; j++)
if (aline[j] == '"') break;
if (j == i) return "";
else return aline.substr(j+1, i - j - 1);
}
/**
* Find the first position of a character, q, in string s,
* which is not immediately preceded by the backslash character
* '\'
*/
static string::size_type findUnbackslashed(string s, const char q,
string::size_type istart = 0) {
string::size_type iloc, icurrent, len;
icurrent = istart;
len = s.size();
while (1) {
iloc = s.find(q, icurrent);
if (iloc == string::npos || iloc == 0) {
return iloc;
}
char cm1 = s[iloc-1];
if (cm1 == '\\') {
if (iloc >= (len -1)) return string::npos;
icurrent = iloc + 1;
} else {
return iloc;
}
}
}
/**
* Find the first position of a character, q, in string s,
* which is not immediately preceded by the backslash character
* '\'
/**
* Searches a string for the first occurrence of a valid
* quoted string. Quotes can start with either a single
* quote or a double quote, but must also end with the same
* type. Quotes may be commented out by preceding with a
* backslash character, '\\'.
*/
int XML_Reader::findQuotedString(const string& s, string &rstring) {
const char q1 = '\'';
const char q2 = '"';
rstring = "";
char qtype = ' ';
string::size_type iloc1, iloc2, ilocStart = 0;
iloc1 = findUnbackslashed(s, q1);
iloc2 = findUnbackslashed(s, q2);
if (iloc2 != string::npos) {
ilocStart = iloc2;
qtype = q2;
}
if (iloc1 != string::npos) {
if (iloc1 < ilocStart) {
ilocStart = iloc1;
qtype = q1;
}
}
if (qtype == ' ') return 0;
iloc1 = findUnbackslashed(s, qtype, ilocStart+1);
if (iloc1 == string::npos) {
return 0;
}
/*
* Define the return string by the two endpoints.
* Strip the surrounding quotes as well
*/
static string::size_type findUnbackslashed(string s, const char q,
string::size_type istart = 0) {
string::size_type iloc, icurrent, len;
icurrent = istart;
len = s.size();
while (1) {
iloc = s.find(q, icurrent);
if (iloc == string::npos || iloc == 0) {
return iloc;
}
char cm1 = s[iloc-1];
if (cm1 == '\\') {
if (iloc >= (len -1)) return string::npos;
icurrent = iloc + 1;
} else {
return iloc;
}
}
}
/**
* Searches a string for the first occurrence of a valid
* quoted string. Quotes can start with either a single
* quote or a double quote, but must also end with the same
* type. Quotes may be commented out by preceding with a
* backslash character, '\\'.
rstring = s.substr(ilocStart + 1, iloc1 - 1);
/*
* Return the first character position past the quotes
*/
int XML_Reader::findQuotedString(const string& s, string &rstring) {
const char q1 = '\'';
const char q2 = '"';
rstring = "";
char qtype = ' ';
string::size_type iloc1, iloc2, ilocStart = 0;
iloc1 = findUnbackslashed(s, q1);
iloc2 = findUnbackslashed(s, q2);
if (iloc2 != string::npos) {
ilocStart = iloc2;
qtype = q2;
}
if (iloc1 != string::npos) {
if (iloc1 < ilocStart) {
ilocStart = iloc1;
qtype = q1;
}
}
if (qtype == ' ') return 0;
iloc1 = findUnbackslashed(s, qtype, ilocStart+1);
if (iloc1 == string::npos) {
return 0;
}
/*
* Define the return string by the two endpoints.
* Strip the surrounding quotes as well
*/
rstring = s.substr(ilocStart + 1, iloc1 - 1);
/*
* Return the first character position past the quotes
*/
return static_cast<int>(iloc1)+1;
}
return static_cast<int>(iloc1)+1;
}
/**
* parseTag parses XML tags, i.e., the XML elements that are
* inbetween angle brackets.
*/
void XML_Reader::parseTag(string tag, string& name,
map<string, string>& attribs) {
string::size_type iloc;
string attr, val;
string s = strip(tag);
iloc = s.find(' ');
if (iloc != string::npos) {
name = s.substr(0, iloc);
s = strip(s.substr(iloc+1,s.size()));
if (s[s.size()-1] == '/') {
name += "/";
}
/**
* parseTag parses XML tags, i.e., the XML elements that are
* inbetween angle brackets.
*/
void XML_Reader::parseTag(string tag, string& name,
map<string, string>& attribs) {
string::size_type iloc;
string attr, val;
string s = strip(tag);
iloc = s.find(' ');
if (iloc != string::npos) {
name = s.substr(0, iloc);
s = strip(s.substr(iloc+1,s.size()));
if (s[s.size()-1] == '/') {
name += "/";
}
// get attributes
while (1) {
iloc = s.find('=');
if (iloc == string::npos) break;
attr = strip(s.substr(0,iloc));
if (attr == "") break;
s = strip(s.substr(iloc+1,s.size()));
iloc = findQuotedString(s, val);
attribs[attr] = val;
if (iloc != string::npos) {
if (iloc < s.size())
s = strip(s.substr(iloc,s.size()));
else
break;
}
}
}
else {
name = s;
}
// get attributes
while (1) {
iloc = s.find('=');
if (iloc == string::npos) break;
attr = strip(s.substr(0,iloc));
if (attr == "") break;
s = strip(s.substr(iloc+1,s.size()));
iloc = findQuotedString(s, val);
attribs[attr] = val;
if (iloc != string::npos) {
if (iloc < s.size())
s = strip(s.substr(iloc,s.size()));
else
break;
}
}
}
else {
name = s;
}
}
string XML_Reader::readTag(map<string, string>& attribs) {
string name, tag = "";
bool incomment = false;
char ch = '-';
while (1) {
if (m_s.eof() || (getchr(ch), ch == '<')) break;
}
char ch1 = ' ', ch2 = ' ';
while (1) {
if (m_s.eof()) { tag = "EOF"; break;}
ch2 = ch1;
ch1 = ch;
getchr(ch);
if (ch == '-') {
if (ch1 == '-' && ch2 == '!') {
incomment = true;
tag = "-";
}
}
else if (ch == '>') {
if (incomment) {
if (ch1 == '-' && ch2 == '-') break;
}
else
break;
}
if (isprint(ch)) tag += ch;
}
if (incomment) {
attribs.clear();
return tag;
}
else {
parseTag(tag, name, attribs);
return name;
}
string XML_Reader::readTag(map<string, string>& attribs) {
string name, tag = "";
bool incomment = false;
char ch = '-';
while (1) {
if (m_s.eof() || (getchr(ch), ch == '<')) break;
}
string XML_Reader::readValue() {
string tag = "";
char ch, lastch;
ch = '\n';
bool front = true;
while (1) {
if (m_s.eof()) break;
lastch = ch;
getchr(ch);
if (ch == '\n')
front = true;
else if (ch != ' ')
front = false;
if (ch == '<') {
m_s.putback(ch);
break;
}
if (front && lastch == ' ' && ch == ' ') ;
else tag += ch;
}
return strip(tag);
char ch1 = ' ', ch2 = ' ';
while (1) {
if (m_s.eof()) { tag = "EOF"; break;}
ch2 = ch1;
ch1 = ch;
getchr(ch);
if (ch == '-') {
if (ch1 == '-' && ch2 == '!') {
incomment = true;
tag = "-";
}
}
else if (ch == '>') {
if (incomment) {
if (ch1 == '-' && ch2 == '-') break;
}
else
break;
}
if (isprint(ch)) tag += ch;
}
if (incomment) {
attribs.clear();
return tag;
}
else {
parseTag(tag, name, attribs);
return name;
}
}
string XML_Reader::readValue() {
string tag = "";
char ch, lastch;
ch = '\n';
bool front = true;
while (1) {
if (m_s.eof()) break;
lastch = ch;
getchr(ch);
if (ch == '\n')
front = true;
else if (ch != ' ')
front = false;
if (ch == '<') {
m_s.putback(ch);
break;
}
if (front && lastch == ' ' && ch == ' ') ;
else tag += ch;
}
return strip(tag);
}
////////////////////////// XML_Node /////////////////////////////////
////////////////////////// XML_Node /////////////////////////////////
XML_Node::XML_Node(string nm, XML_Node* p)

View file

@ -34,20 +34,64 @@ namespace Cantera {
/**
* Class XML_Reader is designed for internal use.
* This function reads an XML file into an XML_Node object.
*/
class XML_Reader {
public:
XML_Reader(std::istream& input) : m_s(input), m_line(0) {}
//! Sole Constructor for the XML_Reader class
/*!
* @param input Reference to the istream object containing
* the XML file
*/
XML_Reader(std::istream& input);
//! Input Stream containing the XML file
std::istream& m_s;
//! Line count
int m_line;
//! Read a single character from the input stream
//! and return it
/*!
* All low level reads occur through this function.
* The function also keeps track of the line numbers.
*
* @param ch Character to be returned.
*/
void getchr(char& ch);
//! Returns string 'aline' stripped of leading and trailing white
//! space.
/*!
* White space is defined by the ISO C function isspace(), and
* includes tabs, spaces, \n. \r, \v, and \f.
*
* @param aline Input line to be stripped
*
* @return Returns a string stripped of leading and trailing white
* space.
*
* @todo why is this a class method?
*/
std::string strip(const std::string& aline);
/// Looks for a substring within 'aline' enclosed in double
/// quotes, and returns this substring (without the quotes) if
/// found. If not, an empty string is returned.
/// @todo why is this a class method?
std::string inquotes(const std::string& aline);
/**
* Searches a string for the first occurrence of a valid
* quoted string. Quotes can start with either a single
* quote or a double quote, but must also end with the same
* type. Quotes may be commented out by preceding with a
* backslash character, '\\'.
*/
int findQuotedString(const std::string& aline, std::string &rstring);
void parseTag(std::string line, std::string& name,
std::map<std::string, std::string>& attribs);
std::string readTag(std::map<std::string, std::string>& attribs);
@ -55,193 +99,193 @@ namespace Cantera {
};
////////////////////////// XML_Node /////////////////////////////////
////////////////////////// XML_Node /////////////////////////////////
class XML_Node {
public:
class XML_Node {
public:
XML_Node(std::string nm = "--", XML_Node* p = 0);
XML_Node(std::string nm = "--", XML_Node* p = 0);
XML_Node(const XML_Node &right);
XML_Node(const XML_Node &right);
//! Assignment operator for XML trees
/*!
* @param right XML tree to copy
*/
XML_Node& operator=(const XML_Node &right);
//! Assignment operator for XML trees
/*!
* @param right XML tree to copy
*/
XML_Node& operator=(const XML_Node &right);
virtual ~XML_Node();
void addComment(std::string comment);
XML_Node& addChild(XML_Node& node);
XML_Node& addChild(std::string name);
XML_Node& addChild(std::string name, std::string value);
XML_Node& addChild(std::string name, double value, std::string fmt="%g");
void removeChild(XML_Node* node);
void addValue(std::string val);
void addValue(doublereal val, std::string fmt="%g");
void addAttribute(std::string attrib, std::string value);
void addAttribute(std::string attrib, double value, std::string fmt="%g");
void writeHeader(std::ostream& s);
std::string value() const { return m_value; }
std::string value(std::string loc) const { return child(loc).value(); }
void setLineNumber(int n) {m_linenum = n;}
int lineNumber() const {return m_linenum;}
doublereal fp_value() const {
return std::atof(m_value.c_str());
}
integer int_value() const {
return std::atoi(m_value.c_str());
}
std::string operator()() const { return m_value; }
std::string operator()(std::string loc) const { return value(loc); }
virtual ~XML_Node();
void addComment(std::string comment);
XML_Node& addChild(XML_Node& node);
XML_Node& addChild(std::string name);
XML_Node& addChild(std::string name, std::string value);
XML_Node& addChild(std::string name, double value, std::string fmt="%g");
void removeChild(XML_Node* node);
void addValue(std::string val);
void addValue(doublereal val, std::string fmt="%g");
void addAttribute(std::string attrib, std::string value);
void addAttribute(std::string attrib, double value, std::string fmt="%g");
void writeHeader(std::ostream& s);
std::string value() const { return m_value; }
std::string value(std::string loc) const { return child(loc).value(); }
void setLineNumber(int n) {m_linenum = n;}
int lineNumber() const {return m_linenum;}
doublereal fp_value() const {
return std::atof(m_value.c_str());
}
integer int_value() const {
return std::atoi(m_value.c_str());
}
std::string operator()() const { return m_value; }
std::string operator()(std::string loc) const { return value(loc); }
//! The operator[] is overloaded to provide a lookup capability
//! on attributes for the current XML element.
/*!
* For example
* xmlNode["id"]
* will return the value of the attribute "id" for the current
* XML element. It will return the blank std::string if there isn't
* an attribute with that name.
*
* @param attr attribute string to look up
*
* @return Returns a string representing the value of the attribute
* within the XML node. If there is no attribute
* with the given name, it returns the null string.
*/
std::string operator[](std::string attr) const {
return attrib(attr);
}
//! The operator[] is overloaded to provide a lookup capability
//! on attributes for the current XML element.
/*!
* For example
* xmlNode["id"]
* will return the value of the attribute "id" for the current
* XML element. It will return the blank std::string if there isn't
* an attribute with that name.
*
* @param attr attribute string to look up
*
* @return Returns a string representing the value of the attribute
* within the XML node. If there is no attribute
* with the given name, it returns the null string.
*/
std::string operator[](std::string attr) const {
return attrib(attr);
}
/**
* This function searches the attibutes vector for the parameter
* std::string attribute. If a match is found, the attribute value
* is returned as a string. If no match is found, the empty string
* is returned.
*
* @param(attr) Std::String containing the attribute to be searched for.
*/
std::string attrib(std::string attr) const {
std::map<std::string,std::string>::const_iterator i = m_attribs.find(attr);
if (i != m_attribs.end()) return i->second;
return "";
}
/**
* This function searches the attibutes vector for the parameter
* std::string attribute. If a match is found, the attribute value
* is returned as a string. If no match is found, the empty string
* is returned.
*
* @param(attr) Std::String containing the attribute to be searched for.
*/
std::string attrib(std::string attr) const {
std::map<std::string,std::string>::const_iterator i = m_attribs.find(attr);
if (i != m_attribs.end()) return i->second;
return "";
}
std::map<std::string,std::string>& attribs() { return m_attribs; }
XML_Node* parent() const { return m_parent; }
XML_Node* setParent(XML_Node* p) { m_parent = p; return p; }
std::map<std::string,std::string>& attribs() { return m_attribs; }
XML_Node* parent() const { return m_parent; }
XML_Node* setParent(XML_Node* p) { m_parent = p; return p; }
//! Tests whether the current node has a child node with a particular name
/*!
* @param ch Name of the child node to test
*
* @return Returns true if the child node exists, false otherwise.
*/
bool hasChild(const std::string ch) const {
return (m_childindex.find(ch) != m_childindex.end());
}
bool hasAttrib(std::string a) const {
return (m_attribs.find(a) != m_attribs.end());
}
//! Tests whether the current node has a child node with a particular name
/*!
* @param ch Name of the child node to test
*
* @return Returns true if the child node exists, false otherwise.
*/
bool hasChild(const std::string ch) const {
return (m_childindex.find(ch) != m_childindex.end());
}
bool hasAttrib(std::string a) const {
return (m_attribs.find(a) != m_attribs.end());
}
//! Returns the name of the XML node
/*!
* The name is the XML node is the XML node name
*/
std::string name() const { return m_name; }
//! Returns the name of the XML node
/*!
* The name is the XML node is the XML node name
*/
std::string name() const { return m_name; }
//! Return the id attribute, if present
/*!
* Returns the id attribute if present. If not
* it return the empty string
*/
std::string id() const;
//! Return the id attribute, if present
/*!
* Returns the id attribute if present. If not
* it return the empty string
*/
std::string id() const;
XML_Node& child(int n) const { return *m_children[n]; }
std::vector<XML_Node*>& children() { return m_children; }
const std::vector<XML_Node*>& children() const { return m_children; }
int nChildren() const { return m_nchildren; }
XML_Node& child(int n) const { return *m_children[n]; }
std::vector<XML_Node*>& children() { return m_children; }
const std::vector<XML_Node*>& children() const { return m_children; }
int nChildren() const { return m_nchildren; }
void build(std::istream& f);
void build(std::istream& f);
void _require(std::string a, std::string v) const;
void _require(std::string a, std::string v) const;
/**
* This routine carries out a search for an XML node based
* on both the xml element name and the attribute ID.
* If exact matches are found for both fields, the pointer
* to the matching XML Node is returned.
*
* The ID attribute may be defaulted by setting it to "".
* In this case the pointer to the first xml element matching the name
* only is returned.
* @internal
* This algorithm does a lateral search of first generation children
* first before diving deeper into each tree branch.
*/
XML_Node* findNameID(const std::string &nameTarget,
const std::string &idTarget) const;
/**
* This routine carries out a search for an XML node based
* on both the xml element name and the attribute ID.
* If exact matches are found for both fields, the pointer
* to the matching XML Node is returned.
*
* The ID attribute may be defaulted by setting it to "".
* In this case the pointer to the first xml element matching the name
* only is returned.
* @internal
* This algorithm does a lateral search of first generation children
* first before diving deeper into each tree branch.
*/
XML_Node* findNameID(const std::string &nameTarget,
const std::string &idTarget) const;
XML_Node* findID(const std::string& id, int depth=100) const;
XML_Node* findByAttr(const std::string& attr, const std::string& val);
const XML_Node* findByName(const std::string& nm) const;
XML_Node* findByName(const std::string& nm);
void getChildren(std::string name, std::vector<XML_Node*>& children) const;
XML_Node& child(std::string loc) const;
void write(std::ostream& s, int level = 0) const;
XML_Node& root() const { return *m_root; }
void setRoot(XML_Node& root) { m_root = &root; }
void copyUnion(XML_Node *node_dest) const;
void copy(XML_Node *node_dest) const;
void lock() {m_locked = true;}
void unlock() {m_locked = false; }
XML_Node* findID(const std::string& id, int depth=100) const;
XML_Node* findByAttr(const std::string& attr, const std::string& val);
const XML_Node* findByName(const std::string& nm) const;
XML_Node* findByName(const std::string& nm);
void getChildren(std::string name, std::vector<XML_Node*>& children) const;
XML_Node& child(std::string loc) const;
void write(std::ostream& s, int level = 0) const;
XML_Node& root() const { return *m_root; }
void setRoot(XML_Node& root) { m_root = &root; }
void copyUnion(XML_Node *node_dest) const;
void copy(XML_Node *node_dest) const;
void lock() {m_locked = true;}
void unlock() {m_locked = false; }
private:
void write_int(std::ostream& s, int level = 0) const;
private:
void write_int(std::ostream& s, int level = 0) const;
protected:
protected:
//! XML node name of the node.
/*!
* For example, if we were in the XML_Node where
* <phase dim="3" id="gas">
* </phase>
* Then, this string would be equal to "phase". "dim" and "id"
* are attributes of the XML_Node.
*/
std::string m_name;
//! XML node name of the node.
/*!
* For example, if we were in the XML_Node where
* <phase dim="3" id="gas">
* </phase>
* Then, this string would be equal to "phase". "dim" and "id"
* are attributes of the XML_Node.
*/
std::string m_name;
//! Value of the xml node
/*!
* This is the string contents of the XML node. For
* example. The xml node named eps:
*
* <eps>
* valueString
* </eps>
*
* has a m_value string containing "valueString".
*/
std::string m_value;
std::map<std::string, XML_Node*> m_childindex;
std::map<std::string, std::string> m_attribs;
XML_Node* m_parent;
XML_Node* m_root;
bool m_locked;
std::vector<XML_Node*> m_children;
//! Value of the xml node
/*!
* This is the string contents of the XML node. For
* example. The xml node named eps:
*
* <eps>
* valueString
* </eps>
*
* has a m_value string containing "valueString".
*/
std::string m_value;
std::map<std::string, XML_Node*> m_childindex;
std::map<std::string, std::string> m_attribs;
XML_Node* m_parent;
XML_Node* m_root;
bool m_locked;
std::vector<XML_Node*> m_children;
//! Number of children of this node
int m_nchildren;
bool m_iscomment;
int m_linenum;
};
//! Number of children of this node
int m_nchildren;
bool m_iscomment;
int m_linenum;
};
XML_Node * findXMLPhase(XML_Node* root, const std::string &id);
XML_Node * findXMLPhase(XML_Node* root, const std::string &id);
}