Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
cmdopt.cpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
17#include "shambase/print.hpp"
18#include "shambase/string.hpp"
20#include "shamcmdopt/cmdopt.hpp"
22#include "shamcmdopt/env.hpp"
23#include <string_view>
24#include <algorithm>
25#include <iostream>
26#include <optional>
27#include <stdexcept>
28#include <string>
29#include <utility>
30#include <vector>
31
35class ShamCmdOptException : public std::exception {
36 public:
38 explicit ShamCmdOptException(const char *message) : msg_(message) {}
39
41 explicit ShamCmdOptException(const std::string &message) : msg_(message) {}
42
44 virtual ~ShamCmdOptException() noexcept {}
45
47 virtual const char *what() const noexcept { return msg_.c_str(); }
48
49 protected:
51 std::string msg_;
52};
53
54namespace shamcmdopt {
55
57 auto err_str = []() {
58 return "[" + shambase::term_colors::col8b_red() + "Error" + shambase::term_colors::reset()
59 + "]";
60 };
61
62 std::string_view executable_name;
63 std::vector<std::string_view> args;
64 bool init_done;
65
67 struct Opts {
68 std::string name;
69 std::optional<std::string> args;
70 std::string description;
71 };
72
74 std::vector<Opts> registered_opts;
75
83 bool is_name_registered(const std::string_view &name) {
84 for (const auto &opt : registered_opts) {
85 if (opt.name == name) {
86 return true;
87 }
88 }
89 return false;
90 }
91
96 bool error = false;
97
98 std::string err_buf;
99
100 for (auto arg : args) {
101 if (arg.rfind("-", 0) == 0) {
102 if (!is_name_registered(arg)) {
104 err_str() + " opts argument : " + std::string(arg) + " is not registered");
105 err_buf += "\"";
106 err_buf += arg;
107 err_buf += "\"";
108 err_buf += " ";
109 error = true;
110 }
111 }
112 }
113
114 if (error) {
115 print_help();
116 throw ShamCmdOptException(err_buf + "names are not registered in ::opts");
117 }
118 }
119
123 void check_init() {
124 if (!init_done)
125 throw ShamCmdOptException("Cmdopt uninitialized");
126 }
127
128 bool has_option(const std::string_view &option_name) {
129 check_init(); // We must init the cmdopt before checking if an option is there
130
131 if (!is_name_registered(option_name)) {
133 err_str() + " opts argument :" + std::string(option_name) + " is not registered");
135 std::string(option_name) + " option is not registered in ::opts");
136 }
137
138 for (auto it = args.begin(), end = args.end(); it != end; ++it) {
139 if (*it == option_name)
140 return true;
141 }
142
143 return false;
144 }
145
146 std::string_view get_option(const std::string_view &option_name) {
147 check_init();
148
149 if (!is_name_registered(option_name)) {
151 err_str() + " opts argument :" + std::string(option_name) + "is not registered");
153 std::string(option_name) + " option is not registered in ::opts");
154 }
155
156 for (auto it = args.begin(), end = args.end(); it != end; ++it) {
157 if (*it == option_name)
158 if (it + 1 != end)
159 return *(it + 1);
160 }
161
162 return "";
163 }
164
165 void register_opt(std::string name, std::optional<std::string> args, std::string description) {
166
167 for (auto &[n, arg, desc] : registered_opts) {
168 if (name == n) {
170 shambase::format("The option {} is already registered", name));
171 }
172 }
173
174 registered_opts.push_back({name, std::move(args), std::move(description)});
175 }
176
178 int argc;
179
181 char **argv;
182
183 void init(int _argc, char *_argv[]) {
184 argc = _argc;
185 argv = _argv;
186
188
189 executable_name = std::string_view(argv[0]);
190 args = std::vector<std::string_view>(argv + 1, argv + argc);
191 init_done = true;
193
195 }
196
197 int get_argc() {
198 if (init_done) {
199 return argc;
200 }
201 return 0;
202 }
203 char **get_argv() {
204 if (init_done) {
205 return argv;
206 }
207 return 0;
208 }
209
210 void print_help() {
211 shambase::println(shambase::format("executable : {}", executable_name));
212
213 fmt::println("\nUsage :");
214
215 std::sort(
216 registered_opts.begin(), registered_opts.end(), [](const auto &lhs, const auto &rhs) {
217 return lhs.name < rhs.name;
218 });
219
220 for (auto &[n, arg, desc] : registered_opts) {
221
222 std::string arg_print = arg.value_or("");
223
226 "%-15s %-15s : %s", n.c_str(), arg_print.c_str(), desc.c_str()));
227 }
229 }
230
232
233 std::string exe(executable_name);
234
235 // keep only the executable name
236 exe = exe.substr(exe.find_last_of('/') + 1);
237
238 // Header required by zsh
239 shambase::println("#compdef " + exe);
241
242 // Function name must be _<cmd>
243 shambase::println("_" + exe + "() {");
244 shambase::println(" _arguments \\");
245
246 std::sort(
247 registered_opts.begin(), registered_opts.end(), [](const auto &lhs, const auto &rhs) {
248 return lhs.name < rhs.name;
249 });
250
251 for (size_t i = 0; i < registered_opts.size(); ++i) {
252 const auto &[name, arg, desc] = registered_opts[i];
253
254 std::string entry;
255
256 if (arg.has_value()) {
257 // Option takes a value
258 // Example: --output=[Output file]:file:_files
259 entry = "'" + name + "[" + desc + "]:" + arg.value() + "'";
260 } else {
261 // Flag without value
262 // Example: --help[Show help]
263 entry = "'" + name + "[" + desc + "]'";
264 }
265
266 // Add trailing backslash except last line
267 if (i != registered_opts.size() - 1)
268 entry += " \\";
269
270 shambase::println(" " + entry);
271 }
272
276
277 shambase::println("compdef _" + exe + " " + exe + " */" + exe);
278 }
279
280 bool is_help_mode() { return has_option("--help"); }
281
282} // namespace shamcmdopt
Exception handler for exeption in this lib.
Definition cmdopt.cpp:35
virtual ~ShamCmdOptException() noexcept
Destructor.
Definition cmdopt.cpp:44
std::string msg_
Held message.
Definition cmdopt.cpp:51
ShamCmdOptException(const char *message)
Exception CTOR from a message (cstring)
Definition cmdopt.cpp:38
virtual const char * what() const noexcept
Get the message attached to the exception.
Definition cmdopt.cpp:47
ShamCmdOptException(const std::string &message)
Exception CTOR from a message (string)
Definition cmdopt.cpp:41
This header file contains utility functions related to exception handling in the code.
This file handler generic cli & env options.
void println(std::string_view sv)
Prints a string to the console followed by a newline.
Definition print.cpp:37
void throw_with_loc(std::string message, SourceLocation loc=SourceLocation{})
Throw an exception and append the source location to it.
namespace for cli utilities
Definition ci_env.hpp:19
bool is_help_mode()
Check if the help mode is enabled.
Definition cmdopt.cpp:280
int argc
supplied argc from main
Definition cmdopt.cpp:178
std::vector< Opts > registered_opts
Registered cli options.
Definition cmdopt.cpp:74
void print_help_env_var()
Print the documentation of the environment variables registered with register_env_var_doc()
Definition env.cpp:47
void process_cmdopt_generic_opts()
Process generic cli and env variables options.
bool has_option(const std::string_view &option_name)
Check if an option is present.
Definition cmdopt.cpp:128
char ** argv
supplied argv from main
Definition cmdopt.cpp:181
std::string_view get_option(const std::string_view &option_name)
Get the value of an option.
Definition cmdopt.cpp:146
std::vector< std::string_view > args
Executable argument list (mapped from argv)
Definition cmdopt.cpp:63
char ** get_argv()
Get the command line arguments.
Definition cmdopt.cpp:203
int get_argc()
Get the number of command line arguments.
Definition cmdopt.cpp:197
void register_cmdopt_generic_opts()
Register generic cli and env variables options.
void init(int argc, char *argv[])
Initialize the command line option parser. We also process generic options in this call (color detect...
Definition cmdopt.cpp:183
void check_args_registered()
Check if all argument passed to shamrock where registered otherwise throw.
Definition cmdopt.cpp:95
std::string_view executable_name
Executable name.
Definition cmdopt.cpp:62
bool init_done
Has cmdopt init been called.
Definition cmdopt.cpp:64
bool is_name_registered(const std::string_view &name)
Check if the option name is registered.
Definition cmdopt.cpp:83
auto err_str
Error string to be printed in case of failure.
Definition cmdopt.cpp:57
void check_init()
Check if init has been performed otherwise throw.
Definition cmdopt.cpp:123
void print_completion_zsh()
print zsh completion script to be sourced
Definition cmdopt.cpp:231
void register_opt(std::string name, std::optional< std::string > args, std::string description)
Register a command line option.
Definition cmdopt.cpp:165
void print_help()
Print the help message.
Definition cmdopt.cpp:210
Struct for data related to an option.
Definition cmdopt.cpp:67
std::optional< std::string > args
Documention of the option argument.
Definition cmdopt.cpp:69
std::string name
Name of the option (including dashes)
Definition cmdopt.cpp:68
std::string description
Description of the otion.
Definition cmdopt.cpp:70