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