fix8  version 1.4.0
Open Source C++ FIX Framework
f8cutils.cpp File Reference
#include "precomp.hpp"
#include <fix8/f8includes.hpp>
#include <fix8/usage.hpp>
#include <f8c.hpp>

Go to the source code of this file.

Functions

void print_usage ()
 
int process (XmlElement &xf, Ctxt &ctxt)
 
int load_fix_version (XmlElement &xf, Ctxt &ctxt)
 
int load_fields (XmlElement &xf, FieldSpecMap &fspec)
 
void process_special_traits (const unsigned short field, FieldTraits &fts)
 
int process_message_fields (const std::string &where, XmlElement *xt, FieldTraits &fts, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, const Components &compon)
 
int load_messages (XmlElement &xf, MessageSpecMap &mspec, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec)
 
void process_ordering (MessageSpecMap &mspec)
 
void process_value_enums (FieldSpecMap::const_iterator itr, ostream &ost_hpp, ostream &ost_cpp)
 
const string & mkel (const string &base, const string &compon, string &where)
 
void process_group_ordering (const CommonGroupMap &gm)
 
unsigned lookup_component (const Components &compon, const f8String &name)
 
string bintoaschex (const string &from)
 
ostream * open_ofile (const string &odir, const string &fname, string &target)
 
const string & filepart (const string &source, string &where)
 
int process_message_fields (const std::string &where, const XmlElement *xt, FieldTraits &fts, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, const Components &compon)
 
void process_message_group_ordering (const GroupMap &gm)
 
string insert_year ()
 
void generate_includes (ostream &to)
 

Variables

string shortName
 
string odir
 
string prefix
 
bool verbose
 
bool nocheck
 
bool nowarn
 
bool incpath
 
string spacer
 
string precompHdr
 
const string GETARGLIST
 
unsigned glob_errors
 
unsigned glob_warnings
 

Function Documentation

string bintoaschex ( const string &  from)

Definition at line 270 of file f8cutils.cpp.

Referenced by process().

271 {
272  ostringstream result;
273  for (const auto& cc : from)
274  result << uppercase << hex << setw(2) << setfill('0') << static_cast<unsigned short>(cc);
275  return "FIX8_" + result.str() + '_';
276 }
const string& filepart ( const string &  source,
string &  where 
)

Definition at line 108 of file f8cutils.cpp.

Referenced by main(), and FIX8::FileLogger::rotate().

109 {
110  string::size_type pos(source.find_last_of('/'));
111  return pos == string::npos ? where = source : where = source.substr(pos + 1);
112 }
void generate_includes ( ostream &  to)

Definition at line 394 of file f8cutils.cpp.

References incpath.

Referenced by process().

395 {
396  static const vector<string> incfiles
397  {
398  //"f8includes.hpp"
399  "f8exception.hpp",
400  "hypersleep.hpp",
401  "mpmc.hpp",
402  "thread.hpp",
403  "f8types.hpp",
404  "f8utils.hpp",
405  "tickval.hpp",
406  "logger.hpp",
407  "traits.hpp",
408  "field.hpp",
409  "message.hpp"
410  };
411 
412  to << "// f8 includes" << endl;
413  for (const auto& pp : incfiles)
414  to << "#include " << (incpath ? "<fix8/" : "<") << pp << '>' << endl;
415 }
bool incpath
string insert_year ( )

Definition at line 376 of file f8cutils.cpp.

Referenced by generate_preamble().

377 {
378  struct tm *ptim;
379  time_t now(time(0));
380 #ifdef _MSC_VER
381  ptim = localtime (&now);
382 #else
383  struct tm tim;
384  localtime_r(&now, &tim);
385  ptim = &tim;
386 #endif
387 
388  ostringstream ostr;
389  ostr << setw(2) << (ptim->tm_year - 100);
390  return ostr.str();
391 }
int load_fields ( XmlElement xf,
FieldSpecMap fspec 
)

Definition at line 453 of file f8c.cpp.

