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

Go to the source code of this file.

Functions

string odir ("./")
 
string prefix ("Myfix")
 
bool verbose (false)
 
bool error_ignore (false)
 
bool gen_fields (false)
 
bool norealm (false)
 
bool nocheck (false)
 
bool nowarn (false)
 
bool incpath (true)
 
bool nconst_router (false)
 
bool no_shared_groups (false)
 
bool no_default_routers (false)
 
bool report_unused (false)
 
unsigned glob_errors (0)
 
unsigned glob_warnings (0)
 
unsigned tabsize (3)
 
unsigned ext_ver (0)
 
const string GETARGLIST ("hvVo:p:dikn:rst:x:NRc:fbCIWPF:UeH:SDu")
 
void print_usage ()
 
string insert_year ()
 
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, const XmlElement *xt, FieldTraits &fts, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, const Components &compon)
 
int load_messages (XmlElement &xf, MessageSpecMap &mspec, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, Components &compon, CommonGroupMap &globmap)
 
void process_ordering (MessageSpecMap &mspec)
 
ostream * open_ofile (const string &odir, const string &fname, string &target)
 
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)
 
const string & filepart (const string &source, string &where)
 
void generate_preamble (ostream &to, const string &fname, bool isheader, bool donotedit=true)
 
void generate_includes (ostream &to)
 
unsigned parse_groups (MessageSpec &ritr, const string &name, const FieldToNumMap &ftonSpec, FieldSpecMap &fspec, XmlElement::XmlSet &grplist, const Components &compon, CommonGroupMap &globmap)
 
int precomp (XmlElement &xf, ostream &outf)
 
void process_group_ordering (const CommonGroupMap &gm)
 
int precompfixt (XmlElement &xft, XmlElement &xf, ostream &outf, bool nounique)
 
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())
 
void generate_nested_group (const MessageSpec &ms, const FieldSpecMap &fspec, int depth, ostream &outh, const std::string &fixns)
 
void generate_common_group_bodies (const FieldSpecMap &fspec, ostream &outp, CommonGroupMap &globmap)
 
void load_components (const XmlElement::XmlSet &comlist, Components &components)
 
unsigned lookup_component (const Components &compon, const f8String &name)
 
void binary_report ()
 
string bintoaschex (const string &from)
 
uint32_t group_hash (const MessageSpec &p1)
 
const MessageSpecfind_group (const CommonGroupMap &globmap, int &vers, unsigned tp, uint32_t key)
 
void generate_group_traits (const FieldSpecMap &fspec, const MessageSpec &ms, const string &gname, const string &prefix, ostream &outp)
 
void generate_export (ostream &to, const string &ns)
 
int main (int argc, char **argv)
 

Variables

string precompFile
 
string spacer
 
string inputFile
 
string precompHdr
 
string shortName
 
string fixt
 
string shortNameFixt
 
string gen_classes
 
string extra_fields
 
unsigned glob_errors
 

Detailed Description


This is the fix8 compiler.

f8c – compile FIX xml schema

Usage: f8c [-CFHINPRSUVWbcdefhiknoprstvx] <input xml schema>
-C,–nocheck do not embed version checking in generated code (default false)
-F,–xfields specify additional fields with associated messages (see documentation for details)
-H,–pch <filename> use specified precompiled header name for Windows (default none)
-I,–info print package info, exit
-N,–nounique do not enforce unique field parsing (default false)
-P,–incpath prefix system include path with "fix8" in generated compilation units (default yes)
-R,–norealm do not generate realm constructed field instantiators (default false)
-U,–noconst Generate non-const Router method declarations (default false, const)")
-S,–noshared Treat every group as unique and expose all static traits. Do not share metadata in message classes (default shared)
-W,–nowarn suppress warning messages (default false)
-V,–verbose be more verbose when processing
-c,–classes <server|client> generate user session classes (default no)
-d,–dump dump 1st pass parsed source xml file, exit
-e,–extension Generate with .cxx/.hxx extensions (default .cpp/.hpp)
-f,–fields generate code for all defined fields even if they are not used in any message (default no)
-h,–help help, this screen
-i,–ignore ignore errors, attempt to generate code anyhow (default no)
-k,–keep retain generated temporaries even if there are errors (.*.tmp)
-n,–namespace <ns> namespace to place generated code in (default FIXMmvv e.g. FIX4400)
-o,–odir <file> output target directory (default ./)
-p,–prefix <prefix> output filename prefix (default Myfix)
-r,–retain retain 1st pass code (default delete)
-s,–second 2nd pass only, no precompile (default both)
-t,–tabwidth tabwidth for generated code (default 3 spaces)
-v,–version print version, exit
-x,–fixt <file> For FIXT hosted transports or for FIX5.0 and above, the input FIXT schema file
e.g.
f8c -Vp Texfix -n TEX myfix.xml
f8c -Vrp Texfix -n TEX -x ../schema/FIXT11.xml myfix.xml
f8c -Vp Texfix -n TEX -c client -x ../schema/FIXT11.xml myfix.xml
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">

