[gnome-commander/gcmd-1-3] XML config: added C++ writer class
- From: Piotr Eljasiak <epiotr src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-commander/gcmd-1-3] XML config: added C++ writer class
- Date: Wed, 2 Sep 2009 17:22:56 +0000 (UTC)
commit 0c0d5009907fb54f767184d0bff20c59b2269bcb
Author: Piotr Eljasiak <epiotr src gnome org>
Date: Wed Sep 2 18:52:54 2009 +0200
XML config: added C++ writer class
src/gnome-cmd-xml-config.cc | 3 +
src/gnome-cmd-xml-config.h | 261 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 263 insertions(+), 1 deletions(-)
---
diff --git a/src/gnome-cmd-xml-config.cc b/src/gnome-cmd-xml-config.cc
index c51238a..b77c770 100644
--- a/src/gnome-cmd-xml-config.cc
+++ b/src/gnome-cmd-xml-config.cc
@@ -55,6 +55,9 @@
using namespace std;
+gchar *XML::xstream::escaped_text = NULL;
+
+
#if !GLIB_CHECK_VERSION (2, 16, 0)
typedef enum
{
diff --git a/src/gnome-cmd-xml-config.h b/src/gnome-cmd-xml-config.h
index 552a577..1bca524 100644
--- a/src/gnome-cmd-xml-config.h
+++ b/src/gnome-cmd-xml-config.h
@@ -18,10 +18,269 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+//////////////////////////////////////////////////////////////////////
+//
+// xmlparser.h: interface & implementation for the XMLStream class.
+//
+// Author: Oboltus, December 2003
+//
+// This code is provided "as is", with absolutely no warranty expressed
+// or implied. Any use is at your own risk.
+//
+//////////////////////////////////////////////////////////////////////
+
#ifndef __GNOME_CMD_XML_CONFIG_H__
#define __GNOME_CMD_XML_CONFIG_H__
-#include "gnome-cmd-data.h"
+#include <stack>
+#include <string>
+#include <sstream>
+
+namespace XML
+{
+ class xstream
+ {
+ public:
+
+ enum {versionMajor=1, versionMinor=0}; // XML version constants
+
+ struct Controller
+ {
+ enum what_type {whatTag, whatTagEnd, whatAttribute, whatCharData, whatComment};
+
+ what_type what;
+ std::string str;
+
+ Controller(const Controller &c) : what(c.what), str(c.str) {}
+ Controller(const what_type _what) : what(_what) {}
+
+ // use template constructor because string field <str> may be initialized from different sources: char*, std::string etc
+ template <typename T>
+ Controller(const what_type _what, const T &_str) : what(_what), str(_str) {}
+ };
+
+ // xstream refers std::ostream object to perform actual output operations
+ xstream(std::ostream &_s) : s(_s), state(stateNone)
+ {
+ s << "<?xml version=\"" << versionMajor << '.' << versionMinor << "\" encoding=\"UTF-8\"?>";
+ }
+
+ // Before destroying check whether all the open tags are closed
+ ~xstream()
+ {
+ if (state==stateTagName)
+ {
+ s << "/>";
+ state = stateNone;
+ }
+
+ while (tags.size())
+ endTag(tags.top().first);
+
+ g_free(escaped_text);
+ escaped_text = NULL;
+ }
+
+ // default behaviour - delegate object output to std::stream
+ template <typename T>
+ xstream &operator << (const T &value)
+ {
+ if (state==stateTagName)
+ tagName << value;
+ s << value;
+
+ return *this;
+ }
+
+ // this is the main working horse and it's long a little
+ xstream &operator << (const Controller &controller)
+ {
+ switch (controller.what)
+ {
+ case Controller::whatTag:
+ closeTagStart();
+ s << '\n' << tabs() << '<';
+ if (controller.str.empty())
+ {
+ clearTagName();
+ state = stateTagName;
+ }
+ else
+ {
+ s << controller.str;
+ tags.push(make_pair(controller.str,false));
+ state = stateTag;
+ }
+ break; // Controller::whatTag
+
+ case Controller::whatTagEnd:
+ endTag(controller.str);
+ break; // Controller::whatTagEnd
+
+ case Controller::whatAttribute:
+ switch (state)
+ {
+ case stateTagName:
+ tags.push(make_pair(tagName.str(),false));
+ break;
+
+ case stateAttribute:
+ s << '"';
+ break;
+
+ default:
+ break;
+ }
+
+ if (stateNone!=state)
+ {
+ s << ' ' << controller.str << "=\"";
+ state = stateAttribute;
+ }
+ // else throw some error - unexpected attribute (out of any tag)
+
+ break; // Controller::whatAttribute
+
+ case Controller::whatCharData:
+ closeTagStart();
+ tags.top().second = true;
+ state = stateNone;
+ break; // Controller::whatCharData
+
+ case Controller::whatComment:
+ s << "\n<!-- " << controller.str << " -->";
+ break; // Controller::whatComment
+ }
+
+ return *this;
+ }
+
+ private:
+
+ enum state_type {stateNone, stateTag, stateAttribute, stateTagName}; // state of the stream
+
+ typedef std::stack<std::pair<std::string, bool> > tag_stack_type; // tag name stack
+
+ std::ostream &s;
+ state_type state;
+ tag_stack_type tags;
+ std::ostringstream tagName;
+
+ static gchar *escaped_text;
+
+ const char *tabs(unsigned offset=0) const
+ {
+ static std::string tabs(32,'\t');
+
+ if (tabs.size() <= tags.size())
+ tabs.append(32,'\t');
+
+ return tabs.c_str() + tabs.size() - tags.size() + offset;
+ }
+
+ // I don't know any way easier (legal) to clear std::stringstream...
+ void clearTagName()
+ {
+ tagName.rdbuf()->str(std::string()); // FIXME: tagName.str(std::string()); ??
+ }
+
+ void closeTagStart(bool self_closed=false) // Close current tag
+ {
+ if (state==stateTagName)
+ tags.push(make_pair(tagName.str(),false));
+
+ switch (state) // note: absence of 'break's is not an error
+ {
+ case stateAttribute:
+ s << '"';
+
+ case stateTagName:
+ case stateTag:
+ if (self_closed)
+ s << "/>";
+ else
+ s << '>';
+
+ default:
+ break;
+ }
+ }
+
+ void endTag(const std::string &tag) // Close tag (may be with closing all of its children)
+ {
+ bool brk = false;
+
+ while (tags.size() && !brk)
+ {
+ if (state==stateNone)
+ {
+ if (!tags.top().second)
+ s << '\n' << tabs(1);
+ s << "</" << tags.top().first << '>';
+ }
+ else
+ {
+ closeTagStart(true);
+ state = stateNone;
+ }
+ brk = tag.empty() || tag==tags.top().first;
+ tags.pop();
+ }
+ }
+
+ friend const gchar *escape(const gchar *s);
+ friend const gchar *escape(const std::string &s);
+ };
+
+ inline const xstream::Controller tag()
+ {
+ return xstream::Controller(xstream::Controller::whatTag);
+ }
+
+ inline const xstream::Controller tag(const char *tag_name)
+ {
+ return xstream::Controller(xstream::Controller::whatTag, tag_name);
+ }
+
+ inline const xstream::Controller endtag()
+ {
+ return xstream::Controller(xstream::Controller::whatTagEnd);
+ }
+
+ inline const xstream::Controller endtag(const char *tag_name)
+ {
+ return xstream::Controller(xstream::Controller::whatTagEnd, tag_name);
+ }
+
+ inline const xstream::Controller attr(const char *attr_name)
+ {
+ return xstream::Controller(xstream::Controller::whatAttribute, attr_name);
+ }
+
+ inline const xstream::Controller chardata()
+ {
+ return xstream::Controller(xstream::Controller::whatCharData);
+ }
+
+ inline const xstream::Controller comment(const char *text)
+ {
+ return xstream::Controller(xstream::Controller::whatComment, text);
+ }
+
+ inline const gchar *escape(const gchar *s)
+ {
+ g_free (xstream::escaped_text);
+ xstream::escaped_text = g_markup_escape_text (s, -1);
+ return xstream::escaped_text;
+ }
+
+ inline const gchar *escape(const std::string &s)
+ {
+ return escape(s.c_str());
+ }
+}
+
+struct GnomeCmdData;
gboolean gnome_cmd_xml_config_parse (const gchar *xml, gsize xml_len, GnomeCmdData &cfg);
gboolean gnome_cmd_xml_config_load (const gchar *path, GnomeCmdData &cfg);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]