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 }