aboutsummaryrefslogtreecommitdiff
path: root/src/headless/main.cpp
blob: 1acf5816419f2f271f75abde11c654395784719e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <cstring>

#include <openvic-simulation/dataloader/Dataloader.hpp>
#include <openvic-simulation/GameManager.hpp>
#include <openvic-simulation/testing/Testing.hpp>
#include <openvic-simulation/utility/Logger.hpp>

using namespace OpenVic;

static void print_help(std::ostream& stream, char const* program_name) {
   stream
      << "Usage: " << program_name << " [-h] [-t] [-b <path>] [path]+\n"
      << "    -h : Print this help message and exit the program.\n"
      << "    -t : Run tests after loading defines.\n"
      << "    -b : Use the following path as the base directory (instead of searching for one).\n"
      << "    -s : Use the following path as a hint to search for a base directory.\n"
      << "Any following paths are read as mod directories, with priority starting at one above the base directory.\n"
      << "(Paths with spaces need to be enclosed in \"quotes\").\n";
}

static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests) {
   bool ret = true;

   GameManager game_manager { []() {
      Logger::info("State updated");
   }, nullptr };

   ret &= game_manager.load_definitions(
      roots,
      [](std::string_view key, Dataloader::locale_t locale, std::string_view localisation) -> bool {
         return true;
      }
   );

   if (run_tests) {
      Testing testing { game_manager.get_definition_manager() };
      std::cout << std::endl << "Testing Loaded" << std::endl << std::endl;
      testing.execute_all_scripts();
      testing.report_results();
      std::cout << "Testing Executed" << std::endl << std::endl;
   }

   return ret;
}

/*
   $ program [-h] [-t] [-b] [path]+
*/

int main(int argc, char const* argv[]) {
   Logger::set_logger_funcs();

   char const* program_name = StringUtils::get_filename(argc > 0 ? argv[0] : nullptr, "<program>");
   fs::path root;
   bool run_tests = false;
   int argn = 0;

   /* Reads the next argument and converts it to a path via path_transform. If reading or converting fails, an error
    * message and the help text are displayed, along with returning false to signify the program should exit.
    */
   const auto _read = [&root, &argn, argc, argv, program_name](
      std::string_view command, std::string_view path_use, auto path_transform) -> bool {
      if (root.empty()) {
         if (++argn < argc) {
            char const* path = argv[argn];
            root = path_transform(path);
            if (!root.empty()) {
               return true;
            } else {
               std::cerr << "Empty path after giving \"" << path << "\" to " << path_use
                  << " command line argument \"" << command << "\"." << std::endl;
            }
         } else {
            std::cerr << "Missing path after " << path_use << " command line argument \"" << command << "\"." << std::endl;
         }
      } else {
         std::cerr << "Duplicate " << path_use << " command line argument \"-b\"." << std::endl;
      }
      print_help(std::cerr, program_name);
      return false;
   };

   while (++argn < argc) {
      char const* arg = argv[argn];
      if (strcmp(arg, "-h") == 0) {
         print_help(std::cout, program_name);
         return 0;
      } else if (strcmp(arg, "-t") == 0) {
         run_tests = true;
      } else if (strcmp(arg, "-b") == 0) {
         if (!_read("-b", "base directory", std::identity {})) {
            return -1;
         }
      } else if (strcmp(arg, "-s") == 0) {
         if (!_read("-s", "search hint", Dataloader::search_for_game_path)) {
            return -1;
         }
      } else {
         break;
      }
   }
   if (root.empty()) {
      root = Dataloader::search_for_game_path();
      if (root.empty()) {
         std::cerr << "Search for base directory path failed!" << std::endl;
         print_help(std::cerr, program_name);
         return -1;
      }
   }
   Dataloader::path_vector_t roots { root };
   while (argn < argc) {
      static const fs::path mod_directory = "mod";
      roots.emplace_back(root / mod_directory / argv[argn++]);
   }

   std::cout << "!!! HEADLESS SIMULATION START !!!" << std::endl;

   const bool ret = run_headless(roots, run_tests);

   std::cout << "!!! HEADLESS SIMULATION END !!!" << std::endl;

   std::cout << "\nLoad returned: " << (ret ? "SUCCESS" : "FAILURE") << std::endl;

   std::cout << "\nLogger Summary: Info = " << Logger::get_info_count() << ", Warning = " << Logger::get_warning_count()
      << ", Error = " << Logger::get_error_count() << std::endl;

   return ret ? 0 : -1;
}