find: Use a Vector for parsing instead of moving optind

This commit is contained in:
Tim Schumacher 2021-11-23 18:43:59 +01:00 committed by Andreas Kling
parent 4ca35ac1b8
commit 5a21c3b389
Notes: sideshowbarker 2024-07-17 23:12:30 +09:00

View file

@ -364,36 +364,37 @@ private:
NonnullOwnPtr<Command> m_rhs;
};
static OwnPtr<Command> parse_complex_command(char* argv[]);
static OwnPtr<Command> parse_complex_command(Vector<char*>& 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<Command> parse_simple_command(char* argv[])
static OwnPtr<Command> parse_simple_command(Vector<char*>& 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<TypeCommand>(argv[++optind]);
return make<TypeCommand>(args.take_first());
} else if (arg == "-links") {
return make<LinksCommand>(argv[++optind]);
return make<LinksCommand>(args.take_first());
} else if (arg == "-user") {
return make<UserCommand>(argv[++optind]);
return make<UserCommand>(args.take_first());
} else if (arg == "-group") {
return make<GroupCommand>(argv[++optind]);
return make<GroupCommand>(args.take_first());
} else if (arg == "-size") {
return make<SizeCommand>(argv[++optind]);
return make<SizeCommand>(args.take_first());
} else if (arg == "-name") {
return make<NameCommand>(argv[++optind], CaseSensitivity::CaseSensitive);
return make<NameCommand>(args.take_first(), CaseSensitivity::CaseSensitive);
} else if (arg == "-iname") {
return make<NameCommand>(argv[++optind], CaseSensitivity::CaseInsensitive);
return make<NameCommand>(args.take_first(), CaseSensitivity::CaseInsensitive);
} else if (arg == "-print") {
g_have_seen_action_command = true;
return make<PrintCommand>();
@ -403,20 +404,25 @@ static OwnPtr<Command> parse_simple_command(char* argv[])
} else if (arg == "-exec") {
g_have_seen_action_command = true;
Vector<char*> 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<ExecCommand>(move(command_argv));
} else {
fatal_error("Unsupported command \033[1m{}", argv[optind]);
fatal_error("Unsupported command \033[1m{}", arg);
}
}
static OwnPtr<Command> parse_complex_command(char* argv[])
static OwnPtr<Command> parse_complex_command(Vector<char*>& 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<Command> 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<Command> parse_complex_command(char* argv[])
return command;
}
static NonnullOwnPtr<Command> parse_all_commands(char* argv[])
static NonnullOwnPtr<Command> parse_all_commands(Vector<char*>& 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<Command> parse_all_commands(char* argv[])
return make<AndCommand>(command.release_nonnull(), make<PrintCommand>());
}
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<int> serenity_main(Main::Arguments arguments)
{
LexicalPath root_path(parse_options(arguments.argc, arguments.argv));
Vector<char*> args;
args.append(arguments.argv + 1, arguments.argc - 1);
OwnPtr<Command> 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<PrintCommand>();
String dirname = root_path.dirname();
String basename = root_path.basename();
@ -581,8 +573,8 @@ ErrorOr<int> 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;
}