aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/os/os_nix.c.v
diff options
context:
space:
mode:
authorIndrajith K L2022-12-03 17:00:20 +0530
committerIndrajith K L2022-12-03 17:00:20 +0530
commitf5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch)
tree2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/vlib/os/os_nix.c.v
downloadcli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.gz
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.bz2
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.zip
Adds most of the toolsHEADmaster
Diffstat (limited to 'v_windows/v/vlib/os/os_nix.c.v')
-rw-r--r--v_windows/v/vlib/os/os_nix.c.v549
1 files changed, 549 insertions, 0 deletions
diff --git a/v_windows/v/vlib/os/os_nix.c.v b/v_windows/v/vlib/os/os_nix.c.v
new file mode 100644
index 0000000..6640ec8
--- /dev/null
+++ b/v_windows/v/vlib/os/os_nix.c.v
@@ -0,0 +1,549 @@
+module os
+
+import strings
+
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <utime.h>
+$if !solaris && !haiku {
+ #include <sys/ptrace.h>
+}
+
+pub const (
+ path_separator = '/'
+ path_delimiter = ':'
+)
+
+const (
+ stdin_value = 0
+ stdout_value = 1
+ stderr_value = 2
+)
+
+// (Must be realized in Syscall) (Must be specified)
+// ref: http://www.ccfit.nsu.ru/~deviv/courses/unix/unix/ng7c229.html
+pub const (
+ s_ifmt = 0xF000 // type of file
+ s_ifdir = 0x4000 // directory
+ s_iflnk = 0xa000 // link
+ s_isuid = 0o4000 // SUID
+ s_isgid = 0o2000 // SGID
+ s_isvtx = 0o1000 // Sticky
+ s_irusr = 0o0400 // Read by owner
+ s_iwusr = 0o0200 // Write by owner
+ s_ixusr = 0o0100 // Execute by owner
+ s_irgrp = 0o0040 // Read by group
+ s_iwgrp = 0o0020 // Write by group
+ s_ixgrp = 0o0010 // Execute by group
+ s_iroth = 0o0004 // Read by others
+ s_iwoth = 0o0002 // Write by others
+ s_ixoth = 0o0001 // Execute by others
+)
+
+struct C.utsname {
+mut:
+ sysname &char
+ nodename &char
+ release &char
+ version &char
+ machine &char
+}
+
+struct C.utimbuf {
+ actime int
+ modtime int
+}
+
+fn C.utime(&char, voidptr) int
+
+fn C.uname(name voidptr) int
+
+fn C.symlink(&char, &char) int
+
+fn C.link(&char, &char) int
+
+fn C.gethostname(&char, int) int
+
+// NB: not available on Android fn C.getlogin_r(&char, int) int
+fn C.getlogin() &char
+
+fn C.getppid() int
+
+fn C.getgid() int
+
+fn C.getegid() int
+
+fn C.ptrace(u32, u32, voidptr, int) u64
+
+enum GlobMatch {
+ exact
+ ends_with
+ starts_with
+ start_and_ends_with
+ contains
+ any
+}
+
+fn glob_match(dir string, pattern string, next_pattern string, mut matches []string) []string {
+ mut subdirs := []string{}
+ if is_file(dir) {
+ return subdirs
+ }
+ mut files := ls(dir) or { return subdirs }
+ mut mode := GlobMatch.exact
+ 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'
+ }
+ }
+ return subdirs
+ }
+ }
+ if pat == '**' {
+ files = walk_ext(dir, '')
+ 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
+}
+
+fn native_glob_pattern(pattern string, mut matches []string) ? {
+ 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 i + 1 != steps.len {
+ 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()
+ }
+}
+
+pub fn utime(path string, actime int, modtime int) ? {
+ mut u := C.utimbuf{actime, modtime}
+ if C.utime(&char(path.str), voidptr(&u)) != 0 {
+ return error_with_code(posix_get_error_msg(C.errno), C.errno)
+ }
+}
+
+pub fn uname() Uname {
+ mut u := Uname{}
+ utsize := sizeof(C.utsname)
+ unsafe {
+ x := malloc_noscan(int(utsize))
+ d := &C.utsname(x)
+ if C.uname(d) == 0 {
+ u.sysname = cstring_to_vstring(d.sysname)
+ u.nodename = cstring_to_vstring(d.nodename)
+ u.release = cstring_to_vstring(d.release)
+ u.version = cstring_to_vstring(d.version)
+ u.machine = cstring_to_vstring(d.machine)
+ }
+ free(d)
+ }
+ return u
+}
+
+pub fn hostname() string {
+ mut hstnme := ''
+ size := 256
+ mut buf := unsafe { &char(malloc_noscan(size)) }
+ if C.gethostname(buf, size) == 0 {
+ hstnme = unsafe { cstring_to_vstring(buf) }
+ unsafe { free(buf) }
+ return hstnme
+ }
+ return ''
+}
+
+pub fn loginname() string {
+ x := C.getlogin()
+ if !isnil(x) {
+ return unsafe { cstring_to_vstring(x) }
+ }
+ return ''
+}
+
+fn init_os_args(argc int, argv &&byte) []string {
+ mut args_ := []string{}
+ // mut args := []string(make(0, argc, sizeof(string)))
+ // mut args := []string{len:argc}
+ for i in 0 .. argc {
+ // args [i] = argv[i].vstring()
+ unsafe { args_ << (&byte(argv[i])).vstring_literal() }
+ }
+ return args_
+}
+
+pub fn ls(path string) ?[]string {
+ mut res := []string{}
+ dir := unsafe { C.opendir(&char(path.str)) }
+ if isnil(dir) {
+ return error('ls() couldnt open dir "$path"')
+ }
+ mut ent := &C.dirent(0)
+ // mut ent := &C.dirent{!}
+ for {
+ ent = C.readdir(dir)
+ if isnil(ent) {
+ break
+ }
+ unsafe {
+ bptr := &byte(&ent.d_name[0])
+ if bptr[0] == 0 || (bptr[0] == `.` && bptr[1] == 0)
+ || (bptr[0] == `.` && bptr[1] == `.` && bptr[2] == 0) {
+ continue
+ }
+ res << tos_clone(bptr)
+ }
+ }
+ C.closedir(dir)
+ return res
+}
+
+/*
+pub fn is_dir(path string) bool {
+ //$if linux {
+ //C.syscall(4, path.str) // sys_newstat
+ //}
+ dir := C.opendir(path.str)
+ res := !isnil(dir)
+ if res {
+ C.closedir(dir)
+ }
+ return res
+}
+*/
+
+// mkdir creates a new directory with the specified path.
+pub fn mkdir(path string) ?bool {
+ if path == '.' {
+ return true
+ }
+ /*
+ mut k := 0
+ defer {
+ k = 1
+ }
+ */
+ apath := real_path(path)
+ // defer {
+ // apath.free()
+ //}
+ /*
+ $if linux {
+ $if !android {
+ ret := C.syscall(sys_mkdir, apath.str, 511)
+ if ret == -1 {
+ return error(posix_get_error_msg(C.errno))
+ }
+ return true
+ }
+ }
+ */
+ r := unsafe { C.mkdir(&char(apath.str), 511) }
+ if r == -1 {
+ return error(posix_get_error_msg(C.errno))
+ }
+ return true
+}
+
+// execute starts the specified command, waits for it to complete, and returns its output.
+[manualfree]
+pub fn execute(cmd string) Result {
+ // if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
+ // return Result{ exit_code: -1, output: ';, &&, || and \\n are not allowed in shell commands' }
+ // }
+ pcmd := if cmd.contains('2>') { cmd } else { '$cmd 2>&1' }
+ f := vpopen(pcmd)
+ if isnil(f) {
+ return Result{
+ exit_code: -1
+ output: 'exec("$cmd") failed'
+ }
+ }
+ buf := unsafe { malloc_noscan(4096) }
+ mut res := strings.new_builder(1024)
+ defer {
+ unsafe { res.free() }
+ }
+ unsafe {
+ bufbp := buf
+ for C.fgets(&char(bufbp), 4096, f) != 0 {
+ buflen := vstrlen(bufbp)
+ res.write_ptr(bufbp, buflen)
+ }
+ }
+ soutput := res.str()
+ exit_code := vpclose(f)
+ unsafe { free(buf) }
+ return Result{
+ exit_code: exit_code
+ output: soutput
+ }
+}
+
+pub struct Command {
+mut:
+ f voidptr
+pub mut:
+ eof bool
+pub:
+ path string
+ redirect_stdout bool
+}
+
+[manualfree]
+pub fn (mut c Command) start() ? {
+ pcmd := c.path + ' 2>&1'
+ defer {
+ unsafe { pcmd.free() }
+ }
+ c.f = vpopen(pcmd)
+ if isnil(c.f) {
+ return error('exec("$c.path") failed')
+ }
+}
+
+[manualfree]
+pub fn (mut c Command) read_line() string {
+ buf := [4096]byte{}
+ mut res := strings.new_builder(1024)
+ defer {
+ unsafe { res.free() }
+ }
+ unsafe {
+ bufbp := &buf[0]
+ for C.fgets(&char(bufbp), 4096, c.f) != 0 {
+ len := vstrlen(bufbp)
+ for i in 0 .. len {
+ if bufbp[i] == `\n` {
+ res.write_ptr(bufbp, i)
+ final := res.str()
+ return final
+ }
+ }
+ res.write_ptr(bufbp, len)
+ }
+ }
+ c.eof = true
+ final := res.str()
+ return final
+}
+
+pub fn (c &Command) close() ? {
+ exit_code := vpclose(c.f)
+ if exit_code == 127 {
+ return error_with_code('error', 127)
+ }
+}
+
+pub fn symlink(origin string, target string) ?bool {
+ res := C.symlink(&char(origin.str), &char(target.str))
+ if res == 0 {
+ return true
+ }
+ return error(posix_get_error_msg(C.errno))
+}
+
+pub fn link(origin string, target string) ?bool {
+ res := C.link(&char(origin.str), &char(target.str))
+ if res == 0 {
+ return true
+ }
+ return error(posix_get_error_msg(C.errno))
+}
+
+// get_error_msg return error code representation in string.
+pub fn get_error_msg(code int) string {
+ return posix_get_error_msg(code)
+}
+
+pub fn (mut f File) close() {
+ if !f.is_opened {
+ return
+ }
+ f.is_opened = false
+ /*
+ $if linux {
+ $if !android {
+ C.syscall(sys_close, f.fd)
+ return
+ }
+ }
+ */
+ C.fflush(f.cfile)
+ C.fclose(f.cfile)
+}
+
+[inline]
+pub fn debugger_present() bool {
+ // check if the parent could trace its process,
+ // if not a debugger must be present
+ $if linux {
+ return C.ptrace(C.PTRACE_TRACEME, 0, 1, 0) == -1
+ } $else $if macos {
+ return C.ptrace(C.PT_TRACE_ME, 0, voidptr(1), 0) == -1
+ }
+ return false
+}
+
+fn C.mkstemp(stemplate &byte) int
+
+// `is_writable_folder` - `folder` exists and is writable to the process
+pub fn is_writable_folder(folder string) ?bool {
+ if !exists(folder) {
+ return error('`$folder` does not exist')
+ }
+ if !is_dir(folder) {
+ return error('`folder` is not a folder')
+ }
+ tmp_perm_check := join_path(folder, 'XXXXXX')
+ unsafe {
+ x := C.mkstemp(&char(tmp_perm_check.str))
+ if -1 == x {
+ return error('folder `$folder` is not writable')
+ }
+ C.close(x)
+ }
+ rm(tmp_perm_check) ?
+ return true
+}
+
+[inline]
+pub fn getpid() int {
+ return C.getpid()
+}
+
+[inline]
+pub fn getppid() int {
+ return C.getppid()
+}
+
+[inline]
+pub fn getuid() int {
+ return C.getuid()
+}
+
+[inline]
+pub fn geteuid() int {
+ return C.geteuid()
+}
+
+[inline]
+pub fn getgid() int {
+ return C.getgid()
+}
+
+[inline]
+pub fn getegid() int {
+ return C.getegid()
+}
+
+// Turns the given bit on or off, depending on the `enable` parameter
+pub fn posix_set_permission_bit(path_s string, mode u32, enable bool) {
+ mut s := C.stat{}
+ mut new_mode := u32(0)
+ path := &char(path_s.str)
+ unsafe {
+ C.stat(path, &s)
+ new_mode = s.st_mode
+ }
+ match enable {
+ true { new_mode |= mode }
+ false { new_mode &= (0o7777 - mode) }
+ }
+ C.chmod(path, int(new_mode))
+}