summaryrefslogtreecommitdiff
path: root/src/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cc')
-rw-r--r--src/main.cc217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/main.cc b/src/main.cc
new file mode 100644
index 00000000..0aec8886
--- /dev/null
+++ b/src/main.cc
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2003-2009, John Wiegley. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of New Artisans LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <system.hh>
+
+#include "global.h" // This is where the meat of main() is, which
+ // was moved there for the sake of clarity here
+#include "session.h"
+
+using namespace ledger;
+
+#ifdef HAVE_BOOST_PYTHON
+namespace ledger {
+ extern char * argv0;
+}
+#endif
+
+int main(int argc, char * argv[], char * envp[])
+{
+ int status = 1;
+
+#ifdef HAVE_BOOST_PYTHON
+ argv0 = argv[0];
+#endif
+
+ // The very first thing we do is handle some very special command-line
+ // options, since they affect how the environment is setup:
+ //
+ // --verify ; turns on memory tracing
+ // --verbose ; turns on logging
+ // --debug CATEGORY ; turns on debug logging
+ // --trace LEVEL ; turns on trace logging
+ handle_debug_options(argc, argv);
+#if defined(VERIFY_ON)
+ IF_VERIFY() initialize_memory_tracing();
+#endif
+
+ INFO("Ledger starting");
+
+ // Initialize global Boost/C++ environment
+ std::ios::sync_with_stdio(false);
+ filesystem::path::default_name_check(filesystem::portable_posix_name);
+
+ std::signal(SIGINT, sigint_handler);
+ std::signal(SIGPIPE, sigpipe_handler);
+
+#if defined(HAVE_GETTEXT)
+ ::textdomain("ledger");
+#endif
+
+ std::auto_ptr<global_scope_t> global_scope;
+
+ try {
+ // Create the session object, which maintains nearly all state relating to
+ // this invocation of Ledger; and register all known journal parsers.
+ global_scope.reset(new global_scope_t(envp));
+
+ global_scope->session().set_flush_on_next_data_file(true);
+
+ // Construct an STL-style argument list from the process command arguments
+ strings_list args;
+ for (int i = 1; i < argc; i++)
+ args.push_back(argv[i]);
+
+ // Look for options and a command verb in the command-line arguments
+ bind_scope_t bound_scope(*global_scope.get(), global_scope->report());
+
+ args = global_scope->read_command_arguments(bound_scope, args);
+
+ if (global_scope->HANDLED(script_)) {
+ // Ledger is being invoked as a script command interpreter
+ global_scope->session().read_journal_files();
+
+ status = 0;
+
+ ifstream in(global_scope->HANDLER(script_).str());
+ while (status == 0 && ! in.eof()) {
+ char line[1024];
+ in.getline(line, 1023);
+
+ char * p = skip_ws(line);
+ if (*p && *p != '#')
+ status = global_scope->execute_command_wrapper(split_arguments(p),
+ true);
+ }
+ }
+ else if (! args.empty()) {
+ // User has invoke a verb at the interactive command-line
+ status = global_scope->execute_command_wrapper(args, false);
+ }
+ else {
+ // Commence the REPL by displaying the current Ledger version
+ global_scope->show_version_info(std::cout);
+
+ global_scope->session().read_journal_files();
+
+ bool exit_loop = false;
+
+#ifdef HAVE_LIBEDIT
+
+ rl_readline_name = const_cast<char *>("Ledger");
+#if 0
+ // jww (2009-02-05): NYI
+ rl_attempted_completion_function = ledger_completion;
+#endif
+
+ while (char * p = readline(global_scope->prompt_string())) {
+ char * expansion = NULL;
+ int result;
+
+ result = history_expand(skip_ws(p), &expansion);
+
+ if (result < 0 || result == 2) {
+ if (expansion)
+ std::free(expansion);
+ std::free(p);
+ throw_(std::logic_error,
+ _("Failed to expand history reference '%1'") << p);
+ }
+ else if (expansion) {
+ add_history(expansion);
+ }
+
+#else // HAVE_LIBEDIT
+
+ while (! std::cin.eof()) {
+ std::cout << global_scope->prompt_string();
+ char line[1024];
+ std::cin.getline(line, 1023);
+
+ char * p = skip_ws(line);
+
+#endif // HAVE_LIBEDIT
+
+ check_for_signal();
+
+ if (*p && *p != '#') {
+ if (std::strncmp(p, "quit", 4) == 0)
+ exit_loop = true;
+ else
+ global_scope->execute_command_wrapper(split_arguments(p), true);
+ }
+
+#ifdef HAVE_LIBEDIT
+ if (expansion)
+ std::free(expansion);
+ std::free(p);
+#endif
+
+ if (exit_loop)
+ break;
+ }
+
+ status = 0; // report success
+ }
+ }
+ catch (const std::exception& err) {
+ if (global_scope.get())
+ global_scope->report_error(err);
+ else
+ std::cerr << "Exception during initialization: " << err.what()
+ << std::endl;
+ }
+ catch (int _status) {
+ status = _status; // used for a "quick" exit, and is used only
+ // if help text (such as --help) was displayed
+ }
+
+ // If memory verification is being performed (which can be very slow), clean
+ // up everything by closing the session and deleting the session object, and
+ // then shutting down the memory tracing subsystem. Otherwise, let it all
+ // leak because we're about to exit anyway.
+ IF_VERIFY() {
+ global_scope.reset();
+
+ INFO("Ledger ended (Boost/libstdc++ may still hold memory)");
+#if defined(VERIFY_ON)
+ shutdown_memory_tracing();
+#endif
+ } else {
+ INFO("Ledger ended");
+ }
+
+ // Return the final status to the operating system, either 1 for error or 0
+ // for a successful completion.
+ return status;
+}
+
+// main.cc ends here.