mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vlib: reimplement glob in V for UNIX to not depend on libc (#10707)
This commit is contained in:
parent
151cd0bfe6
commit
47bf64473c
@ -15,9 +15,25 @@ fn deep_glob() ? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn redeep_glob() ? {
|
||||||
|
os.chdir(@VMODROOT)
|
||||||
|
matches := os.glob('vlib/v/**/*.v') or { panic(err) }
|
||||||
|
assert matches.len > 10
|
||||||
|
assert 'vlib/v/ast/ast.v' in matches
|
||||||
|
assert 'vlib/v/ast/table.v' in matches
|
||||||
|
assert 'vlib/v/token/token.v' in matches
|
||||||
|
for f in matches {
|
||||||
|
if !f.starts_with('vlib/v/') {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
assert f.ends_with('.v')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn test_glob_can_find_v_files_3_levels_deep() ? {
|
fn test_glob_can_find_v_files_3_levels_deep() ? {
|
||||||
$if !windows {
|
$if !windows {
|
||||||
deep_glob() ?
|
deep_glob() ?
|
||||||
|
redeep_glob() ?
|
||||||
}
|
}
|
||||||
assert true
|
assert true
|
||||||
}
|
}
|
||||||
@ -30,9 +46,11 @@ fn test_glob_can_find_files_in_current_folder() ? {
|
|||||||
assert 'cmd/' in matches
|
assert 'cmd/' in matches
|
||||||
assert 'vlib/' in matches
|
assert 'vlib/' in matches
|
||||||
for f in matches {
|
for f in matches {
|
||||||
|
if !f.ends_with(os.path_separator) {
|
||||||
assert !f.ends_with('.v')
|
assert !f.ends_with('.v')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn test_glob_can_be_used_with_multiple_patterns() ? {
|
fn test_glob_can_be_used_with_multiple_patterns() ? {
|
||||||
os.chdir(@VMODROOT)
|
os.chdir(@VMODROOT)
|
||||||
|
@ -627,3 +627,12 @@ pub fn is_atty(fd int) int {
|
|||||||
return C.isatty(fd)
|
return C.isatty(fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn glob(patterns ...string) ?[]string {
|
||||||
|
mut matches := []string{}
|
||||||
|
for pattern in patterns {
|
||||||
|
native_glob_pattern(pattern, mut matches) ?
|
||||||
|
}
|
||||||
|
matches.sort()
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
@ -8,7 +8,6 @@ import strings
|
|||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <glob.h>
|
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
@ -42,14 +41,6 @@ pub const (
|
|||||||
s_ixoth = 0o0001 // Execute by others
|
s_ixoth = 0o0001 // Execute by others
|
||||||
)
|
)
|
||||||
|
|
||||||
[typedef]
|
|
||||||
struct C.glob_t {
|
|
||||||
mut:
|
|
||||||
gl_pathc size_t // number of matched paths
|
|
||||||
gl_pathv &&char // list of matched pathnames
|
|
||||||
gl_offs size_t // slots to reserve in gl_pathv
|
|
||||||
}
|
|
||||||
|
|
||||||
struct C.utsname {
|
struct C.utsname {
|
||||||
mut:
|
mut:
|
||||||
sysname &char
|
sysname &char
|
||||||
@ -84,45 +75,138 @@ fn C.getgid() int
|
|||||||
fn C.getegid() int
|
fn C.getegid() int
|
||||||
|
|
||||||
fn C.ptrace(u32, u32, voidptr, int) u64
|
fn C.ptrace(u32, u32, voidptr, int) u64
|
||||||
fn C.glob(&char, int, voidptr, voidptr) int
|
|
||||||
|
|
||||||
fn C.globfree(voidptr)
|
enum GlobMatch {
|
||||||
|
exact
|
||||||
|
ends_with
|
||||||
|
starts_with
|
||||||
|
start_and_ends_with
|
||||||
|
contains
|
||||||
|
any
|
||||||
|
}
|
||||||
|
|
||||||
pub fn glob(patterns ...string) ?[]string {
|
fn glob_match(dir string, pattern string, next_pattern string, mut matches []string) []string {
|
||||||
$if android {
|
mut subdirs := []string{}
|
||||||
return error('os.glob() is not supported on android yet')
|
if is_file(dir) {
|
||||||
|
return subdirs
|
||||||
}
|
}
|
||||||
mut matches := []string{}
|
mut files := ls(dir) or { return subdirs }
|
||||||
if patterns.len == 0 {
|
mut mode := GlobMatch.exact
|
||||||
return matches
|
mut pat := pattern
|
||||||
|
if pat == '*' {
|
||||||
|
mode = GlobMatch.any
|
||||||
|
if next_pattern != pattern && next_pattern != '' {
|
||||||
|
for file in files {
|
||||||
|
if is_dir('$dir/$file') {
|
||||||
|
subdirs << '$dir/$file'
|
||||||
}
|
}
|
||||||
mut globdata := C.glob_t{
|
|
||||||
gl_pathv: 0
|
|
||||||
gl_pathc: size_t(0)
|
|
||||||
gl_offs: size_t(0)
|
|
||||||
}
|
}
|
||||||
mut flags := int(C.GLOB_DOOFFS | C.GLOB_MARK)
|
return subdirs
|
||||||
for i, pattern in patterns {
|
|
||||||
if i > 0 {
|
|
||||||
flags |= C.GLOB_APPEND
|
|
||||||
}
|
}
|
||||||
unsafe {
|
}
|
||||||
$if !android {
|
if pat == '**' {
|
||||||
if C.glob(&char(pattern.str), flags, C.NULL, &globdata) != 0 {
|
files = walk_ext(dir, '')
|
||||||
return error_with_code(posix_get_error_msg(C.errno), C.errno)
|
pat = next_pattern
|
||||||
|
}
|
||||||
|
if pat.starts_with('*') {
|
||||||
|
mode = .ends_with
|
||||||
|
pat = pat[1..]
|
||||||
|
}
|
||||||
|
if pat.ends_with('*') {
|
||||||
|
mode = if mode == .ends_with { GlobMatch.contains } else { GlobMatch.starts_with }
|
||||||
|
pat = pat[..pat.len - 1]
|
||||||
|
}
|
||||||
|
if pat.contains('*') {
|
||||||
|
mode = .start_and_ends_with
|
||||||
|
}
|
||||||
|
for file in files {
|
||||||
|
mut fpath := file
|
||||||
|
f := if file.contains(os.path_separator) {
|
||||||
|
pathwalk := file.split(os.path_separator)
|
||||||
|
pathwalk[pathwalk.len - 1]
|
||||||
|
} else {
|
||||||
|
fpath = if dir == '.' { file } else { '$dir/$file' }
|
||||||
|
file
|
||||||
|
}
|
||||||
|
if f in ['.', '..'] || f == '' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hit := match mode {
|
||||||
|
.any {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
.exact {
|
||||||
|
f == pat
|
||||||
|
}
|
||||||
|
.starts_with {
|
||||||
|
f.starts_with(pat)
|
||||||
|
}
|
||||||
|
.ends_with {
|
||||||
|
f.ends_with(pat)
|
||||||
|
}
|
||||||
|
.start_and_ends_with {
|
||||||
|
p := pat.split('*')
|
||||||
|
f.starts_with(p[0]) && f.ends_with(p[1])
|
||||||
|
}
|
||||||
|
.contains {
|
||||||
|
f.contains(pat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hit {
|
||||||
|
if is_dir(fpath) {
|
||||||
|
subdirs << fpath
|
||||||
|
if next_pattern == pattern && next_pattern != '' {
|
||||||
|
matches << '$fpath$os.path_separator'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matches << fpath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return subdirs
|
||||||
}
|
}
|
||||||
for i := 0; i < int(globdata.gl_pathc); i++ {
|
|
||||||
unsafe {
|
fn native_glob_pattern(pattern string, mut matches []string) ? {
|
||||||
matches << cstring_to_vstring(globdata.gl_pathv[i])
|
steps := pattern.split(os.path_separator)
|
||||||
|
mut cwd := if pattern.starts_with(os.path_separator) { os.path_separator } else { '.' }
|
||||||
|
mut subdirs := [cwd]
|
||||||
|
for i := 0; i < steps.len; i++ {
|
||||||
|
step := steps[i]
|
||||||
|
step2 := if i + 1 == steps.len { step } else { steps[i + 1] }
|
||||||
|
if step == '' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if is_dir('$cwd$os.path_separator$step') {
|
||||||
|
dd := if cwd == '/' {
|
||||||
|
step
|
||||||
|
} else {
|
||||||
|
if cwd == '.' || cwd == '' {
|
||||||
|
step
|
||||||
|
} else {
|
||||||
|
if step == '.' || step == '/' { cwd } else { '$cwd/$step' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$if !android {
|
if i + 1 != steps.len {
|
||||||
C.globfree(&globdata)
|
if dd !in subdirs {
|
||||||
|
subdirs << dd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut subs := []string{}
|
||||||
|
for sd in subdirs {
|
||||||
|
d := if cwd == '/' {
|
||||||
|
sd
|
||||||
|
} else {
|
||||||
|
if cwd == '.' || cwd == '' {
|
||||||
|
sd
|
||||||
|
} else {
|
||||||
|
if sd == '.' || sd == '/' { cwd } else { '$cwd/$sd' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs << glob_match(d.replace('//', '/'), step, step2, mut matches)
|
||||||
|
}
|
||||||
|
subdirs = subs.clone()
|
||||||
}
|
}
|
||||||
return matches
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn utime(path string, actime int, modtime int) ? {
|
pub fn utime(path string, actime int, modtime int) ? {
|
||||||
|
@ -102,15 +102,7 @@ fn init_os_args_wide(argc int, argv &&byte) []string {
|
|||||||
return args_
|
return args_
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glob(patterns ...string) ?[]string {
|
fn native_glob_pattern(pattern string, mut matches []string) ? {
|
||||||
mut matches := []string{}
|
|
||||||
for pattern in patterns {
|
|
||||||
windows_glob_pattern(pattern, mut matches) ?
|
|
||||||
}
|
|
||||||
return matches
|
|
||||||
}
|
|
||||||
|
|
||||||
fn windows_glob_pattern(pattern string, mut matches []string) ? {
|
|
||||||
$if debug {
|
$if debug {
|
||||||
// FindFirstFile() and FindNextFile() both have a globbing function.
|
// FindFirstFile() and FindNextFile() both have a globbing function.
|
||||||
// Unfortunately this is not as pronounced as under Unix, but should provide some functionality
|
// Unfortunately this is not as pronounced as under Unix, but should provide some functionality
|
||||||
|
Loading…
Reference in New Issue
Block a user