diff options
author | Sergey Bugaev <bugaevc@serenityos.org> | 2020-01-27 20:25:36 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-01-28 13:50:18 +0100 |
commit | f983dfe319978b47b4c5314df9ea3373e3d69c05 (patch) | |
tree | 27d599f2c30ca6bfbfee6fbc3df98a08f33ac887 | |
parent | 92765825358daaed11fa105ca64cf2c7819e5563 (diff) | |
download | serenity-f983dfe319978b47b4c5314df9ea3373e3d69c05.zip |
Userland+Terminal: Port to new CArgsParser API
While at it, also add some niceties and fix some things.
-rw-r--r-- | Applications/Terminal/main.cpp | 11 | ||||
-rw-r--r-- | Userland/cal.cpp | 75 | ||||
-rw-r--r-- | Userland/chroot.cpp | 111 | ||||
-rw-r--r-- | Userland/copy.cpp | 75 | ||||
-rw-r--r-- | Userland/cp.cpp | 37 | ||||
-rw-r--r-- | Userland/head.cpp | 53 | ||||
-rw-r--r-- | Userland/id.cpp | 31 | ||||
-rw-r--r-- | Userland/ln.cpp | 25 | ||||
-rw-r--r-- | Userland/ls.cpp | 60 | ||||
-rw-r--r-- | Userland/mount.cpp | 46 | ||||
-rw-r--r-- | Userland/nl.cpp | 117 | ||||
-rw-r--r-- | Userland/pape.cpp | 30 | ||||
-rw-r--r-- | Userland/paste.cpp | 69 | ||||
-rw-r--r-- | Userland/pidof.cpp | 46 | ||||
-rw-r--r-- | Userland/rm.cpp | 29 | ||||
-rw-r--r-- | Userland/shutdown.cpp | 14 | ||||
-rw-r--r-- | Userland/sysctl.cpp | 19 | ||||
-rw-r--r-- | Userland/tail.cpp | 38 | ||||
-rw-r--r-- | Userland/tee.cpp | 38 | ||||
-rw-r--r-- | Userland/truncate.cpp | 56 | ||||
-rw-r--r-- | Userland/umount.cpp | 20 | ||||
-rw-r--r-- | Userland/wc.cpp | 49 |
22 files changed, 394 insertions, 655 deletions
diff --git a/Applications/Terminal/main.cpp b/Applications/Terminal/main.cpp index d51ce1f2f3..d45a83da8f 100644 --- a/Applications/Terminal/main.cpp +++ b/Applications/Terminal/main.cpp @@ -193,11 +193,11 @@ int main(int argc, char** argv) return 1; } - CArgsParser args_parser("Terminal"); + const char* command_to_execute = "/bin/Shell"; - args_parser.add_arg("e", "execute", "Execute this command inside the terminal."); - - CArgsParserResult args = args_parser.parse(argc, argv); + CArgsParser args_parser; + args_parser.add_option(command_to_execute, "Execute this command inside the terminal", nullptr, 'e', "command"); + args_parser.parse(argc, argv); if (chdir(get_current_user_home_path().characters()) < 0) perror("chdir"); @@ -208,7 +208,7 @@ int main(int argc, char** argv) return 1; } - run_command(ptm_fd, args.get("e")); + run_command(ptm_fd, command_to_execute); auto window = GWindow::construct(); window->set_title("Terminal"); @@ -269,7 +269,6 @@ int main(int argc, char** argv) edit_menu->add_action(terminal->paste_action()); menubar->add_menu(move(edit_menu)); - GActionGroup font_action_group; font_action_group.set_exclusive(true); auto font_menu = GMenu::construct("Font"); diff --git a/Userland/cal.cpp b/Userland/cal.cpp index ee3596983d..dd454f8c54 100644 --- a/Userland/cal.cpp +++ b/Userland/cal.cpp @@ -128,69 +128,56 @@ void clean_buffers() int main(int argc, char** argv) { - CArgsParser args_parser("cal"); - // FIXME: This i a bit of a cheat, as no nested optional args are available on CArgsParser - args_parser.add_single_value("[[day] month] year"); + int day = 0; + int month = 0; + int year = 0; - CArgsParserResult args = args_parser.parse(argc, argv); - Vector<String> values = args.get_single_values(); - - if (values.size() > 3) { - printf("Invalid number of values\n"); - args_parser.print_usage(); - return 0; - } + CArgsParser args_parser; + // FIXME: This should ensure two values get parsed as month + year + args_parser.add_positional_argument(day, "Day of year", "day", CArgsParser::Required::No); + args_parser.add_positional_argument(month, "Month", "month", CArgsParser::Required::No); + args_parser.add_positional_argument(year, "Year", "year", CArgsParser::Required::No); + args_parser.parse(argc, argv); time_t now = time(nullptr); auto* tm = localtime(&now); - target_year = tm->tm_year + 1900; - target_month = tm->tm_mon + 1; - target_day = tm->tm_mday; - - current_year = target_year; - current_month = target_month; - - bool year_mode = false; - switch (values.size()) { - case 3: - target_day = atoi(values[0].characters()); - target_month = atoi(values[1].characters()); - target_year = atoi(values[2].characters()); - - // When passing the 3 parameters (day, month and year) we assume we're there. - current_year = target_year; - current_month = target_month; - break; - case 2: - target_month = atoi(values[0].characters()); - target_year = atoi(values[1].characters()); - break; - case 1: - target_year = atoi(values[0].characters()); - year_mode = true; - break; - default: - break; + // Hack: workaround two values parsing as day + month. + if (day && month && !year) { + year = month; + month = day; + day = 0; } + bool year_mode = !day && !month && year; + + if (!year) + year = tm->tm_year + 1900; + if (!month) + month = tm->tm_mon + 1; + if (!day) + day = tm->tm_mday; + + current_year = year; + current_month = month; + clean_buffers(); if (year_mode) { printf(" "); - printf("Year %4d", target_year); + printf("Year %4d", year); printf(" \n\n"); for (int i = 1; i < 12; ++i) { - insert_month_to_print(0, i++, target_year); - insert_month_to_print(1, i++, target_year); - insert_month_to_print(2, i, target_year); + insert_month_to_print(0, i++, year); + insert_month_to_print(1, i++, year); + insert_month_to_print(2, i, year); printf(print_buffer); printf("\n"); clean_buffers(); } } else { - insert_month_to_print(0, target_month, target_year); + insert_month_to_print(0, month, year); printf(print_buffer); printf("\n\n"); clean_buffers(); diff --git a/Userland/chroot.cpp b/Userland/chroot.cpp index f209f6a197..e4e5cd3b6f 100644 --- a/Userland/chroot.cpp +++ b/Userland/chroot.cpp @@ -24,82 +24,51 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <AK/String.h> #include <AK/StringView.h> +#include <LibCore/CArgsParser.h> #include <stdio.h> #include <unistd.h> -struct Options { - const char* path; - const char* program { "/bin/Shell" }; - int flags { -1 }; -}; - -void print_usage(const char* argv0) -{ - fprintf( - stderr, - "Usage:\n" - "\t%s <path> [program] [-o options]\n", - argv0 - ); -} - -Options parse_options(int argc, char** argv) -{ - Options options; - - if (argc < 2) { - print_usage(argv[0]); - exit(1); - } - - options.path = argv[1]; - int i = 2; - if (i < argc && argv[i][0] != '-') - options.program = argv[i++]; - - if (i >= argc) - return options; - - if (strcmp(argv[i], "-o") != 0) { - print_usage(argv[0]); - exit(1); - } - i++; - if (i >= argc) { - print_usage(argv[0]); - exit(1); - } - - options.flags = 0; - - StringView arg = argv[i]; - Vector<StringView> parts = arg.split_view(','); - for (auto& part : parts) { - if (part == "defaults") - continue; - else if (part == "nodev") - options.flags |= MS_NODEV; - else if (part == "noexec") - options.flags |= MS_NOEXEC; - else if (part == "nosuid") - options.flags |= MS_NOSUID; - else if (part == "bind") - fprintf(stderr, "Ignoring -o bind, as it doesn't make sense for chroot"); - else - fprintf(stderr, "Ignoring invalid option: %s\n", String(part).characters()); - } - - return options; -} - int main(int argc, char** argv) { - - Options options = parse_options(argc, argv); - - if (chroot_with_mount_flags(options.path, options.flags) < 0) { + const char* path = nullptr; + const char* program = "/bin/Shell"; + int flags = -1; + + CArgsParser args_parser; + args_parser.add_positional_argument(path, "New root directory", "path"); + args_parser.add_positional_argument(program, "Program to run", "program", CArgsParser::Required::No); + + CArgsParser::Option option { + true, + "Mount options", + "options", + 'o', + "options", + [&flags](const char* s) { + flags = 0; + Vector<StringView> parts = StringView(s).split_view(','); + for (auto& part : parts) { + if (part == "defaults") + continue; + else if (part == "nodev") + flags |= MS_NODEV; + else if (part == "noexec") + flags |= MS_NOEXEC; + else if (part == "nosuid") + flags |= MS_NOSUID; + else if (part == "bind") + fprintf(stderr, "Ignoring -o bind, as it doesn't make sense for chroot\n"); + else + return false; + } + return true; + } + }; + args_parser.add_option(move(option)); + args_parser.parse(argc, argv); + + if (chroot_with_mount_flags(path, flags) < 0) { perror("chroot"); return 1; } @@ -109,7 +78,7 @@ int main(int argc, char** argv) return 1; } - execl(options.program, options.program, nullptr); + execl(program, program, nullptr); perror("execl"); return 1; } diff --git a/Userland/copy.cpp b/Userland/copy.cpp index 708f8e929a..aa74e815f9 100644 --- a/Userland/copy.cpp +++ b/Userland/copy.cpp @@ -27,74 +27,32 @@ #include <AK/ByteBuffer.h> #include <AK/String.h> #include <AK/StringBuilder.h> +#include <LibCore/CArgsParser.h> #include <LibCore/CFile.h> #include <LibGUI/GApplication.h> #include <LibGUI/GClipboard.h> -#include <getopt.h> #include <stdio.h> #include <stdlib.h> struct Options { String data; - String type { "text" }; + StringView type { "text" }; }; -void print_usage(FILE* stream, const char* argv0) -{ - fprintf( - stream, - "Usage:\n" - "\t%s [--type type] text\n" - "\t%s [--type type] < file\n" - "\n" - "\t-t type, --type type\tPick a type.\n" - "\t-h, --help\t\tPrint this help message.\n", - argv0, - argv0); -} - Options parse_options(int argc, char* argv[]) { - Options options; + const char* type = nullptr; + Vector<const char*> text; - static struct option long_options[] = { - { "type", required_argument, 0, 't' }, - { "help", no_argument, 0, 'h' }, - { 0, 0, 0, 0 } - }; - while (true) { - int option_index; - int c = getopt_long(argc, argv, "t:h", long_options, &option_index); - if (c == -1) - break; - if (c == 0) - c = long_options[option_index].val; + CArgsParser args_parser; + args_parser.add_option(type, "Pick a type", "type", 't', "type"); + args_parser.add_positional_argument(text, "Text to copy", "text", CArgsParser::Required::No); + args_parser.parse(argc, argv); - switch (c) { - case 't': - options.type = optarg; - break; - case 'h': - print_usage(stdout, argv[0]); - exit(0); - default: - print_usage(stderr, argv[0]); - exit(1); - } - } + Options options; + options.type = type; - if (optind < argc) { - // Copy the rest of our command-line args. - StringBuilder builder; - bool first = true; - for (int i = optind; i < argc; i++) { - if (!first) - builder.append(' '); - first = false; - builder.append(argv[i]); - } - options.data = builder.to_string(); - } else { + if (text.is_empty()) { // Copy our stdin. auto c_stdin = CFile::construct(); bool success = c_stdin->open( @@ -105,6 +63,17 @@ Options parse_options(int argc, char* argv[]) auto buffer = c_stdin->read_all(); dbg() << "Read size " << buffer.size(); options.data = String((char*)buffer.data(), buffer.size()); + } else { + // Copy the rest of our command-line args. + StringBuilder builder; + bool first = true; + for (auto& word : text) { + if (!first) + builder.append(' '); + first = false; + builder.append(word); + } + options.data = builder.to_string(); } return options; diff --git a/Userland/cp.cpp b/Userland/cp.cpp index b8ba7b49e4..2a6adc1f7f 100644 --- a/Userland/cp.cpp +++ b/Userland/cp.cpp @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <AK/String.h> #include <AK/FileSystemPath.h> +#include <AK/String.h> #include <AK/StringBuilder.h> #include <LibCore/CArgsParser.h> #include <LibCore/CDirIterator.h> @@ -46,27 +46,28 @@ int main(int argc, char** argv) return 1; } - CArgsParser args_parser("cp"); - args_parser.add_arg("r", "copy directories recursively"); - args_parser.add_required_single_value("source"); - args_parser.add_required_single_value("destination"); + bool recursion_allowed = false; + Vector<const char*> sources; + const char* destination = nullptr; + + CArgsParser args_parser; + args_parser.add_option(recursion_allowed, "Copy directories recursively", "recursive", 'r'); + args_parser.add_positional_argument(sources, "Source file path", "source"); + args_parser.add_positional_argument(destination, "Destination file path", "destination"); + args_parser.parse(argc, argv); - CArgsParserResult args = args_parser.parse(argc, argv); - Vector<String> values = args.get_single_values(); - if (values.size() == 0) { - args_parser.print_usage(); - return 0; + for (auto& source : sources) { + bool ok = copy_file_or_directory(source, destination, recursion_allowed); + if (!ok) + return 1; } - bool recursion_allowed = args.is_present("r"); - String src_path = values[0]; - String dst_path = values[1]; - return copy_file_or_directory(src_path, dst_path, recursion_allowed) ? 0 : 1; + return 0; } /** - * Copy a file or directory to a new location. Returns true if successful, false + * Copy a file or directory to a new location. Returns true if successful, false * otherwise. If there is an error, its description is output to stderr. - * + * * Directories should only be copied if recursion_allowed is set. */ bool copy_file_or_directory(String src_path, String dst_path, bool recursion_allowed) @@ -95,9 +96,9 @@ bool copy_file_or_directory(String src_path, String dst_path, bool recursion_all } /** - * Copy a source file to a destination file. Returns true if successful, false + * Copy a source file to a destination file. Returns true if successful, false * otherwise. If there is an error, its description is output to stderr. - * + * * To avoid repeated work, the source file's stat and file descriptor are required. */ bool copy_file(String src_path, String dst_path, struct stat src_stat, int src_fd) diff --git a/Userland/head.cpp b/Userland/head.cpp index 84ccd942c3..aaeac55fa5 100644 --- a/Userland/head.cpp +++ b/Userland/head.cpp @@ -35,56 +35,29 @@ int head(const String& filename, bool print_filename, int line_count, int char_c int main(int argc, char** argv) { - CArgsParser args_parser("head"); - - args_parser.add_arg("n", "lines", "Number of lines to print (default 10)"); - args_parser.add_arg("c", "characters", "Number of characters to print"); - args_parser.add_arg("q", "Never print filenames"); - args_parser.add_arg("v", "Always print filenames"); - - CArgsParserResult args = args_parser.parse(argc, argv); - int line_count = 0; - if (args.is_present("n")) { - line_count = strtol(args.get("n").characters(), NULL, 10); - if (errno) { - args_parser.print_usage(); - return -1; - } - - if (!line_count) { - args_parser.print_usage(); - return -1; - } - } - int char_count = 0; - if (args.is_present("c")) { - char_count = strtol(args.get("c").characters(), NULL, 10); - if (errno) { - args_parser.print_usage(); - return -1; - } - - if (!char_count) { - args_parser.print_usage(); - return -1; - } - } + bool never_print_filenames = false; + bool always_print_filenames = false; + Vector<const char*> files; + + CArgsParser args_parser; + args_parser.add_option(line_count, "Number of lines to print (default 10)", "lines", 'n', "number"); + args_parser.add_option(char_count, "Number of characters to print", "characters", 'c', "number"); + args_parser.add_option(never_print_filenames, "Never print file names", "quiet", 'q'); + args_parser.add_option(always_print_filenames, "Always print file names", "verbose", 'v'); + args_parser.add_positional_argument(files, "File to process", "file", CArgsParser::Required::No); + args_parser.parse(argc, argv); if (line_count == 0 && char_count == 0) { line_count = 10; } - Vector<String> files = args.get_single_values(); - bool print_filenames = files.size() > 1; - - if (args.is_present("v")) { + if (always_print_filenames) print_filenames = true; - } else if (args.is_present("q")) { + else if (never_print_filenames) print_filenames = false; - } if (files.is_empty()) { return head("", print_filenames, line_count, char_count); diff --git a/Userland/id.cpp b/Userland/id.cpp index 6403bf3382..90276e15f0 100644 --- a/Userland/id.cpp +++ b/Userland/id.cpp @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <LibCore/CArgsParser.h> #include <alloca.h> -#include <getopt.h> #include <grp.h> #include <pwd.h> #include <stdio.h> @@ -59,28 +59,13 @@ int main(int argc, char** argv) perror("pledge"); return 1; } - static const char* valid_option_characters = "ugGn"; - int opt; - while ((opt = getopt(argc, argv, valid_option_characters)) != -1) { - switch (opt) { - case 'u': - flag_print_uid = true; - break; - case 'g': - flag_print_gid = true; - break; - case 'G': - flag_print_gid_all = true; - break; - case 'n': - flag_print_name = true; - break; - - default: - fprintf(stderr, "usage: id [-%s]\n", valid_option_characters); - return 1; - } - } + + CArgsParser args_parser; + args_parser.add_option(flag_print_uid, "Print UID", nullptr, 'u'); + args_parser.add_option(flag_print_gid, "Print GID", nullptr, 'g'); + args_parser.add_option(flag_print_gid_all, "Print all GIDs", nullptr, 'G'); + args_parser.add_option(flag_print_name, "Print name", nullptr, 'n'); + args_parser.parse(argc, argv); if (flag_print_name && !(flag_print_uid || flag_print_gid || flag_print_gid_all)) { fprintf(stderr, "cannot print only names or real IDs in default format\n"); diff --git a/Userland/ln.cpp b/Userland/ln.cpp index a1379044b7..c567db7dc9 100644 --- a/Userland/ln.cpp +++ b/Userland/ln.cpp @@ -32,21 +32,18 @@ int main(int argc, char** argv) { - CArgsParser args_parser("ln"); + bool symbolic = false; + const char* target = nullptr; + const char* path = nullptr; - args_parser.add_arg("s", "create a symlink"); - args_parser.add_required_single_value("target"); - args_parser.add_required_single_value("link-path"); + CArgsParser args_parser; + args_parser.add_option(symbolic, "Create a symlink", "symbolic", 's'); + args_parser.add_positional_argument(target, "Link target", "target"); + args_parser.add_positional_argument(path, "Link path", "path"); + args_parser.parse(argc, argv); - CArgsParserResult args = args_parser.parse(argc, argv); - Vector<String> values = args.get_single_values(); - if (values.size() == 0) { - args_parser.print_usage(); - return 0; - } - - if (args.is_present("s")) { - int rc = symlink(values[0].characters(), values[1].characters()); + if (symbolic) { + int rc = symlink(target, path); if (rc < 0) { perror("symlink"); return 1; @@ -54,7 +51,7 @@ int main(int argc, char** argv) return 0; } - int rc = link(values[0].characters(), values[1].characters()); + int rc = link(target, path); if (rc < 0) { perror("link"); return 1; diff --git a/Userland/ls.cpp b/Userland/ls.cpp index 9d15df2f5d..072cb16147 100644 --- a/Userland/ls.cpp +++ b/Userland/ls.cpp @@ -29,12 +29,12 @@ #include <AK/String.h> #include <AK/StringBuilder.h> #include <AK/Vector.h> +#include <LibCore/CArgsParser.h> #include <LibCore/CDirIterator.h> #include <ctype.h> #include <dirent.h> #include <errno.h> #include <fcntl.h> -#include <getopt.h> #include <grp.h> #include <pwd.h> #include <stdio.h> @@ -83,39 +83,19 @@ int main(int argc, char** argv) return 1; } - static const char* valid_option_characters = "ltraiGnh"; - int opt; - while ((opt = getopt(argc, argv, valid_option_characters)) != -1) { - switch (opt) { - case 'a': - flag_show_dotfiles = true; - break; - case 'l': - flag_long = true; - break; - case 't': - flag_sort_by_timestamp = true; - break; - case 'r': - flag_reverse_sort = true; - break; - case 'G': - flag_colorize = false; - break; - case 'i': - flag_show_inode = true; - break; - case 'n': - flag_print_numeric = true; - break; - case 'h': - flag_human_readable = true; - break; - default: - fprintf(stderr, "usage: ls [-%s] [paths...]\n", valid_option_characters); - return 1; - } - } + Vector<const char*> paths; + + CArgsParser args_parser; + args_parser.add_option(flag_show_dotfiles, "Show dotfiles", "all", 'a'); + args_parser.add_option(flag_long, "Display long info", "long", 'l'); + args_parser.add_option(flag_sort_by_timestamp, "Sort files by timestamp", nullptr, 't'); + args_parser.add_option(flag_reverse_sort, "Reverse sort order", "reverse", 'r'); + args_parser.add_option(flag_colorize, "Use pretty colors", nullptr, 'G'); + args_parser.add_option(flag_show_inode, "Show inode ids", "inode", 'i'); + args_parser.add_option(flag_print_numeric, "In long format, display numeric UID/GID", "numeric-uid-gid", 'n'); + args_parser.add_option(flag_human_readable, "Print human-readable sizes", "human-readable", 'h'); + args_parser.add_positional_argument(paths, "Directory to list", "path", CArgsParser::Required::No); + args_parser.parse(argc, argv); if (flag_long) { setpwent(); @@ -135,14 +115,14 @@ int main(int argc, char** argv) }; int status = 0; - if (optind >= argc) { + if (paths.is_empty()) { status = do_file_system_object("."); - } else if (optind + 1 >= argc) { - status = do_file_system_object(argv[optind]); + } else if (paths.size() == 1) { + status = do_file_system_object(paths[0]); } else { - for (; optind < argc; ++optind) { - printf("%s:\n", argv[optind]); - status = do_file_system_object(argv[optind]); + for (auto& path : paths) { + printf("%s:\n", path); + status = do_file_system_object(path); } } return status; diff --git a/Userland/mount.cpp b/Userland/mount.cpp index f2da19c69c..4260946d87 100644 --- a/Userland/mount.cpp +++ b/Userland/mount.cpp @@ -152,35 +152,39 @@ bool print_mounts() int main(int argc, char** argv) { - CArgsParser args_parser("mount"); - args_parser.add_arg("devname", "device path"); - args_parser.add_arg("mountpoint", "mount point"); - args_parser.add_arg("t", "fstype", "file system type"); - args_parser.add_arg("o", "options", "mount options"); - args_parser.add_arg("a", "mount all systems listed in /etc/fstab"); - CArgsParserResult args = args_parser.parse(argc, argv); - - if (args.is_present("a")) { + const char* source = nullptr; + const char* mountpoint = nullptr; + const char* fs_type = nullptr; + const char* options = nullptr; + bool should_mount_all = false; + + CArgsParser args_parser; + args_parser.add_positional_argument(source, "Source path", "source", CArgsParser::Required::No); + args_parser.add_positional_argument(mountpoint, "Mount point", "mountpoint", CArgsParser::Required::No); + args_parser.add_option(fs_type, "File system type", nullptr, 't', "fstype"); + args_parser.add_option(options, "Mount options", nullptr, 'o', "options"); + args_parser.add_option(should_mount_all, "Mount all file systems listed in /etc/fstab", nullptr, 'a'); + args_parser.parse(argc, argv); + + if (should_mount_all) { return mount_all() ? 0 : 1; } - switch (args.get_single_values().size()) { - case 0: + if (!source && !mountpoint) return print_mounts() ? 0 : 1; - case 2: { - String devname = args.get_single_values()[0]; - String mountpoint = args.get_single_values()[1]; - String fstype = args.is_present("t") ? args.get("t") : "ext2"; - int flags = args.is_present("o") ? parse_options(args.get("o")) : 0; - if (mount(devname.characters(), mountpoint.characters(), fstype.characters(), flags) < 0) { + if (source && mountpoint) { + if (!fs_type) + fs_type = "ext2"; + int flags = options ? parse_options(options) : 0; + + if (mount(source, mountpoint, fs_type, flags) < 0) { perror("mount"); return 1; } return 0; } - default: - args_parser.print_usage(); - return 1; - } + + args_parser.print_usage(stderr, argv[0]); + return 1; } diff --git a/Userland/nl.cpp b/Userland/nl.cpp index 32e420023b..ab7ca2615a 100644 --- a/Userland/nl.cpp +++ b/Userland/nl.cpp @@ -31,80 +31,57 @@ #include <stdio.h> #include <string.h> +enum NumberStyle { + NumberAllLines, + NumberNonEmptyLines, + NumberNoLines, +}; + int main(int argc, char** argv) { - CArgsParser args_parser("nl"); - args_parser.add_arg("b", "type", "Line count type. \n\tt counts non-empty lines. \n\ta counts all lines. \n\tn counts no lines."); - args_parser.add_arg("i", "incr", "Set line count increment."); - args_parser.add_arg("s", "delim", "Set buffer between the line numbers and text. 1-63 bytes"); - args_parser.add_arg("v", "startnum", "Initial value used to number logical page lines."); - args_parser.add_arg("w", "width", "The number of characters used for the line number."); - args_parser.add_single_value("file"); - CArgsParserResult args = args_parser.parse(argc, argv); + NumberStyle number_style = NumberNonEmptyLines; + int increment = 1; + const char* separator = " "; + int start_number = 1; + int number_width = 6; + Vector<const char*> files; - bool all_lines_flag = false; - bool line_numbers_flag = true; - String value_of_b; - if (args.is_present("b")) { - value_of_b = args.get("b"); - if (value_of_b == "a") - all_lines_flag = true; - else if (value_of_b == "t") - all_lines_flag = false; - else if (value_of_b == "n") - line_numbers_flag = false; - else { - args_parser.print_usage(); - return 1; - } - } + CArgsParser args_parser; - long line_number_increment = 1; - String value_of_i; - if (args.is_present("i")) { - value_of_i = args.get("i"); - line_number_increment = atol(value_of_i.characters()); - if (!line_number_increment) { - args_parser.print_usage(); - return 1; - } - } + CArgsParser::Option number_style_option { + true, + "Line numbering style: 't' for non-empty lines, 'a' for all lines, 'n' for no lines", + "body-numbering", + 'b', + "style", + [&number_style](const char* s) { + if (!strcmp(s, "t")) + number_style = NumberNonEmptyLines; + else if (!strcmp(s, "a")) + number_style = NumberAllLines; + else if (!strcmp(s, "n")) + number_style = NumberNoLines; + else + return false; - bool delimiter_flag = false; - String value_of_s; - if (args.is_present("s")) { - value_of_s = args.get("s"); - if (value_of_s.length() > 0 && value_of_s.length() < 64) - delimiter_flag = true; - else { - args_parser.print_usage(); - return 1; + return true; } - } - char delimiter[64]; - strcpy(delimiter, delimiter_flag ? value_of_s.characters() : " "); - - long line_number = 1; - String value_of_v; - if (args.is_present("v")) { - value_of_v = args.get("v"); - line_number = atol(value_of_v.characters()); - } + }; - String value_of_w; - unsigned int line_number_width = 6; - if (args.is_present("w")) { - value_of_w = args.get("w"); - line_number_width = atol(value_of_w.characters()); - } + args_parser.add_option(move(number_style_option)); + args_parser.add_option(increment, "Line count increment", "increment", 'i', "number"); + args_parser.add_option(separator, "Separator between line numbers and lines", "separator", 's', "string"); + args_parser.add_option(start_number, "Initial line number", "startnum", 'v', "number"); + args_parser.add_option(number_width, "Number width", "width", 'w', "number"); + args_parser.add_positional_argument(files, "Files to process", "file", CArgsParser::Required::No); + args_parser.parse(argc, argv); - Vector<String> files = args.get_single_values(); Vector<FILE*> file_pointers; - if (files.size() > 0) { + if (!files.is_empty()) { for (auto& file : files) { - FILE* file_pointer; - if ((file_pointer = fopen(file.characters(), "r")) == NULL) { - fprintf(stderr, "unable to open %s\n", file.characters()); + FILE* file_pointer = fopen(file, "r"); + if (!file_pointer) { + fprintf(stderr, "unable to open %s\n", file); continue; } file_pointers.append(file_pointer); @@ -113,21 +90,21 @@ int main(int argc, char** argv) file_pointers.append(stdin); } - line_number -= line_number_increment; // so the line number can start at 1 when added below for (auto& file_pointer : file_pointers) { + int line_number = start_number - increment; // so the line number can start at 1 when added below int previous_character = 0; int next_character = 0; while ((next_character = fgetc(file_pointer)) != EOF) { if (previous_character == 0 || previous_character == '\n') { - if (!all_lines_flag && next_character == '\n') { - // skips printing line count on empty lines if all_lines_flags is false + if (next_character == '\n' && number_style != NumberAllLines) { + // Skip printing line count on empty lines. printf("\n"); continue; } - if (line_numbers_flag) - printf("%*lu%s", line_number_width, (line_number += line_number_increment), delimiter); + if (number_style != NumberNoLines) + printf("%*d%s", number_width, (line_number += increment), separator); else - printf("%*s", line_number_width, ""); + printf("%*s", number_width, ""); } putchar(next_character); previous_character = next_character; diff --git a/Userland/pape.cpp b/Userland/pape.cpp index 2c2fdc2d2a..317f54c133 100644 --- a/Userland/pape.cpp +++ b/Userland/pape.cpp @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <AK/String.h> #include <AK/FileSystemPath.h> +#include <AK/String.h> #include <AK/StringBuilder.h> #include <AK/Vector.h> #include <LibCore/CArgsParser.h> @@ -76,26 +76,22 @@ static int handle_set_pape(const String& name) int main(int argc, char** argv) { - GApplication app(argc, argv); - - CArgsParser args_parser("pape"); + bool show_all = false; + bool show_current = false; + const char* name = nullptr; - args_parser.add_arg("a", "show all wallpapers"); - args_parser.add_arg("c", "show current wallpaper"); - args_parser.add_single_value("name"); + CArgsParser args_parser; + args_parser.add_option(show_all, "Show all wallpapers", "show-all", 'a'); + args_parser.add_option(show_current, "Show current wallpaper", "show-current", 'c'); + args_parser.add_positional_argument(name, "Wallpaper to set", "name", CArgsParser::Required::No); + args_parser.parse(argc, argv); - CArgsParserResult args = args_parser.parse(argc, argv); + GApplication app(argc, argv); - if (args.is_present("a")) + if (show_all) return handle_show_all(); - else if (args.is_present("c")) + else if (show_current) return handle_show_current(); - Vector<String> values = args.get_single_values(); - if (values.size() != 1) { - args_parser.print_usage(); - return 0; - } - - return handle_set_pape(values[0]); + return handle_set_pape(name); } diff --git a/Userland/paste.cpp b/Userland/paste.cpp index 024d06027c..f14ad4588b 100644 --- a/Userland/paste.cpp +++ b/Userland/paste.cpp @@ -25,81 +25,32 @@ */ #include <AK/String.h> +#include <LibCore/CArgsParser.h> #include <LibGUI/GApplication.h> #include <LibGUI/GClipboard.h> -#include <getopt.h> #include <stdio.h> #include <stdlib.h> -struct Options { - bool print_type { false }; - bool no_newline { false }; -}; - -void print_usage(FILE* stream, const char* argv0) -{ - fprintf( - stream, - "Usage:\n" - "\t%s [--print-type] [--no-newline]\n" - "\n" - "\t--print-type\t\tDisplay the copied type.\n" - "\t-n, --no-newline\tDo not append a newline.\n" - "\t-h, --help\t\tPrint this help message.\n", - argv0); -} - -Options parse_options(int argc, char* argv[]) +int main(int argc, char* argv[]) { - Options options; - - static struct option long_options[] = { - { "print-type", no_argument, 0, 'p' }, - { "no-newline", no_argument, 0, 'n' }, - { "help", no_argument, 0, 'h' }, - { 0, 0, 0, 0 } - }; - while (true) { - int option_index; - int c = getopt_long(argc, argv, "hn", long_options, &option_index); - if (c == -1) - break; - if (c == 0) - c = long_options[option_index].val; + bool print_type = false; + bool no_newline = false; - switch (c) { - case 'p': - options.print_type = true; - break; - case 'n': - options.no_newline = true; - break; - case 'h': - print_usage(stdout, argv[0]); - exit(0); - default: - print_usage(stderr, argv[0]); - exit(1); - } - } - - return options; -} + CArgsParser args_parser; + args_parser.add_option(print_type, "Display the copied type", "print-type", 0); + args_parser.add_option(no_newline, "Do not append a newline", "no-newline", 'n'); + args_parser.parse(argc, argv); -int main(int argc, char* argv[]) -{ GApplication app(argc, argv); - Options options = parse_options(argc, argv); - GClipboard& clipboard = GClipboard::the(); auto data_and_type = clipboard.data_and_type(); - if (!options.print_type) { + if (!print_type) { printf("%s", data_and_type.data.characters()); // Append a newline to text contents, but // only if we're not asked not to do this. - if (data_and_type.type == "text" && !options.no_newline) + if (data_and_type.type == "text" && !no_newline) putchar('\n'); } else { printf("%s\n", data_and_type.type.characters()); diff --git a/Userland/pidof.cpp b/Userland/pidof.cpp index 305fad8234..332cc794f0 100644 --- a/Userland/pidof.cpp +++ b/Userland/pidof.cpp @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <AK/String.h> #include <AK/HashMap.h> +#include <AK/String.h> #include <AK/Vector.h> #include <LibCore/CArgsParser.h> #include <LibCore/CProcessStatisticsReader.h> @@ -60,33 +60,29 @@ static int pid_of(const String& process_name, bool single_shot, bool omit_pid, p int main(int argc, char** argv) { - CArgsParser args_parser("pidof"); - - args_parser.add_arg("s", "Single shot - this instructs the program to only return one pid"); - args_parser.add_arg("o", "pid", "Tells pidof to omit processes with that pid. The special pid %PPID can be used to name the parent process of the pidof program."); - - CArgsParserResult args = args_parser.parse(argc, argv); + bool single_shot = false; + const char* omit_pid_value = nullptr; + const char* process_name = nullptr; - bool s_arg = args.is_present("s"); - bool o_arg = args.is_present("o"); - pid_t pid = 0; + CArgsParser args_parser; + args_parser.add_option(single_shot, "Only return one pid", nullptr, 's'); + args_parser.add_option(omit_pid_value, "Omit the given PID, or the parent process if the special value %PPID is passed", nullptr, 'o', "pid"); + args_parser.add_positional_argument(process_name, "Process name to search for", "process-name"); - if (o_arg) { - bool ok = false; - String pid_str = args.get("o"); + args_parser.parse(argc, argv); - if (pid_str == "%PPID") - pid = getppid(); + pid_t pid_to_omit = 0; + if (omit_pid_value) { + bool ok = true; + if (!strcmp(omit_pid_value, "%PPID")) + pid_to_omit = getppid(); else - pid = pid_str.to_uint(ok); - } - - // We should have one single value : the process name - Vector<String> values = args.get_single_values(); - if (values.size() == 0) { - args_parser.print_usage(); - return 0; + pid_to_omit = StringView(omit_pid_value).to_uint(ok); + if (!ok) { + fprintf(stderr, "Invalid value for -o\n"); + args_parser.print_usage(stderr, argv[0]); + return 1; + } } - - return pid_of(values[0], s_arg, o_arg, pid); + return pid_of(process_name, single_shot, omit_pid_value != nullptr, pid_to_omit); } diff --git a/Userland/rm.cpp b/Userland/rm.cpp index 6974fce62a..3e208ae486 100644 --- a/Userland/rm.cpp +++ b/Userland/rm.cpp @@ -35,16 +35,16 @@ #include <sys/stat.h> #include <unistd.h> -int remove(bool recursive, const char* path) +int remove(bool recursive, String path) { struct stat path_stat; - if (lstat(path, &path_stat) < 0) { + if (lstat(path.characters(), &path_stat) < 0) { perror("lstat"); return 1; } if (S_ISDIR(path_stat.st_mode) && recursive) { - DIR* derp = opendir(path); + DIR* derp = opendir(path.characters()); if (!derp) { return 1; } @@ -55,18 +55,18 @@ int remove(bool recursive, const char* path) builder.append(path); builder.append('/'); builder.append(de->d_name); - int s = remove(true, builder.to_string().characters()); + int s = remove(true, builder.to_string()); if (s < 0) return s; } } - int s = rmdir(path); + int s = rmdir(path.characters()); if (s < 0) { perror("rmdir"); return 1; } } else { - int rc = unlink(path); + int rc = unlink(path.characters()); if (rc < 0) { perror("unlink"); return 1; @@ -77,16 +77,13 @@ int remove(bool recursive, const char* path) int main(int argc, char** argv) { - CArgsParser args_parser("rm"); - args_parser.add_arg("r", "Delete directory recursively."); - args_parser.add_required_single_value("path"); + bool recursive = false; + const char* path = nullptr; - CArgsParserResult args = args_parser.parse(argc, argv); - Vector<String> values = args.get_single_values(); - if (values.size() == 0) { - args_parser.print_usage(); - return 1; - } + CArgsParser args_parser; + args_parser.add_option(recursive, "Delete directories recursively", "recursive", 'r'); + args_parser.add_positional_argument(path, "File to remove", "path"); + args_parser.parse(argc, argv); - return remove(args.is_present("r"), values[0].characters()); + return remove(recursive, path); } diff --git a/Userland/shutdown.cpp b/Userland/shutdown.cpp index 3ce7c71923..7dd7fecc57 100644 --- a/Userland/shutdown.cpp +++ b/Userland/shutdown.cpp @@ -30,17 +30,19 @@ int main(int argc, char** argv) { - CArgsParser args_parser("shutdown"); - args_parser.add_arg("n", "shut down now"); - CArgsParserResult args = args_parser.parse(argc, argv); + bool now = false; - if (args.is_present("n")) { + CArgsParser args_parser; + args_parser.add_option(now, "Shut down now", "now", 'n'); + args_parser.parse(argc, argv); + + if (now) { if (halt() < 0) { perror("shutdown"); return 1; } } else { - args_parser.print_usage(); - return 0; + args_parser.print_usage(stderr, argv[0]); + return 1; } } diff --git a/Userland/sysctl.cpp b/Userland/sysctl.cpp index 2fcb57fc64..35497c8cd2 100644 --- a/Userland/sysctl.cpp +++ b/Userland/sysctl.cpp @@ -109,20 +109,17 @@ static int handle_var(const String& var) int main(int argc, char** argv) { - CArgsParser args_parser("sysctl"); + bool show_all = false; + const char* var = nullptr; - args_parser.add_arg("a", "show all variables"); - args_parser.add_single_value("variable=[value]"); + CArgsParser args_parser; + args_parser.add_option(show_all, "Show all variables", nullptr, 'a'); + args_parser.add_positional_argument(var, "Command (var[=value])", "command"); + args_parser.parse(argc, argv); - CArgsParserResult args = args_parser.parse(argc, argv); - - if (args.is_present("a")) { + if (show_all) { return handle_show_all(); - } else if (args.get_single_values().size() != 1) { - args_parser.print_usage(); - return 0; } - Vector<String> values = args.get_single_values(); - return handle_var(values[0]); + return handle_var(var); } diff --git a/Userland/tail.cpp b/Userland/tail.cpp index ba0def38c4..220d9ab2ef 100644 --- a/Userland/tail.cpp +++ b/Userland/tail.cpp @@ -101,34 +101,19 @@ int main(int argc, char* argv[]) return 1; } - CArgsParser args_parser("tail"); + bool follow = false; + int line_count = DEFAULT_LINE_COUNT; + const char* file = nullptr; - args_parser.add_arg("f", "follow -- appended data is output as it is written to the file"); - args_parser.add_arg("n", "lines", "fetch the specified number of lines"); - args_parser.add_required_single_value("file"); + CArgsParser args_parser; + args_parser.add_option(follow, "Output data as it is written to the file", "follow", 'f'); + args_parser.add_option(line_count, "Fetch the specified number of lines", "lines", 'n', "number"); + args_parser.add_positional_argument(file, "File path", "file"); + args_parser.parse(argc, argv); - CArgsParserResult args = args_parser.parse(argc, argv); - - Vector<String> values = args.get_single_values(); - if (values.size() != 1) { - args_parser.print_usage(); - return 1; - } - - int line_count = 0; - if (args.is_present("n")) { - line_count = strtol(args.get("n").characters(), NULL, 10); - if (errno == EINVAL) { - args_parser.print_usage(); - return 1; - } - } else { - line_count = DEFAULT_LINE_COUNT; - } - - auto f = CFile::construct(values[0]); + auto f = CFile::construct(file); if (!f->open(CIODevice::ReadOnly)) { - fprintf(stderr, "Error opening file %s: %s\n", f->filename().characters(), strerror(errno)); + fprintf(stderr, "Error opening file %s: %s\n", file, strerror(errno)); exit(1); } @@ -137,7 +122,6 @@ int main(int argc, char* argv[]) return 1; } - bool flag_follow = args.is_present("f"); auto pos = find_seek_pos(*f, line_count); - return tail_from_pos(*f, pos, flag_follow); + return tail_from_pos(*f, pos, follow); } diff --git a/Userland/tee.cpp b/Userland/tee.cpp index ba07c2e2d6..40005366a9 100644 --- a/Userland/tee.cpp +++ b/Userland/tee.cpp @@ -25,18 +25,18 @@ */ #include <AK/Vector.h> +#include <LibCore/CArgsParser.h> #include <errno.h> #include <fcntl.h> -#include <getopt.h> #include <signal.h> #include <stdio.h> #include <unistd.h> -static Vector<int> collect_fds(int argc, char** argv, int start, bool aflag, bool* err) +static Vector<int> collect_fds(Vector<const char*> paths, bool append, bool* err) { int oflag; mode_t mode; - if (aflag) { + if (append) { oflag = O_APPEND; mode = 0; } else { @@ -45,8 +45,8 @@ static Vector<int> collect_fds(int argc, char** argv, int start, bool aflag, boo } Vector<int> fds; - for (int i = start; i < argc; ++i) { - int fd = open(argv[i], oflag, mode); + for (const char* path : paths) { + int fd = open(path, oflag, mode); if (fd < 0) { perror("failed to open file for writing"); *err = true; @@ -119,28 +119,24 @@ static void int_handler(int) int main(int argc, char** argv) { - bool aflag = false, iflag = false; - int c = 0; - while ((c = getopt(argc, argv, "ai")) != -1) { - switch (c) { - case 'a': - aflag = true; - break; - case 'i': - iflag = true; - break; - } - } + bool append = false; + bool ignore_interrupts = false; + Vector<const char*> paths; + + CArgsParser args_parser; + args_parser.add_option(append, "Append, don't overwrite", "append", 'a'); + args_parser.add_option(ignore_interrupts, "Ignore SIGINT", "ignore-interrupts", 'i'); + args_parser.add_positional_argument(paths, "Files to copy stdin to", "file", CArgsParser::Required::No); + args_parser.parse(argc, argv); - if (iflag) { - if (signal(SIGINT, int_handler) == SIG_ERR) { + if (ignore_interrupts) { + if (signal(SIGINT, int_handler) == SIG_ERR) perror("failed to install SIGINT handler"); - } } bool err_open = false; bool err_write = false; - auto fds = collect_fds(argc, argv, optind, aflag, &err_open); + auto fds = collect_fds(paths, append, &err_open); copy_stdin(fds, &err_write); close_fds(fds); diff --git a/Userland/truncate.cpp b/Userland/truncate.cpp index 0bd5dd27ed..44f5079c17 100644 --- a/Userland/truncate.cpp +++ b/Userland/truncate.cpp @@ -38,29 +38,31 @@ enum TruncateOperation { int main(int argc, char** argv) { - CArgsParser args_parser("truncate"); - - args_parser.add_arg("s", "size", "Resize the target file to (or by) this size. Prefix with + or - to expand or shrink the file, or a bare number to set the size exactly."); - args_parser.add_arg("r", "reference", "Resize the target file to match the size of this one."); - args_parser.add_required_single_value("file"); - - CArgsParserResult args = args_parser.parse(argc, argv); - - if (!args.is_present("s") && !args.is_present("r")) { - args_parser.print_usage(); - return -1; + const char* resize = nullptr; + const char* reference = nullptr; + const char* file = nullptr; + + CArgsParser args_parser; + args_parser.add_option(resize, "Resize the target file to (or by) this size. Prefix with + or - to expand or shrink the file, or a bare number to set the size exactly", "size", 's', "size"); + args_parser.add_option(reference, "Resize the target file to match the size of this one", "reference", 'r', "file"); + args_parser.add_positional_argument(file, "File path", "file"); + args_parser.parse(argc, argv); + + if (!resize && !reference) { + args_parser.print_usage(stderr, argv[0]); + return 1; } - if (args.is_present("s") && args.is_present("r")) { - args_parser.print_usage(); - return -1; + if (resize && reference) { + args_parser.print_usage(stderr, argv[0]); + return 1; } auto op = OP_Set; int size = 0; - if (args.is_present("s")) { - auto str = args.get("s"); + if (resize) { + String str = resize; switch (str[0]) { case '+': @@ -76,35 +78,33 @@ int main(int argc, char** argv) bool ok; size = str.to_int(ok); if (!ok) { - args_parser.print_usage(); - return -1; + args_parser.print_usage(stderr, argv[0]); + return 1; } } - if (args.is_present("r")) { + if (reference) { struct stat st; - int rc = stat(args.get("r").characters(), &st); + int rc = stat(reference, &st); if (rc < 0) { perror("stat"); - return -1; + return 1; } op = OP_Set; size = st.st_size; } - auto name = args.get_single_values()[0]; - - int fd = open(name.characters(), O_RDWR | O_CREAT, 0666); + int fd = open(file, O_RDWR | O_CREAT, 0666); if (fd < 0) { perror("open"); - return -1; + return 1; } struct stat st; if (fstat(fd, &st) < 0) { perror("fstat"); - return -1; + return 1; } switch (op) { @@ -120,12 +120,12 @@ int main(int argc, char** argv) if (ftruncate(fd, size) < 0) { perror("ftruncate"); - return -1; + return 1; } if (close(fd) < 0) { perror("close"); - return -1; + return 1; } return 0; diff --git a/Userland/umount.cpp b/Userland/umount.cpp index 3b68dc98cd..845c3a50bf 100644 --- a/Userland/umount.cpp +++ b/Userland/umount.cpp @@ -30,19 +30,15 @@ int main(int argc, char** argv) { - CArgsParser args_parser("umount"); - args_parser.add_arg("mountpoint", "mount point"); - CArgsParserResult args = args_parser.parse(argc, argv); + const char* mount_point = nullptr; - if (argc == 2) { - if (umount(argv[1]) < 0) { - perror("umount"); - return 1; - } - } else { - args_parser.print_usage(); - return 0; - } + CArgsParser args_parser; + args_parser.add_positional_argument(mount_point, "Mount point", "mountpoint"); + args_parser.parse(argc, argv); + if (umount(mount_point) < 0) { + perror("umount"); + return 1; + } return 0; } diff --git a/Userland/wc.cpp b/Userland/wc.cpp index 54d475f882..5cb2e95185 100644 --- a/Userland/wc.cpp +++ b/Userland/wc.cpp @@ -110,7 +110,7 @@ Count get_count(const String& file_name) Count get_total_count(Vector<Count>& counts) { - Count total_count{ "total" }; + Count total_count { "total" }; for (auto& count : counts) { total_count.lines += count.lines; total_count.words += count.words; @@ -122,47 +122,30 @@ Count get_total_count(Vector<Count>& counts) int main(int argc, char** argv) { - CArgsParser args_parser("wc"); - args_parser.add_arg("l", "Output line count"); - args_parser.add_arg("c", "Output byte count"); - args_parser.add_arg("m", "Output character count"); - args_parser.add_arg("w", "Output word count"); - args_parser.add_arg("h", "Print help message"); - CArgsParserResult args = args_parser.parse(argc, argv); - if (args.is_present("h")) { - args_parser.print_usage(); - return 1; - } - if (args.is_present("l")) { - output_line = true; - } - if (args.is_present("w")) { - output_word = true; - } - if (args.is_present("m")) { - output_character = true; - } - if (args.is_present("c")) { - if (!output_word && !output_line && !output_character) - output_word = output_line = true; - output_byte = true; - } - if (!output_line && !output_character && !output_word && !output_byte) - output_line = output_character = output_word = true; + Vector<const char*> files; + + CArgsParser args_parser; + args_parser.add_option(output_line, "Output line count", "lines", 'l'); + args_parser.add_option(output_byte, "Output byte count", "bytes", 'c'); + args_parser.add_option(output_word, "Output word count", "words", 'w'); + args_parser.add_positional_argument(files, "File to process", "file", CArgsParser::Required::No); + args_parser.parse(argc, argv); + + if (!output_line && !output_byte && !output_word) + output_line = output_byte = output_word = true; - Vector<String> file_names = args.get_single_values(); Vector<Count> counts; - for (auto& file_name : file_names) { - Count count = get_count(file_name); + for (auto& file : files) { + Count count = get_count(file); counts.append(count); } - if (file_names.size() > 1) { + if (files.size() > 1) { Count total_count = get_total_count(counts); counts.append(total_count); } - if (file_names.is_empty()) { + if (files.is_empty()) { Count count = get_count("-"); counts.append(count); } |