ArgumentParser: Add support for version information
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
0c1d33f2ec
commit
80914f0bb9
@ -10,6 +10,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Encode or decode Base64 data. If not given a file, reads from standard input.");
|
parser.add_description("Encode or decode Base64 data. If not given a file, reads from standard input.");
|
||||||
|
parser.add_system_program_info("base64"_sv);
|
||||||
parser.add_positional_argument(path, "file", "-"_sv);
|
parser.add_positional_argument(path, "file", "-"_sv);
|
||||||
parser.add_switch_argument(decode, 'd', "decode", "decode data");
|
parser.add_switch_argument(decode, 'd', "decode", "decode data");
|
||||||
parser.add_switch_argument(allow_garbage, 'i', "ignore-garbage", "when decoding, ignore non-base64 characters");
|
parser.add_switch_argument(allow_garbage, 'i', "ignore-garbage", "when decoding, ignore non-base64 characters");
|
||||||
|
@ -27,6 +27,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Concatenate files to standard output."_sv);
|
parser.add_description("Concatenate files to standard output."_sv);
|
||||||
|
parser.add_system_program_info("cat"_sv);
|
||||||
parser.add_positional_argument(filename, "file"_sv, "-"_sv);
|
parser.add_positional_argument(filename, "file"_sv, "-"_sv);
|
||||||
Vector<StringView> extra_files = TRY(parser.parse(argc, argv));
|
Vector<StringView> extra_files = TRY(parser.parse(argc, argv));
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Change the permissions of a file."_sv);
|
parser.add_description("Change the permissions of a file."_sv);
|
||||||
|
parser.add_system_program_info("chmod"_sv);
|
||||||
parser.add_positional_argument(mode_string, "mode"_sv, true);
|
parser.add_positional_argument(mode_string, "mode"_sv, true);
|
||||||
parser.add_positional_argument(path, "path"_sv, true);
|
parser.add_positional_argument(path, "path"_sv, true);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
@ -12,6 +12,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Change the owner and group of a file."_sv);
|
parser.add_description("Change the owner and group of a file."_sv);
|
||||||
|
parser.add_system_program_info("chown"_sv);
|
||||||
parser.add_positional_argument(user_and_group, "owner"_sv, true);
|
parser.add_positional_argument(user_and_group, "owner"_sv, true);
|
||||||
parser.add_positional_argument(path, "path"_sv, true);
|
parser.add_positional_argument(path, "path"_sv, true);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
@ -11,6 +11,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Display the current (or another) date and time."_sv);
|
parser.add_description("Display the current (or another) date and time."_sv);
|
||||||
|
parser.add_system_program_info("date"_sv);
|
||||||
parser.add_value_argument(date, 'd', "date"_sv, true,
|
parser.add_value_argument(date, 'd', "date"_sv, true,
|
||||||
"the UNIX timestamp to display instead of the current time"_sv);
|
"the UNIX timestamp to display instead of the current time"_sv);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
@ -10,6 +10,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Edit a file using basic line-based shell editing."_sv);
|
parser.add_description("Edit a file using basic line-based shell editing."_sv);
|
||||||
|
parser.add_system_program_info("edit"_sv);
|
||||||
parser.add_positional_argument(pathname, "path"_sv, true);
|
parser.add_positional_argument(pathname, "path"_sv, true);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("List files contained in a directory (defaults to '.', the current directory)"_sv);
|
parser.add_description("List files contained in a directory (defaults to '.', the current directory)"_sv);
|
||||||
|
parser.add_system_program_info("ls"_sv);
|
||||||
parser.add_positional_argument(pathname, "directory"_sv, "."_sv);
|
parser.add_positional_argument(pathname, "directory"_sv, "."_sv);
|
||||||
parser.add_switch_argument(show_all, 'a', "all"_sv, "also list hidden files (whose filename begins with a dot)"_sv);
|
parser.add_switch_argument(show_all, 'a', "all"_sv, "also list hidden files (whose filename begins with a dot)"_sv);
|
||||||
parser.add_switch_argument(show_almost_all, 'A', "almost-all"_sv, "list all files except '.' and '..'"_sv);
|
parser.add_switch_argument(show_almost_all, 'A', "almost-all"_sv, "list all files except '.' and '..'"_sv);
|
||||||
|
@ -31,6 +31,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Create directories."_sv);
|
parser.add_description("Create directories."_sv);
|
||||||
|
parser.add_system_program_info("mkdir"_sv);
|
||||||
parser.add_positional_argument(path, "path"_sv, true);
|
parser.add_positional_argument(path, "path"_sv, true);
|
||||||
parser.add_positional_argument(mode_string, "mode"_sv, "755"_sv);
|
parser.add_positional_argument(mode_string, "mode"_sv, "755"_sv);
|
||||||
parser.add_switch_argument(recursive, 'p', "parents"_sv,
|
parser.add_switch_argument(recursive, 'p', "parents"_sv,
|
||||||
|
@ -8,6 +8,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Remove a path from the file system."_sv);
|
parser.add_description("Remove a path from the file system."_sv);
|
||||||
|
parser.add_system_program_info("rm"_sv);
|
||||||
parser.add_positional_argument(path, "path"_sv, true);
|
parser.add_positional_argument(path, "path"_sv, true);
|
||||||
parser.add_switch_argument(recursive, 'r', "recursive"_sv,
|
parser.add_switch_argument(recursive, 'r', "recursive"_sv,
|
||||||
"remove a directory recursively (by default, rm removes only empty directories)"_sv);
|
"remove a directory recursively (by default, rm removes only empty directories)"_sv);
|
||||||
|
@ -46,6 +46,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("The Luna system's command shell."_sv);
|
parser.add_description("The Luna system's command shell."_sv);
|
||||||
|
parser.add_system_program_info("sh"_sv);
|
||||||
parser.add_positional_argument(path, "path"_sv, "-"_sv);
|
parser.add_positional_argument(path, "path"_sv, "-"_sv);
|
||||||
parser.add_value_argument(command, 'c', "command"_sv, true, "execute a single command and then exit"_sv);
|
parser.add_value_argument(command, 'c', "command"_sv, true, "execute a single command and then exit"_sv);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
@ -19,6 +19,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Display file status.");
|
parser.add_description("Display file status.");
|
||||||
|
parser.add_system_program_info("stat"_sv);
|
||||||
parser.add_positional_argument(path, "path", true);
|
parser.add_positional_argument(path, "path", true);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Switch to a different user (by default, root)."_sv);
|
parser.add_description("Switch to a different user (by default, root)."_sv);
|
||||||
|
parser.add_system_program_info("su"_sv);
|
||||||
parser.add_positional_argument(name, "name"_sv, "root"_sv);
|
parser.add_positional_argument(name, "name"_sv, "root"_sv);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Print system information. If given no options, defaults to -s."_sv);
|
parser.add_description("Print system information. If given no options, defaults to -s."_sv);
|
||||||
|
parser.add_system_program_info("uname"_sv);
|
||||||
parser.add_switch_argument(all, 'a', "all"_sv, "print all information"_sv);
|
parser.add_switch_argument(all, 'a', "all"_sv, "print all information"_sv);
|
||||||
parser.add_switch_argument(kernel_name, 's', "kernel-name"_sv, "print the kernel name"_sv);
|
parser.add_switch_argument(kernel_name, 's', "kernel-name"_sv, "print the kernel name"_sv);
|
||||||
parser.add_switch_argument(node_name, 'n', "nodename"_sv, "print the network hostname"_sv);
|
parser.add_switch_argument(node_name, 'n', "nodename"_sv, "print the network hostname"_sv);
|
||||||
|
@ -7,7 +7,7 @@ namespace os
|
|||||||
class ArgumentParser
|
class ArgumentParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ArgumentParser(bool add_help = true);
|
ArgumentParser();
|
||||||
|
|
||||||
void add_description(StringView description);
|
void add_description(StringView description);
|
||||||
|
|
||||||
@ -23,6 +23,22 @@ namespace os
|
|||||||
|
|
||||||
Result<Vector<StringView>> parse(int argc, char* const* argv);
|
Result<Vector<StringView>> parse(int argc, char* const* argv);
|
||||||
|
|
||||||
|
struct ProgramInfo
|
||||||
|
{
|
||||||
|
StringView name;
|
||||||
|
StringView version;
|
||||||
|
StringView copyright;
|
||||||
|
StringView license;
|
||||||
|
StringView authors;
|
||||||
|
StringView package;
|
||||||
|
};
|
||||||
|
|
||||||
|
void add_program_info(ProgramInfo info);
|
||||||
|
|
||||||
|
/* Used from programs that are part of the Luna source tree, to add the same version info for all programs.
|
||||||
|
* Should not be used otherwise. */
|
||||||
|
void add_system_program_info(StringView name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct PositionalArgument
|
struct PositionalArgument
|
||||||
{
|
{
|
||||||
@ -53,11 +69,16 @@ namespace os
|
|||||||
Result<void> usage(StringView program_name);
|
Result<void> usage(StringView program_name);
|
||||||
void short_usage(StringView program_name);
|
void short_usage(StringView program_name);
|
||||||
|
|
||||||
|
void version();
|
||||||
|
|
||||||
Vector<PositionalArgument> m_positional_args;
|
Vector<PositionalArgument> m_positional_args;
|
||||||
Vector<SwitchArgument> m_switch_args;
|
Vector<SwitchArgument> m_switch_args;
|
||||||
Vector<ValueArgument> m_value_args;
|
Vector<ValueArgument> m_value_args;
|
||||||
|
ProgramInfo m_program_info;
|
||||||
StringView m_description = {};
|
StringView m_description = {};
|
||||||
bool m_add_short_help_flag { false };
|
bool m_add_short_help_flag { false };
|
||||||
bool m_add_long_help_flag { false };
|
bool m_add_long_help_flag { false };
|
||||||
|
bool m_add_short_version_flag { false };
|
||||||
|
bool m_add_long_version_flag { false };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,11 @@
|
|||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
namespace os
|
namespace os
|
||||||
{
|
{
|
||||||
ArgumentParser::ArgumentParser(bool add_help) : m_add_short_help_flag(add_help), m_add_long_help_flag(add_help)
|
ArgumentParser::ArgumentParser() : m_add_short_help_flag(true), m_add_long_help_flag(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,6 +35,8 @@ namespace os
|
|||||||
|
|
||||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||||
|
if (short_flag == 'v') m_add_short_version_flag = false;
|
||||||
|
if (long_flag == "version"_sv) m_add_long_version_flag = false;
|
||||||
|
|
||||||
return m_switch_args.try_append(move(arg));
|
return m_switch_args.try_append(move(arg));
|
||||||
}
|
}
|
||||||
@ -45,6 +48,8 @@ namespace os
|
|||||||
|
|
||||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||||
|
if (short_flag == 'v') m_add_short_version_flag = false;
|
||||||
|
if (long_flag == "version"_sv) m_add_long_version_flag = false;
|
||||||
|
|
||||||
return m_value_args.try_append(move(arg));
|
return m_value_args.try_append(move(arg));
|
||||||
}
|
}
|
||||||
@ -56,10 +61,38 @@ namespace os
|
|||||||
|
|
||||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||||
|
if (short_flag == 'v') m_add_short_version_flag = false;
|
||||||
|
if (long_flag == "version"_sv) m_add_long_version_flag = false;
|
||||||
|
|
||||||
return m_value_args.try_append(move(arg));
|
return m_value_args.try_append(move(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr auto copyright_text = "Copyright (C) 2023, the Luna authors.";
|
||||||
|
constexpr auto license_text = "Licensed under the BSD-2 license <https://opensource.org/license/bsd-2-clause/>";
|
||||||
|
|
||||||
|
void ArgumentParser::add_program_info(ProgramInfo info)
|
||||||
|
{
|
||||||
|
m_program_info = info;
|
||||||
|
m_add_short_version_flag = m_add_long_version_flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgumentParser::add_system_program_info(StringView name)
|
||||||
|
{
|
||||||
|
static utsname info;
|
||||||
|
check(uname(&info) == 0);
|
||||||
|
|
||||||
|
ProgramInfo system_info {
|
||||||
|
.name = name,
|
||||||
|
.version = info.release,
|
||||||
|
.copyright = copyright_text,
|
||||||
|
.license = license_text,
|
||||||
|
.authors = {},
|
||||||
|
.package = "Luna system",
|
||||||
|
};
|
||||||
|
|
||||||
|
add_program_info(system_info);
|
||||||
|
}
|
||||||
|
|
||||||
static bool looks_like_short_flag(StringView arg)
|
static bool looks_like_short_flag(StringView arg)
|
||||||
{
|
{
|
||||||
return arg.length() > 1 && arg[0] == '-';
|
return arg.length() > 1 && arg[0] == '-';
|
||||||
@ -107,6 +140,7 @@ namespace os
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
if (m_add_long_help_flag && flag == "help"_sv) { TRY(usage(program_name)); }
|
if (m_add_long_help_flag && flag == "help"_sv) { TRY(usage(program_name)); }
|
||||||
|
if (m_add_long_version_flag && flag == "version"_sv) { version(); }
|
||||||
|
|
||||||
for (const auto& current : m_switch_args)
|
for (const auto& current : m_switch_args)
|
||||||
{
|
{
|
||||||
@ -144,6 +178,7 @@ namespace os
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
if (m_add_short_help_flag && c == 'h') { TRY(usage(program_name)); }
|
if (m_add_short_help_flag && c == 'h') { TRY(usage(program_name)); }
|
||||||
|
if (m_add_short_version_flag && c == 'v') { version(); }
|
||||||
|
|
||||||
// Last flag, this could be a value flag
|
// Last flag, this could be a value flag
|
||||||
if (j + 1 == flags.length())
|
if (j + 1 == flags.length())
|
||||||
@ -284,6 +319,35 @@ namespace os
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_add_short_help_flag && m_add_long_help_flag)
|
||||||
|
printf(" -h, --%-20s %s\n", "help", "show this help message and exit");
|
||||||
|
else if (m_add_long_help_flag)
|
||||||
|
printf(" --%-20s %s\n", "help", "show this help message and exit");
|
||||||
|
else
|
||||||
|
printf(" -%-25c %s\n", 'h', "show this help message and exit");
|
||||||
|
|
||||||
|
if (m_add_short_version_flag && m_add_long_version_flag)
|
||||||
|
printf(" -v, --%-20s %s\n", "version", "show version information and exit");
|
||||||
|
else if (m_add_long_version_flag)
|
||||||
|
printf(" --%-20s %s\n", "version", "show version information and exit");
|
||||||
|
else
|
||||||
|
printf(" -%-25c %s\n", 'v', "show version information and exit");
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgumentParser::version()
|
||||||
|
{
|
||||||
|
if (m_program_info.package.is_empty())
|
||||||
|
printf("%s %s\n", m_program_info.name.chars(), m_program_info.version.chars());
|
||||||
|
else
|
||||||
|
printf("%s (%s) %s\n", m_program_info.name.chars(), m_program_info.package.chars(),
|
||||||
|
m_program_info.version.chars());
|
||||||
|
|
||||||
|
printf("%s\n%s\n", m_program_info.copyright.chars(), m_program_info.license.chars());
|
||||||
|
|
||||||
|
if (!m_program_info.authors.is_empty()) printf("\n%s\n", m_program_info.authors.chars());
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user