From 9479feb34459b0d1fcdaa6a6545827f3243cb513 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 00:46:15 +0200 Subject: [PATCH 01/16] Add structure test for C++0x. Passes. --- c++0x/Makefile | 3 +++ c++0x/structure.cpp | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 c++0x/structure.cpp diff --git a/c++0x/Makefile b/c++0x/Makefile index f79d37a..b2528df 100644 --- a/c++0x/Makefile +++ b/c++0x/Makefile @@ -20,3 +20,6 @@ namespace: namespace.o $(LIBS) namespace2: namespace2.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) + +structure: structure.o $(LIBS) + $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) diff --git a/c++0x/structure.cpp b/c++0x/structure.cpp new file mode 100644 index 0000000..2447feb --- /dev/null +++ b/c++0x/structure.cpp @@ -0,0 +1,19 @@ +#include + +#include "xml-template.h" + +using namespace std; + +int main(int argc, char **argv) +{ + Substitute master_directive = { + make_pair("#outer", new Clone { + new Substitute { make_pair("#inner", new Replace("One")) }, + new Substitute { make_pair("#inner", new Replace("Two")) }, + new Substitute { make_pair("#inner", new Replace("Three")) }, + }), + }; + + process_file("../xml/structure.xml", argv[1], &master_directive); + return(0); +} -- 2.39.5 From a87410331a3cf42444d92930a9a796a384278c8d Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 01:11:22 +0200 Subject: [PATCH 02/16] Add Alternate support to C++0x version, and corresponding attribute2 test. --- c++0x/Makefile | 3 +++ c++0x/attribute2.cpp | 21 +++++++++++++++++++++ c++0x/xml-template.cpp | 22 +++++++++++++++++++++- c++0x/xml-template.h | 15 +++++++++++++-- 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 c++0x/attribute2.cpp diff --git a/c++0x/Makefile b/c++0x/Makefile index b2528df..3f24295 100644 --- a/c++0x/Makefile +++ b/c++0x/Makefile @@ -15,6 +15,9 @@ clone: clone.o $(LIBS) attribute: attribute.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) +attribute2: attribute2.o $(LIBS) + $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) + namespace: namespace.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) diff --git a/c++0x/attribute2.cpp b/c++0x/attribute2.cpp new file mode 100644 index 0000000..94cf17d --- /dev/null +++ b/c++0x/attribute2.cpp @@ -0,0 +1,21 @@ +#include + +#include "xml-template.h" + +using namespace std; + +int main(int argc, char **argv) +{ + Substitute master_directive = { + make_pair("color", new Replace("blue")), + make_pair("#things", new Alternate { "li/class", { + new Substitute { make_pair("li", new Replace("Raindrops on roses")), }, + new Substitute { make_pair("li", new Replace("Whiskers on kittens")), }, + new Substitute { make_pair("li", new Replace("Bright copper kettles")), }, + new Substitute { make_pair("li", new Replace("Warm, woolen mittens")), }, + }, { "odd", "even" } }), + }; + + process_file("../xml/clone.xml", argv[1], &master_directive); + return(0); +} diff --git a/c++0x/xml-template.cpp b/c++0x/xml-template.cpp index fda97fc..9e19f09 100644 --- a/c++0x/xml-template.cpp +++ b/c++0x/xml-template.cpp @@ -49,7 +49,14 @@ string Replace::get_contents() { return str; } Clone::Clone(const vector &subdirectives) : subdirectives(subdirectives) {} - + +Clone::Clone(const vector &subdirectives_subs) +{ + for (auto it : subdirectives_subs) { + subdirectives.push_back(static_cast(it)); + } +} + Clone::Clone(initializer_list subdirectives) : subdirectives(subdirectives) {} @@ -89,6 +96,19 @@ void Clone::process(xmlNode *node, bool clean) clean_node(node); } } + +Alternate::Alternate(const string &attribute, + const vector &subdirectives_subs, + const vector &alternatives) + : Clone(subdirectives_subs) +{ + for (unsigned ix = 0; ix < subdirectives_subs.size(); ++ix) { + string value = alternatives[ix % alternatives.size()]; + subdirectives_subs[ix]->substitution_map.insert(make_pair( + attribute, + new Replace { value })); + } +} Substitute::Substitute(const unordered_map &substitution_map) : substitution_map(substitution_map) {} diff --git a/c++0x/xml-template.h b/c++0x/xml-template.h index 4728dbf..d29cbae 100644 --- a/c++0x/xml-template.h +++ b/c++0x/xml-template.h @@ -25,15 +25,18 @@ class Replace : public Directive { const std::string str; }; +class Substitute; + class Clone : public Directive { public: Clone(const std::vector &subdirectives); + Clone(const std::vector &subdirectives); Clone(std::initializer_list subdirectives); ~Clone(); virtual void process(xmlNode *node, bool clean); private: - const std::vector subdirectives; + std::vector subdirectives; }; class Substitute : public Directive { @@ -45,7 +48,15 @@ class Substitute : public Directive { virtual void process(xmlNode *node, bool clean); private: - const std::unordered_map substitution_map; + friend class Alternate; + std::unordered_map substitution_map; +}; + +class Alternate : public Clone { + public: + Alternate(const std::string &attribute, + const std::vector &subdirectives_subs, + const std::vector &alternatives); }; void process_file(const std::string &input_filename, -- 2.39.5 From 62c782c572e33a1f03f57a71f63309165da47e73 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 01:24:40 +0200 Subject: [PATCH 03/16] Make Clone and Alternate in C++0x handle embedded NULL values (kind of pointless in C++, but it is good to have equivalent semantics everywhere). Add attribute3 test, which then passes. --- c++0x/Makefile | 3 +++ c++0x/attribute3.cpp | 22 ++++++++++++++++++++++ c++0x/xml-template.cpp | 9 ++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 c++0x/attribute3.cpp diff --git a/c++0x/Makefile b/c++0x/Makefile index 3f24295..837cb06 100644 --- a/c++0x/Makefile +++ b/c++0x/Makefile @@ -18,6 +18,9 @@ attribute: attribute.o $(LIBS) attribute2: attribute2.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) +attribute3: attribute3.o $(LIBS) + $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) + namespace: namespace.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) diff --git a/c++0x/attribute3.cpp b/c++0x/attribute3.cpp new file mode 100644 index 0000000..a3f8b6e --- /dev/null +++ b/c++0x/attribute3.cpp @@ -0,0 +1,22 @@ +#include + +#include "xml-template.h" + +using namespace std; + +int main(int argc, char **argv) +{ + Substitute master_directive = { + make_pair("color", new Replace("blue")), + make_pair("#things", new Alternate { "li/class", { + new Substitute { make_pair("li", new Replace("Raindrops on roses")), }, + new Substitute { make_pair("li", new Replace("Whiskers on kittens")), }, + NULL, + new Substitute { make_pair("li", new Replace("Bright copper kettles")), }, + new Substitute { make_pair("li", new Replace("Warm, woolen mittens")), }, + }, { "odd", "even" } }), + }; + + process_file("../xml/clone.xml", argv[1], &master_directive); + return(0); +} diff --git a/c++0x/xml-template.cpp b/c++0x/xml-template.cpp index 9e19f09..30e5a7e 100644 --- a/c++0x/xml-template.cpp +++ b/c++0x/xml-template.cpp @@ -74,6 +74,9 @@ void Clone::process(xmlNode *node, bool clean) vector new_nodes; for (auto it : subdirectives) { + if (it == NULL) { + continue; + } xmlNode *new_node; xmlDOMWrapCloneNode(NULL, node->doc, node, &new_node, node->doc, NULL, 1, 0); it->process(new_node, clean); @@ -102,8 +105,12 @@ Alternate::Alternate(const string &attribute, const vector &alternatives) : Clone(subdirectives_subs) { + unsigned jx = 0; for (unsigned ix = 0; ix < subdirectives_subs.size(); ++ix) { - string value = alternatives[ix % alternatives.size()]; + if (subdirectives_subs[ix] == NULL) { + continue; + } + string value = alternatives[jx++ % alternatives.size()]; subdirectives_subs[ix]->substitution_map.insert(make_pair( attribute, new Replace { value })); -- 2.39.5 From d9fe760eebc1e40789f2fd769dcba74e3b0dbcbb Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 01:25:53 +0200 Subject: [PATCH 04/16] Add attribute-empty test for C++0x, which passes. --- c++0x/Makefile | 3 +++ c++0x/attribute-empty.cpp | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 c++0x/attribute-empty.cpp diff --git a/c++0x/Makefile b/c++0x/Makefile index 837cb06..79c4024 100644 --- a/c++0x/Makefile +++ b/c++0x/Makefile @@ -21,6 +21,9 @@ attribute2: attribute2.o $(LIBS) attribute3: attribute3.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) +attribute-empty: attribute-empty.o $(LIBS) + $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) + namespace: namespace.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) diff --git a/c++0x/attribute-empty.cpp b/c++0x/attribute-empty.cpp new file mode 100644 index 0000000..b79836b --- /dev/null +++ b/c++0x/attribute-empty.cpp @@ -0,0 +1,16 @@ +#include + +#include "xml-template.h" + +using namespace std; + +int main(int argc, char **argv) +{ + Substitute master_directive = { + make_pair("color", new Replace("blue")), + make_pair("#things", new Clone { }), + }; + + process_file("../xml/clone.xml", argv[1], &master_directive); + return(0); +} -- 2.39.5 From ad45bc892752571fec46b21564e4683c074f1d46 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 01:43:38 +0200 Subject: [PATCH 05/16] Tweak C++0x API a bit, to prepare for include. Also, output to stdout instead of ugly temporary files. --- c++0x/attribute-empty.cpp | 3 ++- c++0x/attribute.cpp | 3 ++- c++0x/attribute2.cpp | 3 ++- c++0x/attribute3.cpp | 3 ++- c++0x/clone.cpp | 3 ++- c++0x/namespace.cpp | 3 ++- c++0x/namespace2.cpp | 3 ++- c++0x/passthru.cpp | 3 ++- c++0x/simple.cpp | 3 ++- c++0x/structure.cpp | 3 ++- c++0x/xml-template.cpp | 16 ++++++++++------ c++0x/xml-template.h | 7 ++++--- tests/test.sh | 2 +- 13 files changed, 35 insertions(+), 20 deletions(-) diff --git a/c++0x/attribute-empty.cpp b/c++0x/attribute-empty.cpp index b79836b..96c587d 100644 --- a/c++0x/attribute-empty.cpp +++ b/c++0x/attribute-empty.cpp @@ -11,6 +11,7 @@ int main(int argc, char **argv) make_pair("#things", new Clone { }), }; - process_file("../xml/clone.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/clone.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/attribute.cpp b/c++0x/attribute.cpp index 6c341bd..e651323 100644 --- a/c++0x/attribute.cpp +++ b/c++0x/attribute.cpp @@ -28,6 +28,7 @@ int main(int argc, char **argv) }), }; - process_file("../xml/clone.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/clone.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/attribute2.cpp b/c++0x/attribute2.cpp index 94cf17d..478dd51 100644 --- a/c++0x/attribute2.cpp +++ b/c++0x/attribute2.cpp @@ -16,6 +16,7 @@ int main(int argc, char **argv) }, { "odd", "even" } }), }; - process_file("../xml/clone.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/clone.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/attribute3.cpp b/c++0x/attribute3.cpp index a3f8b6e..d2746e8 100644 --- a/c++0x/attribute3.cpp +++ b/c++0x/attribute3.cpp @@ -17,6 +17,7 @@ int main(int argc, char **argv) }, { "odd", "even" } }), }; - process_file("../xml/clone.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/clone.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/clone.cpp b/c++0x/clone.cpp index 81b6d11..6911a7d 100644 --- a/c++0x/clone.cpp +++ b/c++0x/clone.cpp @@ -16,6 +16,7 @@ int main(int argc, char **argv) }), }; - process_file("../xml/clone.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/clone.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/namespace.cpp b/c++0x/namespace.cpp index 7298576..3399957 100644 --- a/c++0x/namespace.cpp +++ b/c++0x/namespace.cpp @@ -14,6 +14,7 @@ int main(int argc, char **argv) make_pair("#moretest", new Replace("bar")), }; - process_file("../xml/namespace.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/namespace.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/namespace2.cpp b/c++0x/namespace2.cpp index 2b438d3..060eb0e 100644 --- a/c++0x/namespace2.cpp +++ b/c++0x/namespace2.cpp @@ -11,6 +11,7 @@ int main(int argc, char **argv) make_pair("#hello", new Replace("Replaced.")), }; - process_file("../xml/namespace2.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/namespace2.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/passthru.cpp b/c++0x/passthru.cpp index f4fc636..28cc2f4 100644 --- a/c++0x/passthru.cpp +++ b/c++0x/passthru.cpp @@ -9,6 +9,7 @@ using namespace std; int main(int argc, char **argv) { Substitute master_directive = {}; - process_file("../xml/passthru.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/passthru.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/simple.cpp b/c++0x/simple.cpp index 5ac223d..0c89542 100644 --- a/c++0x/simple.cpp +++ b/c++0x/simple.cpp @@ -11,6 +11,7 @@ int main(int argc, char **argv) make_pair("#hello", new Replace("Hello world!")), }; - process_file("../xml/simple.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/simple.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/structure.cpp b/c++0x/structure.cpp index 2447feb..facaade 100644 --- a/c++0x/structure.cpp +++ b/c++0x/structure.cpp @@ -14,6 +14,7 @@ int main(int argc, char **argv) }), }; - process_file("../xml/structure.xml", argv[1], &master_directive); + xmlDocPtr doc = process_file("../xml/structure.xml", &master_directive); + output_to_fd_and_free(doc, 1); return(0); } diff --git a/c++0x/xml-template.cpp b/c++0x/xml-template.cpp index 30e5a7e..e8fc0ed 100644 --- a/c++0x/xml-template.cpp +++ b/c++0x/xml-template.cpp @@ -196,17 +196,21 @@ void Substitute::process(xmlNode *node, bool clean) } } -void process_file(const string &input_filename, - const string &output_filename, - Directive *root_directive) +xmlDocPtr process_file(const string &input_filename, + Directive *root_directive) { LIBXML_TEST_VERSION xmlDocPtr doc = xmlParseFile(input_filename.c_str()); root_directive->process(xmlDocGetRootElement(doc), true); - xmlSaveFile(output_filename.c_str(), doc); - xmlFreeDoc(doc); - xmlCleanupParser(); xmlMemoryDump(); + return doc; +} + +void output_to_fd_and_free(xmlDocPtr doc, int fd) +{ + xmlOutputBufferPtr buf = xmlOutputBufferCreateFd(fd, NULL); + xmlSaveFileTo(buf, doc, NULL); + xmlFreeDoc(doc); } diff --git a/c++0x/xml-template.h b/c++0x/xml-template.h index d29cbae..3567186 100644 --- a/c++0x/xml-template.h +++ b/c++0x/xml-template.h @@ -59,8 +59,9 @@ class Alternate : public Clone { const std::vector &alternatives); }; -void process_file(const std::string &input_filename, - const std::string &output_filename, - Directive *root_directive); +xmlDocPtr process_file(const std::string &input_filename, + Directive *root_directive); + +void output_to_fd_and_free(xmlDocPtr doc, int fd); #endif // !defined(_XML_TEMPLATE_H) diff --git a/tests/test.sh b/tests/test.sh index 43ccadc..600f095 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -31,7 +31,7 @@ for L in $LANGUAGES; do ruby -I../ruby ../ruby/$T.rb > $TEMPFILE fi if [ "$L" = "c++0x" ]; then - ( cd ../c++0x && make -s $T ) && ../c++0x/$T $TEMPFILE + ( cd ../c++0x && make -s $T ) && ../c++0x/$T > $TEMPFILE fi perl ./xml-diff.pl $TEMPFILE reference/$T.xml -- 2.39.5 From 6d6f69fcdf45c3afc82212c5c3d8085c93ec4717 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 02:11:43 +0200 Subject: [PATCH 06/16] Add include support, and unit test, to C++0x version. All unit tests pass! --- c++0x/Makefile | 3 +++ c++0x/include.cpp | 23 +++++++++++++++++++++++ c++0x/xml-template.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- c++0x/xml-template.h | 15 ++++++++++++++- 4 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 c++0x/include.cpp diff --git a/c++0x/Makefile b/c++0x/Makefile index 79c4024..9c7cef9 100644 --- a/c++0x/Makefile +++ b/c++0x/Makefile @@ -12,6 +12,9 @@ simple: simple.o $(LIBS) clone: clone.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) +include: include.o $(LIBS) + $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) + attribute: attribute.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) diff --git a/c++0x/include.cpp b/c++0x/include.cpp new file mode 100644 index 0000000..546be7b --- /dev/null +++ b/c++0x/include.cpp @@ -0,0 +1,23 @@ +#include + +#include "xml-template.h" + +using namespace std; + +int main(int argc, char **argv) +{ + Substitute doc_directive = { + make_pair("color", new Replace("red")), + }; + xmlDocPtr doc = process_file("../xml/included.xml", &doc_directive, false); + + Substitute master_directive = { + make_pair("title", new Replace("Main HTML title")), + make_pair("h1", new Replace("Nice heading here")), + make_pair("contents", new ReplaceInclude(doc)), + }; + + xmlDocPtr master = process_file("../xml/master.xml", &master_directive); + output_to_fd_and_free(master, 1); + return(0); +} diff --git a/c++0x/xml-template.cpp b/c++0x/xml-template.cpp index e8fc0ed..5bbcb9b 100644 --- a/c++0x/xml-template.cpp +++ b/c++0x/xml-template.cpp @@ -12,7 +12,8 @@ void clean_node(xmlNode *node) if (node->type != XML_ELEMENT_NODE) { return; } - if (strcmp(reinterpret_cast(node->ns->href), "http://template.sesse.net/") == 0) { + if (node->ns != NULL && + strcmp(reinterpret_cast(node->ns->href), "http://template.sesse.net/") == 0) { xmlNode *frag = xmlNewDocFragment(node->doc); xmlReplaceNode(node, frag); frag->children = node->children; @@ -47,6 +48,39 @@ void Replace::process(xmlNode *node, bool clean) { string Replace::get_contents() { return str; } +ReplaceInclude::ReplaceInclude(xmlNodePtr included_node) + : included_node(included_node), + included_doc(NULL) {} + +ReplaceInclude::ReplaceInclude(xmlDocPtr included_doc) + : included_node(xmlDocGetRootElement(included_doc)), + included_doc(included_doc) {} + +ReplaceInclude::~ReplaceInclude() +{ + if (included_doc != NULL) { + xmlFreeDoc(included_doc); + } else { + xmlFreeNode(included_node); + } +} + +void ReplaceInclude::process(xmlNode *node, bool clean) { + xmlFreeNodeList(node->children); + node->content = NULL; + node->children = node->last = NULL; + + xmlNode *new_node; + xmlDOMWrapCloneNode(NULL, NULL, included_node, &new_node, node->doc, node, 1, 0); + xmlAddChild(node, new_node); + + if (clean) { + Substitute dummy_subs {}; + dummy_subs.process(new_node, clean); + clean_node(node); + } +} + Clone::Clone(const vector &subdirectives) : subdirectives(subdirectives) {} @@ -197,12 +231,13 @@ void Substitute::process(xmlNode *node, bool clean) } xmlDocPtr process_file(const string &input_filename, - Directive *root_directive) + Directive *root_directive, + bool clean) { LIBXML_TEST_VERSION xmlDocPtr doc = xmlParseFile(input_filename.c_str()); - root_directive->process(xmlDocGetRootElement(doc), true); + root_directive->process(xmlDocGetRootElement(doc), clean); xmlCleanupParser(); xmlMemoryDump(); return doc; diff --git a/c++0x/xml-template.h b/c++0x/xml-template.h index 3567186..7cfa0d8 100644 --- a/c++0x/xml-template.h +++ b/c++0x/xml-template.h @@ -25,6 +25,18 @@ class Replace : public Directive { const std::string str; }; +class ReplaceInclude : public Directive { + public: + ReplaceInclude(xmlNodePtr included_node); + ReplaceInclude(xmlDocPtr included_doc); + ~ReplaceInclude(); + virtual void process(xmlNode *node, bool clean); + + private: + xmlNodePtr included_node; + xmlDocPtr included_doc; +}; + class Substitute; class Clone : public Directive { @@ -60,7 +72,8 @@ class Alternate : public Clone { }; xmlDocPtr process_file(const std::string &input_filename, - Directive *root_directive); + Directive *root_directive, + bool clean = true); void output_to_fd_and_free(xmlDocPtr doc, int fd); -- 2.39.5 From 052b584d7b60fd9be246d3fcf8bdefdead60d35c Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 02:13:08 +0200 Subject: [PATCH 07/16] Add all and clean targets to C++0x makefile. --- c++0x/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/c++0x/Makefile b/c++0x/Makefile index 9c7cef9..bc6b07f 100644 --- a/c++0x/Makefile +++ b/c++0x/Makefile @@ -3,6 +3,14 @@ CXXFLAGS=-std=gnu++0x -g -Wall $(shell xml2-config --cflags) LDFLAGS=$(shell xml2-config --libs) LIBS=xml-template.o +BINS=passthru simple clone include attribute attribute2 attribute3 attribute-empty namespace namespace2 structure +OBJS=passthru.o simple.o clone.o include.o attribute.o attribute2.o attribute3.o attribute-empty.o namespace.o namespace2.o structure.o xml-template.o + +all: $(BINS) + +clean: + $(RM) $(BINS) $(OBJS) + passthru: passthru.o $(LIBS) $(CXX) -o $@ $< $(LIBS) $(LDFLAGS) -- 2.39.5 From cc0c274ab48363f5a590bcd1b283d7aec01aeae7 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 02:14:48 +0200 Subject: [PATCH 08/16] Fix a Valgrind hit; we cannot take c_str() of a temporary object. --- c++0x/xml-template.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c++0x/xml-template.cpp b/c++0x/xml-template.cpp index 5bbcb9b..317a561 100644 --- a/c++0x/xml-template.cpp +++ b/c++0x/xml-template.cpp @@ -196,13 +196,13 @@ void Substitute::process(xmlNode *node, bool clean) // Attribute substitution. if (begins_with(it.first, tag + "/")) { const xmlChar *attr_key = reinterpret_cast( - it.first.substr(tag.size() + 1).c_str()); + it.first.c_str() + tag.size() + 1); const xmlChar *attr_value = reinterpret_cast( it.second->get_contents().c_str()); xmlSetProp(child, attr_key, attr_value); } else if ((!id.empty() && begins_with(it.first, "#" + id + "/"))) { const xmlChar *attr_key = reinterpret_cast( - it.first.substr(tag.size() + 2).c_str()); + it.first.c_str() + tag.size() + 2); const xmlChar *attr_value = reinterpret_cast( it.second->get_contents().c_str()); xmlSetProp(child, attr_key, attr_value); -- 2.39.5 From dd670f1b631ffb9531f7c58ed6410d8c043b03d6 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 02:16:37 +0200 Subject: [PATCH 09/16] Document that we have a C++0x version. --- doc/intro.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/intro.txt b/doc/intro.txt index 218c754..b727bff 100644 --- a/doc/intro.txt +++ b/doc/intro.txt @@ -17,8 +17,8 @@ to check out the code and this documentation. There is a lot to be said about design philosophy, but let's first give a simple example to give you the feel of how it works. (The example is in Perl, -but there are also functionally equivalent PHP, Python and Ruby versions; -ports to other languages would be welcome.) +but there are also functionally equivalent PHP, Python, Ruby and C++11 +versions; ports to other languages would be welcome.) Template (simple.xml): @@ -255,8 +255,8 @@ The main thoughts behind XML::Template have been, in no particular order: the entire DOM with wrappers for each language. (Thankfully, by relying on the DOM support in each language, the code so far is under 200 lines per implementation, so maintaining this hopefully shouldn't be much work.) As - proof-of-concept, there are got Perl, PHP, Python and Ruby implementations - that work and feel largely the same (and even a SAX-based Perl + proof-of-concept, there are got Perl, PHP, Python, Ruby and C++11 + implementations that work and feel largely the same (and even a SAX-based Perl implementation, for larger trees that won't fit into memory) -- other implementations are welcome. This is backed up by a test suite, which ensures that all the different implementations return structurally -- 2.39.5 From 9673065348fb768fd794926406236263e3ed875c Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 02:17:20 +0200 Subject: [PATCH 10/16] Rename C++0x port to C++11, since that will be the official name. --- {c++0x => c++11}/Makefile | 0 {c++0x => c++11}/attribute-empty.cpp | 0 {c++0x => c++11}/attribute.cpp | 0 {c++0x => c++11}/attribute2.cpp | 0 {c++0x => c++11}/attribute3.cpp | 0 {c++0x => c++11}/clone.cpp | 0 {c++0x => c++11}/include.cpp | 0 {c++0x => c++11}/namespace.cpp | 0 {c++0x => c++11}/namespace2.cpp | 0 {c++0x => c++11}/passthru.cpp | 0 {c++0x => c++11}/simple.cpp | 0 {c++0x => c++11}/structure.cpp | 0 {c++0x => c++11}/xml-template.cpp | 0 {c++0x => c++11}/xml-template.h | 0 tests/test.sh | 6 +++--- 15 files changed, 3 insertions(+), 3 deletions(-) rename {c++0x => c++11}/Makefile (100%) rename {c++0x => c++11}/attribute-empty.cpp (100%) rename {c++0x => c++11}/attribute.cpp (100%) rename {c++0x => c++11}/attribute2.cpp (100%) rename {c++0x => c++11}/attribute3.cpp (100%) rename {c++0x => c++11}/clone.cpp (100%) rename {c++0x => c++11}/include.cpp (100%) rename {c++0x => c++11}/namespace.cpp (100%) rename {c++0x => c++11}/namespace2.cpp (100%) rename {c++0x => c++11}/passthru.cpp (100%) rename {c++0x => c++11}/simple.cpp (100%) rename {c++0x => c++11}/structure.cpp (100%) rename {c++0x => c++11}/xml-template.cpp (100%) rename {c++0x => c++11}/xml-template.h (100%) diff --git a/c++0x/Makefile b/c++11/Makefile similarity index 100% rename from c++0x/Makefile rename to c++11/Makefile diff --git a/c++0x/attribute-empty.cpp b/c++11/attribute-empty.cpp similarity index 100% rename from c++0x/attribute-empty.cpp rename to c++11/attribute-empty.cpp diff --git a/c++0x/attribute.cpp b/c++11/attribute.cpp similarity index 100% rename from c++0x/attribute.cpp rename to c++11/attribute.cpp diff --git a/c++0x/attribute2.cpp b/c++11/attribute2.cpp similarity index 100% rename from c++0x/attribute2.cpp rename to c++11/attribute2.cpp diff --git a/c++0x/attribute3.cpp b/c++11/attribute3.cpp similarity index 100% rename from c++0x/attribute3.cpp rename to c++11/attribute3.cpp diff --git a/c++0x/clone.cpp b/c++11/clone.cpp similarity index 100% rename from c++0x/clone.cpp rename to c++11/clone.cpp diff --git a/c++0x/include.cpp b/c++11/include.cpp similarity index 100% rename from c++0x/include.cpp rename to c++11/include.cpp diff --git a/c++0x/namespace.cpp b/c++11/namespace.cpp similarity index 100% rename from c++0x/namespace.cpp rename to c++11/namespace.cpp diff --git a/c++0x/namespace2.cpp b/c++11/namespace2.cpp similarity index 100% rename from c++0x/namespace2.cpp rename to c++11/namespace2.cpp diff --git a/c++0x/passthru.cpp b/c++11/passthru.cpp similarity index 100% rename from c++0x/passthru.cpp rename to c++11/passthru.cpp diff --git a/c++0x/simple.cpp b/c++11/simple.cpp similarity index 100% rename from c++0x/simple.cpp rename to c++11/simple.cpp diff --git a/c++0x/structure.cpp b/c++11/structure.cpp similarity index 100% rename from c++0x/structure.cpp rename to c++11/structure.cpp diff --git a/c++0x/xml-template.cpp b/c++11/xml-template.cpp similarity index 100% rename from c++0x/xml-template.cpp rename to c++11/xml-template.cpp diff --git a/c++0x/xml-template.h b/c++11/xml-template.h similarity index 100% rename from c++0x/xml-template.h rename to c++11/xml-template.h diff --git a/tests/test.sh b/tests/test.sh index 600f095..ba04ecd 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -4,7 +4,7 @@ if [ -z "$TESTS" ]; then TESTS="passthru simple clone include attribute attribute2 attribute3 attribute-empty namespace namespace2 structure" fi if [ -z "$LANGUAGES" ]; then - LANGUAGES="perl perl-sax php4 php5 python ruby c++0x" + LANGUAGES="perl perl-sax php4 php5 python ruby c++11" fi for L in $LANGUAGES; do @@ -30,8 +30,8 @@ for L in $LANGUAGES; do if [ "$L" = "ruby" ]; then ruby -I../ruby ../ruby/$T.rb > $TEMPFILE fi - if [ "$L" = "c++0x" ]; then - ( cd ../c++0x && make -s $T ) && ../c++0x/$T > $TEMPFILE + if [ "$L" = "c++11" ]; then + ( cd ../c++11 && make -s $T ) && ../c++11/$T > $TEMPFILE fi perl ./xml-diff.pl $TEMPFILE reference/$T.xml -- 2.39.5 From 0ccbc5e506ee3ed6bcc77bc4d6cdbde9791e8ad5 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 22:42:28 +0200 Subject: [PATCH 11/16] Start a PHP5-to-C++11 SWIG layer (!). --- php5-swig/Makefile | 15 ++++++++ php5-swig/simple.php | 11 ++++++ php5-swig/xml-template.swig | 73 +++++++++++++++++++++++++++++++++++++ tests/test.sh | 3 ++ 4 files changed, 102 insertions(+) create mode 100644 php5-swig/Makefile create mode 100644 php5-swig/simple.php create mode 100644 php5-swig/xml-template.swig diff --git a/php5-swig/Makefile b/php5-swig/Makefile new file mode 100644 index 0000000..de44312 --- /dev/null +++ b/php5-swig/Makefile @@ -0,0 +1,15 @@ +CPPFLAGS=$(shell php-config --includes) +CXXFLAGS=-std=gnu++0x $(shell xml2-config --cflags) -fPIC -g +LDFLAGS=-shared +LIBS=../c++11/xml-template.o + +XML_Template_SWIG.so: xml-template_wrap.o + $(CXX) $(LDFLAGS) -o $@ $< $(LIBS) + +xml-template_wrap.cpp XML_Template_SWIG.php php_XML_Template_SWIG.h : xml-template.swig + swig -c++ -php $< + +clean: + $(RM) XML_Template_SWIG.so xml-template_wrap.o + $(RM) xml-template_wrap.cpp XML_Template_SWIG.php php_XML_Template_SWIG.h + diff --git a/php5-swig/simple.php b/php5-swig/simple.php new file mode 100644 index 0000000..44cbd2f --- /dev/null +++ b/php5-swig/simple.php @@ -0,0 +1,11 @@ + 'A very basic example', + '#hello' => 'Hello world!' +), true); +output_to_fd_and_free($doc, 1); + +?> + diff --git a/php5-swig/xml-template.swig b/php5-swig/xml-template.swig new file mode 100644 index 0000000..5a560ce --- /dev/null +++ b/php5-swig/xml-template.swig @@ -0,0 +1,73 @@ +%module XML_Template_SWIG + +%{ + +#include "../c++11/xml-template.h" + +bool is_associative_array(HashTable *ht) +{ + if (ht->nNumOfElements == 0) { + return true; + } + for (unsigned i = 0; i < ht->nNumOfElements; ++i) { + char buf[32]; + sprintf(buf, "%u", i); + if (!zend_hash_exists(ht, buf, strlen(buf))) { + return true; + } + } + return false; +} + +Directive* convert_php_objects_to_directive(zval *obj) +{ + switch (Z_TYPE_P(obj)) { + case IS_ARRAY: { + HashTable *ht = Z_ARRVAL_P(obj); + if (is_associative_array(ht)) { + std::unordered_map my_map; + for (zend_hash_internal_pointer_reset(ht); zend_hash_has_more_elements(ht) == SUCCESS; zend_hash_move_forward(ht)) { + char *str_key; + ulong num_key; + zend_hash_get_current_key(ht, &str_key, &num_key, 0); + + std::string key; + if (zend_hash_get_current_key_type(ht) == HASH_KEY_IS_STRING) { + key = str_key; + } else { + char buf[32]; + sprintf(buf, "%lu", num_key); + key = buf; + } + + zval **data; + zend_hash_get_current_data(ht, (void **)&data); + my_map.insert(make_pair(key, convert_php_objects_to_directive(*data))); + } + return new Substitute(my_map); + } else { + printf("ARRAY\n"); + } + break; + } + case IS_STRING: { + char *str = Z_STRVAL_P(obj); + return new Replace(str); + } + default: + printf("WARNING: Unknown type %d!\n", Z_TYPE_P(obj)); + break; + } + + return NULL; +} + +%} + +%typemap(in) Directive* { + $1 = convert_php_objects_to_directive(*$input); +} + +xmlDocPtr process_file(const char *input_filename, Directive *root_directive, bool clean); +void output_to_fd_and_free(xmlDocPtr doc, int fd); + diff --git a/tests/test.sh b/tests/test.sh index ba04ecd..cb118be 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -24,6 +24,9 @@ for L in $LANGUAGES; do if [ "$L" = "php5" ]; then php5-cgi -q ../php5/$T.php > $TEMPFILE fi + if [ "$L" = "php5-swig" ]; then + ( cd ../c++11 && make -s && cd ../php5-swig && make -s && sudo cp XML_Template_SWIG.so /usr/lib/php5/20090626+lfs ) && php5-cgi -q ../php5-swig/$T.php > $TEMPFILE + fi if [ "$L" = "python" ]; then python ../python/$T.py > $TEMPFILE fi -- 2.39.5 From 9e9959b8065386c5f0adc57faa0a1eaeda0a2928 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 22:44:30 +0200 Subject: [PATCH 12/16] Add passthru test to PHP5-SWIG (passes). --- php5-swig/passthru.php | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 php5-swig/passthru.php diff --git a/php5-swig/passthru.php b/php5-swig/passthru.php new file mode 100644 index 0000000..8102a38 --- /dev/null +++ b/php5-swig/passthru.php @@ -0,0 +1,8 @@ + + -- 2.39.5 From dc9c34267800f553307ee41acf40cb14929385ba Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 22:59:32 +0200 Subject: [PATCH 13/16] Add clone test for php5-swig. Fails. --- php5-swig/clone.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 php5-swig/clone.php diff --git a/php5-swig/clone.php b/php5-swig/clone.php new file mode 100644 index 0000000..abe0e30 --- /dev/null +++ b/php5-swig/clone.php @@ -0,0 +1,16 @@ + 'blue', + '#things' => array( + array( 'li' => 'Raindrops on roses' ), + array( 'li' => 'Whiskers on kittens' ), + array( 'li' => 'Bright copper kettles' ), + array( 'li' => 'Warm, woolen mittens' ) + ) +), true); +output_to_fd_and_free($doc, 1); + +?> + -- 2.39.5 From b6bae3e8cf33edf6bbedcf6d3266e581d06507af Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 23:03:46 +0200 Subject: [PATCH 14/16] Fix is_associative_array() in php5-swig. --- php5-swig/xml-template.swig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/php5-swig/xml-template.swig b/php5-swig/xml-template.swig index 5a560ce..d395ac2 100644 --- a/php5-swig/xml-template.swig +++ b/php5-swig/xml-template.swig @@ -10,9 +10,7 @@ bool is_associative_array(HashTable *ht) return true; } for (unsigned i = 0; i < ht->nNumOfElements; ++i) { - char buf[32]; - sprintf(buf, "%u", i); - if (!zend_hash_exists(ht, buf, strlen(buf))) { + if (!zend_hash_index_exists(ht, i)) { return true; } } -- 2.39.5 From 015976d7d24ac1ae6deb474b9d70e5703f54f449 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 23:05:49 +0200 Subject: [PATCH 15/16] Implement cloning in php5-swig. --- php5-swig/xml-template.swig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/php5-swig/xml-template.swig b/php5-swig/xml-template.swig index d395ac2..fa9e7aa 100644 --- a/php5-swig/xml-template.swig +++ b/php5-swig/xml-template.swig @@ -44,7 +44,13 @@ Directive* convert_php_objects_to_directive(zval *obj) } return new Substitute(my_map); } else { - printf("ARRAY\n"); + std::vector subdirectives; + for (unsigned i = 0; i < ht->nNumOfElements; ++i) { + zval **data; + zend_hash_index_find(ht, i, (void **)&data); + subdirectives.push_back(convert_php_objects_to_directive(*data)); + } + return new Clone(subdirectives); } break; } -- 2.39.5 From 933565bfd7b14e26bf9dbc2afc7271e28ec34398 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Thu, 22 Sep 2011 23:11:12 +0200 Subject: [PATCH 16/16] Add most of the remaining php5-swig tests. Most succeed, but not all. --- php5-swig/attribute-empty.php | 13 +++++++++++++ php5-swig/attribute.php | 14 ++++++++++++++ php5-swig/attribute2.php | 14 ++++++++++++++ php5-swig/attribute3.php | 15 +++++++++++++++ php5-swig/include.php | 13 +++++++++++++ php5-swig/namespace.php | 12 ++++++++++++ php5-swig/namespace2.php | 9 +++++++++ php5-swig/structure.php | 12 ++++++++++++ 8 files changed, 102 insertions(+) create mode 100644 php5-swig/attribute-empty.php create mode 100644 php5-swig/attribute.php create mode 100644 php5-swig/attribute2.php create mode 100644 php5-swig/attribute3.php create mode 100644 php5-swig/include.php create mode 100644 php5-swig/namespace.php create mode 100644 php5-swig/namespace2.php create mode 100644 php5-swig/structure.php diff --git a/php5-swig/attribute-empty.php b/php5-swig/attribute-empty.php new file mode 100644 index 0000000..5a33f63 --- /dev/null +++ b/php5-swig/attribute-empty.php @@ -0,0 +1,13 @@ + 'blue', + '#things' => array(NULL) +), true); +output_to_fd_and_free($doc, 1); +?> diff --git a/php5-swig/attribute.php b/php5-swig/attribute.php new file mode 100644 index 0000000..fa5a0df --- /dev/null +++ b/php5-swig/attribute.php @@ -0,0 +1,14 @@ + 'red', + '#things' => array( + array( 'li' => 'Raindrops on roses', 'li/class' => 'odd' ), + array( 'li' => 'Whiskers on kittens', 'li/class' => 'even' ), + array( 'li' => 'Bright copper kettles', 'li/class' => 'odd' ), + array( 'li' => 'Warm, woolen mittens', 'li/class' => 'even' ) + ) +), true); +output_to_fd_and_free($doc, 1); +?> diff --git a/php5-swig/attribute2.php b/php5-swig/attribute2.php new file mode 100644 index 0000000..adcad31 --- /dev/null +++ b/php5-swig/attribute2.php @@ -0,0 +1,14 @@ + 'blue', + '#things' => XML_Template_alternate('li/class', array( + array( 'li' => 'Raindrops on roses' ), + array( 'li' => 'Whiskers on kittens' ), + array( 'li' => 'Bright copper kettles' ), + array( 'li' => 'Warm, woolen mittens' ), + ), array('odd', 'even')) +), true); +output_to_fd_and_free($doc, 1); +?> diff --git a/php5-swig/attribute3.php b/php5-swig/attribute3.php new file mode 100644 index 0000000..8b84e7d --- /dev/null +++ b/php5-swig/attribute3.php @@ -0,0 +1,15 @@ + 'blue', + '#things' => XML_Template_alternate('li/class', array( + array( 'li' => 'Raindrops on roses' ), + array( 'li' => 'Whiskers on kittens' ), + NULL, + array( 'li' => 'Bright copper kettles' ), + array( 'li' => 'Warm, woolen mittens' ), + ), array('odd', 'even')) +), true); +output_to_fd_and_free($doc, 1); +?> diff --git a/php5-swig/include.php b/php5-swig/include.php new file mode 100644 index 0000000..5e3ff4e --- /dev/null +++ b/php5-swig/include.php @@ -0,0 +1,13 @@ + 'red' +), 0); +$master = process_file('../xml/master.xml', array( + 'title' => 'Main HTML title', + 'h1' => 'Nice heading here', + 'contents' => $doc +), true); +output_to_fd_and_free($doc, 1); +?> diff --git a/php5-swig/namespace.php b/php5-swig/namespace.php new file mode 100644 index 0000000..1dfc9b9 --- /dev/null +++ b/php5-swig/namespace.php @@ -0,0 +1,12 @@ + 'Namespace tests', + '#hello' => 'Hello world!', + '#test' => 'Replaced.', + 'tagname' => 'foo', + '#moretest' => 'bar' +), true); +output_to_fd_and_free($doc, 1); +?> diff --git a/php5-swig/namespace2.php b/php5-swig/namespace2.php new file mode 100644 index 0000000..a4c4426 --- /dev/null +++ b/php5-swig/namespace2.php @@ -0,0 +1,9 @@ + 'Namespace tests', + '#hello' => 'Replaced.', +), true); +output_to_fd_and_free($doc, 1); +?> diff --git a/php5-swig/structure.php b/php5-swig/structure.php new file mode 100644 index 0000000..c3a684e --- /dev/null +++ b/php5-swig/structure.php @@ -0,0 +1,12 @@ + array( + array( '#inner' => 'One' ), + array( '#inner' => 'Two' ), + array( '#inner' => 'Three' ), + ) +), true); +output_to_fd_and_free($doc, 1); +?> -- 2.39.5