Fix compile warnings about initialization order and unused variables
[libt2n] / codegen / main.cpp
CommitLineData
0e627fe2 1/*
19facd85 2 Copyright (C) 2006-2008 by Intra2net AG
1770469c 3 intra2net.com
0e627fe2 4
19facd85
TJ
5 The software in this package is distributed under the GNU General
6 Public License version 2 (with a special exception described below).
0e627fe2 7
19facd85
TJ
8 A copy of GNU General Public License (GPL) is included in this distribution,
9 in the file COPYING.GPL.
0e627fe2 10
19facd85
TJ
11 As a special exception, if other files instantiate templates or use macros
12 or inline functions from this file, or you compile this file and link it
13 with other works to produce a work based on this file, this file
14 does not by itself cause the resulting work to be covered
15 by the GNU General Public License.
16
17 However the source code for this file must still be made available
18 in accordance with section (3) of the GNU General Public License.
19
20 This exception does not invalidate any other reasons why a work based
21 on this file might be covered by the GNU General Public License.
0e627fe2
JT
22*/
23
e50cc1d6
JT
24#include <libxml++/libxml++.h>
25#include <cassert>
26#include <iostream>
060fbd87
JT
27#include <set>
28#include <fstream>
9d3993e5 29#include <list>
6be7b70f 30#include <stdexcept>
7799fec7 31#include <string>
6be7b70f 32#include <boost/lexical_cast.hpp>
3907d211
JT
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
e50cc1d6 36
2f0896ce
JT
37
38//! map group to class name
1770469c
GE
39std::string groupClass(const std::string &group)
40{
2f0896ce
JT
41 return std::string("cmd_group_")+group;
42}
43
52b6f93a 44//! convert string to upper case
1770469c
GE
45std::string toupper(std::string s)
46{
47 for (unsigned i=0; i<s.length(); ++i) s[i]=toupper(s[i]);
48 return s;
e035276b
JT
49}
50
52b6f93a 51//! replace all characters f by r in string s
1770469c
GE
52std::string replace(std::string s, char f, char r)
53{
54 for (unsigned i=0; i<s.length(); ++i) if (s[i]==f) s[i]=r;
55 return s;
e035276b
JT
56}
57
52b6f93a
JT
58//! strip prefix from string s
59/*!
60 \return string s without prefix or an empty string on error
61 */
1770469c 62std::string strip(std::string s, std::string prefix)
e035276b 63{
1770469c
GE
64 std::string error;
65 if ( (prefix.length()>s.length() ) || ( std::string(s,0,prefix.length())!=prefix ) ) return error;
66 return std::string(s, prefix.length(), s.length()-prefix.length());
e035276b
JT
67}
68
e50cc1d6
JT
69//! get child element by id
70/*!
71 \return pointer to element having id or null on error
72 \todo find libxmlpp pendant
73*/
74const xmlpp::Element* get_element_by_id(const xmlpp::Element* element, const std::string &id)
75{
1770469c
GE
76 const xmlpp::Attribute* cid = element->get_attribute("id");
77 if ( cid && ( cid->get_value() == id)) return element;
78
79 //Recurse through child nodes:
80 xmlpp::Node::NodeList list = element->get_children();
81 for (xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
82 {
83 const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(*iter);
84 if (element)
85 {
86 const xmlpp::Element* match = get_element_by_id(element, id);
87 if (match) return match;
88 }
89 }
90 return NULL;
e50cc1d6
JT
91}
92
1770469c 93std::string get_file(const xmlpp::Element* root, const std::string &file_id)
6be7b70f 94{
1770469c
GE
95 std::string error;
96 const xmlpp::Element* e=get_element_by_id(root, file_id);
97 if ((!e)||(!e->get_attribute("name"))) return error;
98 return e->get_attribute("name")->get_value();
6be7b70f
JT
99}
100
e50cc1d6
JT
101//! get namespace by id
102/*!
103 \return namespace name or empty string on error
104*/
105std::string get_namespace(const xmlpp::Element* root, const std::string &id)
106{
1770469c
GE
107 std::string error;
108 const xmlpp::Element* element(get_element_by_id(root, id));
109 // [RP:20071024]: use "demangled" attribute instead of "name" to cover nested namespaces:
110 if ((!element)||(!element->get_attribute("demangled"))) return error;
111 return element->get_attribute("demangled")->get_value();
e50cc1d6
JT
112}
113
ef7b2923 114//! procedure marked for export?
1770469c 115bool is_marked(const std::string &attrs)
d340d435 116{
1770469c
GE
117 // todo: improve this
118 std::string to_match("gccxml(libt2n-");
119 std::string::size_type p(attrs.find(to_match));
120 return (p!=std::string::npos);
d340d435
JT
121}
122
e035276b
JT
123struct type_info
124{
1770469c
GE
125 std::string name;
126 std::string noref_name;
127 bool operator==(const type_info& o) {return (name==o.name) && (noref_name == o.noref_name);}
128 std::string noref() const {return noref_name.empty() ? name : noref_name;}
129 bool isVoid() const {return name=="void";}
e035276b
JT
130};
131
1770469c
GE
132std::ostream &operator<<(std::ostream &o, const type_info &t)
133{
134 o << t.name;
135 return o;
e035276b
JT
136}
137
6be7b70f
JT
138struct parse_error : public std::runtime_error
139{
1770469c
GE
140 parse_error(const std::string &file, unsigned line, const std::string &msg)
141 : std::runtime_error(file+":"+boost::lexical_cast<std::string>(line)+": error: "+msg)
142 {}
6be7b70f
JT
143};
144
e50cc1d6
JT
145//! get type by id
146/*!
147 \return type name or empty string on error
148*/
e035276b 149type_info get_type(const xmlpp::Element* root, const std::string &id)
e50cc1d6 150{
1770469c
GE
151 type_info error;
152 const xmlpp::Element* element(get_element_by_id(root, id));
153 if (!element) return error;
154
155 // TODO: not yet complete
156 // if we recurse - when do we stop?
157 // if it is a typedef? yes? (hmm if the typedef is in the file parsed this will not work)
158
159 // TODO: const and reference types handling is a ugly hack
160
161 std::string tag(element->get_name());
162 if (tag=="ReferenceType")
163 {
164 assert(element->get_attribute("type"));
165 type_info ret(get_type(root, element->get_attribute("type")->get_value()));
166 if (ret==error) return error;
167 // at the moment we only support const &
168 // todo: nice error message!
169 if ((ret.noref_name=strip(ret.name,"const ")).empty()) return error;
170 ret.name=ret.name+"&";
171 return ret;
172 }
173 else if (tag=="CvQualifiedType")
174 {
175 assert(element->get_attribute("type"));
176 type_info ret(get_type(root, element->get_attribute("type")->get_value()));
177 if (ret==error) return error;
178 ret.name=std::string("const ")+ret.name;
179 return ret;
180 }
181 else if (tag=="PointerType")
182 {
183 // todo: nearly the same as reference type handling
184 assert(element->get_attribute("type"));
185 type_info ret(get_type(root, element->get_attribute("type")->get_value()));
186 if (ret==error) return error;
187 // at the moment we only support const &
188 // todo: nice error message!
189 if ((ret.noref_name=strip(ret.name,"const ")).empty()) return error;
190 ret.name=ret.name+"*";
191 return ret;
192 }
193
194 assert(element->get_attribute("name"));
195 type_info ret;
196 if (element->get_attribute("context"))
197 {
198 ret.name=get_namespace(root, element->get_attribute("context")->get_value());
199 if (ret.name!="::")
200 ret.name+="::";
201 else
202 // do not explicitely add ::
203 ret.name="";
204 }
205 ret.name+=element->get_attribute("name")->get_value();
206 return ret;
e50cc1d6
JT
207}
208
73eb04f2
GE
209struct Arg
210{
211 std::string name;
212 type_info type;
213 std::string defaultArg;
214};
215
060fbd87
JT
216struct t2n_procedure
217{
73eb04f2 218 typedef std::list<Arg> Args;
1770469c
GE
219
220 type_info ret_type;
221 std::string name;
222 std::string mangled;
223 Args args;
224
225 std::string ret_classname() const
226 {
227 return name+mangled+"_res";
228 }
229 std::string cmd_classname() const
230 {
231 return name+mangled+"_cmd";
232 }
233 bool hasReturn() const {return !ret_type.isVoid();}
060fbd87 234};
e50cc1d6 235
1770469c
GE
236std::ostream &operator<<(std::ostream &o, const t2n_procedure::Args &args)
237{
238 for (t2n_procedure::Args::const_iterator it=args.begin();it!=args.end();++it)
239 {
240 if (it!=args.begin()) o << ", ";
73eb04f2
GE
241 o << it->type << " " << it->name;
242
243 if (!it->defaultArg.empty())
244 o << "=" << it->defaultArg;
1770469c
GE
245 }
246 return o;
060fbd87 247}
e50cc1d6 248
1770469c
GE
249std::ostream &operator<<(std::ostream &o, const t2n_procedure &f)
250{
251 o << f.ret_type << " " << f.name << "(" << f.args << ")";
252 return o;
060fbd87 253}
e50cc1d6 254
3b7c93a8
JT
255std::pair<std::string, unsigned>
256get_file_and_line(const xmlpp::Element* root, const xmlpp::Element* element)
257{
1770469c
GE
258 return std::pair<std::string, unsigned>(get_file(root, element->get_attribute("file")->get_value()),
259 boost::lexical_cast<unsigned>(element->get_attribute("line")->get_value())-1);
3b7c93a8
JT
260}
261
1770469c 262std::string get_file_and_line_as_string(const xmlpp::Element* root, const xmlpp::Element* element)
3b7c93a8 263{
1770469c
GE
264 std::pair<std::string, unsigned> fl(get_file_and_line(root,element));
265 return std::string(fl.first)+":"+boost::lexical_cast<std::string>(fl.second);
3b7c93a8
JT
266}
267
060fbd87
JT
268class Parser
269{
270public:
1770469c
GE
271 Parser(const std::string &fname) : m_fname(fname) {}
272
273 std::list<t2n_procedure> get_procedures()
274 {
275 xmlpp::DomParser parser;
276 // parser.set_validate();
277 parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically.
278 parser.parse_file(m_fname);
279 if (parser)
280 {
281 //Walk the tree:
282 const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser.
283 const xmlpp::Element* root = dynamic_cast<const xmlpp::Element*>(pNode);
284 assert(root);
285 visit_node(root);
286 }
287 return m_procedures;
288 }
060fbd87 289protected:
1770469c
GE
290 std::string m_fname;
291 std::list<t2n_procedure> m_procedures;
292
293 void parse_function(const xmlpp::Element* root, const xmlpp::Node* node)
294 {
295 const xmlpp::Element* element = dynamic_cast<const xmlpp::Element*>(node);
296 if (!element) return;
297
298 const xmlpp::Attribute* attributes = element->get_attribute("attributes");
299 const xmlpp::Attribute* name = element->get_attribute("name");
300 const xmlpp::Attribute* mangled = element->get_attribute("mangled");
301 const xmlpp::Attribute* returns = element->get_attribute("returns");
302 if ((!attributes)||(!name)||(!mangled)||(!returns)) return;
303
304 // check wether the procedure is marked (TODO: improve)
305 // attributes are speparated by spaces?
306
307 t2n_procedure f;
308 if (!is_marked(attributes->get_value())) return;
309
310 // we need the return type
311 f.ret_type=get_type(root, returns->get_value());
312 f.name=name->get_value();
313 f.mangled=mangled->get_value();
314
315 xmlpp::Node::NodeList list = node->get_children("Argument");
316 for (xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
317 {
318 const xmlpp::Element* arg = dynamic_cast<const xmlpp::Element*>(*iter);
319 if ( arg )
320 {
73eb04f2
GE
321 struct Arg a;
322
1770469c 323 assert(arg->get_name() == "Argument");
73eb04f2 324
1770469c 325 assert(arg->get_attribute("name"));
73eb04f2
GE
326 a.name=arg->get_attribute("name")->get_value();
327
1770469c 328 assert(arg->get_attribute("type"));
73eb04f2
GE
329 a.type=get_type(root, arg->get_attribute("type")->get_value());
330
7799fec7
GE
331 // this would be the nice way of solving the problem of default arguments
332 // but currently the output of gccxml is unreliable (e.g. namespace only
333 // sometimes available)
334 // if(arg->get_attribute("default"))
335 // a.defaultArg=arg->get_attribute("default")->get_value();
336
337 // so we need to get the def. arg. via attribute
338 // which is previously set by the macro LIBT2N_DEFAULT_ARG(type,value)
339 if(arg->get_attribute("attributes"))
340 {
341 std::string attr=arg->get_attribute("attributes")->get_value();
342 const std::string look_for = "gccxml(libt2n-default-arg,";
343
344 if (attr.compare(0,look_for.size(),look_for) == 0)
345 a.defaultArg=attr.substr(look_for.size(),attr.size()-look_for.size()-1);
346 }
73eb04f2 347
1770469c 348 // todo: ugly - could be any other error
73eb04f2 349 if (a.type.name.empty())
1770469c
GE
350 {
351 assert(element->get_attribute("file"));
352 assert(element->get_attribute("line"));
353 std::pair<std::string, unsigned> file_and_line(get_file_and_line(root, element));
354 throw parse_error(file_and_line.first,
355 file_and_line.second,
73eb04f2 356 std::string("type of parameter '")+a.name+"' not (yet?) supported");
1770469c 357 }
73eb04f2
GE
358
359 f.args.push_back(a);
1770469c
GE
360 }
361 }
362 std::cerr << get_file_and_line_as_string(root, element) << ":\texport procedure: " << f << std::endl;
363 m_procedures.push_back(f);
364 }
365
366 void visit_node(const xmlpp::Element* root, const xmlpp::Node* node = NULL, unsigned int indentation = 0)
367 {
368 if (!node) node=root;
369
370 const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
371 const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node);
372 const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::CommentNode*>(node);
373
374 if (nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this.
375 return;
376
377 std::string nodename = node->get_name();
378
379 if (!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text".
380 {
381 if (node->get_name() == "Function") parse_function(root, node);
382 }
383 if (!nodeContent)
384 {
385 //Recurse through child nodes:
386 xmlpp::Node::NodeList list = node->get_children();
387 for (xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
388 {
389 visit_node(root, *iter, indentation + 2); //recursive
390 }
391 }
392 }
060fbd87
JT
393};
394
1770469c
GE
395void output_common_hpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs)
396{
2f0896ce 397 o << "class " << groupClass(group) << " : public libt2n::command\n"
1770469c
GE
398 << "{\n"
399 << "private:\n"
400 << " friend class boost::serialization::access;\n"
401 << " template<class Archive>\n"
402 << " void serialize(Archive & ar, const unsigned int /* version */)\n"
403 << " {ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);}\n"
404 << "};\n";
405
406 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it)
407 {
408 o << "class " << it->ret_classname() << " : public libt2n::result\n"
409 << "{\n"
410 << "private:\n";
411 if (it->hasReturn())
412 o << " " << it->ret_type << " res;\n";
413 o << " friend class boost::serialization::access;\n"
414 << " template<class Archive>\n"
415 << " void serialize(Archive & ar, const unsigned int /* version */)\n"
416 << " {\n"
417 << " ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);\n";
418 if (it->hasReturn())
419 o << " ar & BOOST_SERIALIZATION_NVP(res);\n";
420 o << " }\n"
421 << "public:\n"
422 << " " << it->ret_classname() << "() {}\n";
423 if (it->hasReturn())
424 {
425 o << " " << it->ret_classname() << "(const " << it->ret_type << " &_res) : res(_res) {}\n"
426 << " " << it->ret_type << " get_data() { return res; }\n";
427 }
428 o << "};\n";
d340d435 429 }
1770469c
GE
430 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it)
431 {
432 o << "class " << it->cmd_classname() << " : public " << groupClass(group) << "\n"
433 << "{\n"
434 << "private:\n";
435 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait)
436 {
73eb04f2 437 o << " " << ait->type.noref() << " " << ait->name << ";\n";
1770469c
GE
438 }
439 o << " friend class boost::serialization::access;\n"
440 << " template<class Archive>\n"
441 << " void serialize(Archive & ar, const unsigned int /* version */)\n"
442 << " {\n"
443 << " ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(" << groupClass(group) << ");\n";
444 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait)
445 {
73eb04f2 446 o << " ar & BOOST_SERIALIZATION_NVP(" << ait->name << ");\n";
1770469c
GE
447 }
448
449 // default constructor
450 o << " }\n"
451 << "\n"
452 << "public:\n"
453 << " " << it->cmd_classname() << "() {}\n";
454
455 // constructor taking all arguments
456 if (!it->args.empty())
457 {
458 o << " " << it->cmd_classname() << "(";
459 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait)
460 {
461 if (ait!=it->args.begin()) o << ", ";
73eb04f2 462 o << ait->type << " _" << ait->name;
1770469c
GE
463 }
464 o << ") : ";
465 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait)
466 {
467 if (ait!=it->args.begin()) o << ", ";
468 // pointers are const pointers and must be dereferenced
73eb04f2 469 o << ait->name << "(" << ((ait->type.name.find_first_of('*')!=std::string::npos) ? "*" : "" ) << "_" << ait->name << ")";
1770469c
GE
470 }
471 o << " {}\n";
472 }
473 o << " libt2n::result* operator()();\n"
474 << "};\n";
d340d435 475 }
060fbd87
JT
476}
477
1770469c
GE
478void output_common_cpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs, const std::string &common_hpp)
479{
480 o << "#include \"" << common_hpp << "\"\n"
481 << "#include <boost/serialization/export.hpp>\n"
482 << "\n"
483 << "/* register types with boost serialization */\n";
484 o << "BOOST_CLASS_EXPORT(" << groupClass(group) << ")\n";
485 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it)
486 {
487 o << "BOOST_CLASS_EXPORT("<<it->ret_classname()<<")\n"
488 << "BOOST_CLASS_EXPORT("<<it->cmd_classname()<<")\n";
489 }
060fbd87 490}
e50cc1d6 491
1770469c
GE
492void output_client_hpp(std::ostream &o, const std::string &group, const std::list<t2n_procedure> &procs)
493{
494 o << "#include <command_client.hxx>\n";
495
496 o << "class " << groupClass(group) << "_client : public libt2n::command_client\n"
497 << "{\n"
498 << "public:\n"
f6d1a1e3 499 << groupClass(group) << "_client(libt2n::client_connection *_c,\n"
1770469c
GE
500 << " long long _command_timeout_usec=command_timeout_usec_default,\n"
501 << " long long _hello_timeout_usec=hello_timeout_usec_default)\n"
502 << " : libt2n::command_client(_c,_command_timeout_usec,_hello_timeout_usec)\n"
503 << " {}\n";
504 for (std::list<t2n_procedure>::const_iterator pit=procs.begin();pit!=procs.end();++pit)
505 {
506 o << " " << *pit << ";\n";
507 }
508 o << "};\n";
060fbd87 509}
e50cc1d6 510
1770469c
GE
511void 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)
512{
513 o << "#include \"" << client_hpp << "\"\n"
514 << "#include \"" << common_hpp << "\"\n"
515 << "// fake\n";
516 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it)
517 {
518 o << "libt2n::result* " << it->cmd_classname() << "::operator()() { return NULL; }\n";
519 }
520
521 for (std::list<t2n_procedure>::const_iterator pit=procs.begin();pit!=procs.end();++pit)
522 {
73eb04f2
GE
523 o << pit->ret_type << " " << groupClass(group) << "_client::" << pit->name << "(";
524
525 // we need to do this by hand here because we don't want default arguments within the cpp
526 for (t2n_procedure::Args::const_iterator xit=pit->args.begin();xit!=pit->args.end();++xit)
527 {
528 if (xit!=pit->args.begin())
529 o << ", ";
530 o << xit->type << " " << xit->name;
531 }
532
533 o << ")\n"
1770469c
GE
534 << "{\n"
535 << " libt2n::result_container rc;\n"
536 << " send_command(new " << pit->cmd_classname() << "(";
537 for (t2n_procedure::Args::const_iterator ait=pit->args.begin();ait!=pit->args.end();++ait)
538 {
539 if (ait!=pit->args.begin()) o << ", ";
73eb04f2 540 o << ait->name;
1770469c
GE
541 }
542 o << "), rc);\n"
543 << " " << pit->ret_classname() << "* res=dynamic_cast<" << pit->ret_classname() << "*>(rc.get_result());\n"
544 << " if (!res) throw libt2n::t2n_communication_error(\"result object of wrong type\");\n";
545 if (pit->hasReturn())
546 o << " return res->get_data();\n";
547 o << "}\n";
548 }
549
550 // include in this compilation unit to ensure the compilation unit is used
551 // see also:
552 // http://www.google.de/search?q=g%2B%2B+static+initializer+in+static+library
553 o << "#include \"" << common_cpp << "\"\n";
060fbd87
JT
554}
555
1770469c
GE
556void output_server_hpp(std::ostream &o, const std::string & /* group */, const std::list<t2n_procedure> &procs, const std::string &common_hpp)
557{
558 o << "#include \"" << common_hpp << "\"\n";
a96ab628 559
1770469c
GE
560 // output function declarations
561 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it)
562 o << *it << ";\n";
a96ab628
JT
563}
564
1770469c
GE
565void 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)
566{
567 o << "#include \"" << common_hpp << "\"\n";
568
569 for (std::list<t2n_procedure>::const_iterator it=procs.begin();it!=procs.end();++it)
570 {
571 o << *it << ";\n";
572 o << "libt2n::result* " << it->cmd_classname() << "::operator()() { ";
573
574 if (it->hasReturn())
575 o << "return new " << it->ret_classname() << "(";
576
577 // output function name and args
578 o << it->name << "(";
579 for (t2n_procedure::Args::const_iterator ait=it->args.begin();ait!=it->args.end();++ait)
580 {
581 if (ait!=it->args.begin()) o << ", ";
582 // get pointer
73eb04f2 583 if (ait->type.name.find_first_of('*')!=std::string::npos)
1770469c 584 o << '&';
73eb04f2 585 o << ait->name;
1770469c
GE
586 }
587
588 if (it->hasReturn())
589 o << "));";
590 else
9c627fab
TJ
591 o << "); return new " << it->ret_classname() << "();";
592
1770469c
GE
593 o << " }\n";
594 }
595 o << "#include \"" << common_cpp << "\"\n";
060fbd87
JT
596}
597
060fbd87
JT
598struct header_file : public std::ofstream
599{
1770469c
GE
600 header_file(const char* fname) : std::ofstream(fname)
601 {
602 std::cerr << "create header: '" << fname << "'" << std::endl;
603 std::string macro(replace(toupper(fname),'.','_'));
604 *this << "// automatically generated code (generated by libt2n-codegen " << VERSION << ") - do not edit\n" << std::endl;
605 *this << "#ifndef " << macro << "\n"
606 << "#define " << macro << "\n";
607 }
608 ~header_file()
609 {
610 *this << "#endif" << std::endl;
611 }
060fbd87
JT
612};
613
614struct cpp_file : public std::ofstream
615{
1770469c
GE
616 cpp_file(const char* fname) : std::ofstream(fname)
617 {
618 std::cerr << "create cpp: '" << fname << "'" << std::endl;
619 *this << "// automatically generated code - do not edit\n" << std::endl;
620 }
060fbd87
JT
621};
622
623int
624main(int argc, char* argv[])
e50cc1d6 625{
3907d211 626 // todo: maybe use getopt
1770469c
GE
627 if ((argc>1)&&(std::string(argv[1])=="--version"))
628 {
629 std::cerr << VERSION << std::endl;
630 return 0;
3907d211
JT
631 }
632 if (argc < 3)
633 {
1770469c
GE
634 std::cerr << "Usage: " << argv[0] << "default-group gccxml-file1 gccxml-file2 ... " << std::endl;
635 return 1;
3907d211 636 }
060fbd87 637
1770469c
GE
638 try
639 {
640 std::string group(argv[1]);
641 std::list<std::string> xmlfiles;
642 for (int i=2;i<argc;++i)
643 xmlfiles.push_back(argv[i]);
644
645 std::string prefix=group+"_";
646 std::list<t2n_procedure> procedures;
647 for (std::list<std::string>::iterator it=xmlfiles.begin();it!=xmlfiles.end();++it)
648 {
649 std::cerr << "Parse " << *it << std::endl;
650 Parser parser(*it);
651 const std::list<t2n_procedure> &p(parser.get_procedures());
652 std::copy(p.begin(), p.end(), std::back_inserter(procedures));
653 }
654
655 std::cerr << "All procedures:" << std::endl;
656 for (std::list<t2n_procedure>::const_iterator it=procedures.begin();it!=procedures.end();++it)
657 std::cerr << *it << ";" << std::endl;
658
659 std::string common_hpp_fname(prefix+"common.hxx");
660 std::string common_cpp_fname(prefix+"common.cpp");
661 std::string client_hpp_fname(prefix+"client.hxx");
662 std::string client_cpp_fname(prefix+"client.cpp");
663 std::string server_hpp_fname(prefix+"server.hxx");
664 std::string server_cpp_fname(prefix+"server.cpp");
665
666 header_file common_hpp(common_hpp_fname.c_str());
667 common_hpp << "// boost serialization is picky about order of include files => we have to include this one first\n"
668 << "#include \"codegen-stubhead.hxx\"\n"
669 << "#include \"" << group << ".hxx\"\n";
670
671 output_common_hpp(common_hpp, group, procedures);
672
673 cpp_file common_cpp(common_cpp_fname.c_str());
674 output_common_cpp(common_cpp, group, procedures, common_hpp_fname);
675
676 header_file client_hpp(client_hpp_fname.c_str());
677 client_hpp << "// boost serialization is picky about order of include files => we have to include this one first\n"
678 << "#include \"codegen-stubhead.hxx\"\n"
679 << "#include \"" << group << ".hxx\"\n";
680 output_client_hpp(client_hpp, group, procedures);
681
682 cpp_file client_cpp(client_cpp_fname.c_str());
683 output_client_cpp(client_cpp, group, procedures, common_hpp_fname, common_cpp_fname, client_hpp_fname);
684
685 header_file server_hpp(server_hpp_fname.c_str());
686 output_server_hpp(server_hpp, group, procedures, common_hpp_fname);
687
688 cpp_file server_cpp(server_cpp_fname.c_str());
689 output_server_cpp(server_cpp, group, procedures, common_hpp_fname, common_cpp_fname);
690 }
691 catch (const parse_error &e)
692 {
693 std::cerr << e.what() << std::endl;
694 return EXIT_FAILURE;
695 }
696 return EXIT_SUCCESS;
e50cc1d6 697}