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
15
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 = []() {
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(
175 {.name = name, .args = std::move(args), .description = std::move(description)});
176 }
177
179 int argc;
180
182 char **argv;
183
184 void init(int _argc, char *_argv[]) {
185 argc = _argc;
186 argv = _argv;
187
189
190 executable_name = std::string_view(argv[0]);
191 args = std::vector<std::string_view>(argv + 1, argv + argc);
192 init_done = true;
194
196 }
197
198 int get_argc() {
199 if (init_done) {
200 return argc;
201 }
202 return 0;
203 }
204 char **get_argv() {
205 if (init_done) {
206 return argv;
207 }
208 return 0;
209 }
210
211 void print_help() {
212 shambase::println(shambase::format("executable : {}", executable_name));
213
214 fmt::println("\nUsage :");
215
216 std::sort(
217 registered_opts.begin(), registered_opts.end(), [](const auto &lhs, const auto &rhs) {
218 return lhs.name < rhs.name;
219 });
220
221 for (auto &[n, arg, desc] : registered_opts) {
222
223 std::string arg_print = arg.value_or("");
224
226 shambase::format_printf(
227 "%-15s %-15s : %s", n.c_str(), arg_print.c_str(), desc.c_str()));
228 }
230 }
231
233
234 std::string exe(executable_name);
235
236 // keep only the executable name
237 exe = exe.substr(exe.find_last_of('/') + 1);
238
239 // Header required by zsh
240 shambase::println("#compdef " + exe);
242
243 // Function name must be _<cmd>
244 shambase::println("_" + exe + "() {");
245 shambase::println(" _arguments \\");
246
247 std::sort(
248 registered_opts.begin(), registered_opts.end(), [](const auto &lhs, const auto &rhs) {
249 return lhs.name < rhs.name;
250 });
251
252 for (size_t i = 0; i < registered_opts.size(); ++i) {
253 const auto &[name, arg, desc] = registered_opts[i];
254
255 std::string entry;
256
257 if (arg.has_value()) {
258 // Option takes a value
259 // Example: --output=[Output file]:file:_files
260 entry = "'" + name + "[" + desc + "]:" + arg.value() + "'";
261 } else {
262 // Flag without value
263 // Example: --help[Show help]
264 entry = "'" + name + "[" + desc + "]'";
265 }
266
267 // Add trailing backslash except last line
268 if (i != registered_opts.size() - 1)
269 entry += " \\";
270
271 shambase::println(" " + entry);
272 }
273
277
278 shambase::println("compdef _" + exe + " " + exe + " */" + exe);
279 }
280
281 bool is_help_mode() { return has_option("--help"); }
282
283} // 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:281
int argc
supplied argc from main
Definition cmdopt.cpp:179
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:55
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:182
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:204
int get_argc()
Get the number of command line arguments.
Definition cmdopt.cpp:198
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:184
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:232
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:211
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
const std::string reset()
Get the reset terminal escape char.
const std::string col8b_red()
Get the red terminal escape char.