mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
os: add a glob() function (#10497)
This commit is contained in:
parent
f029f7e897
commit
d2f19ac494
62
vlib/os/glob_test.v
Normal file
62
vlib/os/glob_test.v
Normal file
@ -0,0 +1,62 @@
|
||||
import os
|
||||
|
||||
fn deep_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() ? {
|
||||
$if !windows {
|
||||
deep_glob() ?
|
||||
}
|
||||
assert true
|
||||
}
|
||||
|
||||
fn test_glob_can_find_files_in_current_folder() ? {
|
||||
os.chdir(@VMODROOT)
|
||||
matches := os.glob('*') ?
|
||||
assert 'README.md' in matches
|
||||
assert 'v.mod' in matches
|
||||
assert 'cmd/' in matches
|
||||
assert 'vlib/' in matches
|
||||
for f in matches {
|
||||
assert !f.ends_with('.v')
|
||||
}
|
||||
}
|
||||
|
||||
fn test_glob_can_be_used_with_multiple_patterns() ? {
|
||||
os.chdir(@VMODROOT)
|
||||
matches := os.glob('*', 'cmd/tools/*') ?
|
||||
assert 'README.md' in matches
|
||||
assert 'Makefile' in matches
|
||||
$if !windows {
|
||||
assert 'cmd/tools/test_if_v_test_system_works.v' in matches
|
||||
}
|
||||
$if windows {
|
||||
assert 'test_if_v_test_system_works.v' in matches
|
||||
}
|
||||
}
|
||||
|
||||
fn test_glob_star() ? {
|
||||
os.chdir(@VMODROOT)
|
||||
matches := os.glob('*ake*') ?
|
||||
assert 'Makefile' in matches
|
||||
assert 'make.bat' in matches
|
||||
}
|
||||
|
||||
fn test_glob_not_found() ? {
|
||||
os.glob('an_unknown_folder/*.v') or {
|
||||
assert true
|
||||
return
|
||||
}
|
||||
}
|
@ -183,7 +183,7 @@ pub fn file_size(path string) u64 {
|
||||
}
|
||||
$if x32 {
|
||||
$if debug {
|
||||
println('Using os.file_size() on 32bit systems may not work on big files.')
|
||||
eprintln('Using os.file_size() on 32bit systems may not work on big files.')
|
||||
}
|
||||
$if windows {
|
||||
if C._wstat(path.to_wide(), voidptr(&s)) != 0 {
|
||||
|
@ -8,6 +8,7 @@ import strings
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <glob.h>
|
||||
|
||||
pub const (
|
||||
path_separator = '/'
|
||||
@ -49,6 +50,14 @@ mut:
|
||||
machine &char
|
||||
}
|
||||
|
||||
[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
|
||||
}
|
||||
|
||||
fn C.uname(name voidptr) int
|
||||
|
||||
fn C.symlink(&char, &char) int
|
||||
@ -67,6 +76,37 @@ fn C.getgid() int
|
||||
fn C.getegid() int
|
||||
|
||||
fn C.ptrace(u32, u32, voidptr, int) u64
|
||||
fn C.glob(&char, int, voidptr, voidptr) int
|
||||
|
||||
fn C.globfree(voidptr)
|
||||
|
||||
pub fn glob(patterns ...string) ?[]string {
|
||||
mut matches := []string{}
|
||||
if patterns.len == 0 {
|
||||
return matches
|
||||
}
|
||||
mut globdata := C.glob_t{
|
||||
gl_pathv: 0
|
||||
}
|
||||
mut flags := int(C.GLOB_DOOFFS | C.GLOB_MARK)
|
||||
for i, pattern in patterns {
|
||||
if i > 0 {
|
||||
flags |= C.GLOB_APPEND
|
||||
}
|
||||
unsafe {
|
||||
if C.glob(&char(pattern.str), flags, C.NULL, &globdata) != 0 {
|
||||
return error_with_code(posix_get_error_msg(C.errno), C.errno)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < int(globdata.gl_pathc); i++ {
|
||||
unsafe {
|
||||
matches << cstring_to_vstring(globdata.gl_pathv[i])
|
||||
}
|
||||
}
|
||||
C.globfree(&globdata)
|
||||
return matches
|
||||
}
|
||||
|
||||
pub fn uname() Uname {
|
||||
mut u := Uname{}
|
||||
|
@ -699,3 +699,28 @@ fn test_truncate() {
|
||||
fn test_hostname() {
|
||||
assert os.hostname().len > 2
|
||||
}
|
||||
|
||||
fn test_glob() {
|
||||
os.mkdir('test_dir') or { panic(err) }
|
||||
for i in 0 .. 4 {
|
||||
if i == 3 {
|
||||
mut f := os.create('test_dir/test0_another') or { panic(err) }
|
||||
f.close()
|
||||
mut f1 := os.create('test_dir/test') or { panic(err) }
|
||||
f1.close()
|
||||
} else {
|
||||
mut f := os.create('test_dir/test' + i.str()) or { panic(err) }
|
||||
f.close()
|
||||
}
|
||||
}
|
||||
files := os.glob('test_dir/t*') or { panic(err) }
|
||||
assert files.len == 5
|
||||
assert os.base(files[0]) == 'test'
|
||||
|
||||
for i in 0 .. 3 {
|
||||
os.rm('test_dir/test' + i.str()) or { panic(err) }
|
||||
}
|
||||
os.rm('test_dir/test0_another') or { panic(err) }
|
||||
os.rm('test_dir/test') or { panic(err) }
|
||||
os.rmdir_all('test_dir') or { panic(err) }
|
||||
}
|
||||
|
@ -94,6 +94,57 @@ fn init_os_args_wide(argc int, argv &&byte) []string {
|
||||
return args_
|
||||
}
|
||||
|
||||
pub fn glob(patterns ...string) ?[]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 {
|
||||
// FindFirstFile() and FindNextFile() both have a globbing function.
|
||||
// Unfortunately this is not as pronounced as under Unix, but should provide some functionality
|
||||
eprintln('os.glob() does not have all the features on Windows as it has on Unix operating systems')
|
||||
}
|
||||
mut find_file_data := Win32finddata{}
|
||||
wpattern := pattern.replace('/', '\\').to_wide()
|
||||
h_find_files := C.FindFirstFile(wpattern, voidptr(&find_file_data))
|
||||
|
||||
defer {
|
||||
C.FindClose(h_find_files)
|
||||
}
|
||||
|
||||
if h_find_files == C.INVALID_HANDLE_VALUE {
|
||||
return error('os.glob(): Could not get a file handle: ' +
|
||||
get_error_msg(int(C.GetLastError())))
|
||||
}
|
||||
|
||||
// save first finding
|
||||
fname := unsafe { string_from_wide(&find_file_data.c_file_name[0]) }
|
||||
if fname !in ['.', '..'] {
|
||||
mut fp := fname.replace('\\', '/')
|
||||
if find_file_data.dw_file_attributes & u32(C.FILE_ATTRIBUTE_DIRECTORY) > 0 {
|
||||
fp += '/'
|
||||
}
|
||||
matches << fp
|
||||
}
|
||||
|
||||
// check and save next findings
|
||||
for i := 0; C.FindNextFile(h_find_files, voidptr(&find_file_data)) > 0; i++ {
|
||||
filename := unsafe { string_from_wide(&find_file_data.c_file_name[0]) }
|
||||
if filename in ['.', '..'] {
|
||||
continue
|
||||
}
|
||||
mut fpath := filename.replace('\\', '/')
|
||||
if find_file_data.dw_file_attributes & u32(C.FILE_ATTRIBUTE_DIRECTORY) > 0 {
|
||||
fpath += '/'
|
||||
}
|
||||
matches << fpath
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ls(path string) ?[]string {
|
||||
mut find_file_data := Win32finddata{}
|
||||
mut dir_files := []string{}
|
||||
|
Loading…
Reference in New Issue
Block a user