From 5a21c3b38968fa5b5bdfd2f1aaa02fec154c6ec0 Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Tue, 23 Nov 2021 18:43:59 +0100 Subject: [PATCH] find: Use a Vector for parsing instead of moving optind --- Userland/Utilities/find.cpp | 124 +++++++++++++++++------------------- 1 file changed, 58 insertions(+), 66 deletions(-) diff --git a/Userland/Utilities/find.cpp b/Userland/Utilities/find.cpp index a8d6e83500d..500c9ecf60d 100644 --- a/Userland/Utilities/find.cpp +++ b/Userland/Utilities/find.cpp @@ -364,36 +364,37 @@ private: NonnullOwnPtr m_rhs; }; -static OwnPtr parse_complex_command(char* argv[]); +static OwnPtr parse_complex_command(Vector& args); // Parse a simple command starting at optind; leave optind at its the last // argument. Return nullptr if we reach the end of arguments. -static OwnPtr parse_simple_command(char* argv[]) +static OwnPtr parse_simple_command(Vector& args) { - StringView arg = argv[optind]; - - if (arg.is_null()) { + if (args.is_empty()) return {}; - } else if (arg == "(") { - optind++; - auto command = parse_complex_command(argv); - if (command && argv[optind] && StringView(argv[++optind]) == ")") + + char* raw_arg = args.take_first(); + StringView arg = raw_arg; + + if (arg == "(") { + auto command = parse_complex_command(args); + if (command && !args.is_empty() && StringView(args.first()) == ")") return command; fatal_error("Unmatched \033[1m("); } else if (arg == "-type") { - return make(argv[++optind]); + return make(args.take_first()); } else if (arg == "-links") { - return make(argv[++optind]); + return make(args.take_first()); } else if (arg == "-user") { - return make(argv[++optind]); + return make(args.take_first()); } else if (arg == "-group") { - return make(argv[++optind]); + return make(args.take_first()); } else if (arg == "-size") { - return make(argv[++optind]); + return make(args.take_first()); } else if (arg == "-name") { - return make(argv[++optind], CaseSensitivity::CaseSensitive); + return make(args.take_first(), CaseSensitivity::CaseSensitive); } else if (arg == "-iname") { - return make(argv[++optind], CaseSensitivity::CaseInsensitive); + return make(args.take_first(), CaseSensitivity::CaseInsensitive); } else if (arg == "-print") { g_have_seen_action_command = true; return make(); @@ -403,20 +404,25 @@ static OwnPtr parse_simple_command(char* argv[]) } else if (arg == "-exec") { g_have_seen_action_command = true; Vector command_argv; - while (argv[++optind] && StringView(argv[optind]) != ";") - command_argv.append(argv[optind]); + while (!args.is_empty()) { + char* next = args.take_first(); + if (next[0] == ';') + break; + command_argv.append(next); + } return make(move(command_argv)); } else { - fatal_error("Unsupported command \033[1m{}", argv[optind]); + fatal_error("Unsupported command \033[1m{}", arg); } } -static OwnPtr parse_complex_command(char* argv[]) +static OwnPtr parse_complex_command(Vector& args) { - auto command = parse_simple_command(argv); + auto command = parse_simple_command(args); - while (command && argv[optind] && argv[optind + 1]) { - StringView arg = argv[++optind]; + while (command && !args.is_empty()) { + char* raw_arg = args.take_first(); + StringView arg = raw_arg; enum { And, @@ -424,21 +430,20 @@ static OwnPtr parse_complex_command(char* argv[]) } binary_operation { And }; if (arg == "-a") { - optind++; binary_operation = And; } else if (arg == "-o") { - optind++; binary_operation = Or; } else if (arg == ")") { // Ooops, looked too far. - optind--; + args.prepend(raw_arg); return command; } else { // Juxtaposition is an And too, and there's nothing to skip. + args.prepend(raw_arg); binary_operation = And; } - auto rhs = parse_complex_command(argv); + auto rhs = parse_complex_command(args); if (!rhs) fatal_error("Missing right-hand side"); @@ -451,9 +456,9 @@ static OwnPtr parse_complex_command(char* argv[]) return command; } -static NonnullOwnPtr parse_all_commands(char* argv[]) +static NonnullOwnPtr parse_all_commands(Vector& args) { - auto command = parse_complex_command(argv); + auto command = parse_complex_command(args); if (g_have_seen_action_command) { VERIFY(command); @@ -467,41 +472,6 @@ static NonnullOwnPtr parse_all_commands(char* argv[]) return make(command.release_nonnull(), make()); } -static const char* parse_options(int argc, char* argv[]) -{ - // Sadly, we can't use Core::ArgsParser, because find accepts arguments in - // an extremely unusual format. We're going to try to use getopt(), though. - opterr = 0; - while (true) { - int opt = getopt(argc, argv, "+L"); - switch (opt) { - case -1: { - // No more options. - StringView arg = argv[optind]; - if (!arg.is_null() && !arg.starts_with('-')) { - // It's our root path! - return argv[optind++]; - } else { - // It's a part of the script, and our root path is the current - // directory by default. - return "."; - } - } - case '?': - // Some error. Most likely, it's getopt() getting confused about - // what it thought was an option, but is actually a command. Return - // the default path, and hope the command parsing logic deals with - // this. - return "."; - case 'L': - g_follow_symlinks = true; - break; - default: - VERIFY_NOT_REACHED(); - } - } -} - static void walk_tree(FileData& root_data, Command& command) { command.evaluate(root_data); @@ -567,7 +537,29 @@ static void walk_tree(FileData& root_data, Command& command) ErrorOr serenity_main(Main::Arguments arguments) { - LexicalPath root_path(parse_options(arguments.argc, arguments.argv)); + Vector args; + args.append(arguments.argv + 1, arguments.argc - 1); + + OwnPtr command; + LexicalPath root_path = LexicalPath("."); + + while (!args.is_empty()) { + char* raw_arg = args.take_first(); + StringView arg = raw_arg; + if (arg == "-L") { + g_follow_symlinks = true; + } else if (!arg.starts_with('-')) { + root_path = LexicalPath(arg); + } else { + // No special case, so add back the argument and try to parse a command. + args.prepend(raw_arg); + command = parse_all_commands(args); + } + } + + if (!command) + command = make(); + String dirname = root_path.dirname(); String basename = root_path.basename(); @@ -581,8 +573,8 @@ ErrorOr serenity_main(Main::Arguments arguments) false, DT_UNKNOWN, }; - auto command = parse_all_commands(arguments.argv); walk_tree(file_data, *command); close(dirfd); + return g_there_was_an_error ? 1 : 0; }