diff options
Diffstat (limited to 'cli/cli/cli.cxx')
-rw-r--r-- | cli/cli/cli.cxx | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/cli/cli/cli.cxx b/cli/cli/cli.cxx new file mode 100644 index 0000000..c57caee --- /dev/null +++ b/cli/cli/cli.cxx @@ -0,0 +1,165 @@ +// file : cli/cli.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// license : MIT; see accompanying LICENSE file + +#include <vector> +#include <string> +#include <memory> // unique_ptr +#include <fstream> +#include <iostream> + +#include <cutl/compiler/code-stream.hxx> + +#include <cli/semantics/doc.hxx> + +#include <cli/options.hxx> +#include <cli/parser.hxx> +#include <cli/generator.hxx> + +#include <cli/version.hxx> + +using namespace std; +using namespace cutl; + +int +main (int argc, char* argv[]) +{ + ostream& e (cerr); + const char* file (0); + + try + { + cli::argv_file_scanner scan (argc, argv, "--options-file"); + options ops (scan); + + // Handle --build2-metadata (see also buildfile). + // + if (ops.build2_metadata ()) + { + ostream& o (cout); + + o << "# build2 buildfile cli" << endl + << "cli.version = '" << CLI_VERSION_ID << '\'' << endl + << "cli.checksum = '" << CLI_CHECKSUM << '\'' << endl; + + return 0; + } + + // Handle --version + // + if (ops.version ()) + { + ostream& o (cout); + + o << "CLI (command line interface compiler) " << CLI_VERSION_ID << endl + << "Copyright (c) " << CLI_COPYRIGHT << "." << endl; + + o << "This is free software; see the source for copying conditions. " + << "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS " + << "FOR A PARTICULAR PURPOSE." << endl; + + return 0; + } + + // Handle --help + // + if (ops.help ()) + { + ostream& o (cout); + + o << "Usage: " << argv[0] << " [options] file" << endl + << "Options:" << endl; + + options::print_usage (o); + + return 0; + } + + if (!scan.more ()) + { + e << "error: no input file specified" << endl + << "info: try '" << argv[0] << " --help' for more information" << endl; + + return 1; + } + + // Extract include search paths. + // + parser::paths include_paths; + for (vector<string>::const_iterator i (ops.include_path ().begin ()); + i != ops.include_path ().end (); ++i) + { + // Invalid path exception is handled below. + // + include_paths.push_back (semantics::path (*i)); + } + + // Open the input file. + // + file = scan.next (); + semantics::path path (file); + + ifstream ifs (path.string ().c_str ()); + if (!ifs.is_open ()) + { + e << path << ": error: unable to open in read mode" << endl; + return 1; + } + + ifs.exceptions (ifstream::failbit | ifstream::badbit); + + // Parse and generate. + // + parser p (include_paths); + unique_ptr<semantics::cli_unit> unit (p.parse (ifs, path)); + + // Merge documentation variables from the command line. + // + for (map<string, string>::const_iterator i (ops.docvar ().begin ()); + i != ops.docvar ().end (); + ++i) + { + using semantics::doc; + + // Values specified in the .cli file override command line. + // + if (unit->lookup<doc> ("", "var: " + i->first) != 0) + continue; + + doc& d (unit->new_node<doc> (semantics::path ("<command line>"), 0, 0)); + unit->new_edge<semantics::names> (*unit, d, "var: " + i->first); + d.push_back (i->second); + } + + generator g; + g.generate (ops, *unit, path); + } + catch (cli::exception const& ex) + { + e << ex << endl; + return 1; + } + catch (semantics::invalid_path const& ex) + { + e << "error: '" << ex.path () << "' is not a valid filesystem path" + << endl; + return 1; + } + catch (std::ios_base::failure const&) + { + e << file << ": error: read failure" << endl; + return 1; + } + catch (parser::invalid_input const&) + { + // Diagnostics has already been issued by the parser. + // + return 1; + } + catch (generator::failed const&) + { + // Diagnostics has already been issued by the generator. + // + return 1; + } +} |