#include #include "error.h" #include "command.h" #include "log.h" #include "argv.h" #include "file.h" #include "util.h" #include "machine.h" #include "show.h" #include "target_registry.h" #include "klammerset_registry.h" int main(int argc, char* argv[]) { try { set_verbose_level(argc, argv); Argv args {}; args.req("filenames", "Input files in Klammertext format. ", "'list'"); args.opt("s", "Text processed before input files.", "input-string", "", "'text'"); args.opt("t","Output target; default is general (unspecified)", "target", Target_registry::general_name, "'word'"); args.opt("o", "Output basename; meaning and default defined by target.", "basename", "", "'word'"); args.flag("d", "Display the output to the screen, rather than writing a file."); args.opt("klammersets", "Klammersets to load, as a list of symbols resolved on the " "klammerset search path. Several combine: they are loaded in the order given " "and share one namespace. The default is the Standard Klammer Set; " "\"none\" loads none.", "symbols", "", "'list'"); args.opt("v", "'verbosity'", "degree", "0", "'verbosity'"); if (show_usage(argc, argv)) { // A bare command is a REQUEST for information, not a failure: // usage goes to stdout (it is the result being asked for) and the // exit status is 0, so "ktext && echo ok" reports what happened. args.usage(file_basename(argv[0])); exit(0); } args.parse(argc, argv); if (verbose_level > 0) { args.describe(); } std::string input_text = args.as_string("s"); // argv boundaries are authoritative (a shell-quoted "my file.kt" is // one element); group_filename_tokens adds the standalone-"/" list // form, the existence rescue for unquoted spaces, and ~ expansion. std::vector input_filenames = group_filename_tokens(args.as_vector("filenames")); if (input_text.empty() && input_filenames.empty()) { throw Argument_error( "You must specify input filenames and/or text", Locator()); } auto [target, output_dir, output_basename, output_filename, write_files, display_only] = parse_args(input_filenames, args.as_string("t"), expand_tilde(args.as_string("o")), args.as_bool("d")); Machine M; M.m_state.open_frame("ktext"); M.m_state.set("K_target", target); M.m_state.set("K_output_dir", output_dir); M.m_state.set("K_output_basename", output_basename); M.m_state.set("K_stdout_only", display_only ? "true" : "false"); // The list form uses the standalone-"/" separator (filenames may // contain spaces); K_input_filename is the single root input file. M.m_state.set("K_input_filenames", join(input_filenames, " / ")); M.m_state.set("K_input_filename", input_filenames.empty() ? "" : input_filenames[0]); M.m_state.set("K_verbose_level", std::to_string(verbose_level)); if (!input_filenames.empty()) { M.m_state.set( "K_input_dir",absolute_pathname(file_directory(input_filenames[0]))); } else { M.m_state.set("K_input_dir", fs::current_path().string()); } load_klammersets(M, word_split(args.as_string("klammersets"))); if (!input_text.empty()) { M.read(input_text + "\n"); } for (auto p : input_filenames) { M.read(fs::path(p)); } std::string result = trim(M.apply(target)); if (display_only && !result.empty()) { std::cout << result << "\n"; } else if (!result.empty()) { string_to_file(output_filename, result + "\n"); (void)K::log(1, "Wrote file: " + output_filename); } } catch (Error& err) { err.print_message(); std::cerr << "\n"; return 1; } return 0; }