fix8  version 1.4.0
Open Source C++ FIX Framework
consolemenu.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 #include <fix8/f8includes.hpp>
39 #include <fix8/consolemenu.hpp>
40 
41 //-------------------------------------------------------------------------------------------------
42 using namespace FIX8;
43 using namespace std;
44 
45 //-------------------------------------------------------------------------------------------------
46 const f8String ConsoleMenu::_opt_keys("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+-={}[]:\";'<>,?/|");
47 const f8String ConsoleMenu::_fld_prompt("Press ENTER for next page, '.' to Quit or type an option> ");
48 
49 //-------------------------------------------------------------------------------------------------
51 {
52  for(;;)
53  {
54  const MsgTable::Pair *pp(_ctx._bme.begin());
55  char opt(0);
56  _os << endl;
57  _os << "--------------------------------------------------" << endl;
58  _os << " Select message to create" << endl;
59  _os << "--------------------------------------------------" << endl;
60 
61  int page(0);
62  for (unsigned nlines(0); pp != _ctx._bme.end(); ++pp)
63  {
64  _os << '[' << _opt_keys[nlines] << "] " << pp->_value._name << '(' << pp->_key << ')' << endl;
65 
66  ++nlines;
67  if (nlines % _lpp == 0 || (nlines + _lpp * page) == _ctx._bme.size())
68  {
69  _os << "Page " << (page + 1) << '/' << (1 + (_ctx._bme.size() / _lpp)) << ' ';
70  if ((opt = get_key(_fld_prompt, true)))
71  break;
72  ++page;
73  nlines = 0;
74  _os << endl;
75  }
76  }
77 
78  size_t idx;
79  if (opt)
80  {
81  if (opt == '.')
82  return nullptr;
83 
84  if ((idx = _opt_keys.find_first_of(opt)) != f8String::npos)
85  {
86  idx += (page * _lpp);
87  if (idx < _ctx._bme.size())
88  {
89  const MsgTable::Pair *pr(_ctx._bme.at(idx));
90  if (pr)
91  return &pr->_value;
92  }
93  }
94  }
95  }
96 
97  return nullptr;
98 }
99 
100 //-------------------------------------------------------------------------------------------------
101 const FieldTable::Pair *ConsoleMenu::SelectField(const Message *msg, int grpid) const
102 {
103  ostringstream ostr;
104  if (grpid)
105  ostr << msg->get_msgtype() << " (" << grpid << ')';
106  else
107  ostr << _ctx._bme.find_ptr(msg->get_msgtype().c_str())->_name;
108 
109  for(;;)
110  {
112  char opt(0);
113  _os << endl;
114  _os << "--------------------------------------------------" << endl;
115  _os << ' ' << ostr.str() << ": Select field to add (*:mandatory +:present)" << endl;
116  _os << "--------------------------------------------------" << endl;
117 
118  int page(0);
119  for (unsigned nlines(0); itr != msg->get_fp().get_presence().end(); ++itr)
120  {
121  const BaseEntry *tbe(_ctx.find_be(itr->_fnum));
122  _os << '[' << _opt_keys[nlines] << "] ";
123  if (msg->have(itr->_fnum))
124  {
125  _os << '+';
126  msg->print_field(itr->_fnum, _os);
127  _os << endl;
128  }
129  else
130  _os << (msg->get_fp().is_mandatory(itr->_fnum) ? '*' : ' ')
131  << tbe->_name << '(' << itr->_fnum << ')' << endl;
132 
133  ++nlines;
134 
135  if (nlines % _lpp == 0 || (nlines + _lpp * page) == msg->get_fp().get_presence().size())
136  {
137  _os << "Page " << (page + 1) << '/' << (1 + (msg->get_fp().get_presence().size() / _lpp)) << ' ';
138  if ((opt = get_key(_fld_prompt, true)))
139  break;
140  ++page;
141  nlines = 0;
142  _os << endl;
143  }
144  }
145 
146  size_t idx;
147  if (opt)
148  {
149  if (opt == '.')
150  return nullptr;
151 
152  if ((idx = _opt_keys.find_first_of(opt)) != f8String::npos)
153  {
154  idx += (page * _lpp);
155  Presence::const_iterator fitr(msg->get_fp().get_presence().at(idx));
156  if (fitr != msg->get_fp().get_presence().end())
157  return _ctx._be.find_pair_ptr(fitr->_fnum);
158  }
159  }
160  }
161 
162  return nullptr;
163 }
164 
165 //-------------------------------------------------------------------------------------------------
166 int ConsoleMenu::SelectRealm(const unsigned short fnum, const RealmBase *rb) const
167 {
168  const BaseEntry *be(_ctx.find_be(fnum));
169 
170  for(;;)
171  {
172  int pp(0);
173  char opt(0);
174 
175  _os << endl;
176  _os << "--------------------------------------------------" << endl;
177  _os << ' ' << be->_name << ": Select realm value to add" << endl;
178  _os << "--------------------------------------------------" << endl;
179 
180  int page(0);
181  for (int nlines(0); pp < rb->_sz; ++pp)
182  {
183  _os << '[' << _opt_keys[nlines] << "] " << *(rb->_descriptions + pp) << " (";
184  rb->print(_os, pp);
185  _os << ')' << endl;
186 
187  ++nlines;
188  if (nlines % _lpp == 0 || (nlines + _lpp * page) == rb->_sz)
189  {
190  _os << "Page " << (page + 1) << '/' << (1 + (rb->_sz / _lpp)) << ' ';
191  if ((opt = get_key(_fld_prompt, true)))
192  break;
193  ++page;
194  nlines = 0;
195  _os << endl;
196  }
197  }
198 
199  int idx;
200  if (opt)
201  {
202  if (opt == '.')
203  return 0;
204 
205  if (static_cast<size_t>((idx = (static_cast<int>(_opt_keys.find_first_of(opt))))) != f8String::npos)
206  {
207  idx += (page * _lpp);
208  if (idx < rb->_sz)
209  return idx;
210  }
211  }
212  }
213 
214  return 0;
215 }
216 
217 //-------------------------------------------------------------------------------------------------
219 {
220  if (lst.empty())
221  return nullptr;
222 
223  for(;;)
224  {
225  MsgList::const_iterator itr(lst.begin());
226  char opt(0);
227  _os << endl;
228  _os << "--------------------------------------------------" << endl;
229  _os << "Select from " << lst.size() << " messages" << endl;
230  _os << "--------------------------------------------------" << endl;
231 
232  int page(0);
233  for (unsigned nlines(0); itr != lst.end(); ++itr)
234  {
235  const MsgTable::Pair *tbme(_ctx._bme.find_pair_ptr((*itr)->get_msgtype().c_str()));
236  text txt;
237  (*itr)->get(txt);
238  sending_time sndtime;
239  msg_seq_num msgseqnum;
240  if ((*itr)->Header())
241  {
242  (*itr)->Header()->get(sndtime);
243  (*itr)->Header()->get(msgseqnum);
244  }
245  _os << '[' << _opt_keys[nlines] << "] " << tbme->_value._name << '(' << tbme->_key << ")\t"
246  << sndtime() << ' ' << msgseqnum() << ' ' << txt() << endl;
247 
248  ++nlines;
249  if (nlines % _lpp == 0 || (nlines + _lpp * page) == lst.size())
250  {
251  _os << "Page " << (page + 1) << ' ';
252  if ((opt = get_key(_fld_prompt, true)))
253  break;
254  ++page;
255  nlines = 0;
256  _os << endl;
257  }
258  }
259 
260  size_t idx;
261  if (opt)
262  {
263  if (opt == '.')
264  return nullptr;
265 
266  if ((idx = _opt_keys.find_first_of(opt)) != f8String::npos)
267  {
268  idx += (page * _lpp);
269  if (idx < lst.size())
270  return lst[idx];
271  }
272  }
273  }
274 
275  return nullptr;
276 }
277 
278 //-------------------------------------------------------------------------------------------------
279 int ConsoleMenu::CreateMsgsFrom(tty_save_state& tty, MsgList& lst, const MsgList& from) const
280 {
281  for (;;)
282  {
283  const BaseMsgEntry *mc(SelectMsg());
284  if (!mc)
285  break;
286  unique_ptr<Message> msg(mc->_create._do(true));
287  Message *fmsg(SelectFromMsg(from));
288  if (fmsg)
289  fmsg->copy_legal(msg.get());
290  const FieldTable::Pair *fld;
291  while((fld = SelectField(msg.get())))
292  EditMsg(tty, fld, msg.get());
293  _os << endl << endl << *static_cast<MessageBase *>(msg.get()) << endl;
294  if (get_yn("Add to list? (y/n):", true))
295  lst.push_back(msg.release());
296  }
297 
298  return static_cast<int>(lst.size());
299 }
300 
301 //-------------------------------------------------------------------------------------------------
303 {
304  for (;;)
305  {
306  const BaseMsgEntry *mc(SelectMsg());
307  if (!mc)
308  break;
309  unique_ptr<Message> msg(mc->_create._do(true));
310  const FieldTable::Pair *fld;
311  while((fld = SelectField(msg.get())))
312  EditMsg(tty, fld, msg.get());
313  _os << endl << endl << *static_cast<MessageBase *>(msg.get()) << endl;
314  if (get_yn("Add to list? (y/n):", true))
315  lst.push_back(msg.release());
316  }
317 
318  return static_cast<int>(lst.size());
319 }
320 
321 //-------------------------------------------------------------------------------------------------
323 {
324  char buff[128] {};
325  tty.unset_raw_mode();
326  _is.getline(buff, sizeof(buff));
327  tty.set_raw_mode();
328  return to = buff;
329 }
330 
331 //-------------------------------------------------------------------------------------------------
333 {
334  string txt;
335  int rval(-1);
336  if (fld->_value._rlm)
337  rval = SelectRealm(fld->_key, fld->_value._rlm);
338  else
339  {
340  _os << endl << fld->_value._name << ": " << flush;
341  GetString(tty, txt);
342  if (msg->get_fp().is_group(fld->_key))
343  {
344  int cnt(stoi(txt));
345  GroupBase *gb(msg->find_group(fld->_key));
346  if (gb && cnt)
347  {
348  for (int ii(0); ii < cnt; ++ii)
349  {
350  Message *gmsg(static_cast<Message *>(gb->create_group(true)));
351  const FieldTable::Pair *fld;
352  while((fld = SelectField(gmsg, ii + 1)))
353  EditMsg(tty, fld, gmsg);
354  _os << endl << endl << *static_cast<MessageBase *>(gmsg) << endl;
355  if (get_yn("Add group to msg? (y/n):", true))
356  *gb += gmsg;
357  }
358  }
359  }
360  }
361 
362  BaseField *bf(fld->_value._create._do(txt.c_str(), fld->_value._rlm, rval));
363  msg->add_field(bf->get_tag(), msg->get_fp().get_presence().end(), 0, bf, true);
364 }
365 
366 //-------------------------------------------------------------------------------------------------
368 {
369  for (;;)
370  {
371  Message *msg(SelectFromMsg(lst));
372  if (!msg)
373  break;
374  const FieldTable::Pair *fld;
375  while((fld = SelectField(msg)))
376  EditMsg(tty, fld, msg);
377  _os << endl << endl << *static_cast<MessageBase *>(msg) << endl;
378  }
379 
380  return static_cast<int>(lst.size());
381 }
382 
383 //-------------------------------------------------------------------------------------------------
385 {
386  Message *msg(SelectFromMsg(lst));
387  if (msg)
388  {
389  for (MsgList::iterator itr(lst.begin()); itr != lst.end(); ++itr)
390  {
391  if (*itr == msg)
392  {
393  _os << endl;
394  if (get_yn("Remove msg from list? (y/n, n=return a copy):", true))
395  {
396  lst.erase(itr);
397  return msg;
398  }
399  return msg->clone();
400  }
401  }
402  }
403 
404  return nullptr;;
405 }
406 
407 //-------------------------------------------------------------------------------------------------
409 {
410  if (lst.size() && get_yn("Delete all msgs? (y/n):", true))
411  {
412  for_each(lst.begin(), lst.end(), [](const Message *pp){ delete pp; pp = nullptr; });
413  lst.clear();
414  }
415 
416  return 0;
417 }
418 
419 //-------------------------------------------------------------------------------------------------
421 {
422  for (;;)
423  {
424  Message *msg(SelectFromMsg(lst));
425  if (!msg)
426  break;
427  for (MsgList::iterator itr(lst.begin()); itr != lst.end(); ++itr)
428  {
429  if (*itr == msg)
430  {
431  if (get_yn(" Delete msg? (y/n):", true))
432  {
433  delete *itr;
434  lst.erase(itr);
435  }
436  break;
437  }
438  }
439  }
440 
441  return static_cast<int>(lst.size());
442 }
443 
bool have(const unsigned short fnum) const
Definition: message.hpp:725
F8API f8String & GetString(tty_save_state &tty, f8String &to) const
virtual F8API void print_field(const unsigned short fnum, std::ostream &os) const
Definition: message.cpp:554
Message instantiation table entry.
Definition: message.hpp:192
Pair abstraction for use with GeneratedTable.
Definition: f8types.hpp:69
GroupBase * find_group() const
Definition: message.hpp:792
Val _value
Definition: f8types.hpp:72
bool is_mandatory(const unsigned short field) const
Definition: traits.hpp:596
F8API Message * RemoveMsg(tty_save_state &tty, MsgList &lst) const
std::function< Message *(bool)> _do
Definition: message.hpp:176
F8API int CreateMsgsFrom(tty_save_state &tty, MsgList &lst, const MsgList &from) const
F8API void EditMsg(tty_save_state &tty, const FieldTable::Pair *fld, Message *msg) const
const Presence & get_presence() const
Definition: traits.hpp:658
std::deque< FIX8::Message * > MsgList
Definition: consolemenu.hpp:44
virtual F8API int SelectRealm(const unsigned short fnum, const RealmBase *rb) const
Domain range/set static metadata base class.
Definition: field.hpp:58
virtual F8API int EditMsgs(tty_save_state &tty, MsgList &lst) const
static const f8String _fld_prompt
Definition: consolemenu.hpp:54
Abstract base class for all repeating groups.
Definition: message.hpp:59
Used for static trait interrogation.
Definition: traits.hpp:57
const int _sz
Definition: field.hpp:65
const f8String & get_msgtype() const
Definition: message.hpp:538
F8API Message * clone() const
Definition: message.cpp:668
A complete Fix message with header, body and trailer.
Definition: message.hpp:1058
bool is_group(const unsigned short field, Presence::const_iterator &itr) const
Definition: traits.hpp:602
F8API Message * SelectFromMsg(const MsgList &lst) const
Field template. There will ONLY be partial template specialisations of this template.
Definition: field.hpp:256
std::ostream & print(std::ostream &os, int idx) const
Definition: field.hpp:116
virtual F8API int CreateMsgs(tty_save_state &tty, MsgList &lst) const
const FieldTraits & get_fp() const
Definition: message.hpp:878
void add_field(const unsigned short fnum, Presence::const_iterator itr, const unsigned pos, BaseField *what, bool check)
Definition: message.hpp:556
The base field class (ABC) for all fields.
Definition: field.hpp:127
virtual F8API const FieldTable::Pair * SelectField(const Message *msg, int groupid=0) const
const Minst _create
Definition: message.hpp:194
virtual F8API int DeleteAllMsgs(tty_save_state &tty, MsgList &lst) const
virtual F8API const BaseMsgEntry * SelectMsg() const
Definition: consolemenu.cpp:50
static const f8String _opt_keys
Definition: consolemenu.hpp:54
std::string f8String
Definition: f8types.hpp:47
unsigned short get_tag() const
Definition: field.hpp:145
const char *const * _descriptions
Definition: field.hpp:66
virtual F8API int DeleteMsgs(tty_save_state &tty, MsgList &lst) const