fix8  version 1.4.0
Open Source C++ FIX Framework
f8c.cpp
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------------------
2 /*
3 
4 Fix8 is released under the GNU LESSER GENERAL PUBLIC LICENSE Version 3.
5 
6 Fix8 Open Source FIX Engine.
7 Copyright (C) 2010-16 David L. Dight <fix@fix8.org>
8 
9 Fix8 is free software: you can redistribute it and / or modify it under the terms of the
10 GNU Lesser General Public License as published by the Free Software Foundation, either
11 version 3 of the License, or (at your option) any later version.
12 
13 Fix8 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 You should have received a copy of the GNU Lesser General Public License along with Fix8.
17 If not, see <http://www.gnu.org/licenses/>.
18 
19 THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE
20 COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
21 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
23 THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
24 YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
25 
26 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT
27 HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED
28 ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
29 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
30 NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
31 THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
32 HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
33 
34 */
35 //-----------------------------------------------------------------------------------------
78 //-----------------------------------------------------------------------------------------
79 #include "precomp.hpp"
80 // f8 headers
81 #include <fix8/f8includes.hpp>
82 #include <f8c.hpp>
83 
84 #ifdef FIX8_HAVE_GETOPT_H
85 #include <getopt.h>
86 #endif
87 
88 //-----------------------------------------------------------------------------------------
89 using namespace std;
90 using namespace FIX8;
91 
92 //-----------------------------------------------------------------------------------------
93 const string Ctxt::_exts[count] { "_types.c", "_types.h", "_traits.c", "_classes.c",
94  "_classes.h", "_router.h", "_session.h" },
95  Ctxt::_exts_ver[2] { "pp", "xx" };
98 bool verbose(false), error_ignore(false), gen_fields(false), norealm(false), nocheck(false), nowarn(false),
99  incpath(true), nconst_router(false), no_shared_groups(false), no_default_routers(false), report_unused(false);
100 unsigned glob_errors(0), glob_warnings(0), tabsize(3), ext_ver(0);
101 extern unsigned glob_errors;
102 extern const string GETARGLIST("hvVo:p:dikn:rst:x:NRc:fbCIWPF:UeH:SDu");
103 extern string spacer, shortName, precompHdr;
104 
105 //-----------------------------------------------------------------------------------------
106 // static data
107 #include <f8cstatic.hpp>
108 
109 //-----------------------------------------------------------------------------------------
110 void print_usage();
111 string insert_year();
112 int process(XmlElement& xf, Ctxt& ctxt);
113 int load_fix_version (XmlElement& xf, Ctxt& ctxt);
114 int load_fields(XmlElement& xf, FieldSpecMap& fspec);
115 void process_special_traits(const unsigned short field, FieldTraits& fts);
116 int process_message_fields(const std::string& where, const XmlElement *xt, FieldTraits& fts,
117  const FieldToNumMap& ftonSpec, FieldSpecMap& fspec, const Components& compon);
118 int load_messages(XmlElement& xf, MessageSpecMap& mspec, const FieldToNumMap& ftonSpec,
119  FieldSpecMap& fspec, Components& compon, CommonGroupMap& globmap);
120 void process_ordering(MessageSpecMap& mspec);
121 ostream *open_ofile(const string& odir, const string& fname, string& target);
122 void process_value_enums(FieldSpecMap::const_iterator itr, ostream& ost_hpp, ostream& ost_cpp);
123 const string& mkel(const string& base, const string& compon, string& where);
124 const string& filepart(const string& source, string& where);
125 void generate_preamble(ostream& to, const string& fname, bool isheader, bool donotedit=true);
126 void generate_includes(ostream& to);
127 unsigned parse_groups(MessageSpec& ritr, const string& name,
128  const FieldToNumMap& ftonSpec, FieldSpecMap& fspec, XmlElement::XmlSet& grplist,
129  const Components& compon, CommonGroupMap& globmap);
130 int precomp(XmlElement& xf, ostream& outf);
131 void process_group_ordering(const CommonGroupMap& gm);
132 int precompfixt(XmlElement& xft, XmlElement& xf, ostream& outf, bool nounique);
133 void generate_group_bodies(const MessageSpec& ms, const FieldSpecMap& fspec, int depth,
134  const string& msname, ostream& outp, ostream& outh, const CommonGroupMap& globmap, const std::string& fixns, const string cls_prefix=string());
135 void generate_nested_group(const MessageSpec& ms, const FieldSpecMap& fspec, int depth, ostream& outh, const std::string& fixns);
136 void generate_common_group_bodies(const FieldSpecMap& fspec, ostream& outp, CommonGroupMap& globmap);
137 void load_components(const XmlElement::XmlSet& comlist, Components& components);
138 unsigned lookup_component(const Components& compon, const f8String& name);
139 void binary_report();
140 string bintoaschex(const string& from);
141 uint32_t group_hash(const MessageSpec& p1);
142 const MessageSpec *find_group(const CommonGroupMap& globmap, int& vers, unsigned tp, uint32_t key);
143 void generate_group_traits(const FieldSpecMap& fspec, const MessageSpec& ms, const string& gname, const string& prefix, ostream& outp);
144 void generate_export( ostream& to, const string& ns );
145 
146 //-----------------------------------------------------------------------------------------
147 int main(int argc, char **argv)
148 {
149  int val;
150  bool dump(false), keep_failed(false), retain_precomp(false), second_only(false), nounique(false);
151  Ctxt ctxt;
152 
153 #ifdef FIX8_HAVE_GETOPT_LONG
154  option long_options[]
155  {
156  { "help", 0, 0, 'h' },
157  { "version", 0, 0, 'v' },
158  { "verbose", 0, 0, 'V' },
159  { "nounique", 0, 0, 'N' },
160  { "norealm", 0, 0, 'R' },
161  { "incpath", 0, 0, 'P' },
162  { "nowarn", 0, 0, 'W' },
163  { "odir", 1, 0, 'o' },
164  { "dump", 0, 0, 'd' },
165  { "extension", 0, 0, 'e' },
166  { "ignore", 0, 0, 'i' },
167  { "nocheck", 0, 0, 'C' },
168  { "noconst", 0, 0, 'U' },
169  { "info", 0, 0, 'I' },
170  { "unused", 0, 0, 'u' },
171  { "fields", 0, 0, 'f' },
172  { "xfields", 1, 0, 'F' },
173  { "keep", 0, 0, 'k' },
174  { "retain", 0, 0, 'r' },
175  { "binary", 0, 0, 'b' },
176  { "classes", 1, 0, 'c' },
177  { "pch", 1, 0, 'H' },
178  { "second", 0, 0, 's' },
179  { "defaulted", 0, 0, 'D' },
180  { "noshared", 0, 0, 'S' },
181  { "prefix", 1, 0, 'p' },
182  { "namespace", 1, 0, 'n' },
183  { "tabsize", 1, 0, 't' },
184  { "fixt", 1, 0, 'x' },
185  { 0 },
186  };
187 
188  while ((val = getopt_long (argc, argv, GETARGLIST.c_str(), long_options, 0)) != -1)
189 #else
190  while ((val = getopt (argc, argv, GETARGLIST.c_str())) != -1)
191 #endif
192  {
193  switch (val)
194  {
195  case 'v':
196  cout << "f8c for " << Session::copyright_string() << endl;
197  return 0;
198  case 'I':
199  for (const auto& pp : package_info())
200  cout << pp.first << ": " << pp.second << endl;
201  return 0;
202  case 'V': verbose = true; break;
203  case 'f': gen_fields = true; break;
204  case 'N': nounique = true; break;
205  case 'R': norealm = true; break;
206  case 'C': nocheck = true; break;
207  case 'U': nconst_router = true; break;
208  case 'u': report_unused = true; break;
209  case 'c': gen_classes = optarg; break;
210  case 'F': extra_fields = optarg; break;
211  case 'h': print_usage(); return 0;
212  case ':': case '?': return 1;
213  case 'o': CheckAddTrailingSlash(odir = optarg); break;
214  case 'd': dump = true; break;
215  case 'e': ext_ver = 1; break;
216  case 'i': error_ignore = true; break;
217  case 'P': incpath = false; break;
218  case 'k': keep_failed = true; break;
219  case 'r': retain_precomp = true; break;
220  case 's': second_only = true; break;
221  case 'S': no_shared_groups = true; break;
222  case 'D': no_default_routers = true; break;
223  case 't': tabsize = stoul(optarg); break;
224  case 'p': prefix = optarg; break;
225  case 'H': precompHdr = optarg; break;
226  case 'b': binary_report(); return 0;
227  case 'x': fixt = optarg; break;
228  case 'n': ctxt._fixns = optarg; break;
229  default: break;
230  }
231  }
232 
233  spacer.assign(tabsize, ' ');
234 
235  if (optind < argc)
236  {
237  inputFile = argv[optind];
239  if (!fixt.empty())
241  }
242  else
243  {
244  cerr << "no input xml file specified" << endl;
245  print_usage();
246  return 1;
247  }
248 
249  if (!gen_classes.empty() && gen_classes != "server" && gen_classes != "client")
250  {
251  cerr << "Error: " << gen_classes << " not a valid role for class generation. Choose 'server' or 'client'." << endl;
252  print_usage();
253  return 1;
254  }
255 
256  unique_ptr<XmlElement> cfr;
257  if (second_only)
258  {
259  cfr.reset(XmlElement::Factory(inputFile));
260  if (!cfr.get())
261  {
262  cerr << "Error reading file \'" << inputFile << '\'';
263  if (errno)
264  cerr << " (" << strerror(errno) << ')';
265  cerr << endl;
266  return 1;
267  }
268  }
269  else
270  {
271  cout << "expanding " << shortName << ' ';
272  cout.flush();
273  unique_ptr<ostream> pre_out(open_ofile(odir, shortName + ".p1", precompFile));
274  if (!pre_out.get())
275  {
276  cerr << endl << "Error opening: " << odir << '/' << shortName;
277  if (errno)
278  cerr << " (" << strerror(errno) << ')';
279  cerr << endl;
280  return 1;
281  }
282  unique_ptr<XmlElement> pcmp(XmlElement::Factory(inputFile)), pcmpfixt;
283  if (!pcmp.get())
284  {
285  cerr << "Error reading file \'" << inputFile << '\'' << " (" << precompFile << ')';
286  if (errno)
287  cerr << " (" << strerror(errno) << ')';
288  cerr << endl;
289  return 1;
290  }
291  unsigned xmlsz(pcmp->GetLineCnt()), fixtsz(0);
292  if (!fixt.empty())
293  {
294  pcmpfixt.reset(XmlElement::Factory(fixt));
295  if (!pcmpfixt.get())
296  {
297  cerr << "Error reading file \'" << fixt << '\'';
298  if (errno)
299  cerr << " (" << strerror(errno) << ')';
300  cerr << endl;
301  return 1;
302  }
303  fixtsz = pcmpfixt->GetLineCnt();
304  }
305  cout << (fixtsz + xmlsz) << " => ";
306  cout.flush();
307  if (!fixt.empty())
308  precompfixt(*pcmpfixt, *pcmp, *pre_out, nounique);
309  else
310  precomp(*pcmp, *pre_out);
311  pre_out.reset();
312  cfr.reset(XmlElement::Factory(precompFile));
313  cout << cfr->GetLineCnt() << " lines" << endl;
314  if (!retain_precomp)
315  remove(precompFile.c_str());
316  }
317 
318  if (cfr->GetErrorCnt())
319  {
320  cerr << cfr->GetErrorCnt() << " error"
321  << (cfr->GetErrorCnt() == 1 ? " " : "s ") << "found in \'" << shortName << '\'' << endl;
322  return 1;
323  }
324 
325  if (dump)
326  {
327  cout << *cfr;
328  return 0;
329  }
330 
331  if (load_fix_version (*cfr, ctxt) < 0)
332  return 1;
333  if (ctxt._beginstr.compare(0, 4, "FIX.") == 0 && ctxt._version >= 5000)
334  {
335  cerr << "Error: " << ctxt._beginstr << " requires an additional FIXT schema specification." << endl;
336  return 1;
337  }
338 
339  for (unsigned ii(0); ii < Ctxt::count; ++ii)
340  {
341  ctxt._out[ii].first.second = prefix + ctxt._exts[ii] + ctxt._exts_ver[ext_ver];
342  ctxt._out[ii].first.first = ctxt._out[ii].first.second + ".p2";
343  remove(ctxt._out[ii].first.first.c_str());
344  string target;
345  if ((ctxt._out[ii].second = open_ofile(odir, ctxt._out[ii].first.first, target)) == 0)
346  return 1;
347  }
348 
349  int result(1);
350  if (!glob_errors)
351  {
352  cout << "compiling " << shortName << endl;
353 
354  // insert any fields passed on the command line into the DOM
355  if (!extra_fields.empty())
356  {
357  XmlElement *flds(const_cast<XmlElement*>(cfr->find("fix/fields"))),
358  *msgs(const_cast<XmlElement*>(cfr->find("fix/messages")));
359  if (flds && msgs)
360  {
361  const RegExp rMS("([^:]+):(Y|N)");
362  istringstream istr(extra_fields);
363  size_t added(0);
364  while (istr.good())
365  {
366  unique_ptr<XmlElement> nel(new XmlElement(istr, 0, flds));
367  string what;
368  if (nel->GetTag().empty() || !nel->GetAttr("messages", what) || !flds->Insert(nel.get()))
369  continue;
370 
371  // messages='NewOrderSingle:Y ExecutionReport:Y OrderCancelRequest:N'
372  RegMatch match;
373  while (rMS.SearchString(match, what, 3) == 3)
374  {
375  string msg_name, mandatory;
376  rMS.SubExpr(match, what, msg_name, 0, 1);
377  rMS.SubExpr(match, what, mandatory, 0, 2);
378  trim(msg_name);
379  rMS.Erase(match, what);
380  const string name_tag("name");
381  XmlElement *tmsg(const_cast<XmlElement*>(msgs->find("messages/message", &name_tag, &msg_name)));
382  if (!tmsg)
383  {
384  if (!nowarn)
385  cerr << "message: " << msg_name << " not found for custom specification" << endl;
386  ++glob_warnings;
387  continue;
388  }
389  ostringstream ostr;
390  string field_name;
391  nel->GetAttr(name_tag, field_name);
392  ostr << "<field name='" << field_name << "' required='" << mandatory << "' />";
393  istringstream mistr(ostr.str());
394  unique_ptr<XmlElement> mel(new XmlElement(mistr, 0, msgs));
395  if (!mel->GetTag().empty() && tmsg->Insert(mel.get()))
396  mel.release();
397  }
398 
399  ++added;
400  nel.release();
401 
402  }
403  if (verbose)
404  cout << added << " candidate custom fields found" << endl;
405  }
406  }
407 
408  result = process(*cfr, ctxt);
409 
410  for (unsigned ii(0); ii < Ctxt::count; ++ii)
411  {
412  delete ctxt._out[ii].second;
413  if (glob_errors && !error_ignore)
414  {
415  if (!keep_failed)
416  remove(ctxt._out[ii].first.first.c_str());
417  }
418  else
419  {
420  try
421  {
422  push_dir pd(odir);
423  string backup(ctxt._out[ii].first.second + ".old");
424  remove(backup.c_str());
425  rename(ctxt._out[ii].first.second.c_str(), backup.c_str());
426  if (rename(ctxt._out[ii].first.first.c_str(), ctxt._out[ii].first.second.c_str()))
427  {
428  cerr << "Error renaming files \'" << ctxt._out[ii].first.first << "' to '" << ctxt._out[ii].first.second;
429  if (errno)
430  cerr << " (" << strerror(errno) << ')';
431  cerr << endl;
432  }
433 
434  if (gen_classes.empty())
435  remove(ctxt._out[Ctxt::session_hpp].first.second.c_str());
436  }
437  catch (f8Exception& e)
438  {
439  cerr << "exception: " << e.what() << endl;
440  }
441  }
442  }
443  }
444 
445  if (glob_errors)
446  cerr << glob_errors << " error" << (glob_errors == 1 ? "." : "s.") << endl;
447  if (glob_warnings)
448  cerr << glob_warnings << " warning" << (glob_warnings == 1 ? "." : "s.") << endl;
449  return result;
450 }
451 
452 //-----------------------------------------------------------------------------------------
454 {
455  XmlElement::XmlSet flist;
456  if (!xf.find("fix/fields/field", flist))
457  {
458  cerr << "error: No fields found in " << shortName << endl;
459  return 0;
460  }
461 
462  int fieldsLoaded(0);
463 
464  for(const auto *pp : flist)
465  {
466  string number, name, type;
467  if (pp->GetAttr("number", number) && pp->GetAttr("name", name) && pp->GetAttr("type", type))
468  {
469  trim(number);
470  trim(name);
471  trim(type);
472  InPlaceStrToUpper(type);
473  const auto bmitr(FieldSpec::_baseTypeMap.find(type));
474  FieldTrait::FieldType ft(bmitr == FieldSpec::_baseTypeMap.end() ? FieldTrait::ft_untyped : bmitr->second);
475  pair<FieldSpecMap::iterator, bool> result;
476  if (ft != FieldTrait::ft_untyped)
477  {
478  try
479  {
480  result = fspec.insert({stoul(number), FieldSpec(name, ft)});
481  }
482  catch (exception& e)
483  {
484  cerr << shortName << ':' << recover_line(*pp) << ": error: Failed to convert (stoul) number " << number << " in " << name << endl;
485  ++glob_errors;
486  }
487  }
488  else
489  {
490  if (!nowarn)
491  cerr << shortName << ':' << recover_line(*pp) << ": warning: Unknown field type: " << type << " in " << name << endl;
492  ++glob_warnings;
493  continue;
494  }
495 
496  pp->GetAttr("description", result.first->second._description);
497  pp->GetAttr("comment", result.first->second._comment);
498 
499  ++fieldsLoaded;
500 
501  XmlElement::XmlSet realmlist;
502  if (pp->find("field/value", realmlist))
503  {
504  for(const auto *pp : realmlist)
505  {
506  string enum_str, description;
507  if (pp->GetAttr("enum", enum_str))
508  {
509  if (!pp->GetAttr("description", description) || description.empty())
510  description = enum_str; // use enum if no description supplied
511 
512  if (!result.first->second._dvals)
513  result.first->second._dvals = new RealmMap;
514  string rangeend;
515  bool isRange(pp->GetAttr("range", rangeend) && (rangeend == "lower" || rangeend == "upper"));
516  RealmObject *realmval(RealmObject::create(enum_str, ft, isRange));
517  if (isRange)
518  result.first->second._dtype = RealmBase::dt_range;
519  if (realmval)
520  result.first->second._dvals->insert({realmval, description});
521  }
522  else
523  {
524  cerr << shortName << ':' << recover_line(*pp) << ": error: field value element missing required attribute (enum)." << endl;
525  ++glob_errors;
526  }
527  }
528  }
529  }
530  else
531  {
532  cerr << shortName << ':' << recover_line(*pp) << ": error: field definition element missing required attributes (number, name or type)" << endl;
533  ++glob_errors;
534  }
535  }
536 
537  return fieldsLoaded;
538 }
539 
540 //-----------------------------------------------------------------------------------------
541 int load_messages(XmlElement& xf, MessageSpecMap& mspec, const FieldToNumMap& ftonSpec,
542  FieldSpecMap& fspec, Components& compon, CommonGroupMap& globmap)
543 {
544  int msgssLoaded(0), grpsparsed(0);
545 
546  XmlElement::XmlSet mlist;
547  if (!xf.find("fix/messages/message", mlist))
548  {
549  cerr << "error: No messages found in " << shortName << endl;
550  ++glob_errors;
551  return 0;
552  }
553 
554  if (!xf.find("fix/header", mlist))
555  {
556  cerr << "error: No header element found in " << shortName << endl;
557  ++glob_errors;
558  return 0;
559  }
560 
561  if (!xf.find("fix/trailer", mlist))
562  {
563  cerr << "error: No trailer element found in " << shortName << endl;
564  ++glob_errors;
565  return 0;
566  }
567 
568  // lookup msgtype realm - all messages must have corresponding entry here
569  FieldSpecMap::const_iterator fsitr(fspec.find(35)); // always 35
570  if (fsitr == fspec.end() || !fsitr->second._dvals)
571  {
572  cerr << "error: Could not locate MsgType realm defintions in '" << shortName
573  << "'. See FAQ for more details." << endl;
574  ++glob_errors;
575  return 0;
576  }
577 
578  for(const auto *pp : mlist)
579  {
580  string msgcat, name, msgtype, elname;
581  if (pp->GetTag() == "header")
582  msgtype = name = elname = "header";
583  else if (pp->GetTag() == "trailer")
584  msgtype = name = elname = "trailer";
585  else if (pp->GetAttr("msgtype", msgtype) && pp->GetAttr("name", name) && pp->GetAttr("msgcat", msgcat))
586  {
587  StringRealm srealm(msgtype, false);
588  RealmMap::const_iterator ditr(fsitr->second._dvals->find(&srealm));
589  if (ditr == fsitr->second._dvals->end())
590  {
591  cerr << shortName << ':' << recover_line(*pp) << ": error: Message '"
592  << name << "' does not have corrresponding entry in MsgType field realm. See FAQ for more details." << endl;
593  ++glob_errors;
594  continue;
595  }
596 
597  elname = "message";
598  }
599  else
600  {
601  cerr << shortName << ':' << recover_line(*pp) << ": error: Message element missing required attributes" << endl;
602  ++glob_errors;
603  continue;
604  }
605 
606  pair<MessageSpecMap::iterator, bool> result(mspec.insert({msgtype, MessageSpec(name, msgcat % "admin")}));
607  if (!result.second)
608  {
609  cerr << shortName << ':' << recover_line(*pp) << ": error: Could not add message '" << name << "' (" << msgtype << ")" << endl;
610  ++glob_errors;
611  continue;
612  }
613 
614  string elpart;
615  XmlElement::XmlSet grplist;
616  if (pp->find(mkel(elname, "group", elpart), grplist))
617  grpsparsed += parse_groups(result.first->second, name, ftonSpec, fspec, grplist, compon, globmap);
618 
619  pp->GetAttr("comment", result.first->second._comment);
620 
621  process_message_fields(mkel(elname, "field", elpart), pp, result.first->second._fields, ftonSpec, fspec, compon);
622 
623  ++msgssLoaded;
624  }
625 
626  if (verbose)
627  cout << grpsparsed << " repeating groups defined" << endl;
628 
629  return msgssLoaded;
630 }
631 
632 //-----------------------------------------------------------------------------------------
633 unsigned parse_groups(MessageSpec& ritr, const string& name,
634  const FieldToNumMap& ftonSpec, FieldSpecMap& fspec, XmlElement::XmlSet& grplist,
635  const Components& compon, CommonGroupMap& globmap)
636 {
637  unsigned result(0);
638 
639  for(const auto *pp : grplist)
640  {
641  string gname, required;
642  if (pp->GetAttr("name", gname) && pp->GetAttr("required", required))
643  {
644  string compname;
645  unsigned compidx(pp->GetAttr("component", compname) ? lookup_component(compon, compname) : 0);
646 
647  // add group FieldTrait
648  FieldToNumMap::const_iterator ftonItr(ftonSpec.find(gname));
649  FieldSpecMap::const_iterator fs_itr;
650  if (ftonItr != ftonSpec.end() && (fs_itr = fspec.find(ftonItr->second)) != fspec.end())
651  {
652  if (!ritr._fields.add(FieldTrait(fs_itr->first, FieldTrait::ft_int, pp->GetSubIdx(),
653  required == "Y", true, compidx)))
654  {
655  if (!nowarn)
656  cerr << "warning: Could not add group trait object '" << gname << "' (duplicate ?)" << endl;
657  ++glob_warnings;
658  }
659  else
660  {
661  fs_itr->second._used = true; // we always assume group count fields are used
662  pair<GroupMap::iterator, bool> gresult(ritr._groups.insert({fs_itr->first, MessageSpec(gname)}));
663  if (gresult.second)
664  {
665  process_message_fields("group/field", pp, gresult.first->second._fields, ftonSpec, fspec, compon);
666  XmlElement::XmlSet comlist;
667  ++result;
668  if (pp->find("group/group", comlist))
669  result += parse_groups(gresult.first->second, gname, ftonSpec, fspec, comlist, compon, globmap);
670  CommonGroupMap::iterator cgitr(globmap.find(fs_itr->first));
671  if (cgitr == globmap.end())
672  cgitr = globmap.insert(make_pair(fs_itr->first, CommonGroups())).first;
673  const uint32_t hv(group_hash(gresult.first->second));
674  gresult.first->second._hash = hv;
675  cgitr->second.insert(make_pair(hv, gresult.first->second));
676  CommonGroups::iterator cghitr(cgitr->second.find(hv));
677  if (cghitr != cgitr->second.end())
678  {
679  cghitr->second._group_refcnt++;
680  cghitr->second._hash = hv;
681  }
682  }
683  else
684  {
685  if (!nowarn)
686  cerr << "warning: Could not add group map '" << fs_itr->first << "' (duplicate ?)" << endl;
687  ++glob_warnings;
688  }
689  }
690  }
691  else
692  {
693  cerr << shortName << ':' << recover_line(*pp)
694  << ": error: Could not locate group Field '" << gname << "' from known field types in " << shortName << endl;
695  ++glob_errors;
696  continue;
697  }
698  }
699  else
700  {
701  cerr << shortName << ':' << recover_line(*pp) << ": error: group element missing required attributes (name or required)" << endl;
702  ++glob_errors;
703  }
704  }
705  ritr._hash = group_hash(ritr);
706 
707  return result;
708 }
709 
710 //-----------------------------------------------------------------------------------------
711 void generate_nested_group(const MessageSpec& ms, const FieldSpecMap& fspec, int depth, ostream& outh, const std::string& fixns)
712 {
713  if (ms._groups.size())
714  {
715  const string dspacer(depth * tabsize, ' '), d2spacer((depth + 1) * tabsize, ' ');
716 
717  outh << dspacer << "GroupBase *create_nested_group(unsigned short fnum) const" << endl;
718  if (ms._groups.size() > 1)
719  {
720  outh << dspacer << '{' << endl;
721  outh << dspacer << spacer << "switch(fnum)" << endl << dspacer << spacer << '{' << endl;
722  for (const auto& pp : ms._groups)
723  {
724  FieldSpecMap::const_iterator gsitr(fspec.find(pp.first));
725  outh << dspacer << spacer << "case " << gsitr->first << ": return new " << gsitr->second._name << ';' << endl;
726  }
727  outh << dspacer << spacer << "default: return nullptr;" << endl;
728  outh << dspacer << spacer << '}' << endl;
729  outh << dspacer << '}' << endl;
730  }
731  else
732  {
733  const auto& pp(*ms._groups.cbegin());
734  FieldSpecMap::const_iterator gsitr(fspec.find(pp.first));
735  outh << dspacer << spacer << "{ return fnum == " << gsitr->first << " ? new "
736  << gsitr->second._name << " : nullptr; }" << endl;
737  }
738  }
739 }
740 
741 //-----------------------------------------------------------------------------------------
742 void generate_group_bodies(const MessageSpec& ms, const FieldSpecMap& fspec, int depth, const string& msname,
743  ostream& outp, ostream& outh, const CommonGroupMap& globmap, const std::string& fixns, const string cls_prefix)
744 {
745  const string dspacer(depth * tabsize, ' '), d2spacer((depth + 1) * tabsize, ' ');
746 
747  string prefix;
748  if (!cls_prefix.empty())
749  prefix = cls_prefix + "::";
750 
751  for (const auto& pp : ms._groups)
752  {
753  FieldSpecMap::const_iterator gsitr(fspec.find(pp.first));
754  outp << _csMap.find(cs_divider)->second << endl;
755 
756  int vers(0);
757  const MessageSpec *tgroup (find_group(globmap, vers, pp.first, pp.second._hash));
758  if (!tgroup)
759  {
760  cout << pp.first << " not found" << endl;
761  continue;
762  }
763 
764  ostringstream rnme;
765  rnme << gsitr->second._name;
766  if (tgroup->_group_refcnt > 1)
767  rnme << 'V' << vers;
768 
769  if (tgroup->_group_refcnt > 1)
770  outp << "const FieldTrait *" << prefix << ms._name << "::" << gsitr->second._name << "::_traits("
771  << rnme.str() << "_traits);" << endl;
772  else
773  generate_group_traits(fspec, *tgroup, rnme.str(), prefix + ms._name + "::", outp);
774 
775  if (tgroup->_group_refcnt > 1)
776  {
777  outp << "const FieldTrait_Hash_Array" << "& " << prefix << ms._name << "::" << gsitr->second._name << "::_ftha("
778  << rnme.str() << "_ftha);" << endl;
779  outp << "const MsgType" << "& " << prefix << ms._name << "::" << gsitr->second._name << "::_msgtype("
780  << rnme.str() << "_msgtype);" << endl;
781  }
782  else
783  outp << "const MsgType " << prefix << ms._name << "::" << gsitr->second._name << "::_msgtype("
784  << '"' << gsitr->second._name << "\");" << endl;
785 
786  // nested class decl.
787  outh << endl << dspacer << "/// " << tgroup->_name << " (" << pp.first << "), "
788  << (tgroup->_is_admin ? "admin" : "application") << ", " << tgroup->_fields.get_presence().size()
789  << " fiel" << (tgroup->_fields.get_presence().size() == 1 ? "d, " : "ds, ")
790  << tgroup->_groups.size() << " grou" << (tgroup->_groups.size() == 1 ? "p, " : "ps, ")
791  << (tgroup->_group_refcnt > 1 ? "shares static data" : "is unique") << ", hash: 0x"
792  << hex << tgroup->_hash << dec << endl;
793  outh << dspacer << "// " << prefix << ms._name << "::" << gsitr->second._name << endl;
794  outh << dspacer << "class " << gsitr->second._name
795  << " : public GroupBase // depth: " << depth << endl << dspacer << '{' << endl;
796  if (tgroup->_group_refcnt > 1)
797  {
798  outh << d2spacer << "static F8_" << fixns << "_API const FieldTrait *_traits;" << endl;
799  outh << d2spacer << "static F8_" << fixns << "_API const FieldTrait_Hash_Array& _ftha;" << endl;
800  outh << d2spacer << "static F8_" << fixns << "_API const MsgType& _msgtype;" << endl;
801  }
802  else
803  {
804  outh << d2spacer << "static F8_" << fixns << "_API const FieldTrait _traits[];" << endl;
805  outh << d2spacer << "static F8_" << fixns << "_API const FieldTrait_Hash_Array _ftha;" << endl;
806  outh << d2spacer << "static F8_" << fixns << "_API const MsgType _msgtype;" << endl;
807  }
808  outh << d2spacer << "static const unsigned _fieldcnt = " << tgroup->_fields.get_presence().size() << ';' << endl << endl;
809  outh << dspacer << "public:" << endl;
810  outh << d2spacer << "enum { _fnum = " << gsitr->first << " };" << endl << endl;
811  outh << d2spacer << gsitr->second._name << "() : GroupBase(_fnum) {}" << endl;
812  outh << d2spacer << "~" << gsitr->second._name << "() = default;" << endl;
813  if (tgroup->_groups.empty())
814  outh << d2spacer << "MessageBase *create_group(bool) const { return new MessageBase(ctx(), _msgtype(), _traits, _fieldcnt, &_ftha); }" << endl;
815  else
816  {
817  outh << d2spacer << "MessageBase *create_group(bool deepctor) const" << endl << d2spacer << '{' << endl;
818  outh << d2spacer << spacer << "MessageBase *mb(new MessageBase(ctx(), _msgtype(), _traits, _fieldcnt, &_ftha));" << endl;
819  outh << d2spacer << spacer << "if (deepctor)" << endl;
820  outh << d2spacer << spacer << spacer << "mb->get_groups().insert({";
821  if (tgroup->_groups.size() == 1)
822  outh << tgroup->_groups.begin()->first << ", new " << tgroup->_groups.begin()->second._name << " });" << endl;
823  else
824  {
825  outh << endl;
826  for (const auto& qq : tgroup->_groups)
827  outh << d2spacer << spacer << spacer << spacer << "{ " << qq.first << ", new " << qq.second._name << " }," << endl;
828  outh << d2spacer << spacer << spacer << "});" << endl;
829  }
830 
831  outh << d2spacer << spacer << "return mb;" << endl;
832  outh << d2spacer << '}' << endl;
833  }
834  outh << endl << d2spacer << "static const " << msname << "& get_msgtype() { return _msgtype; }" << endl;
835 #if defined FIX8_HAVE_EXTENDED_METADATA
836  outh << d2spacer << "static const FieldTrait *get_traits() { return _traits; };" << endl;
837  outh << d2spacer << "static const unsigned get_fieldcnt() { return _fieldcnt; };" << endl;
838 #endif
839 
840  // process nested groups
841  if (!tgroup->_groups.empty())
842  {
843  outh << endl;
844  generate_nested_group(*tgroup, fspec, depth + 1, outh, fixns);
845  generate_group_bodies(*tgroup, fspec, depth + 1, msname, outp, outh, globmap, fixns, prefix + ms._name);
846  }
847 
848  outh << dspacer << "};" << endl;
849  }
850 }
851 
852 //-----------------------------------------------------------------------------------------
853 void generate_group_traits(const FieldSpecMap& fspec, const MessageSpec& ms, const string& gname, const string& prefix, ostream& outp)
854 {
855  if (prefix.empty())
856  outp << "const FieldTrait " << gname << "_traits[]"
857  << " // refs:" << ms._group_refcnt << endl << '{' << endl;
858  else
859  outp << "const FieldTrait " << prefix << gname << "::_traits[]" << endl << '{' << endl;
860  int felpos(0);
862  flitr != ms._fields.get_presence().end(); ++flitr, ++felpos)
863  {
864  bool spaceme(true);
865  if (flitr != ms._fields.get_presence().begin())
866  {
867  outp << ',';
868  if (felpos % 4 == 0)
869  outp << endl;
870  else
871  spaceme = false;
872  }
873 
874  ostringstream tostr;
875  tostr << "0x" << setfill('0') << setw(2) << hex << flitr->_field_traits.get();
876  outp << (spaceme ? spacer : " ");
877  outp << '{' << setw(4) << right << flitr->_fnum << ',' << setw(2)
878  << right << flitr->_ftype << ',' << setw(3) << right << flitr->_pos <<
879  ',' << setw(3) << right << flitr->_component << ',' << tostr.str();
880 #if defined FIX8_HAVE_EXTENDED_METADATA
881  if (no_shared_groups && flitr->_field_traits.has(FieldTrait::group))
882  {
883  outp << ", " << endl << spacer << spacer;
884  FieldSpecMap::const_iterator gsitr(fspec.find(flitr->_fnum));
885  outp << gsitr->second._name << "::get_traits(), " << gsitr->second._name << "::get_fieldcnt()";
886  outp << endl << spacer << '}';
887  felpos = -1;
888  }
889  else
890 #endif
891  outp << '}';
892  }
893  outp << endl << "};" << endl;
894  if (prefix.empty())
895  {
896  outp << "const FieldTrait_Hash_Array " << gname << "_ftha(" << gname << "_traits, "
897  << ms._fields.get_presence().size() << ");" << endl;
898  outp << "const MsgType " << gname << "_msgtype(\"" << gname << "\");" << endl;
899  }
900  else
901  outp << "const FieldTrait_Hash_Array " << endl << spacer << prefix << gname
902  << "::_ftha(" << prefix << gname << "::_traits, " << gname << "::_fieldcnt);" << endl;
903 }
904 
905 //-----------------------------------------------------------------------------------------
906 void generate_common_group_bodies(const FieldSpecMap& fspec, ostream& outp, CommonGroupMap& globmap)
907 {
908  for (const auto& pp : globmap)
909  {
910  int vers(1);
911  for (const auto& ii : pp.second)
912  {
913  if (ii.second._group_refcnt > 1) // if there is only one variant, don't generate code in common section
914  {
915  FieldSpecMap::const_iterator gsitr(fspec.find(pp.first));
916  outp << _csMap.find(cs_divider)->second << endl;
917  ostringstream gostr;
918  gostr << gsitr->second._name << 'V' << vers;
919 
920  generate_group_traits(fspec, ii.second, gostr.str(), string(), outp);
921  }
922  ++vers;
923  }
924  }
925 }
926 
927 //-----------------------------------------------------------------------------------------
928 int process(XmlElement& xf, Ctxt& ctxt)
929 {
930  ostream& ost_cpp(*ctxt._out[Ctxt::types_cpp].second);
931  ostream& ost_hpp(*ctxt._out[Ctxt::types_hpp].second);
932  ostream& osr_cpp(*ctxt._out[Ctxt::traits_cpp].second);
933  ostream& osc_hpp(*ctxt._out[Ctxt::classes_hpp].second);
934  ostream& osc_cpp(*ctxt._out[Ctxt::classes_cpp].second);
935  ostream& osu_hpp(*ctxt._out[Ctxt::router_hpp].second);
936  ostream& oss_hpp(*ctxt._out[Ctxt::session_hpp].second);
937  int result(0);
938 
939 // ================================= Field loading =======================================
940  FieldSpecMap fspec;
941  int fields(load_fields(xf, fspec));
942  if (!fields || glob_errors)
943  return 0;
944  if (verbose)
945  cout << fields << " fields defined" << endl;
946 
947 // ================================= Message processing ===================================
948 
949  FieldToNumMap ftonSpec;
950  for (const auto& pp : fspec)
951  ftonSpec.insert({pp.second._name, pp.first});
952 
953  XmlElement::XmlSet comlist;
954  Components components;
955  xf.find("fix/components/component", comlist);
956  load_components(comlist, components);
957 
958  MessageSpecMap mspec;
959  CommonGroupMap globmap;
960 
961  int msgsloaded(load_messages(xf, mspec, ftonSpec, fspec, components, globmap));
962  if (!msgsloaded)
963  return result;
964  if (verbose)
965  {
966  cout << msgsloaded << " messages defined" << endl;
967  if (components.size())
968  cout << components.size() << " components defined" << endl;
969  if (globmap.size())
970  {
971  unsigned cgs(0), ugs(0), vars(0);
972  for (const auto& pp : globmap)
973  {
974  vars += static_cast<unsigned>(pp.second.size());
975  for (const auto& ii : pp.second)
976  {
977  if (ii.second._group_refcnt > 1)
978  ugs += ii.second._group_refcnt;
979  else
980  ++cgs;
981  }
982  }
983  cout << globmap.size() << " repeating group catagories (" << vars << " variants, "
984  << ugs << " common, " << cgs << " unique) processed" << endl;
985  }
986  }
987 
988  process_ordering(mspec);
989  process_group_ordering(globmap);
990 
991  // output file preambles
992  generate_preamble(osu_hpp, ctxt._out[Ctxt::router_hpp].first.second, true);
993  osu_hpp << "#ifndef " << bintoaschex(ctxt._out[Ctxt::router_hpp].first.second) << endl;
994  osu_hpp << "#define " << bintoaschex(ctxt._out[Ctxt::router_hpp].first.second) << endl << endl;
995  osu_hpp << _csMap.find(cs_start_namespace)->second << endl;
996  osu_hpp << "namespace " << ctxt._fixns << " {" << endl;
997  osu_hpp << endl << _csMap.find(cs_divider)->second << endl;
998 
999  generate_preamble(osc_hpp, ctxt._out[Ctxt::classes_hpp].first.second, true);
1000  osc_hpp << "#ifndef " << bintoaschex(ctxt._out[Ctxt::classes_hpp].first.second) << endl;
1001  osc_hpp << "#define " << bintoaschex(ctxt._out[Ctxt::classes_hpp].first.second) << endl << endl;
1002  generate_export(osc_hpp, ctxt._fixns);
1003  osc_hpp << _csMap.find(cs_start_namespace)->second << endl;
1004  osc_hpp << endl << "extern \"C\"" << endl << '{' << endl
1005  << spacer << "F8_" << ctxt._fixns << "_API const F8MetaCntx& " << ctxt._fixns << "_ctx();" << endl << '}' << endl << endl;
1006  osc_hpp << "namespace " << ctxt._fixns << " {" << endl;
1007 
1008  osc_hpp << endl << _csMap.find(cs_divider)->second << endl;
1009  osc_hpp << "using " << ctxt._clname << "_BaseMsgEntry = MsgTable;" << endl;
1010  osc_hpp << "/// Compiler generated metadata object, accessed through this function." << endl;
1011  osc_hpp << "F8_" << ctxt._fixns << "_API " << "const F8MetaCntx& ctx();" << endl;
1012  osc_hpp << "class " << ctxt._clname << "_Router;" << endl;
1013  osc_hpp << endl << _csMap.find(cs_divider)->second << endl;
1014 
1015  generate_preamble(osc_cpp, ctxt._out[Ctxt::classes_cpp].first.second, false);
1016  osc_cpp << _csMap.find(cs_generated_includes)->second << endl;
1017  generate_includes(osc_cpp);
1018  osc_cpp << "#include \"" << ctxt._out[Ctxt::types_hpp].first.second << '"' << endl;
1019  osc_cpp << "#include \"" << ctxt._out[Ctxt::router_hpp].first.second << '"' << endl;
1020  osc_cpp << "#include \"" << ctxt._out[Ctxt::classes_hpp].first.second << '"' << endl;
1021  osc_cpp << _csMap.find(cs_divider)->second << endl;
1022  osc_cpp << _csMap.find(cs_start_namespace)->second << endl;
1023  osc_cpp << "namespace " << ctxt._fixns << " {" << endl << endl;
1024  osc_cpp << _csMap.find(cs_start_anon_namespace)->second << endl << endl;
1025  osc_cpp << _csMap.find(cs_divider)->second << endl;
1026 
1027  generate_preamble(osr_cpp, ctxt._out[Ctxt::traits_cpp].first.second, false);
1028  osr_cpp << _csMap.find(cs_generated_includes)->second << endl;
1029  generate_includes(osr_cpp);
1030  osr_cpp << "#include \"" << ctxt._out[Ctxt::types_hpp].first.second << '"' << endl;
1031  osr_cpp << "#include \"" << ctxt._out[Ctxt::router_hpp].first.second << '"' << endl;
1032  osr_cpp << "#include \"" << ctxt._out[Ctxt::classes_hpp].first.second << '"' << endl;
1033  osr_cpp << _csMap.find(cs_divider)->second << endl;
1034  osr_cpp << _csMap.find(cs_start_namespace)->second << endl;
1035  osr_cpp << "namespace " << ctxt._fixns << " {" << endl << endl;
1036 
1037  osr_cpp << _csMap.find(cs_divider)->second << endl;
1038 
1039 // =============================== Message class definitions ==============================
1040 
1041  if (!no_shared_groups)
1042  {
1043  osr_cpp << "// Common group traits" << endl;
1044  osr_cpp << "namespace {" << endl;
1045  generate_common_group_bodies(fspec, osr_cpp, globmap);
1046  osr_cpp << "} // namespace" << endl << endl;
1047  }
1048 #if defined FIX8_HAVE_EXTENDED_METADATA
1049  else
1050  {
1051  osr_cpp << "//" << endl;
1052  osr_cpp << "// Shared groups disabled (--noshared). Static traits are now exposed." << endl;
1053  osr_cpp << "//" << endl;
1054  }
1055 #endif
1056  osr_cpp << _csMap.find(cs_divider)->second << endl;
1057  osr_cpp << "// Message traits" << endl;
1058 
1059  FieldSpecMap::const_iterator fsitr(fspec.find(35)); // always 35
1060  for (const auto& pp : mspec)
1061  {
1062  bool isTrailer(pp.second._name == "trailer");
1063  bool isHeader(pp.second._name == "header");
1064  osc_hpp << "/// " << pp.second._name << " (" << pp.first << "), "
1065  << (pp.second._is_admin ? "admin" : "application")
1066  << ", " << pp.second._fields.get_presence().size() << " fiel"
1067  << (pp.second._fields.get_presence().size() == 1 ? "d, " : "ds, ")
1068  << pp.second._groups.size() << " grou" << (pp.second._groups.size() == 1 ? "p." : "ps.");
1069  if (!pp.second._comment.empty())
1070  osc_hpp << ' ' << pp.second._comment;
1071  osc_hpp << endl;
1072  osc_hpp << "class " << pp.second._name << " : public "
1073  << (isTrailer || isHeader ? "MessageBase" : "Message") << endl << '{' << endl;
1074 
1075  if (pp.second._fields.get_presence().size())
1076  {
1077  osr_cpp << _csMap.find(cs_divider)->second << endl;
1078  osr_cpp << "const FieldTrait " << pp.second._name << "::_traits[]"
1079  << endl << '{' << endl;
1080  int felpos(0);
1081  for (Presence::const_iterator flitr(pp.second._fields.get_presence().begin());
1082  flitr != pp.second._fields.get_presence().end(); ++flitr, ++felpos)
1083  {
1084  bool spaceme(true);
1085  if (flitr != pp.second._fields.get_presence().begin())
1086  {
1087  osr_cpp << ',';
1088  if (felpos % 4 == 0)
1089  osr_cpp << endl;
1090  else
1091  spaceme = false;
1092  }
1093 
1094  ostringstream tostr;
1095  tostr << "0x" << setfill('0') << setw(2) << hex << flitr->_field_traits.get();
1096  osr_cpp << (spaceme ? spacer : " ");
1097  osr_cpp << '{' << setw(4) << right << flitr->_fnum << ','
1098  << setw(2) << right << flitr->_ftype << ',' << setw(3) << right
1099  << flitr->_pos << ',' << setw(3) << right << flitr->_component << ',' << tostr.str();
1100 #if defined FIX8_HAVE_EXTENDED_METADATA
1101  if (no_shared_groups && flitr->_field_traits.has(FieldTrait::group))
1102  {
1103  osr_cpp << ", " << endl << spacer << spacer;
1104  FieldSpecMap::const_iterator gsitr(fspec.find(flitr->_fnum));
1105  osr_cpp << gsitr->second._name << "::get_traits(), " << gsitr->second._name << "::get_fieldcnt()";
1106  osr_cpp << endl << spacer << '}';
1107  felpos = -1;
1108  }
1109  else
1110 #endif
1111  osr_cpp << '}';
1112  }
1113  osr_cpp << endl << "};" << endl;
1114  osr_cpp << "const FieldTrait_Hash_Array " << pp.second._name << "::_ftha(" << pp.second._name << "::_traits, "
1115  << pp.second._name << "::_fieldcnt);" << endl;
1116  osr_cpp << "const MsgType " << pp.second._name << "::_msgtype(\"" << pp.first << "\");" << endl;
1117  osc_hpp << spacer << "static F8_" << ctxt._fixns << "_API const FieldTrait _traits[];" << endl;
1118  osc_hpp << spacer << "static F8_" << ctxt._fixns << "_API const FieldTrait_Hash_Array _ftha; " << endl;
1119  osc_hpp << spacer << "static F8_" << ctxt._fixns << "_API const MsgType _msgtype;" << endl;
1120  osc_hpp << spacer << "static F8_" << ctxt._fixns << "_API const unsigned _fieldcnt = " << pp.second._fields.get_presence().size() << ';' << endl;
1121  }
1122 
1123  if (isHeader)
1124  {
1125  osc_hpp << endl << spacer << "begin_string *_begin_string;" << endl;
1126  osc_hpp << spacer << "body_length *_body_length;" << endl;
1127  osc_hpp << spacer << "msg_type *_msg_type;" << endl;
1128  }
1129  else if (isTrailer)
1130  osc_hpp << endl << spacer << "check_sum *_check_sum;" << endl;
1131 
1132  osc_hpp << endl;
1133 
1134  osc_hpp << "public:" << endl;
1135  osc_hpp << spacer << "explicit " << pp.second._name << "(bool deepctor=true)";
1136  if (pp.second._fields.get_presence().size())
1137  osc_hpp << " : " << (isTrailer || isHeader ? "MessageBase" : "Message")
1138  << "(ctx(), _msgtype(), _traits, _fieldcnt, &_ftha)";
1139  if (isHeader || isTrailer)
1140  {
1141  osc_hpp << ',' << endl << spacer << spacer;
1142  if (isHeader)
1143  osc_hpp << "_begin_string(new begin_string(ctx()._beginStr)), _body_length(new body_length), _msg_type(new msg_type)";
1144  else
1145  osc_hpp << "_check_sum(new check_sum)";
1146  osc_hpp << " { add_preamble(); }" << endl;
1147  }
1148  else if (!pp.second._groups.empty())
1149  {
1150  osc_hpp << endl << spacer << '{' << endl;
1151  osc_hpp << spacer << spacer << "if (deepctor)" << endl;
1152  osc_hpp << spacer << spacer << spacer << "_groups.insert({";
1153  if (pp.second._groups.size() == 1)
1154  osc_hpp << pp.second._groups.begin()->first << ", new " << pp.second._groups.begin()->second._name << " });" << endl;
1155  else
1156  {
1157  osc_hpp << endl;
1158  for (const auto& ii : pp.second._groups)
1159  {
1160  FieldSpecMap::const_iterator gsitr(fspec.find(ii.first));
1161  osc_hpp << spacer << spacer << spacer << spacer << "{ " << gsitr->first << ", new " << gsitr->second._name << " }," << endl;
1162  }
1163  osc_hpp << spacer << spacer << spacer << "});" << endl;
1164  }
1165  osc_hpp << spacer << '}' << endl;
1166  }
1167  else
1168  osc_hpp << " {}" << endl;
1169 
1170  osc_hpp << spacer << "~" << pp.second._name << "() = default;" << endl;
1171  if (!isHeader && !isTrailer)
1172  {
1173  osc_hpp << spacer << "bool process(Router& rt) const { return (static_cast<" << ctxt._clname << "_Router&>(rt))(this); }" << endl;
1174  if (pp.second._is_admin)
1175  osc_hpp << spacer << "bool is_admin() const { return true; }" << endl;
1176  }
1177 
1178  osc_hpp << endl << spacer << "static const " << fsitr->second._name << "& get_msgtype() { return _msgtype; }" << endl;
1179 #if defined FIX8_HAVE_EXTENDED_METADATA
1180  osc_hpp << spacer << "static const FieldTrait *get_traits() { return _traits; };" << endl;
1181  osc_hpp << spacer << "static const unsigned get_fieldcnt() { return _fieldcnt; };" << endl;
1182 #endif
1183  if (isHeader)
1184  osc_hpp << endl << _csMap.find(cs_header_preamble)->second << endl;
1185  else if (isTrailer)
1186  osc_hpp << endl << _csMap.find(cs_trailer_preamble)->second << endl;
1187 
1188 // =============================== Repeating group nested classes ==============================
1189 
1190  generate_nested_group(pp.second, fspec, 1, osc_hpp, ctxt._fixns);
1191  generate_group_bodies(pp.second, fspec, 1, fsitr->second._name, osr_cpp, osc_hpp, globmap, ctxt._fixns);
1192 
1193  osc_hpp << "};" << endl << endl;
1194  osc_hpp << _csMap.find(cs_divider)->second << endl;
1195  }
1196 
1197 // =============================== Message class instantiation ==============================
1198 
1199  osc_cpp << endl;
1200 
1201  osc_cpp << "const char *cn[] // Component names" << endl << '{' << endl;
1202  osc_cpp << spacer << "\"\"," << endl;
1203  for (Components::iterator citr(components.begin()); citr != components.end(); ++citr)
1204  osc_cpp << spacer << '"' << citr->first << "\", // " << (1 + distance(components.begin(), citr)) << endl;
1205  osc_cpp << "};" << endl;
1206 
1207  osc_cpp << endl << _csMap.find(cs_end_anon_namespace)->second << endl;
1208 
1209  osc_cpp << endl << _csMap.find(cs_divider)->second << endl;
1210  osc_cpp << "const " << ctxt._fixns << "::" << ctxt._clname << "_BaseMsgEntry::Pair "
1211  << "msgpairs[] " << endl << '{' << endl;
1212  for (MessageSpecMap::const_iterator mitr(mspec.begin()); mitr != mspec.end(); ++mitr)
1213  {
1214  if (mitr != mspec.begin())
1215  osc_cpp << ',' << endl;
1216  osc_cpp << spacer << "{ \"" << mitr->first << "\", { ";
1217  if (mitr->second._name == "trailer" || mitr->second._name == "header")
1218  osc_cpp << "Type2Type<" << ctxt._fixns << "::" << mitr->second._name << ", bool>()";
1219  else
1220  osc_cpp << "Type2Type<" << ctxt._fixns << "::" << mitr->second._name << ">()";
1221  osc_cpp << ", \"" << mitr->second._name << '"';
1222  if (!mitr->second._comment.empty())
1223  osc_cpp << ',' << endl << spacer << spacer << '"' << mitr->second._comment << "\" }";
1224  else
1225  osc_cpp << " }";
1226  osc_cpp << " }";
1227  }
1228  osc_cpp << endl << "}; // " << mspec.size() << endl;
1229 
1230  size_t fields_generated(0);
1231  for (const auto& pp : fspec)
1232  if (gen_fields || pp.second._used)
1233  ++fields_generated;
1234 
1235  osc_cpp << endl << "extern const " << ctxt._clname << "_BaseEntry::Pair fldpairs[];" << endl << endl
1236  << "/// Compiler generated metadata object, accessed through this function." << endl
1237  << "const F8MetaCntx& ctx() // avoid SIOF" << endl << '{' << endl
1238  << spacer << "static const " << ctxt._clname << "_BaseMsgEntry "
1239  << "bme(msgpairs, " << mspec.size() << ");" << endl
1240  << spacer << "static const " << ctxt._clname << "_BaseEntry "
1241  << "be(fldpairs, " << fields_generated << ");" << endl
1242  << spacer << "static const F8MetaCntx _ctx(" << ctxt._version << ", bme, be, cn, \"" << ctxt._beginstr << "\");" << endl
1243  << spacer << "return _ctx;" << endl << '}' << endl;
1244  osc_cpp << endl << "} // namespace " << ctxt._fixns << endl;
1245 
1246 // ==================================== Message router ==================================
1247 
1248  osu_hpp << "class " << ctxt._clname << "_Router : public Router" << endl
1249  << '{' << endl << "public:" << endl;
1250  osu_hpp << spacer << ctxt._clname << "_Router() {}" << endl;
1251  osu_hpp << spacer << "virtual ~" << ctxt._clname << "_Router() {}" << endl << endl;
1252  osu_hpp << spacer << "virtual bool operator() (const class Message *msg) ";
1253  if (!nconst_router)
1254  osu_hpp << "const ";
1255  osu_hpp << "{ return false; }" << endl;
1256  for (const auto& pp : mspec)
1257  {
1258  if (pp.second._name == "trailer" || pp.second._name == "header")
1259  continue;
1260  osu_hpp << spacer << "virtual bool operator() (const class " << pp.second._name << " *msg)";
1261  if (no_default_routers)
1262  osu_hpp << ';' << endl;
1263  else
1264  {
1265  if (!nconst_router)
1266  osu_hpp << " const";
1267  osu_hpp << " { return " << (pp.second._is_admin ? "true" : "false") << "; }" << endl;
1268  }
1269  }
1270  osu_hpp << "};" << endl;
1271 
1272  // terminate files
1273  osc_hpp << endl << "} // namespace " << ctxt._fixns << endl;
1274  osc_hpp << _csMap.find(cs_end_namespace)->second << endl;
1275  osc_hpp << "#endif // " << bintoaschex(ctxt._out[Ctxt::classes_hpp].first.second) << endl;
1276  osu_hpp << endl << "} // namespace " << ctxt._fixns << endl;
1277  osu_hpp << _csMap.find(cs_end_namespace)->second << endl;
1278  osu_hpp << "#endif // " << bintoaschex(ctxt._out[Ctxt::router_hpp].first.second) << endl;
1279  osr_cpp << endl << "} // namespace " << ctxt._fixns << endl;
1280  osr_cpp << _csMap.find(cs_end_namespace)->second << endl;
1281  osc_cpp << endl << "// Compiler generated metadata object accessible outside namespace through this function." << endl;
1282  osc_cpp << "extern \"C\"" << endl << '{' << endl
1283  << spacer << "const F8MetaCntx& " << ctxt._fixns << "_ctx() { return " << ctxt._fixns << "::ctx(); }"
1284  << endl << '}' << endl << endl;
1285  osc_cpp << _csMap.find(cs_end_namespace)->second << endl;
1286  osc_cpp << endl;
1287 
1288 // =============================== Generate optional user session and router ==============================
1289 
1290  if (!gen_classes.empty())
1291  {
1292  bool is_server(gen_classes == "server");
1293  generate_preamble(oss_hpp, ctxt._out[Ctxt::session_hpp].first.second, true, false);
1294  oss_hpp << "#ifndef " << bintoaschex(ctxt._out[Ctxt::session_hpp].first.second) << endl;
1295  oss_hpp << "#define " << bintoaschex(ctxt._out[Ctxt::session_hpp].first.second) << endl;
1296  oss_hpp << endl << _csMap.find(cs_divider)->second << endl;
1297 
1298  oss_hpp << "// " << gen_classes << " session and router classes" << endl;
1299  oss_hpp << _csMap.find(cs_divider)->second << endl;
1300 
1301  oss_hpp << "class " << ctxt._clname << "_session_" << gen_classes << ';' << endl << endl;
1302  oss_hpp << "class " << ctxt._clname << "_router_" << gen_classes
1303  << " : public FIX8::" << ctxt._fixns << "::" << ctxt._clname << "_Router" << endl << '{' << endl;
1304  oss_hpp << spacer << ctxt._clname << "_session_" << gen_classes << "& _session; " << endl << endl;
1305  oss_hpp << "public:" << endl;
1306  oss_hpp << spacer << ctxt._clname << "_router_" << gen_classes
1307  << '(' << ctxt._clname << "_session_" << gen_classes << "& session) : _session(session) {}" << endl;
1308  oss_hpp << spacer << "virtual ~" << ctxt._clname << "_router_" << gen_classes << "() {}" << endl << endl;
1309  oss_hpp << spacer << "// Override these methods to receive specific message callbacks." << endl;
1310  for (const auto& pp : mspec)
1311  {
1312  if (pp.second._name == "trailer" || pp.second._name == "header")
1313  continue;
1314  oss_hpp << spacer << "// bool operator() (const FIX8::"
1315  << ctxt._fixns << "::" << pp.second._name << " *msg) const;" << endl;
1316  }
1317  oss_hpp << "};" << endl;
1318 
1319  oss_hpp << endl << _csMap.find(cs_divider)->second << endl;
1320  oss_hpp << "class " << ctxt._clname << "_session_" << gen_classes
1321  << " : public FIX8::Session" << endl << '{' << endl;
1322  oss_hpp << spacer << ctxt._clname << "_router_" << gen_classes << " _router; " << endl << endl;
1323  oss_hpp << "public:" << endl;
1324  oss_hpp << spacer << ctxt._clname << "_session_" << gen_classes;
1325  if (is_server)
1326  {
1327  oss_hpp << "(const FIX8::F8MetaCntx& ctx, FIX8::Persister *persist=0," << endl;
1328  oss_hpp << spacer << spacer << "FIX8::Logger *logger=0, FIX8::Logger *plogger=0) : Session"
1329  "(ctx, persist, logger, plogger), _router(*this) {} " << endl << endl;
1330  }
1331  else
1332  {
1333  oss_hpp << "(const FIX8::F8MetaCntx& ctx, const FIX8::SessionID& sid, FIX8::Persister *persist=0," << endl;
1334  oss_hpp << spacer << spacer << "FIX8::Logger *logger=0, FIX8::Logger *plogger=0) : Session"
1335  "(ctx, sid, persist, logger, plogger), _router(*this) {} " << endl << endl;
1336  }
1337 
1338  oss_hpp << spacer << "// Override these methods if required but remember to call the base class method first." << endl
1339  << spacer << "// bool handle_logon(const unsigned seqnum, const FIX8::Message *msg);" << endl
1340  << spacer << "// Message *generate_logon(const unsigned heartbeat_interval, const f8String davi=f8String());" << endl
1341  << spacer << "// bool handle_logout(const unsigned seqnum, const FIX8::Message *msg);" << endl
1342  << spacer << "// Message *generate_logout();" << endl
1343  << spacer << "// bool handle_heartbeat(const unsigned seqnum, const FIX8::Message *msg);" << endl
1344  << spacer << "// Message *generate_heartbeat(const f8String& testReqID);" << endl
1345  << spacer << "// bool handle_resend_request(const unsigned seqnum, const FIX8::Message *msg);" << endl
1346  << spacer << "// Message *generate_resend_request(const unsigned begin, const unsigned end=0);" << endl
1347  << spacer << "// bool handle_sequence_reset(const unsigned seqnum, const FIX8::Message *msg);" << endl
1348  << spacer << "// Message *generate_sequence_reset(const unsigned newseqnum, const bool gapfillflag=false);" << endl
1349  << spacer << "// bool handle_test_request(const unsigned seqnum, const FIX8::Message *msg);" << endl
1350  << spacer << "// Message *generate_test_request(const f8String& testReqID);" << endl
1351  << spacer << "// bool handle_reject(const unsigned seqnum, const FIX8::Message *msg);" << endl
1352  << spacer << "// Message *generate_reject(const unsigned seqnum, const char *what);" << endl
1353  << spacer << "// bool handle_admin(const unsigned seqnum, const FIX8::Message *msg);" << endl
1354  << spacer << "// void modify_outbound(FIX8::Message *msg);" << endl
1355  << spacer << "// bool authenticate(SessionID& id, const FIX8::Message *msg);" << endl << endl;
1356 
1357  oss_hpp << spacer << "// Override these methods to intercept admin and application methods." << endl
1358  << spacer << "// bool handle_admin(const unsigned seqnum, const FIX8::Message *msg);" << endl << endl
1359  << spacer << "bool handle_application(const unsigned seqnum, const FIX8::Message *&msg);" << endl
1360  << spacer << "/* In your compilation unit, this should be implemented with something like the following:" << endl
1361  << spacer << "bool " << ctxt._clname << "_session_" << gen_classes << "::handle_application(const unsigned seqnum, const FIX8::Message *&msg)" << endl
1362  << spacer << '{' << endl << spacer << spacer << "return enforce(seqnum, msg) || msg->process(_router);" << endl
1363  << spacer << '}' << endl << spacer << "*/" << endl;
1364 
1365  oss_hpp << "};" << endl;
1366 
1367  oss_hpp << endl << "#endif // " << bintoaschex(ctxt._out[Ctxt::session_hpp].first.second) << endl;
1368  }
1369 
1370 // ================================= Field processing =====================================
1371 
1372  // output file preambles
1373  generate_preamble(ost_hpp, ctxt._out[Ctxt::types_hpp].first.second, true);
1374  ost_hpp << "#ifndef " << bintoaschex(ctxt._out[Ctxt::types_hpp].first.second) << endl;
1375  ost_hpp << "#define " << bintoaschex(ctxt._out[Ctxt::types_hpp].first.second) << endl << endl;
1376  ost_hpp << _csMap.find(cs_start_namespace)->second << endl;
1377  ost_hpp << "namespace " << ctxt._fixns << " {" << endl;
1378 
1379  ost_hpp << endl << _csMap.find(cs_divider)->second << endl;
1380  generate_preamble(ost_cpp, ctxt._out[Ctxt::types_cpp].first.second, false);
1381  ost_cpp << _csMap.find(cs_generated_includes)->second << endl;
1382  generate_includes(ost_cpp);
1383  ost_cpp << "#include \"" << ctxt._out[Ctxt::types_hpp].first.second << '"' << endl;
1384  ost_cpp << _csMap.find(cs_divider)->second << endl;
1385  ost_cpp << _csMap.find(cs_start_namespace)->second << endl;
1386  ost_cpp << "namespace " << ctxt._fixns << " {" << endl << endl;
1387 
1388  ost_cpp << _csMap.find(cs_start_anon_namespace)->second << endl;
1389  ost_cpp << endl << _csMap.find(cs_divider)->second << endl;
1390  // generate field types
1391  for (FieldSpecMap::const_iterator fitr(fspec.begin()); fitr != fspec.end(); ++fitr)
1392  {
1393  if (!gen_fields && !fitr->second._used)
1394  continue;
1395  if (!fitr->second._comment.empty())
1396  ost_hpp << "// " << fitr->second._comment << endl;
1397  const auto tyitr(FieldSpec::_typeToCPP.find(fitr->second._ftype));
1398  ost_hpp << "using " << fitr->second._name << " = Field<"
1399  << (tyitr == FieldSpec::_typeToCPP.end() ? "unknown" : tyitr->second.first) << ", " << fitr->first << ">;" << endl;
1400  if (fitr->second._dvals)
1401  process_value_enums(fitr, ost_hpp, ost_cpp);
1402  ost_hpp << _csMap.find(cs_divider)->second << endl;
1403  }
1404 
1405  // generate realmbase objs
1406  ost_cpp << endl << _csMap.find(cs_divider)->second << endl;
1407  ost_cpp << "const RealmBase realmbases[] " << endl << '{' << endl;
1408  unsigned dcnt(0);
1409  for (auto& pp : fspec)
1410  {
1411  if ((!pp.second._used && !gen_fields) || !pp.second._dvals)
1412  continue;
1413  const auto tyitr(FieldSpec::_typeToCPP.find(pp.second._ftype));
1414  ost_cpp << spacer << "{ reinterpret_cast<const void *>(" << pp.second._name << "_realm), "
1415  << "RealmBase::" << (pp.second._dtype == RealmBase::dt_set ? "dt_set" : "dt_range") << ", "
1416  << "FieldTrait::" << tyitr->second.second << ", "
1417  << pp.second._dvals->size() << ", " << pp.second._name << "_descriptions }," << endl;
1418  pp.second._doffset = dcnt++;
1419  }
1420  ost_cpp << "};" << endl;
1421 
1422  // generate field instantiators
1423  ost_cpp << endl << _csMap.find(cs_divider)->second << endl;
1424  ost_cpp << endl << _csMap.find(cs_end_anon_namespace)->second << endl;
1425 
1426  // generate field instantiator lookup
1427  ost_hpp << "using " << ctxt._clname << "_BaseEntry = FieldTable;" << endl;
1428 
1429  ost_cpp << endl << _csMap.find(cs_divider)->second << endl;
1430  ost_cpp << "extern const " << ctxt._clname << "_BaseEntry::Pair fldpairs[];" << endl;
1431  ost_cpp << "const " << ctxt._clname << "_BaseEntry::Pair fldpairs[] "
1432  << endl << '{' << endl;
1433  for (FieldSpecMap::const_iterator fitr(fspec.begin()); fitr != fspec.end(); ++fitr)
1434  {
1435  if (!gen_fields && !fitr->second._used)
1436  continue;
1437  if (fitr != fspec.begin())
1438  ost_cpp << ',' << endl;
1439  ost_cpp << spacer << "{ " << fitr->first << ", { ";
1440  if (fitr->second._dvals && !norealm) // generate code to create a Field using a value taken from an index into a Realm
1441  {
1442  ost_cpp << "Type2Type<" << ctxt._fixns << "::" << fitr->second._name << ", ";
1443  string ttype;
1444  if (!FieldTrait::get_type_string(fitr->second._ftype, ttype).empty())
1445  ost_cpp << ttype;
1446  else
1447  {
1448  ost_cpp << "unknown";
1449  cerr << shortName << ": error: unknown FieldTrait::type in realm '" << fitr->second._name << '\'' << endl;
1450  ++glob_errors;
1451  }
1452  }
1453  else
1454  ost_cpp << "Type2Type<" << ctxt._fixns << "::" << fitr->second._name;
1455  ost_cpp << ">(), \"" << fitr->second._name << "\", " << fitr->first;
1456  if (fitr->second._dvals)
1457  ost_cpp << ", &" << ctxt._fixns << "::realmbases[" << fitr->second._doffset << ']';
1458  if (!fitr->second._comment.empty())
1459  {
1460  ost_cpp << ", ";
1461  if (!fitr->second._dvals)
1462  ost_cpp << "nullptr, ";
1463  ost_cpp << endl << spacer << spacer << '"' << fitr->second._comment << '"';
1464  }
1465  ost_cpp << " } }";
1466  }
1467  ost_cpp << endl << "}; // " << fields_generated << endl;
1468 
1469  // terminate files
1470  ost_cpp << "} // namespace " << ctxt._fixns << endl;
1471  ost_hpp << endl << "} // namespace " << ctxt._fixns << endl;
1472  ost_hpp << _csMap.find(cs_end_namespace)->second << endl;
1473  ost_hpp << "#endif // " << bintoaschex(ctxt._out[Ctxt::types_hpp].first.second) << endl;
1474  ost_cpp << endl << _csMap.find(cs_end_namespace)->second << endl;
1475 
1476  if (verbose)
1477  {
1478  unsigned cnt(0), ucnt(0);
1479  for (const auto& pp : fspec)
1480  {
1481  if (pp.second._used)
1482  ++cnt;
1483  else if (report_unused)
1484  {
1485  if (ucnt++)
1486  cout << ',';
1487  else
1488  cout << "Unused fields: ";
1489  cout << pp.second._name << '(' << pp.first << ')';
1490  }
1491  }
1492  if (report_unused && ucnt)
1493  cout << endl;
1494  cout << cnt << " of " << fspec.size() << " fields used in messages" << endl;
1495  }
1496 
1497  return result;
1498 }
1499 
1500 //-------------------------------------------------------------------------------------------------
1502 {
1503 #if defined __GNUG__
1504 #if defined __GNUC_MINOR__ && __GNUC_PATCHLEVEL__
1505  cout << "Compiled with gcc version " << __GNUG__ << '.' << __GNUC_MINOR__ << '.' <<__GNUC_PATCHLEVEL__ << endl;
1506 #endif
1507 #ifndef __APPLE__
1508  const size_t confbufsz(256);
1509  char confbuf[confbufsz];
1510  if (confstr(_CS_GNU_LIBC_VERSION, confbuf, confbufsz))
1511  {
1512  cout << "GNU glibc version is " << confbuf << endl;
1513  }
1514  if (confstr(_CS_GNU_LIBPTHREAD_VERSION, confbuf, confbufsz))
1515  {
1516  cout << "GNU libpthread version is " << confbuf << endl;
1517  }
1518 #endif
1519 #if defined __GXX_ABI_VERSION
1520  cout << "GXX ABI version is " << __GXX_ABI_VERSION << endl;
1521 #endif
1522 #else
1523  cout << "GCC not used. No information available." << endl;
1524 #endif
1525 }
1526 
1527 //-------------------------------------------------------------------------------------------------
1528 unsigned lookup_component(const Components& compon, const f8String& name)
1529 {
1530  Components::const_iterator citr(compon.find(name));
1531  return citr != compon.end() ? 1 + distance(compon.begin(), citr) : 0;
1532 }
1533 
1534 //-------------------------------------------------------------------------------------------------
1535 uint32_t group_hash(const MessageSpec& p1)
1536 {
1537  if (no_shared_groups) // hack so every group hash is unique
1538  {
1539  static uint32_t result(0);
1540  return ++result;
1541  }
1542 
1543  uint32_t result(0);
1544 
1545  for (const auto& pp : p1._fields.get_presence())
1546  result = rothash(result, pp._fnum);
1547  for (const auto& pp : p1._groups)
1548  result = rothash(result, group_hash(pp.second));
1549 
1550  return result;
1551 }
1552 
1553 //-------------------------------------------------------------------------------------------------
1554 const MessageSpec *find_group(const CommonGroupMap& globmap, int& vers, unsigned tp, uint32_t key)
1555 {
1556  CommonGroupMap::const_iterator tp_result(globmap.find(tp));
1557  if (tp_result == globmap.end())
1558  return nullptr;
1559  CommonGroups::const_iterator key_result(tp_result->second.find(key));
1560  if (key_result == tp_result->second.end())
1561  return nullptr;
1562  vers = 1 + distance(tp_result->second.begin(), key_result);
1563  return &key_result->second;
1564 }
1565 
1566 //-------------------------------------------------------------------------------------------------
1567 void generate_preamble(ostream& to, const string& fname, bool isheader, bool donotedit)
1568 {
1569  to << _csMap.find(cs_divider)->second << endl;
1570  string result;
1571  if (donotedit)
1572  {
1573  to << _csMap.find(cs_do_not_edit)->second << GetTimeAsStringMS(result, 0, 0) << " ***" << endl;
1574  to << _csMap.find(cs_divider)->second << endl;
1575  }
1576  to << _csMap.find(cs_copyright)->second << insert_year() << _csMap.find(cs_copyright2)->second << endl;
1577  to << _csMap.find(cs_divider)->second << endl;
1578  if (!precompHdr.empty() && !isheader)
1579  {
1580  to << "#include ";
1581  if (precompHdr[0] == '<')
1582  to << precompHdr;
1583  else
1584  to << '"' << precompHdr << '"';
1585  to << endl;
1586  }
1587  to << "#include " << (incpath ? "<fix8/" : "<") << "f8config.h" << '>' << endl;
1588  if (!nocheck)
1589  {
1590  to << "#if defined FIX8_MAGIC_NUM && FIX8_MAGIC_NUM > " << FIX8_MAGIC_NUM << 'L' << endl;
1591  to << "#error " << fname << " version " << FIX8_PACKAGE_VERSION << " is out of date. Please regenerate with f8c." << endl;
1592  to << "#endif" << endl;
1593  }
1594  to << _csMap.find(cs_divider)->second << endl;
1595  to << "// " << fname << endl;
1596  to << _csMap.find(cs_divider)->second << endl;
1597 }
1598 //-------------------------------------------------------------------------------------------------
1599 void generate_export(ostream& to, const string& ns)
1600 {
1601  to <<
1602  "#if defined(_MSC_VER) && defined(F8_" << ns << "_API_SHARED)\n"
1603  " #if defined(BUILD_F8_" << ns << "_API)\n"
1604  " #define F8_" << ns << "_API __declspec(dllexport)\n"
1605  " #else\n"
1606  " #define F8_" << ns << "_API __declspec(dllimport)\n"
1607  " #endif\n"
1608  "#else\n"
1609  " #define F8_" << ns << "_API\n"
1610  "#endif\n";
1611 }
1612 
1613 /* vim: set ts=3 sw=3 tw=0 et :*/
FieldTraits _fields
Definition: f8c.hpp:157
static F8API XmlElement * Factory(std::istream &istr, const char *docpath=nullptr)
string extra_fields
Definition: f8c.cpp:97
int load_fields(XmlElement &xf, FieldSpecMap &fspec)
Definition: f8c.cpp:453
const MessageSpec * find_group(const CommonGroupMap &globmap, int &vers, unsigned tp, uint32_t key)
Definition: f8c.cpp:1554
const CSMap _csMap
Definition: f8cstatic.hpp:126
int precompfixt(XmlElement &xft, XmlElement &xf, ostream &outf, bool nounique)
Definition: f8precomp.cpp:112
unsigned tabsize(3)
f8c compilation context.
Definition: f8c.hpp:45
int load_fix_version(XmlElement &xf, Ctxt &ctxt)
Definition: f8cutils.cpp:115
string inputFile
Definition: f8c.cpp:96
void process_group_ordering(const CommonGroupMap &gm)
Definition: f8cutils.cpp:312
static std::string & SubExpr(RegMatch &match, const std::string &source, std::string &target, const int offset=0, const int num=0)
Definition: f8utils.hpp:452
void print_usage()
Definition: f8cutils.cpp:320
POSIX regex wrapper class.
Definition: f8utils.hpp:370
void generate_group_traits(const FieldSpecMap &fspec, const MessageSpec &ms, const string &gname, const string &prefix, ostream &outp)
Definition: f8c.cpp:853
string shortName
Definition: f8c.cpp:96
bool no_shared_groups(false)
const string & filepart(const string &source, string &where)
Definition: f8cutils.cpp:108
string precompFile
Definition: f8c.cpp:96
unsigned glob_warnings(0)
string fixt
Definition: f8c.cpp:96
std::string trim(const std::string &source, const std::string &ws=" \t")
Definition: f8utils.hpp:153
bool nconst_router(false)
void load_components(const XmlElement::XmlSet &comlist, Components &components)
Definition: f8precomp.cpp:182
std::map< std::string, const XmlElement * > Components
Definition: f8c.hpp:183
static const std::string _exts_ver[2]
Definition: f8c.hpp:51
string insert_year()
Definition: f8cutils.cpp:376
std::string _name
Definition: f8c.hpp:160
bool no_default_routers(false)
unsigned lookup_component(const Components &compon, const f8String &name)
Definition: f8c.cpp:1528
f8c internal message representation.
Definition: f8c.hpp:155
void generate_nested_group(const MessageSpec &ms, const FieldSpecMap &fspec, int depth, ostream &outh, const std::string &fixns)
Definition: f8c.cpp:711
#define FIX8_PACKAGE_VERSION
Definition: f8config.h:631
void binary_report()
Definition: f8c.cpp:1501
int process_message_fields(const std::string &where, const XmlElement *xt, FieldTraits &fts, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, const Components &compon)
Definition: f8cutils.cpp:220
string prefix("Myfix")
string odir("./")
void generate_includes(ostream &to)
Definition: f8cutils.cpp:394
unsigned rothash(unsigned result, unsigned value)
Definition: f8utils.hpp:230
const Presence & get_presence() const
Definition: traits.hpp:658
static const std::string _exts[count]
Definition: f8c.hpp:51
void generate_preamble(ostream &to, const string &fname, bool isheader, bool donotedit=true)
Definition: f8c.cpp:1567
bool nowarn(false)
std::string _fixns
Definition: f8c.hpp:53
int recover_line(const XmlElement &xf)
Definition: f8c.hpp:204
void process_value_enums(FieldSpecMap::const_iterator itr, ostream &ost_hpp, ostream &ost_cpp)
Definition: f8cutils.cpp:176
int process(XmlElement &xf, Ctxt &ctxt)
Definition: f8c.cpp:928
string spacer
Definition: f8c.cpp:96
std::string _clname
Definition: f8c.hpp:53
Used for static trait interrogation.
Definition: traits.hpp:57
ostream * open_ofile(const string &odir, const string &fname, string &target)
Definition: f8cutils.cpp:77
const string & mkel(const string &base, const string &compon, string &where)
Definition: f8cutils.cpp:100
F8API bool Insert(XmlElement *what)
Definition: xml.cpp:523
std::map< unsigned, struct FieldSpec > FieldSpecMap
Definition: f8c.hpp:118
Base exception class.
Definition: f8exception.hpp:49
int load_messages(XmlElement &xf, MessageSpecMap &mspec, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, Components &compon, CommonGroupMap &globmap)
Definition: f8c.cpp:541
bool gen_fields(false)
bool verbose(false)
A simple xml parser with Xpath style lookup.
Definition: xml.hpp:48
bool nocheck(false)
f8c range or set domain realm.
Definition: f8c.hpp:58
F8API const Package_info & package_info()
Definition: f8utils.cpp:247
string precompHdr
Definition: f8c.cpp:96
string bintoaschex(const string &from)
Definition: f8cutils.cpp:270
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
bool incpath(true)
std::map< std::string, unsigned > FieldToNumMap
Definition: f8c.hpp:119
unsigned glob_errors
F8API const std::string & GetTimeAsStringMS(std::string &result, const class Tickval *tv=0, const unsigned dplaces=6, bool use_gm=false)
std::map< RealmObject *, std::string, RealmObject::less > RealmMap
Definition: f8c.hpp:115
int SearchString(RegMatch &match, const std::string &source, const int subExpr, const int offset=0) const
Definition: f8utils.hpp:431
int main(int argc, char **argv)
Definition: f8c.cpp:147
string shortNameFixt
Definition: f8c.cpp:96
bool report_unused(false)
unsigned parse_groups(MessageSpec &ritr, const string &name, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, XmlElement::XmlSet &grplist, const Components &compon, CommonGroupMap &globmap)
Definition: f8c.cpp:633
f8c internal field representation.
Definition: f8c.hpp:127
Output _out[count]
Definition: f8c.hpp:50
void generate_group_bodies(const MessageSpec &ms, const FieldSpecMap &fspec, int depth, const string &msname, ostream &outp, ostream &outh, const CommonGroupMap &globmap, const std::string &fixns, const string cls_prefix=string())
Definition: f8c.cpp:742
f8c string realm type.
Definition: f8c.hpp:102
void generate_common_group_bodies(const FieldSpecMap &fspec, ostream &outp, CommonGroupMap &globmap)
Definition: f8c.cpp:906
std::map< const std::string, MessageSpec > MessageSpecMap
Definition: f8c.hpp:175
static std::string & Erase(RegMatch &match, std::string &source, const int num=0)
Definition: f8utils.hpp:471
F8API std::string & InPlaceStrToUpper(std::string &src)
const string GETARGLIST("hvVo:p:dikn:rst:x:NRc:fbCIWPF:UeH:SDu")
GroupMap _groups
Definition: f8c.hpp:158
F8API std::string & CheckAddTrailingSlash(std::string &source)
std::map< unsigned, CommonGroups > CommonGroupMap
Definition: f8c.hpp:180
bool add(const FieldTrait &what)
Definition: traits.hpp:575
A collection of FieldTraits for a message. Which fields are required, which are present.
Definition: traits.hpp:437
unsigned _version
Definition: f8c.hpp:52
void process_ordering(MessageSpecMap &mspec)
Definition: f8cutils.cpp:279
A class to contain regex matches using RegExp.
Definition: f8utils.hpp:308
unsigned ext_ver(0)
bool _is_admin
Definition: f8c.hpp:161
std::map< uint32_t, struct MessageSpec > CommonGroups
Definition: f8c.hpp:179
string gen_classes
Definition: f8c.cpp:97
const char * what() const
Definition: f8exception.hpp:85
bool norealm(false)
uint32_t group_hash(const MessageSpec &p1)
Definition: f8c.cpp:1535
uint32_t _hash
Definition: f8c.hpp:159
int precomp(XmlElement &xf, ostream &outf)
Definition: f8precomp.cpp:71
bool error_ignore(false)
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
void generate_export(ostream &to, const string &ns)
Definition: f8c.cpp:1599
std::string f8String
Definition: f8types.hpp:47
uint32_t _group_refcnt
Definition: f8c.hpp:159
void process_special_traits(const unsigned short field, FieldTraits &fts)
Definition: f8cutils.cpp:159
std::string _beginstr
Definition: f8c.hpp:53
#define FIX8_MAGIC_NUM
Definition: f8config.h:536