mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
Shell: Allow * and ? wildcard expansion in arguments
Should also presumably allow for escaping and such, but this is a start. Fixes #112.
This commit is contained in:
parent
4040c6137d
commit
9947ee9566
Notes:
sideshowbarker
2024-07-19 13:53:19 +09:00
Author: https://github.com/rburchell Commit: https://github.com/SerenityOS/serenity/commit/9947ee9566a Pull-request: https://github.com/SerenityOS/serenity/pull/125 Reviewed-by: https://github.com/awesomekling ✅
3 changed files with 115 additions and 2 deletions
|
@ -61,7 +61,13 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class CaseSensitivity {
|
||||||
|
CaseInsensitive,
|
||||||
|
CaseSensitive,
|
||||||
|
};
|
||||||
|
|
||||||
static String repeated(char, int count);
|
static String repeated(char, int count);
|
||||||
|
bool matches(const String& pattern, CaseSensitivity = CaseSensitivity::CaseInsensitive) const;
|
||||||
|
|
||||||
int to_int(bool& ok) const;
|
int to_int(bool& ok) const;
|
||||||
unsigned to_uint(bool& ok) const;
|
unsigned to_uint(bool& ok) const;
|
||||||
|
@ -136,6 +142,7 @@ public:
|
||||||
StringView view() const { return { characters(), length() }; }
|
StringView view() const { return { characters(), length() }; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool match_helper(const String& mask) const;
|
||||||
RetainPtr<StringImpl> m_impl;
|
RetainPtr<StringImpl> m_impl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -196,4 +196,58 @@ String String::repeated(char ch, int count)
|
||||||
return *impl;
|
return *impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool String::matches(const String& mask, CaseSensitivity case_sensitivity) const
|
||||||
|
{
|
||||||
|
if (case_sensitivity == CaseSensitivity::CaseInsensitive) {
|
||||||
|
String this_lower = this->to_lowercase();
|
||||||
|
String mask_lower = mask.to_lowercase();
|
||||||
|
return this_lower.match_helper(mask_lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
return match_helper(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::match_helper(const String& mask) const
|
||||||
|
{
|
||||||
|
if (is_null() || mask.is_null())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char* string_ptr = characters();
|
||||||
|
const char* mask_ptr = mask.characters();
|
||||||
|
|
||||||
|
// Match string against mask directly unless we hit a *
|
||||||
|
while ((*string_ptr) && (*mask_ptr != '*')) {
|
||||||
|
if ((*mask_ptr != *string_ptr) && (*mask_ptr != '?'))
|
||||||
|
return false;
|
||||||
|
mask_ptr++;
|
||||||
|
string_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* cp = nullptr;
|
||||||
|
const char* mp = nullptr;
|
||||||
|
|
||||||
|
while (*string_ptr) {
|
||||||
|
if (*mask_ptr == '*') {
|
||||||
|
// If we have only a * left, there is no way to not match.
|
||||||
|
if (!*++mask_ptr)
|
||||||
|
return true;
|
||||||
|
mp = mask_ptr;
|
||||||
|
cp = string_ptr+1;
|
||||||
|
} else if ((*mask_ptr == *string_ptr) || (*mask_ptr == '?')) {
|
||||||
|
mask_ptr++;
|
||||||
|
string_ptr++;
|
||||||
|
} else {
|
||||||
|
mask_ptr = mp;
|
||||||
|
string_ptr = cp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle any trailing mask
|
||||||
|
while (*mask_ptr == '*')
|
||||||
|
mask_ptr++;
|
||||||
|
|
||||||
|
// If we 'ate' all of the mask then we match.
|
||||||
|
return !*mask_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <AK/FileSystemPath.h>
|
#include <AK/FileSystemPath.h>
|
||||||
#include <LibCore/CElapsedTimer.h>
|
#include <LibCore/CElapsedTimer.h>
|
||||||
|
#include <LibCore/CDirIterator.h>
|
||||||
#include "GlobalState.h"
|
#include "GlobalState.h"
|
||||||
#include "Parser.h"
|
#include "Parser.h"
|
||||||
#include "LineEditor.h"
|
#include "LineEditor.h"
|
||||||
|
@ -223,6 +224,47 @@ struct CommandTimer {
|
||||||
CElapsedTimer timer;
|
CElapsedTimer timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Vector<String> process_arguments(const Vector<String>& args)
|
||||||
|
{
|
||||||
|
Vector<String> argv_string;
|
||||||
|
for (auto& arg : args) {
|
||||||
|
bool is_glob = false;
|
||||||
|
for (int i = 0; i < arg.length(); i++) {
|
||||||
|
char c = arg.characters()[i];
|
||||||
|
if (c == '*' || c == '?') {
|
||||||
|
is_glob = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_glob == false) {
|
||||||
|
argv_string.append(arg.characters());
|
||||||
|
} else {
|
||||||
|
CDirIterator di(".", CDirIterator::NoFlags);
|
||||||
|
if (di.has_error()) {
|
||||||
|
fprintf(stderr, "CDirIterator: %s\n", di.error_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (di.has_next()) {
|
||||||
|
String name = di.next_path();
|
||||||
|
|
||||||
|
// Dotfiles have to be explicitly requested
|
||||||
|
if (name[0] == '.' && arg[0] != '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// And even if they are, skip . and ..
|
||||||
|
if (name == "." || name == "..")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (name.matches(arg, String::CaseSensitivity::CaseSensitive))
|
||||||
|
argv_string.append(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return argv_string;
|
||||||
|
}
|
||||||
|
|
||||||
static int run_command(const String& cmd)
|
static int run_command(const String& cmd)
|
||||||
{
|
{
|
||||||
if (cmd.is_empty())
|
if (cmd.is_empty())
|
||||||
|
@ -330,11 +372,21 @@ static int run_command(const String& cmd)
|
||||||
|
|
||||||
for (int i = 0; i < subcommands.size(); ++i) {
|
for (int i = 0; i < subcommands.size(); ++i) {
|
||||||
auto& subcommand = subcommands[i];
|
auto& subcommand = subcommands[i];
|
||||||
|
Vector<String> argv_string = process_arguments(subcommand.args);
|
||||||
Vector<const char*> argv;
|
Vector<const char*> argv;
|
||||||
for (auto& arg : subcommand.args)
|
argv.ensure_capacity(argv_string.size());
|
||||||
argv.append(arg.characters());
|
for (const auto& s : argv_string) {
|
||||||
|
argv.append(s.characters());
|
||||||
|
}
|
||||||
argv.append(nullptr);
|
argv.append(nullptr);
|
||||||
|
|
||||||
|
#ifdef SH_DEBUG
|
||||||
|
for (auto& arg : argv) {
|
||||||
|
dbgprintf("<%s> ", arg);
|
||||||
|
}
|
||||||
|
dbgprintf("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
if (handle_builtin(argv.size() - 1, const_cast<char**>(argv.data()), retval))
|
if (handle_builtin(argv.size() - 1, const_cast<char**>(argv.data()), retval))
|
||||||
return retval;
|
return retval;
|
||||||
|
|
Loading…
Reference in a new issue