summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AK/AKString.h7
-rw-r--r--AK/String.cpp54
-rw-r--r--Shell/main.cpp56
3 files changed, 115 insertions, 2 deletions
diff --git a/AK/AKString.h b/AK/AKString.h
index 8df1bf162d..80014ac8e1 100644
--- a/AK/AKString.h
+++ b/AK/AKString.h
@@ -61,7 +61,13 @@ public:
{
}
+ enum class CaseSensitivity {
+ CaseInsensitive,
+ CaseSensitive,
+ };
+
static String repeated(char, int count);
+ bool matches(const String& pattern, CaseSensitivity = CaseSensitivity::CaseInsensitive) const;
int to_int(bool& ok) const;
unsigned to_uint(bool& ok) const;
@@ -136,6 +142,7 @@ public:
StringView view() const { return { characters(), length() }; }
private:
+ bool match_helper(const String& mask) const;
RetainPtr<StringImpl> m_impl;
};
diff --git a/AK/String.cpp b/AK/String.cpp
index 3298e833aa..8544e4c98a 100644
--- a/AK/String.cpp
+++ b/AK/String.cpp
@@ -196,4 +196,58 @@ String String::repeated(char ch, int count)
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;
+}
+
}
diff --git a/Shell/main.cpp b/Shell/main.cpp
index 2cba5b352d..b596fc2c93 100644
--- a/Shell/main.cpp
+++ b/Shell/main.cpp
@@ -12,6 +12,7 @@
#include <sys/utsname.h>
#include <AK/FileSystemPath.h>
#include <LibCore/CElapsedTimer.h>
+#include <LibCore/CDirIterator.h>
#include "GlobalState.h"
#include "Parser.h"
#include "LineEditor.h"
@@ -223,6 +224,47 @@ struct CommandTimer {
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)
{
if (cmd.is_empty())
@@ -330,11 +372,21 @@ static int run_command(const String& cmd)
for (int i = 0; i < subcommands.size(); ++i) {
auto& subcommand = subcommands[i];
+ Vector<String> argv_string = process_arguments(subcommand.args);
Vector<const char*> argv;
- for (auto& arg : subcommand.args)
- argv.append(arg.characters());
+ argv.ensure_capacity(argv_string.size());
+ for (const auto& s : argv_string) {
+ argv.append(s.characters());
+ }
argv.append(nullptr);
+#ifdef SH_DEBUG
+ for (auto& arg : argv) {
+ dbgprintf("<%s> ", arg);
+ }
+ dbgprintf("\n");
+#endif
+
int retval = 0;
if (handle_builtin(argv.size() - 1, const_cast<char**>(argv.data()), retval))
return retval;