Definition in file f8c.cpp.

Function Documentation

void binary_report ( )

Definition at line 1501 of file f8c.cpp.

Referenced by main().

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 }
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 }
bool error_ignore ( false  )

Referenced by main().

unsigned ext_ver ( )

Referenced by main().

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 }
const MessageSpec * find_group ( const CommonGroupMap globmap,
int &  vers,
unsigned  tp,
uint32_t  key 
)

Definition at line 1554 of file f8c.cpp.

Referenced by FIX8::MessageBase::copy_legal(), FIX8::Configuration::create_clients(), FIX8::Configuration::create_logger(), FIX8::Configuration::create_login_schedule(), FIX8::Configuration::create_persister(), FIX8::Configuration::create_session_schedule(), FIX8::MessageBase::encode_group(), generate_group_bodies(), FIX8::Configuration::get_addresses(), and FIX8::MessageBase::print_group().

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 }
bool gen_fields ( false  )

Referenced by main(), and process().

void generate_common_group_bodies ( const FieldSpecMap fspec,
ostream &  outp,
CommonGroupMap globmap 
)

Definition at line 906 of file f8c.cpp.

References FIX8::_csMap, FIX8::cs_divider, and generate_group_traits().

Referenced by process().

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 }
const CSMap _csMap
Definition: f8cstatic.hpp:126
void generate_group_traits(const FieldSpecMap &fspec, const MessageSpec &ms, const string &gname, const string &prefix, ostream &outp)
Definition: f8c.cpp:853
void generate_export ( ostream &  to,
const string &  ns 
)

Definition at line 1599 of file f8c.cpp.

Referenced by process().

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 }
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 at line 742 of file f8c.cpp.

References FIX8::_csMap, FIX8::MessageSpec::_fields, FIX8::MessageSpec::_group_refcnt, FIX8::MessageSpec::_groups, FIX8::MessageSpec::_hash, FIX8::MessageSpec::_is_admin, FIX8::MessageSpec::_name, FIX8::cs_divider, find_group(), generate_group_traits(), generate_nested_group(), FIX8::FieldTraits::get_presence(), prefix(), FIX8::presorted_set< unsigned short, FieldTrait, FieldTrait::Compare >::size(), spacer, and tabsize().

Referenced by process().

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 }
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
unsigned tabsize(3)
void generate_group_traits(const FieldSpecMap &fspec, const MessageSpec &ms, const string &gname, const string &prefix, ostream &outp)
Definition: f8c.cpp:853
std::string _name
Definition: f8c.hpp:160
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
string prefix("Myfix")
string spacer
Definition: f8c.cpp:96
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
GroupMap _groups
Definition: f8c.hpp:158
void generate_group_traits ( const FieldSpecMap fspec,
const MessageSpec ms,
const string &  gname,
const string &  prefix,
ostream &  outp 
)

Definition at line 853 of file f8c.cpp.

References FIX8::MessageSpec::_fields, FIX8::MessageSpec::_group_refcnt, FIX8::presorted_set< unsigned short, FieldTrait, FieldTrait::Compare >::begin(), FIX8::presorted_set< unsigned short, FieldTrait, FieldTrait::Compare >::end(), FIX8::FieldTraits::get_presence(), no_shared_groups(), FIX8::presorted_set< unsigned short, FieldTrait, FieldTrait::Compare >::size(), and spacer.

Referenced by generate_common_group_bodies(), and generate_group_bodies().

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 }
FieldTraits _fields
Definition: f8c.hpp:157
bool no_shared_groups(false)
string prefix("Myfix")
const Presence & get_presence() const
Definition: traits.hpp:658
string spacer
Definition: f8c.cpp:96
Used for static trait interrogation.
Definition: traits.hpp:57
uint32_t _group_refcnt
Definition: f8c.hpp:159
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
void generate_nested_group ( const MessageSpec ms,
const FieldSpecMap fspec,
int  depth,
ostream &  outh,
const std::string &  fixns 
)

Definition at line 711 of file f8c.cpp.

References FIX8::MessageSpec::_groups, spacer, and tabsize().

