2025-07-17 12:22:04 -05:00

433 lines
7.7 KiB
Go

package fs
import (
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"time"
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
)
func GetFunctionList() map[string]luajit.GoFunction {
return map[string]luajit.GoFunction{
"file_exists": file_exists,
"file_size": file_size,
"file_is_dir": file_is_dir,
"file_read": file_read,
"file_write": file_write,
"file_append": file_append,
"file_copy": file_copy,
"file_move": file_move,
"file_delete": file_delete,
"file_mtime": file_mtime,
"dir_create": dir_create,
"dir_remove": dir_remove,
"dir_list": dir_list,
"path_join": path_join,
"path_dir": path_dir,
"path_basename": path_basename,
"path_ext": path_ext,
"path_abs": path_abs,
"path_clean": path_clean,
"path_split": path_split,
"temp_file": temp_file,
"temp_dir": temp_dir,
"glob": glob,
"walk": walk,
"getcwd": getcwd,
"chdir": chdir,
"file_lines": file_lines,
"touch": touch,
}
}
func file_exists(s *luajit.State) int {
path := s.ToString(1)
_, err := os.Stat(path)
s.PushBoolean(err == nil)
return 1
}
func file_size(s *luajit.State) int {
path := s.ToString(1)
info, err := os.Stat(path)
if err != nil {
s.PushNumber(-1)
return 1
}
s.PushNumber(float64(info.Size()))
return 1
}
func file_is_dir(s *luajit.State) int {
path := s.ToString(1)
info, err := os.Stat(path)
if err != nil {
s.PushBoolean(false)
return 1
}
s.PushBoolean(info.IsDir())
return 1
}
func file_read(s *luajit.State) int {
path := s.ToString(1)
data, err := os.ReadFile(path)
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
s.PushString(string(data))
return 1
}
func file_write(s *luajit.State) int {
path := s.ToString(1)
content := s.ToString(2)
err := os.WriteFile(path, []byte(content), 0644)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func file_append(s *luajit.State) int {
path := s.ToString(1)
content := s.ToString(2)
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
defer file.Close()
_, err = file.WriteString(content)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func file_copy(s *luajit.State) int {
src := s.ToString(1)
dst := s.ToString(2)
srcFile, err := os.Open(src)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
defer srcFile.Close()
dstFile, err := os.Create(dst)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
defer dstFile.Close()
_, err = io.Copy(dstFile, srcFile)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func file_move(s *luajit.State) int {
src := s.ToString(1)
dst := s.ToString(2)
err := os.Rename(src, dst)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func file_delete(s *luajit.State) int {
path := s.ToString(1)
err := os.Remove(path)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func file_mtime(s *luajit.State) int {
path := s.ToString(1)
info, err := os.Stat(path)
if err != nil {
s.PushNumber(-1)
return 1
}
s.PushNumber(float64(info.ModTime().Unix()))
return 1
}
func dir_create(s *luajit.State) int {
path := s.ToString(1)
err := os.MkdirAll(path, 0755)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func dir_remove(s *luajit.State) int {
path := s.ToString(1)
err := os.RemoveAll(path)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func dir_list(s *luajit.State) int {
path := s.ToString(1)
entries, err := os.ReadDir(path)
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
s.CreateTable(len(entries), 0)
for i, entry := range entries {
s.PushNumber(float64(i + 1))
s.CreateTable(0, 4)
s.PushString("name")
s.PushString(entry.Name())
s.SetTable(-3)
s.PushString("is_dir")
s.PushBoolean(entry.IsDir())
s.SetTable(-3)
if info, err := entry.Info(); err == nil {
s.PushString("size")
s.PushNumber(float64(info.Size()))
s.SetTable(-3)
s.PushString("mtime")
s.PushNumber(float64(info.ModTime().Unix()))
s.SetTable(-3)
}
s.SetTable(-3)
}
return 1
}
func path_join(s *luajit.State) int {
var parts []string
for i := 1; i <= s.GetTop(); i++ {
parts = append(parts, s.ToString(i))
}
s.PushString(filepath.Join(parts...))
return 1
}
func path_dir(s *luajit.State) int {
path := s.ToString(1)
s.PushString(filepath.Dir(path))
return 1
}
func path_basename(s *luajit.State) int {
path := s.ToString(1)
s.PushString(filepath.Base(path))
return 1
}
func path_ext(s *luajit.State) int {
path := s.ToString(1)
s.PushString(filepath.Ext(path))
return 1
}
func path_abs(s *luajit.State) int {
path := s.ToString(1)
abs, err := filepath.Abs(path)
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
s.PushString(abs)
return 1
}
func path_clean(s *luajit.State) int {
path := s.ToString(1)
s.PushString(filepath.Clean(path))
return 1
}
func path_split(s *luajit.State) int {
path := s.ToString(1)
dir, file := filepath.Split(path)
s.PushString(dir)
s.PushString(file)
return 2
}
func temp_file(s *luajit.State) int {
var prefix string
if s.GetTop() >= 1 {
prefix = s.ToString(1)
}
file, err := os.CreateTemp("", prefix)
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
defer file.Close()
s.PushString(file.Name())
return 1
}
func temp_dir(s *luajit.State) int {
var prefix string
if s.GetTop() >= 1 {
prefix = s.ToString(1)
}
dir, err := os.MkdirTemp("", prefix)
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
s.PushString(dir)
return 1
}
func glob(s *luajit.State) int {
pattern := s.ToString(1)
matches, err := filepath.Glob(pattern)
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
s.PushValue(matches)
return 1
}
func walk(s *luajit.State) int {
root := s.ToString(1)
var files []string
err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return nil // Skip errors
}
files = append(files, path)
return nil
})
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
s.PushValue(files)
return 1
}
func getcwd(s *luajit.State) int {
cwd, err := os.Getwd()
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
s.PushString(cwd)
return 1
}
func chdir(s *luajit.State) int {
path := s.ToString(1)
err := os.Chdir(path)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}
func file_lines(s *luajit.State) int {
path := s.ToString(1)
data, err := os.ReadFile(path)
if err != nil {
s.PushNil()
s.PushString(err.Error())
return 2
}
lines := strings.Split(string(data), "\n")
// Remove empty last line if file ends with newline
if len(lines) > 0 && lines[len(lines)-1] == "" {
lines = lines[:len(lines)-1]
}
s.PushValue(lines)
return 1
}
func touch(s *luajit.State) int {
path := s.ToString(1)
now := time.Now()
err := os.Chtimes(path, now, now)
if os.IsNotExist(err) {
// Create file if it doesn't exist
file, err := os.Create(path)
if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
file.Close()
} else if err != nil {
s.PushBoolean(false)
s.PushString(err.Error())
return 2
}
s.PushBoolean(true)
return 1
}