started docu
[libt2n] / codegen / main.cpp
CommitLineData
0e627fe2
JT
1/*
2 Copyright (C) 2006
3 intra2net.com
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19
a930cc99
JT
20/*! \mainpage libt2n - (talk2neighbor)
21 \section intro_sec Introduction
22 libt2n (talk2neighbor) is a C++ library for inter-process communication (IPC, s.a. http://en.wikipedia.org/wiki/Inter-process_communication)
23 with an additional code generator to make remote procedure calls simple. XXX: improve this paragraph: The input for the code generator is standard C++ code (in fact we use gccxml to parse the C++ code and the code generator takes the XML as input) and you mark the procedures you want to expose to other processes.
24 It then generates the stubs needed.
25 The exported procedures can be grouped. For each group the code generator is called which generates 6 outputfiles: group_common.hxx, group_common.cpp, group_client.hxx, group_client.cpp, group_server.hxx, group_server.cpp. The _common files are used by client and server whereas the _client files are used by the client and the _server files by the server.
26
27 \section install_sec Installation
28
29 \subsection requirements Requirements
30 - boost <http://www.boost.org/> (serialization <http://www.boost.org/libs/serialization/doc/>)
31 - gccxml <http://www.gccxml.org>
32 - libxmlpp <http://libxmlplusplus.sourceforge.net/>
33
34 \section usage Usage example
35
36 In this example we create two packages:
37 - server program and library to connect to the server. The server exports a simple procedure using one group: "t2nexample"
38 - client program using the library
39
40 \subsection server Example server program and client library
41
42 \par The procedure to export (input for the code generator - libt2n-codegen): t2nexample.cpp:
43 \verbinclude libt2n-example1/t2nexample.cpp
44
45 \par Required includes must be put into a seperate group header file: t2nexample.hxx:
46 \verbinclude libt2n-example1/t2nexample.hxx
47
48 \par The server program:
49 \verbinclude libt2n-example1/server.cpp
50
51 \par Using autoconf and automake to build a example server program and a client library.
52 In the configure.in(.ac) we put a check for libt2n:
53 \verbinclude libt2n-example1/configure.in
54 Writing the Makefile.am isn't difficult either:
55 \verbinclude libt2n-example1/Makefile.am
56
57 \subsection client Client using the library
58 Using the library is as simple as using any other library using pkg-config (the pkg-config .pc file is created automatically by the included Makefile snippet)
59 \par We only have to check that the library is installed
60 \verbinclude libt2n-example1-client/configure.in
61 \par Nothing special
62 \verbinclude libt2n-example1-client/Makefile.am
63 \par The client program
64 \verbinclude libt2n-example1-client/client.cpp
65
66*/
67
68/*!
69 \example t2nexample.cpp
70 example input for libt2n-codegen
71*/
72
e50cc1d6
JT
73#include <libxml++/libxml++.h>
74#include <cassert>
75#include <iostream>
060fbd87
JT
76#include <set>
77#include <fstream>
9d3993e5 78#include <list>
6be7b70f
JT
79#include <stdexcept>
80#include <boost/lexical_cast.hpp>
3907d211
JT
81#ifdef HAVE_CONFIG_H
82#include "config.h"
83#endif
e50cc1d6 84
2f0896ce
JT
85
86//! map group to class name
87std::string
88groupClass(const std::string &group) {
89 return std::string("cmd_group_")+group;
90}
91
52b6f93a 92//! convert string to upper case
e035276b
JT
93std::string
94toupper(std::string s) {
95 for (unsigned i=0; i<s.length(); ++i) s[i]=toupper(s[i]);
96 return s;
97}
98
52b6f93a 99//! replace all characters f by r in string s
e035276b
JT
100std::string
101replace(std::string s, char f, char r) {
102 for (unsigned i=0; i<s.length(); ++i) if (s[i]==f) s[i]=r;
103 return s;
104}
105
52b6f93a
JT
106//! strip prefix from string s
107/*!
108 \return string s without prefix or an empty string on error
109 */
e035276b
JT
110std::string
111strip(std::string s, std::string prefix)
112{
113 std::string error;
114 if ( (prefix.length()>s.length() ) || ( std::string(s,0,prefix.length())!=prefix ) ) return error;
115 return std::string(s, prefix.length(), s.length()-prefix.length());
116}
117
e50cc1d6
JT
118//! get child element by id
119/*!
120 \return pointer to element having id or null on error
121 \todo find libxmlpp pendant
122*/
123const xmlpp::Element* get_element_by_id(const xmlpp::Element* element, const std::string &id)
124{
125 const xmlpp::Attribute* cid = element->get_attribute("id");
126 if ( cid && ( cid->get_value() == id)) return element;
127
128 //Recurse through child nodes:
129 xmlpp::Node::NodeList list = element->get_children();
130 for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
131 {
132 const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(*iter);
133 if (element) {
134 const xmlpp::Element* match = get_element_by_id(element, id);
135 if (match) return match;
136 }
137 }
138 return NULL;
139}
140
6be7b70f
JT
141std::string
142get_file(const xmlpp::Element* root, const std::string &file_id)
143{
144 std::string error;
145 const xmlpp::Element* e=get_element_by_id(root, file_id);
146 if ((!e)||(!e->get_attribute("name"))) return error;
147 return e->get_attribute("name")->get_value();
148}
149
e50cc1d6
JT
150//! get namespace by id
151/*!
152 \return namespace name or empty string on error
153*/
154std::string get_namespace(const xmlpp::Element* root, const std::string &id)
155{
156 std::string error;
157 const xmlpp::Element* element(get_element_by_id(root, id));
158 if ((!element)||(!element->get_attribute("name"))) return error;
159 return element->get_attribute("name")->get_value();
160}
161
d340d435
JT
162//! extract group from attributes
163std::string
164extract_group(const std::string &attrs)
165{
166 // todo: improve this
167 std::string error;
168 std::string to_match("gccxml(libt2n-");
169 std::string::size_type p(attrs.find(to_match));
170 if (p==std::string::npos) return error;
171 std::string group(attrs, p+to_match.length(), attrs.length());
172 p=group.find_first_of(')');
173 assert(p!=std::string::npos);
174 return std::string(group,0,p);
175}
176
e035276b
JT
177struct type_info
178{
179 std::string name;
180 std::string noref_name;
181 bool operator==(const type_info& o) {return (name==o.name) && (noref_name == o.noref_name);}
9d3993e5 182 std::string noref() const {return noref_name.empty() ? name : noref_name;}
e035276b
JT
183};
184
185std::ostream &operator<<(std::ostream &o, const type_info &t) {
186 o << t.name;
187 return o;
188}
189
6be7b70f
JT
190struct parse_error : public std::runtime_error
191{
192 parse_error(const std::string &file, unsigned line, const std::string &msg)
193 : std::runtime_error(file+":"+boost::lexical_cast<std::string>(line)+": error: "+msg)
194 {}
195};
196
e50cc1d6
JT
197//! get type by id
198/*!
199 \return type name or empty string on error
200*/
e035276b 201type_info get_type(const xmlpp::Element* root, const std::string &id)
e50cc1d6 202{
e035276b 203 type_info error;
e50cc1d6
JT
204 const xmlpp::Element* element(get_element_by_id(root, id));
205 if (!element) return error;
206
207 // TODO: not yet complete
208 // if we recurse - when do we stop?
209 // if it is a typedef? yes? (hmm if the typedef is in the file parsed this will not work)
060fbd87 210
9d3993e5 211 // TODO: const and reference types handling is a ugly hack
060fbd87 212
e50cc1d6
JT
213 std::string tag(element->get_name());
214 if (tag=="ReferenceType") {
215 assert(element->get_attribute("type"));
e035276b 216 type_info ret(get_type(root, element->get_attribute("type")->get_value()));
e50cc1d6 217 if (ret==error) return error;
e035276b
JT
218 // at the moment we only support const &
219 // todo: nice error message!
220 if ((ret.noref_name=strip(ret.name,"const ")).empty()) return error;
221 ret.name=ret.name+"&";
222 return ret;
e50cc1d6
JT
223 }else if (tag=="CvQualifiedType") {
224 assert(element->get_attribute("type"));
e035276b 225 type_info ret(get_type(root, element->get_attribute("type")->get_value()));
e50cc1d6 226 if (ret==error) return error;
e035276b
JT
227 ret.name=std::string("const ")+ret.name;
228 return ret;
6be7b70f
JT
229 }else if (tag=="PointerType") {
230 // not yet supported
231 return error;
e50cc1d6
JT
232 }
233
234 assert(element->get_attribute("name"));
e035276b 235 type_info ret;
fb5c13c6
JT
236 if (element->get_attribute("context")) {
237 ret.name=get_namespace(root, element->get_attribute("context")->get_value());
238 if (ret.name!="::")
239 ret.name+="::";
240 else
241 // do not explicitely add ::
242 ret.name="";
243 }
9d3993e5 244 ret.name+=element->get_attribute("name")->get_value();
e035276b 245 return ret;
e50cc1d6
JT
246}
247
060fbd87
JT
248struct t2n_procedure
249{
9d3993e5 250 typedef std::list<std::pair<std::string, type_info> > Args;
e50cc1d6 251
e035276b 252 type_info ret_type;
060fbd87 253 std::string name;
52b6f93a 254 std::string mangled;
060fbd87 255 Args args;
e50cc1d6 256
060fbd87 257 std::string ret_classname() const {
52b6f93a 258 return name+mangled+"_res";
060fbd87
JT
259 }
260 std::string cmd_classname() const {
52b6f93a 261 return name+mangled+"_cmd";
060fbd87
JT
262 }
263};
e50cc1d6 264
060fbd87
JT
265std::ostream &operator<<(std::ostream &o, const t2n_procedure::Args &args) {
266 for (t2n_procedure::Args::const_iterator it=args.begin();it!=args.end();++it) {
267 if (it!=args.begin()) o << ", ";
268 o << it->second << " " << it->first;
269 }
270 return o;
271}
e50cc1d6 272
060fbd87
JT
273std::ostream &operator<<(std::ostream &o, const t2n_procedure &f) {
274 o << f.ret_type << " " << f.name << "(" << f.args << ")";
275 return o;
276}
e50cc1d6 277
060fbd87
JT
278class Parser
279{
280public:
d340d435 281 Parser(const std::string &fname) : m_fname(fname) {}
e50cc1d6 282
060fbd87
JT
283 std::list<t2n_procedure> get_procedures() {
284 xmlpp::DomParser parser;
285 // parser.set_validate();
286 parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically.
287 parser.parse_file(m_fname);
288 if(parser)
289 {
290 //Walk the tree:
291 const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser.
292 const xmlpp::Element* root = dynamic_cast<const xmlpp::Element*>(pNode);
293 assert(root);
294 visit_node(root);
e50cc1d6 295 }
060fbd87 296 return m_procedures;
e50cc1d6 297 }
060fbd87
JT
298protected:
299 std::string m_fname;
300 std::list<t2n_procedure> m_procedures;
301
302 void parse_function(const xmlpp::Element* root, const xmlpp::Node* node) {
303 const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(node);
304 if (!element) return;
305
306 const xmlpp::Attribute* attributes = element->get_attribute("attributes");
307 const xmlpp::Attribute* name = element->get_attribute("name");
52b6f93a 308 const xmlpp::Attribute* mangled = element->get_attribute("mangled");
060fbd87 309 const xmlpp::Attribute* returns = element->get_attribute("returns");
52b6f93a 310 if ((!attributes)||(!name)||(!mangled)||(!returns)) return;
060fbd87
JT
311
312 // check wether the procedure is marked (TODO: improve)
313 // attributes are speparated by spaces?
060fbd87 314
060fbd87 315 t2n_procedure f;
d340d435 316 if (extract_group(attributes->get_value()).empty()) return;
e50cc1d6 317
060fbd87
JT
318 // we need the return type
319 f.ret_type=get_type(root, returns->get_value());
320 f.name=name->get_value();
52b6f93a 321 f.mangled=mangled->get_value();
060fbd87
JT
322
323 xmlpp::Node::NodeList list = node->get_children("Argument");
324 for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
325 {
326 const xmlpp::Element* arg = dynamic_cast<const xmlpp::Element*>(*iter);
327 if ( arg ) {
328 assert(arg->get_name() == "Argument");
329 assert(arg->get_attribute("name"));
330 assert(arg->get_attribute("type"));
9d3993e5 331 f.args.push_back(std::pair<std::string, type_info>(arg->get_attribute("name")->get_value(), get_type(root, arg->get_attribute("type")->get_value())));
6be7b70f
JT
332 // todo: ugly - could be any other error
333 if (f.args.back().second.name.empty()) {
334 assert(element->get_attribute("file"));
335 assert(element->get_attribute("line"));
336 throw parse_error(get_file(root, element->get_attribute("file")->get_value()),
337 boost::lexical_cast<unsigned>(element->get_attribute("line")->get_value())-1,
338 std::string("type of parameter `")+f.args.back().first+"' not (yet?) supported");
339 }
060fbd87
JT
340 }
341 }
9d3993e5 342 std::cerr << "Found function: " << f << std::endl;
060fbd87 343 m_procedures.push_back(f);
e50cc1d6 344 }
e50cc1d6 345
060fbd87
JT
346 void visit_node(const xmlpp::Element* root, const xmlpp::Node* node = NULL, unsigned int indentation = 0)
347 {
348 if (!node) node=root;
060fbd87
JT
349
350 const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
351 const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node);
352 const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::CommentNode*>(node);
e50cc1d6 353
060fbd87
JT
354 if(nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this.
355 return;
e50cc1d6 356
060fbd87 357 std::string nodename = node->get_name();
e50cc1d6 358
060fbd87
JT
359 if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text".
360 {
52b6f93a 361 if (node->get_name() == "Function") parse_function(root, node);
060fbd87 362 }
060fbd87
JT
363 if(!nodeContent)
364 {
365 //Recurse through child nodes:
366 xmlpp::Node::NodeList list = node->get_children();
367 for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
368 {
369 visit_node(root, *iter, indentation + 2); //recursive
370 }
371 }
e50cc1d6 372 }
060fbd87
JT
373};
374
d340d435 375void output_common_hpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs) {
2f0896ce 376 o << "class " << groupClass(group) << " : public libt2n::command\n"
d340d435
JT
377 << "{\n"
378 << "private:\n"
379 << " friend class boost::serialization::access;\n"
380 << " template<class Archive>\n"
381 << " void serialize(Archive & ar, const unsigned int /* version */)\n"
382 << " {ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);}\n"
383 << "};\n";
060fbd87 384
d340d435
JT
385 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it) {
386 o << "class " << it->ret_classname() << " : public libt2n::result\n"
387 << "{\n"
388 << "private:\n"
389 << " " << it->ret_type << " res;\n"
390 << " friend class boost::serialization::access;\n"
391 << " template<class Archive>\n"
392 << " void serialize(Archive & ar, const unsigned int /* version */)\n"
393 << " {\n"
394 << " ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);\n"
395 << " ar & BOOST_SERIALIZATION_NVP(res);\n"
396 << " }\n"
397 << "public:\n"
398 << " " << it->ret_classname() << "() {}\n"
399 << " " << it->ret_classname() << "(const " << it->ret_type << " &_res) : res(_res) {}\n"
400 << " " << it->ret_type << " get_data() { return res; }\n"
401 << "};\n";
402 }
403 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it) {
2f0896ce 404 o << "class " << it->cmd_classname() << " : public " << groupClass(group) << "\n"
d340d435
JT
405 << "{\n"
406 << "private:\n";
407 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait) {
408 o << " " << ait->second.noref() << " " << ait->first << ";\n";
409 }
410 o << " friend class boost::serialization::access;\n"
411 << " template<class Archive>\n"
412 << " void serialize(Archive & ar, const unsigned int /* version */)\n"
413 << " {\n"
2f0896ce 414 << " ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(" << groupClass(group) << ");\n";
d340d435
JT
415 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait) {
416 o << " ar & BOOST_SERIALIZATION_NVP(" << ait->first << ");\n";
417 }
418
419 // default constructor
420 o << " }\n"
421 << "\n"
422 << "public:\n"
423 << " " << it->cmd_classname() << "() {}\n";
424
425 // constructor taking all arguments
426 o << " " << it->cmd_classname() << "(";
427 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait) {
428 if (ait!=it->args.begin()) o << ", ";
429 o << ait->second << " _" << ait->first;
430 }
431 o << ") : ";
432 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait) {
433 if (ait!=it->args.begin()) o << ", ";
434 o << ait->first << "(_" << ait->first << ")";
435 }
436 o << " {}\n"
437 << " libt2n::result* operator()();\n"
438 << "};\n";
439 }
060fbd87
JT
440}
441
d340d435 442void output_common_cpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs, const std::string &common_hpp) {
060fbd87 443 o << "#include \"" << common_hpp << "\"\n"
e035276b 444 << "#include <boost/serialization/export.hpp>\n"
060fbd87
JT
445 << "\n"
446 << "/* register types with boost serialization */\n";
2f0896ce 447 o << "BOOST_CLASS_EXPORT(" << groupClass(group) << ")\n";
060fbd87
JT
448 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it) {
449 o << "BOOST_CLASS_EXPORT("<<it->ret_classname()<<")\n"
450 << "BOOST_CLASS_EXPORT("<<it->cmd_classname()<<")\n";
e50cc1d6 451 }
060fbd87 452}
e50cc1d6 453
d340d435 454void output_client_hpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs) {
060fbd87
JT
455 o << "#include <command_client.hxx>\n";
456
2f0896ce 457 o << "class " << groupClass(group) << "_client : public libt2n::command_client\n"
d340d435
JT
458 << "{\n"
459 << "public:\n"
2f0896ce 460 << groupClass(group) << "_client(libt2n::client_connection &_c,\n"
d340d435
JT
461 << " long long _command_timeout_usec=command_timeout_usec_default,\n"
462 << " long long _hello_timeout_usec=hello_timeout_usec_default)\n"
463 << " : libt2n::command_client(_c,_command_timeout_usec,_hello_timeout_usec)\n"
464 << " {}\n";
465 for (std::list<t2n_procedure>::const_iterator pit=procs.begin();pit!=procs.end();++pit) {
466 o << " " << *pit << ";\n";
060fbd87 467 }
d340d435 468 o << "};\n";
060fbd87 469}
e50cc1d6 470
d340d435 471void output_client_cpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs, const std::string &common_hpp, const std::string &common_cpp, const std::string &client_hpp) {
060fbd87
JT
472 o << "#include \"" << client_hpp << "\"\n"
473 << "#include \"" << common_hpp << "\"\n"
474 << "// fake\n";
475 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it) {
476 o << "libt2n::result* " << it->cmd_classname() << "::operator()() { return NULL; }\n";
477 }
478
d340d435 479 for (std::list<t2n_procedure>::const_iterator pit=procs.begin();pit!=procs.end();++pit) {
2f0896ce 480 o << pit->ret_type << " " << groupClass(group) << "_client::" << pit->name << "(" << pit->args << ")\n"
d340d435
JT
481 << "{\n"
482 << " libt2n::result_container rc;\n"
483 << " send_command(new " << pit->cmd_classname() << "(";
484 for (t2n_procedure::Args::const_iterator ait=pit->args.begin();ait!=pit->args.end();++ait) {
485 if (ait!=pit->args.begin()) o << ", ";
486 o << ait->first;
487 }
488 o << "), rc);\n"
489 << " " << pit->ret_classname() << "* res=dynamic_cast<" << pit->ret_classname() << "*>(rc.get_result());\n"
490 << " if (!res) throw libt2n::t2n_communication_error(\"result object of wrong type\");\n"
491 << " return res->get_data();\n"
492 << "}\n";
e50cc1d6 493 }
060fbd87
JT
494
495 // include in this compilation unit to ensure the compilation unit is used
496 // see also:
497 // http://www.google.de/search?q=g%2B%2B+static+initializer+in+static+library
498 o << "#include \"" << common_cpp << "\"\n";
499}
500
d340d435 501void output_server_hpp(std::ostream &o, const std::string & /* group */, const std::list<t2n_procedure> &procs, const std::string &common_hpp) {
a96ab628
JT
502 o << "#include \"" << common_hpp << "\"\n";
503
504 // output function declarations
505 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it)
506 o << *it << ";\n";
507}
508
d340d435 509void output_server_cpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs, const std::string &common_hpp, const std::string &common_cpp) {
060fbd87
JT
510 o << "#include \"" << common_hpp << "\"\n";
511
512 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it) {
513 o << *it << ";\n";
514 o << "libt2n::result* " << it->cmd_classname() << "::operator()() { return new " << it->ret_classname() << "(" << it->name << "(";
515 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait) {
516 if (ait!=it->args.begin()) o << ", ";
517 o << ait->first;
e50cc1d6 518 }
060fbd87 519 o << ")); }\n";
e50cc1d6 520 }
060fbd87
JT
521 o << "#include \"" << common_cpp << "\"\n";
522}
523
060fbd87
JT
524struct header_file : public std::ofstream
525{
526 header_file(const char* fname) : std::ofstream(fname) {
527 std::cerr << "create header: '" << fname << "'" << std::endl;
528 std::string macro(replace(toupper(fname),'.','_'));
3907d211 529 *this << "// automatically generated code (generated by libt2n-codegen " << VERSION << ") - do not edit\n" << std::endl;
060fbd87
JT
530 *this << "#ifndef " << macro << "\n"
531 << "#define " << macro << "\n";
532 }
533 ~header_file() {
534 *this << "#endif" << std::endl;
535 }
536};
537
538struct cpp_file : public std::ofstream
539{
540 cpp_file(const char* fname) : std::ofstream(fname) {
541 std::cerr << "create cpp: '" << fname << "'" << std::endl;
542 *this << "// automatically generated code - do not edit\n" << std::endl;
543 }
544};
545
546int
547main(int argc, char* argv[])
e50cc1d6 548{
3907d211
JT
549 // todo: maybe use getopt
550 if ((argc>1)&&(std::string(argv[1])=="--version")) {
551 std::cerr << VERSION << std::endl;
552 return 0;
553 }
554 if (argc < 3)
555 {
556 std::cerr << "Usage: " << argv[0] << "default-group gccxml-file1 gccxml-file2 ... " << std::endl;
557 return 1;
558 }
060fbd87 559
3907d211 560 try{
85106017 561 std::string group(argv[1]);
0cfa3fb2 562 std::list<std::string> xmlfiles;
85106017 563 for (int i=2;i<argc;++i)
0cfa3fb2
JT
564 xmlfiles.push_back(argv[i]);
565
a96ab628 566 std::string prefix=group+"_";
0cfa3fb2
JT
567 std::list<t2n_procedure> procedures;
568 for (std::list<std::string>::iterator it=xmlfiles.begin();it!=xmlfiles.end();++it) {
d340d435
JT
569 std::cerr << "Parse " << *it << std::endl;
570 Parser parser(*it);
571 const std::list<t2n_procedure> &p(parser.get_procedures());
572 std::copy(p.begin(), p.end(), std::back_inserter(procedures));
0cfa3fb2 573 }
6be7b70f
JT
574
575 std::cerr << "Procedures:" << std::endl;
576 for (std::list<t2n_procedure>::const_iterator it=procedures.begin();it!=procedures.end();++it)
577 std::cerr << *it << ";" << std::endl;
578
6be7b70f
JT
579 std::string common_hpp_fname(prefix+"common.hxx");
580 std::string common_cpp_fname(prefix+"common.cpp");
581 std::string client_hpp_fname(prefix+"client.hxx");
582 std::string client_cpp_fname(prefix+"client.cpp");
a96ab628 583 std::string server_hpp_fname(prefix+"server.hxx");
6be7b70f
JT
584 std::string server_cpp_fname(prefix+"server.cpp");
585
586 header_file common_hpp(common_hpp_fname.c_str());
587 common_hpp << "// boost serialization is picky about order of include files => we have to include this one first\n"
85106017
JT
588 << "#include \"codegen-stubhead.hxx\"\n"
589 << "#include \"" << group << ".hxx\"\n";
590
d340d435 591 output_common_hpp(common_hpp, group, procedures);
6be7b70f 592
25924cae 593 cpp_file common_cpp(common_cpp_fname.c_str());
d340d435 594 output_common_cpp(common_cpp, group, procedures, common_hpp_fname);
6be7b70f 595
25924cae
JT
596 header_file client_hpp(client_hpp_fname.c_str());
597 client_hpp << "// boost serialization is picky about order of include files => we have to include this one first\n"
85106017
JT
598 << "#include \"codegen-stubhead.hxx\"\n"
599 << "#include \"" << group << ".hxx\"\n";
d340d435 600 output_client_hpp(client_hpp, group, procedures);
6be7b70f 601
25924cae 602 cpp_file client_cpp(client_cpp_fname.c_str());
d340d435 603 output_client_cpp(client_cpp, group, procedures, common_hpp_fname, common_cpp_fname, client_hpp_fname);
6be7b70f 604
25924cae 605 header_file server_hpp(server_hpp_fname.c_str());
d340d435 606 output_server_hpp(server_hpp, group, procedures, common_hpp_fname);
a96ab628 607
25924cae 608 cpp_file server_cpp(server_cpp_fname.c_str());
d340d435 609 output_server_cpp(server_cpp, group, procedures, common_hpp_fname, common_cpp_fname);
6be7b70f 610 }catch(const parse_error &e){
25924cae
JT
611 std::cerr << e.what() << std::endl;
612 return EXIT_FAILURE;
6be7b70f
JT
613 }
614 return EXIT_SUCCESS;
e50cc1d6 615}