Referenced by generate_group_bodies(), and process().

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 }
unsigned tabsize(3)
string spacer
Definition: f8c.cpp:96
GroupMap _groups
Definition: f8c.hpp:158
void generate_preamble ( ostream &  to,
const string &  fname,
bool  isheader,
bool  donotedit = true 
)

Definition at line 1567 of file f8c.cpp.

References FIX8::_csMap, FIX8::cs_copyright, FIX8::cs_copyright2, FIX8::cs_divider, FIX8::cs_do_not_edit, FIX8_MAGIC_NUM, FIX8_PACKAGE_VERSION, FIX8::GetTimeAsStringMS(), incpath(), insert_year(), nocheck(), and precompHdr.

Referenced by process().

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 }
const CSMap _csMap
Definition: f8cstatic.hpp:126
string insert_year()
Definition: f8cutils.cpp:376
#define FIX8_PACKAGE_VERSION
Definition: f8config.h:631
bool nocheck(false)
string precompHdr
Definition: f8c.cpp:96
bool incpath(true)
F8API const std::string & GetTimeAsStringMS(std::string &result, const class Tickval *tv=0, const unsigned dplaces=6, bool use_gm=false)
#define FIX8_MAGIC_NUM
Definition: f8config.h:536
const string GETARGLIST ( "hvVo:p:dikn:rst:x:NRc:fbCIWPF:UeH:SDu"  )

Referenced by main().

unsigned glob_errors ( )
unsigned glob_warnings ( )

Referenced by load_fields(), main(), and parse_groups().

uint32_t group_hash ( const MessageSpec p1)

Definition at line 1535 of file f8c.cpp.

References FIX8::MessageSpec::_fields, FIX8::MessageSpec::_groups, FIX8::FieldTraits::get_presence(), no_shared_groups(), and FIX8::rothash().

Referenced by parse_groups().

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 }
FieldTraits _fields
Definition: f8c.hpp:157
bool no_shared_groups(false)
unsigned rothash(unsigned result, unsigned value)
Definition: f8utils.hpp:230
const Presence & get_presence() const
Definition: traits.hpp:658
GroupMap _groups
Definition: f8c.hpp:158
uint32_t group_hash(const MessageSpec &p1)
Definition: f8c.cpp:1535
bool incpath ( true  )

Referenced by generate_preamble(), and main().

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 }
void load_components ( const XmlElement::XmlSet comlist,
Components components 
)

Definition at line 182 of file f8precomp.cpp.

Referenced by precomp(), and process().

183 {
184  for(const auto *pp : comlist)
185  {
186  string name;
187  if (pp->GetAttr("name", name))
188  components.insert({name, pp});
189  }
190 }
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,
Components compon,
CommonGroupMap globmap 
)

Definition at line 541 of file f8c.cpp.

References XmlElement::find(), glob_errors, mkel(), parse_groups(), process_message_fields(), FIX8::recover_line(), shortName, and verbose().

Referenced by process().

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 }
string shortName
Definition: f8c.cpp:96
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
int recover_line(const XmlElement &xf)
Definition: f8c.hpp:204
const string & mkel(const string &base, const string &compon, string &where)
Definition: f8cutils.cpp:100
bool verbose(false)
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
unsigned glob_errors
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 string realm type.
Definition: f8c.hpp:102
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
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 }
int main ( int  argc,
char **  argv 
)

Definition at line 147 of file f8c.cpp.