References XmlElement::find(), glob_errors, glob_warnings(), FIX8::InPlaceStrToUpper(), nowarn(), FIX8::recover_line(), shortName, and FIX8::trim().

Referenced by process().

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 }
string shortName
Definition: f8c.cpp:96
unsigned glob_warnings(0)
std::string trim(const std::string &source, const std::string &ws=" \t")
Definition: f8utils.hpp:153
bool nowarn(false)
int recover_line(const XmlElement &xf)
Definition: f8c.hpp:204
f8c range or set domain realm.
Definition: f8c.hpp:58
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
unsigned glob_errors
std::map< RealmObject *, std::string, RealmObject::less > RealmMap
Definition: f8c.hpp:115
f8c internal field representation.
Definition: f8c.hpp:127
F8API std::string & InPlaceStrToUpper(std::string &src)
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
int load_fix_version ( XmlElement xf,
Ctxt ctxt 
)

Definition at line 115 of file f8cutils.cpp.

References FIX8::Ctxt::_beginstr, FIX8::Ctxt::_clname, FIX8::Ctxt::_fixns, FIX8::Ctxt::_systemns, FIX8::Ctxt::_version, XmlElement::find(), prefix, and shortName.

Referenced by main().

116 {
117  const XmlElement *fix(xf.find("fix"));
118  if (!fix)
119  {
120  cerr << "No fix header element found in " << shortName << endl;
121  return -1;
122  }
123 
124  string major, minor, revision("0"), type("FIX");
125 
126  if (!fix->GetAttr("major", major) || !fix->GetAttr("minor", minor))
127  {
128  cerr << "Missing required attributes (major/minor) from fix header in " << shortName << endl;
129  return -1;
130  }
131 
132  if (!fix->GetAttr("revision", revision))
133  fix->GetAttr("servicepack", revision);
134  fix->GetAttr("type", type);
135 
136  // fix version: <Major:1><Minor:1><Revision:2> eg. 4.2r10 is 4210
137  ctxt._version = stoi(major) * 1000 + stoi(minor) * 100 + stoi(revision);
138  if (type == "FIX" && ctxt._version < 4000)
139  {
140  cerr << "Unsupported FIX version " << ctxt._version << " from fix header in " << shortName << endl;
141  return -1;
142  }
143 
144  ostringstream ostr;
145  ostr << type << ctxt._version;
146  ctxt._systemns = ostr.str();
147  if (ctxt._fixns.empty())
148  ctxt._fixns = ctxt._systemns;
149  ctxt._clname = prefix;
150 
151  ostr.str("");
152  ostr << type << '.' << major << '.' << minor;
153  ctxt._beginstr = ostr.str();
154 
155  return 0;
156 }
std::string _systemns
Definition: f8c.hpp:53
string prefix
std::string _fixns
Definition: f8c.hpp:53
std::string _clname
Definition: f8c.hpp:53
A simple xml parser with Xpath style lookup.
Definition: xml.hpp:48
string shortName
Definition: f8c.cpp:96
unsigned _version
Definition: f8c.hpp:52
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
std::string _beginstr
Definition: f8c.hpp:53
int load_messages ( XmlElement xf,
MessageSpecMap mspec,
const FieldToNumMap ftonSpec,
FieldSpecMap fspec 
)
unsigned lookup_component ( const Components compon,
const f8String name 
)

Definition at line 1528 of file f8c.cpp.

Referenced by parse_groups(), and process_message_fields().

1529 {
1530  Components::const_iterator citr(compon.find(name));
1531  return citr != compon.end() ? 1 + distance(compon.begin(), citr) : 0;
1532 }
const string& mkel ( const string &  base,
const string &  compon,
string &  where 
)

Definition at line 100 of file f8cutils.cpp.

Referenced by load_messages().

101 {
102  ostringstream ostr;
103  ostr << base << '/' << compon;
104  return where = ostr.str();
105 }
ostream* open_ofile ( const string &  odir,
const string &  fname,
string &  target 
)

Definition at line 77 of file f8cutils.cpp.

References FIX8::CheckAddTrailingSlash(), and FIX8::exist().

