GnuCash  5.6-150-g038405b370+
gnucash-cli.cpp
1 /*
2  * gnucash-cli.cpp -- The command line entry point for GnuCash
3  *
4  * Copyright (C) 2020 Geert Janssens <geert@kobaltwit.be>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation Voice: +1-617-542-5942
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21  * Boston, MA 02110-1301, USA gnu@gnu.org
22  */
23 #include <config.h>
24 
25 #ifdef __MINGW32__
26 #include <Windows.h>
27 #include <fcntl.h>
28 #endif
29 
30 #include "gnucash-commands.hpp"
31 #include "gnucash-core-app.hpp"
32 
33 #include <glib/gi18n.h>
34 #include <gnc-engine.h>
35 #include <gnc-prefs.h>
36 
37 #include <boost/locale.hpp>
38 #include <boost/optional.hpp>
39 #ifdef __MINGW32__
40 #include <boost/nowide/args.hpp>
41 #endif
42 #include <iostream>
43 #include <gnc-quotes.hpp>
44 
45 namespace bl = boost::locale;
46 
47 /* This static indicates the debugging module that this .o belongs to. */
48 [[maybe_unused]] static QofLogModule log_module = GNC_MOD_GUI;
49 
50 namespace Gnucash {
51 
52  class GnucashCli : public CoreApp
53  {
54  public:
55  GnucashCli (const char* app_name);
56  void parse_command_line (int argc, char **argv);
57  int start (int argc, char **argv);
58  private:
59  void configure_program_options (void);
60 
61  std::vector<std::string> m_quotes_cmd;
62  boost::optional <std::string> m_namespace;
63  bool m_verbose = false;
64 
65  boost::optional <std::string> m_report_cmd;
66  boost::optional <std::string> m_report_name;
67  boost::optional <std::string> m_export_type;
68  boost::optional <std::string> m_output_file;
69  };
70 
71 }
72 
73 Gnucash::GnucashCli::GnucashCli (const char *app_name) : Gnucash::CoreApp (app_name)
74 {
75  configure_program_options();
76 }
77 
78 void
79 Gnucash::GnucashCli::parse_command_line (int argc, char **argv)
80 {
81  Gnucash::CoreApp::parse_command_line (argc, argv);
82 
83  if (!m_log_to_filename || m_log_to_filename->empty())
84  m_log_to_filename = "stderr";
85 
86  if (m_namespace)
87  gnc_prefs_set_namespace_regexp (m_namespace->c_str());
88 }
89 
90 // Define command line options specific to gnucash-cli.
91 void
92 Gnucash::GnucashCli::configure_program_options (void)
93 {
94  bpo::options_description quotes_options(_("Price Quotes Retrieval Options"));
95  quotes_options.add_options()
96  ("quotes,Q", bpo::value<std::vector<std::string>> (&m_quotes_cmd)->multitoken(),
97  _("Execute price quote related commands. The following commands are supported.\n\n"
98  " info: \tShow Finance::Quote version and exposed quote sources.\n"
99  " get: \tFetch current quotes for all foreign currencies and stocks in the given GnuCash datafile.\n"
100  " dump: \tFetch current quotes for specified currencies or stocks from a specified namespace and print the results to the console.\n"
101  " \tThis must be followed with a source and one or more symbols, unless the source is \"currency\" in which case it must be followed with two or more symbols, the first of which is the currency in which exchange rates for the rest will be quoted.\n"))
102  ("namespace", bpo::value (&m_namespace),
103  _("Regular expression determining which namespace commodities will be retrieved for when using the get command"))
104  ("verbose,V", bpo::bool_switch (&m_verbose),
105  _("When using the dump command list all of the parameters Finance::Quote returns for the symbol instead of the ones that Gnucash requires."));
106 
107  m_opt_desc_display->add (quotes_options);
108  m_opt_desc_all.add (quotes_options);
109 
110  bpo::options_description report_options(_("Report Generation Options"));
111  report_options.add_options()
112  ("report,R", bpo::value (&m_report_cmd),
113  _("Execute report related commands. The following commands are supported.\n\n"
114  " list: \tLists available reports.\n"
115  " show: \tDescribe the options modified in the named report. A datafile \
116 may be specified to describe some saved options.\n"
117  " run: \tRun the named report in the given GnuCash datafile.\n"))
118  ("name", bpo::value (&m_report_name),
119  _("Name of the report to run\n"))
120  ("export-type", bpo::value (&m_export_type),
121  _("Specify export type\n"))
122  ("output-file", bpo::value (&m_output_file),
123  _("Output file for report\n"));
124  m_opt_desc_display->add (report_options);
125  m_opt_desc_all.add (report_options);
126 
127 }
128 
129 int
130 Gnucash::GnucashCli::start ([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
131 {
132  Gnucash::CoreApp::start();
133 
134  if (!m_quotes_cmd.empty())
135  {
136  if (m_quotes_cmd.front() == "info")
137  {
138  return Gnucash::check_finance_quote ();
139  }
140  else if (m_quotes_cmd.front() == "get")
141  {
142  if (!m_file_to_load && m_quotes_cmd.size() == 2)
143  m_file_to_load = m_quotes_cmd[1];
144 
145  if (!m_file_to_load || m_file_to_load->empty())
146  {
147  std::cerr << bl::translate("Missing data file parameter") << "\n\n"
148  << *m_opt_desc_display.get() << std::endl;
149  return 1;
150  }
151  else
152  return Gnucash::add_quotes (m_file_to_load);
153  }
154  else if (m_quotes_cmd.front() == "dump")
155  {
156  if (m_quotes_cmd.size() < 3 ||
157  (m_quotes_cmd[1] == "currency" &&
158  m_quotes_cmd.size() < 4))
159  {
160  std::cerr << bl::translate("Not enough information for quotes dump") << std::endl;
161  return 1;
162  }
163  auto source = m_quotes_cmd[1];
164  m_quotes_cmd.erase(m_quotes_cmd.begin(), m_quotes_cmd.begin() + 2);
165  return Gnucash::report_quotes(source.c_str(), m_quotes_cmd,
166  m_verbose);
167  }
168  else
169  {
170  std::cerr << bl::format (bl::translate("Unknown quotes command '{1}'")) % m_quotes_cmd.front() << "\n\n"
171  << *m_opt_desc_display.get() << std::endl;
172  return 1;
173  }
174  }
175 
176  if (m_report_cmd)
177  {
178  if (*m_report_cmd == "run")
179  {
180  if (!m_file_to_load || m_file_to_load->empty())
181  {
182  std::cerr << _("Missing data file parameter") << "\n\n"
183  << *m_opt_desc_display.get() << std::endl;
184  return 1;
185  }
186  else
187  return Gnucash::run_report(m_file_to_load, m_report_name,
188  m_export_type, m_output_file);
189  }
190 
191  // The command "list" does *not* test&pass the m_file_to_load
192  // argument because the reports are global rather than
193  // per-file objects. In the future, saved reports may be saved
194  // into the datafile, therefore one will need to be specified
195  // for loading.
196  else if (*m_report_cmd == "list")
197  return Gnucash::report_list ();
198 
199  // The command "show" does test&pass the m_file_to_load
200  // argument, and will attempt to load datafile prior to
201  // describing report. If loading fails, it will continue
202  // showing report options.
203  else if (*m_report_cmd == "show")
204  if (!m_report_name || m_report_name->empty())
205  {
206  std::cerr << _("Missing --name parameter") << "\n\n"
207  << *m_opt_desc_display.get() << std::endl;
208  return 1;
209  }
210  else
211  return Gnucash::report_show (m_file_to_load, m_report_name);
212  else
213  {
214  std::cerr << bl::format (std::string{_("Unknown report command '{1}'")}) % *m_report_cmd << "\n\n"
215  << *m_opt_desc_display.get();
216  return 1;
217  }
218  }
219 
220  std::cerr << _("Missing command or option") << "\n\n"
221  << *m_opt_desc_display.get() << std::endl;
222 
223  return 1;
224 }
225 
226 int
227 main(int argc, char **argv)
228 {
229  const char *app_name = PROJECT_NAME "-cli";
230  Gnucash::GnucashCli application (app_name);
231 #ifdef __MINGW32__
232  boost::nowide::args a(argc, argv); // Fix arguments - make them UTF-8
233 #endif
234  application.parse_command_line (argc, argv);
235  application.start (argc, argv);
236 
237  return 0;
238 }
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.