References FIX8::Ctxt::_beginstr, FIX8::Ctxt::_exts, FIX8::Ctxt::_exts_ver, FIX8::Ctxt::_fixns, FIX8::Ctxt::_out, FIX8::Ctxt::_version, binary_report(), FIX8::CheckAddTrailingSlash(), FIX8::RegExp::Erase(), error_ignore(), ext_ver(), extra_fields, XmlElement::Factory(), filepart(), XmlElement::find(), fixt, gen_classes, gen_fields(), GETARGLIST(), glob_errors, glob_warnings(), incpath(), inputFile, XmlElement::Insert(), load_fix_version(), nconst_router(), no_default_routers(), no_shared_groups(), nocheck(), norealm(), nowarn(), odir(), open_ofile(), FIX8::package_info(), precomp(), precompFile, precompfixt(), precompHdr, prefix(), print_usage(), process(), report_unused(), FIX8::RegExp::SearchString(), shortName, shortNameFixt, spacer, FIX8::RegExp::SubExpr(), tabsize(), FIX8::trim(), verbose(), and FIX8::f8Exception::what().

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 }
static F8API XmlElement * Factory(std::istream &istr, const char *docpath=nullptr)
string extra_fields
Definition: f8c.cpp:97
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 print_usage()
Definition: f8cutils.cpp:320
POSIX regex wrapper class.
Definition: f8utils.hpp:370
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)
static const std::string _exts_ver[2]
Definition: f8c.hpp:51
bool no_default_routers(false)
void binary_report()
Definition: f8c.cpp:1501
string prefix("Myfix")
string odir("./")
static const std::string _exts[count]
Definition: f8c.hpp:51
bool nowarn(false)
std::string _fixns
Definition: f8c.hpp:53
int process(XmlElement &xf, Ctxt &ctxt)
Definition: f8c.cpp:928
string spacer
Definition: f8c.cpp:96
ostream * open_ofile(const string &odir, const string &fname, string &target)
Definition: f8cutils.cpp:77
Base exception class.
Definition: f8exception.hpp:49
bool gen_fields(false)
bool verbose(false)
A simple xml parser with Xpath style lookup.
Definition: xml.hpp:48
bool nocheck(false)
F8API const Package_info & package_info()
Definition: f8utils.cpp:247
string precompHdr
Definition: f8c.cpp:96
bool incpath(true)
unsigned glob_errors
string shortNameFixt
Definition: f8c.cpp:96
bool report_unused(false)
Output _out[count]
Definition: f8c.hpp:50
const string GETARGLIST("hvVo:p:dikn:rst:x:NRc:fbCIWPF:UeH:SDu")
F8API std::string & CheckAddTrailingSlash(std::string &source)
unsigned _version
Definition: f8c.hpp:52
A class to contain regex matches using RegExp.
Definition: f8utils.hpp:308
unsigned ext_ver(0)
string gen_classes
Definition: f8c.cpp:97
const char * what() const
Definition: f8exception.hpp:85
bool norealm(false)
int precomp(XmlElement &xf, ostream &outf)
Definition: f8precomp.cpp:71
bool error_ignore(false)
std::string _beginstr
Definition: f8c.hpp:53
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 }
bool nconst_router ( false  )

Referenced by main(), and process().

bool no_default_routers ( false  )

Referenced by main(), and process().

bool no_shared_groups ( false  )
bool nocheck ( false  )

Referenced by generate_preamble(), and main().

bool norealm ( false  )

Referenced by main(), and process().

bool nowarn ( false  )

Referenced by load_fields(), main(), and parse_groups().

string odir ( "./"  )

Referenced by main().

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
unsigned parse_groups ( MessageSpec ritr,
const string &  name,
const FieldToNumMap ftonSpec,
FieldSpecMap fspec,
XmlElement::XmlSet grplist,
const Components compon,
CommonGroupMap globmap 
)

Definition at line 633 of file f8c.cpp.

References FIX8::MessageSpec::_fields, FIX8::MessageSpec::_groups, FIX8::MessageSpec::_hash, FIX8::FieldTraits::add(), glob_errors, glob_warnings(), group_hash(), lookup_component(), nowarn(), process_message_fields(), FIX8::recover_line(), and shortName.

Referenced by load_messages().

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 }
FieldTraits _fields
Definition: f8c.hpp:157
string shortName
Definition: f8c.cpp:96
unsigned glob_warnings(0)
unsigned lookup_component(const Components &compon, const f8String &name)
Definition: f8c.cpp:1528
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
bool nowarn(false)
int recover_line(const XmlElement &xf)
Definition: f8c.hpp:204
Used for static trait interrogation.
Definition: traits.hpp:57
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
unsigned glob_errors
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
GroupMap _groups
Definition: f8c.hpp:158
bool add(const FieldTrait &what)
Definition: traits.hpp:575
std::map< uint32_t, struct MessageSpec > CommonGroups
Definition: f8c.hpp:179
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 at line 71 of file f8precomp.cpp.

References doctype(), XmlElement::find(), XmlElement::GetTag(), load_components(), and output_attributes().

Referenced by main().