Referenced by main().

78 {
79  if (!exist(odir))
80  return nullptr;
81  ostringstream ofs;
82  string odirect(odir);
83  ofs << CheckAddTrailingSlash(odirect) << fname;
84  target = ofs.str();
85  unique_ptr<ofstream> os(new ofstream(target.c_str()));
86  if (!*os)
87  {
88  cerr << "Error opening file \'" << target << '\'';
89  if (errno)
90  cerr << " (" << strerror(errno) << ')';
91  cerr << endl;
92 
93  return nullptr;
94  }
95 
96  return os.release();
97 }
string odir
F8API std::string & CheckAddTrailingSlash(std::string &source)
bool exist(const std::string &fname)
Definition: f8utils.hpp:1068
void print_usage ( )

Definition at line 320 of file f8cutils.cpp.

References UsageMan::add(), GETARGLIST, UsageMan::print(), and UsageMan::setdesc().

321 {
322  UsageMan um("f8c", GETARGLIST, "<input xml schema>");
323  um.setdesc("f8c -- compile FIX xml schema");
324  um.add('o', "odir <dir>", "output target directory (default ./)");
325  um.add('p', "prefix <prefix>", "output filename prefix (default Myfix)");
326  um.add('H', "pch <filename>", "use specified precompiled header name for Windows (default none)");
327  um.add('d', "dump", "dump 1st pass parsed source xml file, exit");
328  um.add('e', "extension", "Generate with .cxx/.hxx extensions (default .cpp/.hpp)");
329  um.add('f', "fields", "generate code for all defined fields even if they are not used in any message (default no)");
330  um.add('F', "xfields", "specify additional fields with associated messages (see documentation for details)");
331  um.add('h', "help", "help, this screen");
332  um.add('i', "ignore", "ignore errors, attempt to generate code anyhow (default no)");
333  um.add('k', "keep", "retain generated temporaries even if there are errors (.*.tmp)");
334  um.add('v', "version", "print version, exit");
335  um.add('I', "info", "print package info, exit");
336  um.add('s', "second", "2nd pass only, no precompile (default both)");
337  um.add('S', "noshared", "Treat every group as unique and expose all static traits. Do not share metadata in message classes (default shared)");
338  um.add('N', "nounique", "do not enforce unique field parsing (default false)");
339  um.add('R', "norealm", "do not generate realm constructed field instantiators (default false)");
340  um.add('W', "nowarn", "suppress warning messages (default false)");
341  um.add('C', "nocheck", "do not embed version checking in generated code (default false)");
342  um.add('D', "defaulted", "do not generate default router bodies. Application must provide all router definitions (default false)");
343  um.add('U', "noconst", "Generate non-const Router method declarations (default false, const)");
344  um.add('u', "unused", "Report unused fields, requires verbose option (default false)");
345  um.add('r', "retain", "retain 1st pass code (default delete)");
346  um.add('b', "binary", "print binary/ABI details, exit");
347  um.add('P', "incpath", "prefix system include path with \"fix8\" in generated compilation units (default yes)");
348  um.add('c', "classes <server|client>", "generate user session classes (default neither)");
349  um.add('t', "tabwidth", "tabwidth for generated code (default 3 spaces)");
350  um.add('x', "fixt <file>", "For FIXT hosted transports or for FIX5.0 and above, the input FIXT schema file");
351  um.add('V', "verbose", "be more verbose when processing");
352  um.add('n', "namespace <ns>", "namespace to place generated code in (default FIXMmvv e.g. FIX4400)");
353  um.add("e.g.");
354  um.add("@f8c -p Texfix -n TEX myfix.xml");
355  um.add("@f8c -rp Texfix -n TEX -x ../schema/FIXT11.xml myfix.xml");
356  um.add("@f8c -p Texfix -n TEX -c client -x ../schema/FIXT11.xml myfix.xml");
357  um.add("@f8c -p Texfix -n TEX -c client -x ../schema/FIXT11.xml myfix.xml -F \"<field number='9999' name='SampleUserField' type='STRING' messages='NewOrderSingle:Y ExecutionReport:Y OrderCancelRequest:N' />");
358  um.print(cerr);
359 }
const string GETARGLIST
Convenient program help/usage wrapper. Generates a standardised usage message.
Definition: usage.hpp:42
int process ( XmlElement xf,
Ctxt ctxt 
)

