diff --git a/AK/ArgsParser.cpp b/AK/ArgsParser.cpp index 0e2b629775..0bd4112013 100644 --- a/AK/ArgsParser.cpp +++ b/AK/ArgsParser.cpp @@ -112,6 +112,12 @@ bool ArgsParser::check_required_args(const ArgsParserResult& res) return false; } } + + if (m_single_value_required) { + if (res.m_single_values.size() == 0) + return false; + } + return true; } @@ -135,6 +141,18 @@ void ArgsParser::add_arg(const String& name, const String& value_name, const Str m_args.set(name, Arg(name, value_name, description, false)); } +void ArgsParser::set_single_value(const String& name) +{ + m_single_value_name = name; + m_single_value_required = false; +} + +void ArgsParser::set_required_single_value(const String& name) +{ + m_single_value_name = name; + m_single_value_required = true; +} + String ArgsParser::get_usage() const { StringBuilder sb; @@ -163,6 +181,20 @@ String ArgsParser::get_usage() const sb.append("] "); } + if (m_single_value_name.length()) { + if (m_single_value_required) + sb.append("<"); + else + sb.append("["); + + sb.append(m_single_value_name); + + if (m_single_value_required) + sb.append(">"); + else + sb.append("]"); + } + sb.append("\n"); for (auto& it : m_args) { diff --git a/AK/ArgsParser.h b/AK/ArgsParser.h index 8879b127bc..53eebc8127 100644 --- a/AK/ArgsParser.h +++ b/AK/ArgsParser.h @@ -38,6 +38,8 @@ public: void add_required_arg(const String& name, const String& value_name, const String& description); void add_arg(const String& name, const String& description); void add_arg(const String& name, const String& value_name, const String& description); + void set_single_value(const String& name); + void set_required_single_value(const String& name); String get_usage() const; void print_usage() const; @@ -59,6 +61,8 @@ private: String m_program_name; String m_prefix; + String m_single_value_name; + bool m_single_value_required = false; HashMap m_args; }; diff --git a/Userland/tail.cpp b/Userland/tail.cpp index c0970fc407..46e0e0a214 100644 --- a/Userland/tail.cpp +++ b/Userland/tail.cpp @@ -2,17 +2,11 @@ #include #include #include -#include #include #include +#include #include -static void print_usage_and_exit() -{ - printf("usage: tail [-f, -n ] \n"); - exit(1); -} - int tail_from_pos(CFile& file, off_t startline, bool want_follow) { if (!file.seek(startline + 1)) @@ -81,37 +75,38 @@ static void exit_because_we_wanted_lines() int main(int argc, char *argv[]) { + AK::ArgsParser args_parser("tail"); + + 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.set_required_single_value("file"); + + AK::ArgsParserResult args = args_parser.parse(argc, (const char**)argv); + + Vector values = args.get_single_values(); + if (values.size() != 1) { + args_parser.print_usage(); + return -1; + } + int line_count = 0; - bool flag_follow = false; - int opt; - while ((opt = getopt(argc, argv, "fn:")) != -1) { - switch (opt) { - case 'f': - flag_follow = true; - break; - case 'n': - line_count = strtol(optarg, NULL, 10); - if (errno == EINVAL) { - exit_because_we_wanted_lines(); - } - break; - default: - print_usage_and_exit(); + if (args.is_present("n")) { + line_count = strtol(args.get("n").characters(), NULL, 10); + if (errno == EINVAL) { + args_parser.print_usage(); + return -1; } } - const char *path = nullptr; - if (optind >= argc) { - print_usage_and_exit(); - } - path = argv[optind]; - - CFile f(path); + CFile f(values[0]); if (!f.open(CIODevice::ReadOnly)) { - fprintf(stderr, "Error opening file %s: %s\n", path, strerror(errno)); + fprintf(stderr, "Error opening file %s: %s\n", f.filename().characters(), strerror(errno)); exit(-1); } + bool flag_follow = args.is_present("f"); + bool o_arg = args.is_present("o"); + auto pos = find_seek_pos(f, line_count); return tail_from_pos(f, pos, flag_follow); }