72 {
73  int depth(1);
74  XmlElement::XmlSet fldlist;
75  xf.find("fix/fields/field", fldlist);
76 
77  XmlElement::XmlSet comlist;
78  xf.find("fix/components/component", comlist);
79  Components components;
80  load_components(comlist, components);
81 
82  XmlElement::XmlSet msglist;
83  xf.find("fix/messages/message", msglist);
84 
85  outf << doctype << endl;
86  outf << '<' << xf.GetTag();
87  output_attributes(xf, outf);
88  outf << '>' << endl;
89 
90  const XmlElement *header(xf.find("fix/header"));
91  if (header)
92  process_messages(*header, components, "header", 0, outf);
93  const XmlElement *trailer(xf.find("fix/trailer"));
94  if (trailer)
95  process_messages(*trailer, components, "trailer", 0, outf);
96 
97  outf << string(depth * 2, ' ') << "<messages>" << endl;
98  for(auto const *pp : msglist)
99  process_messages(*pp, components, "message", depth, outf);
100  outf << string(depth * 2, ' ') << "</messages>" << endl;
101 
102  process_fields(fldlist, depth, outf);
103 
104  dump_components(components, outf);
105 
106  outf << "</" << xf.GetTag() << '>' << endl;
107 
108  return 0;
109 }
void output_attributes(const XmlElement &xf, ostream &outf, bool required=true)
Definition: f8precomp.cpp:229
std::map< std::string, const XmlElement * > Components
Definition: f8c.hpp:183
void load_components(const XmlElement::XmlSet &comlist, Components &components)
Definition: f8precomp.cpp:182
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
const std::string & GetTag() const
Definition: xml.hpp:292
const string doctype("<?xml version='1.0' encoding='ISO-8859-1'?>")
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
int precompfixt ( XmlElement xft,
XmlElement xf,
ostream &  outf,
bool  nounique 
)

Definition at line 112 of file f8precomp.cpp.

Referenced by main().

113 {
114  int depth(1);
115  XmlElement::XmlSet fldlist;
116  xft.find("fix/fields/field", fldlist);
117  xf.find("fix/fields/field", fldlist);
118  if (!nounique)
119  filter_unique(fldlist);
120 
121  XmlElement::XmlSet comlist, comlistfixt;
122  Components components, componentsfixt;
123  xft.find("fix/components/component", comlistfixt);
124  xf.find("fix/components/component", comlist);
125  load_components(comlistfixt, componentsfixt);
126  load_components(comlist, components);
127 
128  outf << doctype << endl;
129  outf << '<' << xft.GetTag();
130  output_attributes(xft, outf);
131  outf << '>' << endl;
132 
133  const XmlElement *header(xft.find("fix/header"));
134  if (header)
135  process_messages(*header, componentsfixt, "header", 0, outf);
136  const XmlElement *trailer(xft.find("fix/trailer"));
137  if (trailer)
138  process_messages(*trailer, componentsfixt, "trailer", 0, outf);
139 
140  outf << string(depth * 2, ' ') << "<messages>" << endl;
141 
142  XmlElement::XmlSet msglist;
143  xft.find("fix/messages/message", msglist);
144  for(auto const *pp : msglist)
145  process_messages(*pp, componentsfixt, "message", depth, outf);
146 
147  msglist.clear();
148  xf.find("fix/messages/message", msglist);
149  for(auto const *pp : msglist)
150  process_messages(*pp, components, "message", depth, outf);
151  outf << string(depth * 2, ' ') << "</messages>" << endl;
152 
153  process_fields(fldlist, depth, outf);
154 
155  dump_components(components, outf);
156 
157  outf << "</" << xft.GetTag() << '>' << endl;
158 
159  return 0;
160 }
void filter_unique(XmlElement::XmlSet &fldlist)
Definition: f8precomp.cpp:163
void output_attributes(const XmlElement &xf, ostream &outf, bool required=true)
Definition: f8precomp.cpp:229
std::map< std::string, const XmlElement * > Components
Definition: f8c.hpp:183
void load_components(const XmlElement::XmlSet &comlist, Components &components)
Definition: f8precomp.cpp:182
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
const std::string & GetTag() const
Definition: xml.hpp:292
const string doctype("<?xml version='1.0' encoding='ISO-8859-1'?>")
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
string prefix ( "Myfix"  )

Referenced by generate_group_bodies(), and main().

void print_usage ( )

Definition at line 320 of file f8cutils.cpp.

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

Referenced by main().

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,
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_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
bool report_unused ( false  )

Referenced by main(), and process().

bool verbose ( false  )

Referenced by load_messages(), main(), and process().

Variable Documentation

string extra_fields

Definition at line 97 of file f8c.cpp.

Referenced by main().

string fixt

Definition at line 96 of file f8c.cpp.

Referenced by main().

string gen_classes

Definition at line 97 of file f8c.cpp.

Referenced by main(), and process().

unsigned glob_errors
string inputFile

Definition at line 96 of file f8c.cpp.

Referenced by main().

string precompFile

Definition at line 96 of file f8c.cpp.

Referenced by main().

string precompHdr

Definition at line 96 of file f8c.cpp.

Referenced by generate_preamble(), and main().

string shortName
string shortNameFixt

Definition at line 96 of file f8c.cpp.

Referenced by main().