Skip to content

Commit

Permalink
Shell: Implement more advanced globbing.
Browse files Browse the repository at this point in the history
A glob has to be resolved against the directory corresponding to
the part of the path it is found in, not the current directory.
For example, in /usr/i*/AK/, the glob has to be resolved inside
/usr. Moreover, an argument can contain more than one glob, such
as /u*/*/?, in which case they have to be resolved recursively.

In case a glob matches nothing, the argument should be used as is.
  • Loading branch information
bugaevc authored and awesomekling committed Jun 14, 2019
1 parent d211307 commit 802612f
Showing 1 changed file with 93 additions and 26 deletions.
119 changes: 93 additions & 26 deletions Shell/main.cpp
Expand Up @@ -2,6 +2,7 @@
#include "LineEditor.h"
#include "Parser.h"
#include <AK/FileSystemPath.h>
#include <AK/StringBuilder.h>
#include <LibCore/CDirIterator.h>
#include <LibCore/CElapsedTimer.h>
#include <errno.h>
Expand Down Expand Up @@ -219,42 +220,108 @@ struct CommandTimer {
CElapsedTimer timer;
};

static Vector<String> process_arguments(const Vector<String>& args)
static bool is_glob(const StringView& s)
{
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;
}
for (int i = 0; i < s.length(); i++) {
char c = s.characters()[i];
if (c == '*' || c == '?')
return true;
}
return false;
}

static Vector<StringView> split_path(const StringView &path)
{
Vector<StringView> parts;

ssize_t substart = 0;
for (ssize_t i = 0; i < path.length(); i++) {
char ch = path.characters()[i];
if (ch != '/')
continue;
ssize_t sublen = i - substart;
if (sublen != 0)
parts.append(path.substring_view(substart, sublen));
parts.append(path.substring_view(i, 1));
substart = i + 1;
}

ssize_t taillen = path.length() - substart;
if (taillen != 0)
parts.append(path.substring_view(substart, taillen));

return parts;
}

static Vector<String> expand_globs(const StringView& path, const StringView& base)
{
auto parts = split_path(path);

StringBuilder builder;
builder.append(base);
Vector<String> res;

for (int i = 0; i < parts.size(); ++i) {
auto& part = parts[i];
if (!is_glob(part)) {
builder.append(part);
continue;
}

// Found a glob.
String new_base = builder.to_string();
StringView new_base_v = new_base;
if (new_base_v.is_empty())
new_base_v = ".";
CDirIterator di(new_base_v, CDirIterator::NoFlags);

if (di.has_error()) {
return res;
}

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());
while (di.has_next()) {
String name = di.next_path();

// Dotfiles have to be explicitly requested
if (name[0] == '.' && part[0] != '.')
continue;
}

while (di.has_next()) {
String name = di.next_path();
// And even if they are, skip . and ..
if (name == "." || name == "..")
continue;

// Dotfiles have to be explicitly requested
if (name[0] == '.' && arg[0] != '.')
continue;
if (name.matches(part, String::CaseSensitivity::CaseSensitive)) {

// And even if they are, skip . and ..
if (name == "." || name == "..")
continue;
StringBuilder nested_base;
nested_base.append(new_base);
nested_base.append(name);

if (name.matches(arg, String::CaseSensitivity::CaseSensitive))
argv_string.append(name);
StringView remaining_path = path.substring_view_starting_after_substring(part);
Vector<String> nested_res = expand_globs(remaining_path, nested_base.to_string());
for (auto& s : nested_res)
res.append(s);
}
}
return res;
}

// Found no globs.
String new_path = builder.to_string();
if (access(new_path.characters(), F_OK) == 0)
res.append(new_path);
return res;
}

static Vector<String> process_arguments(const Vector<String>& args)
{
Vector<String> argv_string;
for (auto& arg : args) {
auto expanded = expand_globs(arg, "");
if (expanded.is_empty())
argv_string.append(arg);
else
for (auto& path : expand_globs(arg, ""))
argv_string.append(path);
}

return argv_string;
Expand Down

0 comments on commit 802612f

Please sign in to comment.