// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // builtin-os-file.go package expr import ( "fmt" "io" "git.portale-stac.it/go-pkg/expr/file" "git.portale-stac.it/go-pkg/expr/kern" ) const ( osLimitCh = "limitCh" ) func errMissingFilePath(funcName string) error { return fmt.Errorf("%s(): missing or invalid file path", funcName) } func errInvalidFileHandle(funcName string, v any) error { if v != nil { return fmt.Errorf("%s(): invalid file handle %v [%T]", funcName, v, v) } else { return fmt.Errorf("%s(): invalid file handle", funcName) } } func openFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 { // var fh *os.File // if fh, err = os.Open(filePath); err == nil { // result = file.NewReader(fh) // } result, err = file.OpenReader(filePath) } else { err = errMissingFilePath(name) } return } func createFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 { // var fh *os.File // if fh, err = os.Create(filePath); err == nil { // result = file.NewWriter(fh) // } result, err = file.CreateWriter(filePath) } else { err = errMissingFilePath(name) } return } func appendFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 { // var fh *os.File // if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0660); err == nil { // result = file.NewWriter(fh) // } result, err = file.AppendWriter(filePath) } else { err = errMissingFilePath(name) } return } func closeFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle file.Handle var invalidFileHandle any var ok bool if handle, ok = args[kern.ParamHandle].(file.Handle); !ok { invalidFileHandle = args[kern.ParamHandle] } if handle != nil { if fh := handle.GetFile(); fh != nil { if w, ok := handle.(*file.Writer); ok { err = w.Flush() } if err == nil { err = fh.Close() } } } if err == nil && (handle == nil || invalidFileHandle != nil) { err = errInvalidFileHandle(name, handle) } result = err == nil return } func fileWriteTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle file.Handle var invalidFileHandle any var ok bool if handle, ok = args[kern.ParamHandle].(file.Handle); !ok { invalidFileHandle = args[kern.ParamHandle] } if handle != nil { if w, ok := handle.(*file.Writer); ok { if v, exists := args[kern.ParamItem]; exists { argv := v.([]any) // result, err = fmt.Fprint(w.writer, argv...) result, err = w.Write(argv...) } } else { invalidFileHandle = handle } } if err == nil && (handle == nil || invalidFileHandle != nil) { err = errInvalidFileHandle(name, invalidFileHandle) } return } func fileReadTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle file.Handle var invalidFileHandle any var ok bool result = nil if handle, ok = args[kern.ParamHandle].(file.Handle); !ok || args[kern.ParamHandle] == nil { invalidFileHandle = args[kern.ParamHandle] } if handle != nil { if r, ok := handle.(*file.Reader); ok { var limit byte = '\n' var v string if s, ok := args[osLimitCh].(string); ok && len(s) > 0 { limit = s[0] } v, err = r.ReadString(limit) if err == io.EOF { err = nil } if len(v) > 0 { if v[len(v)-1] == limit { result = v[0 : len(v)-1] } else { result = v } } } else { invalidFileHandle = handle } } if err == nil && (handle == nil || invalidFileHandle != nil) { err = errInvalidFileHandle(name, invalidFileHandle) } return } func fileReadTextAllFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle file.Handle var invalidFileHandle any var ok bool result = nil if handle, ok = args[kern.ParamHandle].(file.Handle); !ok || args[kern.ParamHandle] == nil { invalidFileHandle = args[kern.ParamHandle] } if handle != nil { if r, ok := handle.(*file.Reader); ok { var b []byte b, err = r.ReadAll() result = string(b) } else { invalidFileHandle = handle } } if err == nil && (handle == nil || invalidFileHandle != nil) { err = errInvalidFileHandle(name, invalidFileHandle) } return } func ImportOsFuncs(ctx kern.ExprContext) { ctx.RegisterFunc("fileOpen", kern.NewGolangFunctor(openFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamFilepath), }) ctx.RegisterFunc("fileAppend", kern.NewGolangFunctor(appendFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamFilepath), }) ctx.RegisterFunc("fileCreate", kern.NewGolangFunctor(createFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamFilepath), }) ctx.RegisterFunc("fileClose", kern.NewGolangFunctor(closeFileFunc), kern.TypeBoolean, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamHandle), }) ctx.RegisterFunc("fileWriteText", kern.NewGolangFunctor(fileWriteTextFunc), kern.TypeInt, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamHandle), kern.NewFuncParamFlagDef(kern.ParamItem, kern.PfDefault|kern.PfRepeat, ""), }) ctx.RegisterFunc("fileReadText", kern.NewGolangFunctor(fileReadTextFunc), kern.TypeString, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamHandle), kern.NewFuncParamFlagDef(osLimitCh, kern.PfDefault, "\n"), }) ctx.RegisterFunc("fileReadTextAll", kern.NewGolangFunctor(fileReadTextAllFunc), kern.TypeString, []kern.ExprFuncParam{ kern.NewFuncParam(kern.ParamHandle), }) ctx.RegisterFunc("fileLineIterator", kern.NewGolangFunctor(fileLineIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{ kern.NewFuncParam(paramHandleOrPath), }) ctx.RegisterFunc("fileByteIterator", kern.NewGolangFunctor(fileByteIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{ kern.NewFuncParam(paramHandleOrPath), }) } func init() { RegisterBuiltinModule("os.file", ImportOsFuncs, "Operating system file functions") }