fix8  version 1.4.0
Open Source C++ FIX Framework
f8precomp.cpp
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------------------
2 /*
3 
4 Fix8 is released under the GNU LESSER GENERAL PUBLIC LICENSE Version 3.
5 
6 Fix8 Open Source FIX Engine.
7 Copyright (C) 2010-16 David L. Dight <fix@fix8.org>
8 
9 Fix8 is free software: you can redistribute it and / or modify it under the terms of the
10 GNU Lesser General Public License as published by the Free Software Foundation, either
11 version 3 of the License, or (at your option) any later version.
12 
13 Fix8 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 You should have received a copy of the GNU Lesser General Public License along with Fix8.
17 If not, see <http://www.gnu.org/licenses/>.
18 
19 BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO
20 THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE
21 COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
22 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
24 THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
25 YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
26 
27 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT
28 HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED
29 ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
30 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
31 NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
32 THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
33 HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34 
35 */
36 //-----------------------------------------------------------------------------------------
37 #include "precomp.hpp"
38 // f8 headers
39 #include <fix8/f8includes.hpp>
40 #include <f8c.hpp>
41 
42 //-----------------------------------------------------------------------------------------
43 using namespace std;
44 using namespace FIX8;
45 
46 //-----------------------------------------------------------------------------------------
47 const string doctype("<?xml version='1.0' encoding='ISO-8859-1'?>");
48 
49 //-----------------------------------------------------------------------------------------
50 extern unsigned glob_errors;
51 extern string shortName;
52 
53 //-----------------------------------------------------------------------------------------
54 void output_field(const XmlElement& xf, const int depth, ostream& outf, const string& compon=string(), bool required=true);
55 void output_attributes(const XmlElement& xf, ostream& outf, bool required=true);
56 void process_component(const XmlElement& xf, const Components& components, const int depth, ostream& outf, bool required=true);
57 void process_group(const XmlElement& xf, const Components& components, const int depth,
58  ostream& outf, const string& compon=string(), bool required=true);
59 void process_messages(const XmlElement& xf, const Components& components, const string& tag, const int depth,
60  ostream& outf, bool required=true);
61 void process_elements(XmlElement::XmlSet::const_iterator itr, const Components& components, const int depth,
62  ostream& outf, const string& compon=string(), bool required=true);
63 void process_fields(const XmlElement::XmlSet& fldlist, const int depth, ostream& outf, bool required=true);
64 void load_components(const XmlElement::XmlSet& comlist, Components& components);
65 void dump_components(const Components& components, ostream& outf);
66 int precomp(XmlElement& xf, ostream& outf);
67 int precompfixt(XmlElement& xft, XmlElement& xf, ostream& outf, bool nounique);
68 void filter_unique(XmlElement::XmlSet& fldlist);
69 
70 //-----------------------------------------------------------------------------------------
71 int precomp(XmlElement& xf, ostream& outf)
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 }
110 
111 //-----------------------------------------------------------------------------------------
112 int precompfixt(XmlElement& xft, XmlElement& xf, ostream& outf, bool nounique)
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 }
161 
162 //-----------------------------------------------------------------------------------------
163 void filter_unique(XmlElement::XmlSet& fldlist)
164 {
165  using UniqueFieldMap = map<string, const XmlElement *>;
166  UniqueFieldMap ufm;
167  unsigned dupls(0);
168  for(const auto *pp : fldlist)
169  {
170  string name;
171  pp->GetAttr("name", name);
172  if (!ufm.insert({name, pp}).second)
173  ++dupls; // cerr << "Duplicate field: " << name << endl;
174  }
175 
176  fldlist.clear();
177  for(const auto& pp : ufm)
178  fldlist.insert(pp.second);
179 }
180 
181 //-----------------------------------------------------------------------------------------
182 void load_components(const XmlElement::XmlSet& comlist, Components& components)
183 {
184  for(const auto *pp : comlist)
185  {
186  string name;
187  if (pp->GetAttr("name", name))
188  components.insert({name, pp});
189  }
190 }
191 
192 //-----------------------------------------------------------------------------------------
193 void process_fields(const XmlElement::XmlSet& fldlist, const int depth, ostream& outf, bool required)
194 {
195  outf << string(depth * 2, ' ') << "<fields>" << endl;
196  for(XmlElement::XmlSet::const_iterator itr(fldlist.begin()); itr != fldlist.end(); ++itr)
197  {
198  outf << string((depth + 1) * 2, ' ') << "<field";
199  output_attributes(**itr, outf, required);
200 
201  if ((*itr)->GetChildCnt())
202  {
203  outf << '>' << endl;
204  for(XmlElement::XmlSet::const_iterator fitr((*itr)->begin()); fitr != (*itr)->end(); ++fitr)
205  {
206  outf << string((depth + 2) * 2, ' ') << '<' << (*fitr)->GetTag();
207  output_attributes(**fitr, outf, required);
208  outf << "/>" << endl;
209  }
210  outf << string((depth + 1) * 2, ' ') << "</field>" << endl;
211  }
212  else
213  outf << "/>" << endl;
214  }
215  outf << string(depth * 2, ' ') << "</fields>" << endl;
216 }
217 
218 //-----------------------------------------------------------------------------------------
219 void output_field(const XmlElement& xf, const int depth, ostream& outf, const string& compon, bool required)
220 {
221  outf << string(depth * 2, ' ') << "<field";
222  output_attributes(xf, outf, required);
223  if (!compon.empty())
224  outf << " component=\'" << compon << '\'';
225  outf << "/>" << endl;
226 }
227 
228 //-----------------------------------------------------------------------------------------
229 void output_attributes(const XmlElement& xf, ostream& outf, bool required)
230 {
231  for (XmlElement::XmlAttrs::const_iterator itr(xf.abegin()); itr != xf.aend(); ++itr)
232  outf << ' ' << itr->first << "='"
233  << (itr->first == "required" && itr->second == "Y" && !required ? "N" : itr->second) << '\'';
234  if (xf.GetLine())
235  outf << " line=\'" << xf.GetLine() << '\'';
236 }
237 
238 //-----------------------------------------------------------------------------------------
239 void process_elements(XmlElement::XmlSet::const_iterator itr, const Components& components, const int depth,
240  ostream& outf, const string& compon, bool required)
241 {
242  if ((*itr)->GetTag() == "field")
243  output_field(**itr, depth, outf, compon, required);
244  else if ((*itr)->GetTag() == "component")
245  process_component(**itr, components, depth, outf, required);
246  else if ((*itr)->GetTag() == "group")
247  process_group(**itr, components, depth, outf, compon, required);
248 }
249 
250 //-----------------------------------------------------------------------------------------
251 void process_messages(const XmlElement& xf, const Components& components, const string& tag, const int depth, ostream& outf, bool required)
252 {
253  outf << string((depth + 1) * 2, ' ') << '<' << tag;
254  output_attributes(xf, outf, required);
255  outf << '>' << endl;
256 
257  for(XmlElement::XmlSet::const_iterator mitr(xf.begin()); mitr != xf.end(); ++mitr)
258  process_elements(mitr, components, depth + 2, outf, string(), required);
259  outf << string((depth + 1) * 2, ' ') << "</" << tag << '>' << endl;
260 }
261 
262 //-----------------------------------------------------------------------------------------
263 void process_component(const XmlElement& xf, const Components& components, const int depth, ostream& outf, bool required)
264 {
265  string name;
266  xf.GetAttr("name", name);
267  bool comp_required(xf.FindAttr("required", false));
268 
269  Components::const_iterator citr(components.find(name));
270  if (citr == components.end())
271  {
272  cerr << shortName << ':' << recover_line(xf) << ": error: Could not find component '" << name << '\'' << endl;
273  ++glob_errors;
274  }
275  else
276  {
277  for(XmlElement::XmlSet::const_iterator itr(citr->second->begin()); itr != citr->second->end(); ++itr)
278  process_elements(itr, components, depth, outf, name,
279  depth == 3 ? comp_required : comp_required && required);
280  }
281 }
282 
283 //-----------------------------------------------------------------------------------------
284 void process_group(const XmlElement& xf, const Components& components, const int depth,
285  ostream& outf, const string& compon, bool required)
286 {
287  outf << string(depth * 2, ' ') << "<group";
288  output_attributes(xf, outf, required);
289  if (!compon.empty())
290  outf << " component=\'" << compon << '\'';
291  outf << '>' << endl;
292 
293  for(XmlElement::XmlSet::const_iterator itr(xf.begin()); itr != xf.end(); ++itr)
294  process_elements(itr, components, depth + 1, outf, string(), required);
295  outf << string(depth * 2, ' ') << "</group>" << endl;
296 }
297 
298 //-----------------------------------------------------------------------------------------
299 void dump_components(const Components& components, ostream& outf)
300 {
301  if (components.empty())
302  return;
303 
304  int depth(1);
305 
306  outf << string(depth * 2, ' ') << "<components>" << endl;
307 
308  for (Components::const_iterator citr(components.begin()); citr != components.end(); ++citr)
309  {
310  outf << string((depth + 1) * 2, ' ') << "<component name=\"";
311  outf << citr->first << "\" id=\"" << (1 + distance(components.begin(), citr)) << "\"/>" << endl;
312  }
313 
314  outf << string(depth * 2, ' ') << "</components>" << endl;
315 }
316 
int GetLine() const
Definition: xml.hpp:268
void dump_components(const Components &components, ostream &outf)
Definition: f8precomp.cpp:299
void process_group(const XmlElement &xf, const Components &components, const int depth, ostream &outf, const string &compon=string(), bool required=true)
Definition: f8precomp.cpp:284
void filter_unique(XmlElement::XmlSet &fldlist)
Definition: f8precomp.cpp:163
string shortName
Definition: f8c.cpp:96
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 process_elements(XmlElement::XmlSet::const_iterator itr, const Components &components, const int depth, ostream &outf, const string &compon=string(), bool required=true)
Definition: f8precomp.cpp:239
void process_messages(const XmlElement &xf, const Components &components, const string &tag, const int depth, ostream &outf, bool required=true)
Definition: f8precomp.cpp:251
int precomp(XmlElement &xf, ostream &outf)
Definition: f8precomp.cpp:71
void load_components(const XmlElement::XmlSet &comlist, Components &components)
Definition: f8precomp.cpp:182
void process_component(const XmlElement &xf, const Components &components, const int depth, ostream &outf, bool required=true)
Definition: f8precomp.cpp:263
A simple xml parser with Xpath style lookup.
Definition: xml.hpp:48
XmlAttrs::const_iterator abegin() const
Definition: xml.hpp:324
void output_field(const XmlElement &xf, const int depth, ostream &outf, const string &compon=string(), bool required=true)
Definition: f8precomp.cpp:219
void process_fields(const XmlElement::XmlSet &fldlist, const int depth, ostream &outf, bool required=true)
Definition: f8precomp.cpp:193
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
unsigned glob_errors
XmlAttrs::const_iterator aend() const
Definition: xml.hpp:328
const std::string & GetTag() const
Definition: xml.hpp:292
const string doctype("<?xml version='1.0' encoding='ISO-8859-1'?>")
int precompfixt(XmlElement &xft, XmlElement &xf, ostream &outf, bool nounique)
Definition: f8precomp.cpp:112
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const