Skip to content

Commit

Permalink
path: add path.glob
Browse files Browse the repository at this point in the history
  • Loading branch information
MoLow committed Apr 9, 2023
1 parent 284e6ac commit c0a38c1
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/path.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const {
StringPrototypeToLowerCase,
} = primordials;

const { glob } = internalBinding('path');

const {
CHAR_UPPERCASE_A,
CHAR_LOWERCASE_A,
Expand Down Expand Up @@ -1064,6 +1066,7 @@ const win32 = {

return ret;
},
glob,

sep: '\\',
delimiter: ';',
Expand Down Expand Up @@ -1530,6 +1533,7 @@ const posix = {

return ret;
},
glob,

sep: '/',
delimiter: ':',
Expand Down
2 changes: 2 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
'src/node_metadata.cc',
'src/node_options.cc',
'src/node_os.cc',
'src/node_path.cc',
'src/node_perf.cc',
'src/node_platform.cc',
'src/node_postmortem_metadata.cc',
Expand Down Expand Up @@ -225,6 +226,7 @@
'src/node_object_wrap.h',
'src/node_options.h',
'src/node_options-inl.h',
'src/node_path.h',
'src/node_perf.h',
'src/node_perf_common.h',
'src/node_platform.h',
Expand Down
1 change: 1 addition & 0 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
V(mksnapshot) \
V(options) \
V(os) \
V(path) \
V(performance) \
V(permission) \
V(pipe_wrap) \
Expand Down
120 changes: 120 additions & 0 deletions src/node_path.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include "node_path.h"
#include "env-inl.h"
#include "node_errors.h"
#include "node_external_reference.h"

namespace node {

namespace path {
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Local;
using v8::Object;
using v8::Value;

// extracted from
// https://github.com/torvalds/linux/blob/cdc9718d5e590d6905361800b938b93f2b66818e/lib/glob.c
bool glob(char const* pat, char const* str) {
/*
* Backtrack to previous * on mismatch and retry starting one
* character later in the string. Because * matches all characters
* (no exception for /), it can be easily proved that there's
* never a need to backtrack multiple levels.
*/
char const* back_pat = nullptr;
char const* back_str;

/*
* Loop over each token (character or class) in pat, matching
* it against the remaining unmatched tail of str. Return false
* on mismatch, or true after matching the trailing nul bytes.
*/
for (;;) {
unsigned char c = *str++;
unsigned char d = *pat++;

switch (d) {
case '?': /* Wildcard: anything but nul */
if (c == '\0') return false;
break;
case '*': /* Any-length wildcard */
if (*pat == '\0') /* Optimize trailing * case */
return true;
back_pat = pat;
back_str = --str; /* Allow zero-length match */
break;
case '[': { /* Character class */
bool match = false, inverted = (*pat == '!');
char const* cls = pat + inverted;
unsigned char a = *cls++;

/*
* Iterate over each span in the character class.
* A span is either a single character a, or a
* range a-b. The first span may begin with ']'.
*/
do {
unsigned char b = a;

if (a == '\0') /* Malformed */
goto literal;

if (cls[0] == '-' && cls[1] != ']') {
b = cls[1];

if (b == '\0') goto literal;

cls += 2;
/* Any special action if a > b? */
}
match |= (a <= c && c <= b);
} while ((a = *cls++) != ']');

if (match == inverted) goto backtrack;
pat = cls;
} break;
case '\\':
d = *pat++;
// fallthrough;
default: /* Literal character */
literal:
if (c == d) {
if (d == '\0') return true;
break;
}
backtrack:
if (c == '\0' || !back_pat) return false; /* No point continuing */
/* Try again from last *, one character later in str. */
pat = back_pat;
str = ++back_str;
break;
}
}
}
void glob(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_GE(args.Length(), 2);
CHECK(args[0]->IsString());
CHECK(args[1]->IsString());

std::string pattern = Utf8Value(env->isolate(), args[0]).ToString();
std::string str = Utf8Value(env->isolate(), args[1]).ToString();
args.GetReturnValue().Set(glob(pattern.c_str(), str.c_str()));
}

void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
SetMethod(context, target, "glob", glob);
}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(glob);
}
} // namespace path

} // namespace node

NODE_BINDING_CONTEXT_AWARE_INTERNAL(path, node::path::Initialize)
NODE_BINDING_EXTERNAL_REFERENCE(path, node::path::RegisterExternalReferences)
17 changes: 17 additions & 0 deletions src/node_path.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef SRC_NODE_PATH_H_
#define SRC_NODE_PATH_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "base_object.h"
#include "node_snapshotable.h"
#include "v8.h"

namespace node {

namespace path {} // namespace path
} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_NODE_PATH_H_

0 comments on commit c0a38c1

Please sign in to comment.