فهرست منبع

Userland+Terminal: Port to new CArgsParser API

While at it, also add some niceties and fix some things.
Sergey Bugaev 5 سال پیش
والد
کامیت
f983dfe319
22فایلهای تغییر یافته به همراه394 افزوده شده و 655 حذف شده
  1. 5 6
      Applications/Terminal/main.cpp
  2. 31 44
      Userland/cal.cpp
  3. 40 71
      Userland/chroot.cpp
  4. 22 53
      Userland/copy.cpp
  5. 19 18
      Userland/cp.cpp
  6. 13 40
      Userland/head.cpp
  7. 8 23
      Userland/id.cpp
  8. 11 14
      Userland/ln.cpp
  9. 20 40
      Userland/ls.cpp
  10. 25 21
      Userland/mount.cpp
  11. 47 70
      Userland/nl.cpp
  12. 13 17
      Userland/pape.cpp
  13. 10 59
      Userland/paste.cpp
  14. 21 25
      Userland/pidof.cpp
  15. 13 16
      Userland/rm.cpp
  16. 8 6
      Userland/shutdown.cpp
  17. 8 11
      Userland/sysctl.cpp
  18. 11 27
      Userland/tail.cpp
  19. 17 21
      Userland/tee.cpp
  20. 28 28
      Userland/truncate.cpp
  21. 8 12
      Userland/umount.cpp
  22. 16 33
      Userland/wc.cpp

+ 5 - 6
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");

+ 31 - 44
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();

+ 40 - 71
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;
 }

+ 22 - 53
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;

+ 19 - 18
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)

+ 13 - 40
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);

+ 8 - 23
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");

+ 11 - 14
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;

+ 20 - 40
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;

+ 25 - 21
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;
 }

+ 47 - 70
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;

+ 13 - 17
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);
 }

+ 10 - 59
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());

+ 21 - 25
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);
 }

+ 13 - 16
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);
 }

+ 8 - 6
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;
     }
 }

+ 8 - 11
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);
 }

+ 11 - 27
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);
 }

+ 17 - 21
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);
 

+ 28 - 28
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;

+ 8 - 12
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;
 }

+ 16 - 33
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);
     }