Definition at line 928 of file f8c.cpp.

References FIX8::Ctxt::_beginstr, FIX8::Ctxt::_clname, FIX8::_csMap, FIX8::Ctxt::_fixns, FIX8::Ctxt::_out, FIX8::Ctxt::_version, bintoaschex(), FIX8::cs_divider, FIX8::cs_end_anon_namespace, FIX8::cs_end_namespace, FIX8::cs_generated_includes, FIX8::cs_header_preamble, FIX8::cs_start_anon_namespace, FIX8::cs_start_namespace, FIX8::cs_trailer_preamble, XmlElement::find(), gen_classes, gen_fields(), generate_common_group_bodies(), generate_export(), generate_group_bodies(), generate_includes(), generate_nested_group(), generate_preamble(), glob_errors, load_components(), load_fields(), load_messages(), nconst_router(), no_default_routers(), no_shared_groups(), norealm(), process_group_ordering(), process_ordering(), process_value_enums(), report_unused(), shortName, spacer, and verbose().

Referenced by main().

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 }
int load_fields(XmlElement &xf, FieldSpecMap &fspec)
Definition: f8c.cpp:453
const CSMap _csMap
Definition: f8cstatic.hpp:126
void process_group_ordering(const CommonGroupMap &gm)
Definition: f8cutils.cpp:312
string shortName
Definition: f8c.cpp:96
bool no_shared_groups(false)
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
bool no_default_routers(false)
void generate_nested_group(const MessageSpec &ms, const FieldSpecMap &fspec, int depth, ostream &outh, const std::string &fixns)
Definition: f8c.cpp:711
void generate_includes(ostream &to)
Definition: f8cutils.cpp:394
void generate_preamble(ostream &to, const string &fname, bool isheader, bool donotedit=true)
Definition: f8c.cpp:1567
std::string _fixns
Definition: f8c.hpp:53
void process_value_enums(FieldSpecMap::const_iterator itr, ostream &ost_hpp, ostream &ost_cpp)
Definition: f8cutils.cpp:176
string spacer
Definition: f8c.cpp:96
std::string _clname
Definition: f8c.hpp:53
Used for static trait interrogation.
Definition: traits.hpp:57
std::map< unsigned, struct FieldSpec > FieldSpecMap
Definition: f8c.hpp:118
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)
string bintoaschex(const string &from)
Definition: f8cutils.cpp:270
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
std::map< std::string, unsigned > FieldToNumMap
Definition: f8c.hpp:119
unsigned glob_errors
bool report_unused(false)
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
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
std::map< unsigned, CommonGroups > CommonGroupMap
Definition: f8c.hpp:180
unsigned _version
Definition: f8c.hpp:52
void process_ordering(MessageSpecMap &mspec)
Definition: f8cutils.cpp:279
string gen_classes
Definition: f8c.cpp:97
bool norealm(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 _beginstr
Definition: f8c.hpp:53
void process_group_ordering ( const CommonGroupMap gm)

Definition at line 312 of file f8cutils.cpp.

References process_message_group_ordering().

Referenced by process().

313 {
314  for (const auto& pp : globmap)
315  for (const auto& ii : pp.second)
316  process_message_group_ordering(ii.second._groups);
317 }
void process_message_group_ordering(const GroupMap &gm)
Definition: f8cutils.cpp:294
int process_message_fields ( const std::string &  where,
XmlElement xt,
FieldTraits fts,
const FieldToNumMap ftonSpec,
FieldSpecMap fspec,
const Components compon 
)
int process_message_fields ( const std::string &  where,
const XmlElement xt,
FieldTraits fts,
const FieldToNumMap ftonSpec,
FieldSpecMap fspec,
const Components compon 
)

Definition at line 220 of file f8cutils.cpp.

References FIX8::FieldTraits::add(), XmlElement::find(), glob_errors, glob_warnings, lookup_component(), nowarn, process_special_traits(), FIX8::recover_line(), and shortName.

Referenced by load_messages(), and parse_groups().

222 {
223  unsigned processed(0);
224  XmlElement::XmlSet flist;
225  if (xt->find(where, flist))
226  {
227  for(const auto *pp : flist)
228  {
229  string fname, required;
230  if (pp->GetAttr("name", fname) && pp->GetAttr("required", required))
231  {
232  FieldToNumMap::const_iterator ftonItr(ftonSpec.find(fname));
233  FieldSpecMap::iterator fs_itr;
234  if (ftonItr == ftonSpec.end() || (fs_itr = fspec.find(ftonItr->second)) == fspec.end())
235  {
236  cerr << shortName << ':' << recover_line(*pp) << ": error: Field element missing required attributes" << endl;
237  ++glob_errors;
238  continue;
239  }
240 
241  string compname;
242  unsigned compidx(pp->GetAttr("component", compname) ? lookup_component(compon, compname) : 0);
243 
244  // add FieldTrait
245  if (!fts.add(FieldTrait(fs_itr->first, fs_itr->second._ftype, pp->GetSubIdx(), required == "Y", false, compidx)))
246  {
247  if (!nowarn)
248  cerr << shortName << ':' << recover_line(*pp) << ": warning: Could not add trait object '" << fname << "' (duplicate ?)" << endl;
249  ++glob_warnings;
250  }
251  else
252  {
253  process_special_traits(fs_itr->first, fts);
254  ++processed;
255  fs_itr->second.set_used();
256  }
257  }
258  else
259  {
260  cerr << shortName << ':' << recover_line(*pp) << ": error: Field element missing required attributes" << endl;
261  ++glob_errors;
262  }
263  }
264  }
265 
266  return processed;
267 }
bool nowarn
int recover_line(const XmlElement &xf)
Definition: f8c.hpp:204
unsigned lookup_component(const Components &compon, const f8String &name)
Definition: f8c.cpp:1528
void process_special_traits(const unsigned short field, FieldTraits &fts)
Definition: f8cutils.cpp:159
Used for static trait interrogation.
Definition: traits.hpp:57
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
string shortName
Definition: f8c.cpp:96
unsigned glob_errors
bool add(const FieldTrait &what)
Definition: traits.hpp:575
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
unsigned glob_warnings
void process_message_group_ordering ( const GroupMap gm)

Definition at line 294 of file f8cutils.cpp.

Referenced by process_group_ordering().

295 {
296  for (const auto& pp : gm)
297  {
298  FieldTraitOrder go;
299  for (const auto& ii : pp.second._fields.get_presence())
300  go.insert({&ii});
301 
302  unsigned gcnt(0);
303  for (auto *ii : go)
304  ii->_pos = ++gcnt;
305 
306  if (!pp.second._groups.empty())
307  process_message_group_ordering(pp.second._groups);
308  }
309 }
std::multiset< const FieldTrait *, FieldTrait::PosCompare > FieldTraitOrder
Definition: f8c.hpp:176
void process_message_group_ordering(const GroupMap &gm)
Definition: f8cutils.cpp:294
void process_ordering ( MessageSpecMap mspec)

Definition at line 279 of file f8cutils.cpp.

Referenced by process().

280 {
281  for (const auto& pp : mspec)
282  {
283  FieldTraitOrder mo;
284  for (const auto& ii : pp.second._fields.get_presence())
285  mo.insert({&ii});
286 
287  unsigned cnt(0);
288  for (auto *ii : mo)
289  ii->_pos = ++cnt;
290  }
291 }
std::multiset< const FieldTrait *, FieldTrait::PosCompare > FieldTraitOrder
Definition: f8c.hpp:176
void process_special_traits ( const unsigned short  field,
FieldTraits fts 
)

Definition at line 159 of file f8cutils.cpp.

References FIX8::FieldTraits::clear(), FIX8::Common_BeginString(), FIX8::Common_BodyLength(), FIX8::Common_CheckSum(), FIX8::Common_MsgType(), and FIX8::FieldTraits::set().

Referenced by process_message_fields().

160 {
161  switch(field)
162  {
163  case Common_BeginString:
164  case Common_BodyLength:
165  case Common_CheckSum:
166  fts.set(field, FieldTrait::suppress); // drop through
167  case Common_MsgType:
168  fts.set(field, FieldTrait::automatic);
169  fts.clear(field, FieldTrait::mandatory); // don't check for presence
170  default:
171  break;
172  }
173 }
const unsigned short Common_CheckSum(10)
void clear(const unsigned short field, Presence::const_iterator &itr, FieldTrait::TraitTypes type=FieldTrait::present)
Definition: traits.hpp:550
const unsigned short Common_MsgType(35)
const unsigned short Common_BodyLength(9)
const unsigned short Common_BeginString(8)
void set(const unsigned short field, Presence::const_iterator &itr, FieldTrait::TraitTypes type)
Definition: traits.hpp:524
void process_value_enums ( FieldSpecMap::const_iterator  itr,
ostream &  ost_hpp,
ostream &  ost_cpp 
)

Definition at line 176 of file f8cutils.cpp.

References FIX8::InPlaceReplaceInSet(), and spacer.

Referenced by process().

177 {
178  string typestr;
179  if (FieldTrait::get_type_string(itr->second._ftype, typestr).empty())
180  return;
181  typestr.insert(0, "const ");
182  typestr += ' ';
183 
184  ost_cpp << typestr << itr->second._name << "_realm[] " << endl << spacer << "{ ";
185  unsigned cnt(0);
186  for (RealmMap::const_iterator ditr(itr->second._dvals->begin()); ditr != itr->second._dvals->end(); ++ditr)
187  {
188  if (cnt)
189  ost_cpp << ", ";
190  ost_cpp << *ditr->first;
191  string transdesc(ditr->second);
192  // replace any illegal c++ identifier characters
193  InPlaceReplaceInSet(ident_set, transdesc, '_');
194  ost_hpp << typestr << itr->second._name << '_';
195  if (ditr->first->is_range())
196  ost_hpp << (cnt == 0 ? "lower" : "upper");
197  else if (transdesc.empty())
198  ost_hpp << *ditr->first;
199  else
200  ost_hpp << transdesc;
201  ost_hpp << '(' << *ditr->first << ");" << endl;
202  ++cnt;
203  }
204  ost_hpp << "const size_t " << itr->second._name << "_realm_els(" << itr->second._dvals->size() << ");" << endl;
205  ost_cpp << " };" << endl;
206 
207  ost_cpp << "const char *" << itr->second._name << "_descriptions[] " << endl << spacer << "{ ";
208  cnt = 0;
209  for (RealmMap::const_iterator ditr(itr->second._dvals->begin()); ditr != itr->second._dvals->end(); ++ditr)
210  {
211  if (cnt)
212  ost_cpp << ", ";
213  ost_cpp << '"' << ditr->second << '"';
214  ++cnt;
215  }
216  ost_cpp << " };" << endl;
217 }
F8API std::string & InPlaceReplaceInSet(const std::string &iset, std::string &src, const char repl='_')
string spacer
Definition: f8c.cpp:96

Variable Documentation

const string GETARGLIST

Referenced by print_usage().

unsigned glob_errors

Referenced by process_message_fields().

unsigned glob_warnings

Referenced by process_message_fields().

bool incpath

Referenced by generate_includes().

bool nocheck
bool nowarn

Referenced by process_message_fields().

string odir
string precompHdr

Definition at line 96 of file f8c.cpp.

Referenced by generate_preamble(), and main().

string prefix

Referenced by load_fix_version().

string shortName

Definition at line 96 of file f8c.cpp.

Referenced by load_fix_version(), and process_message_fields().

bool verbose