- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline - Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch - RTL: 351 Harbour-compatible functions - RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization - Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec) - HB_FUNC API: Full Harbour C API compatible Go bridge - Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT - Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST - Macro Compiler: Runtime AST parsing and evaluation - Debugger: TUI debugger with source display, breakpoints, stepping - FRB: Native + Pcode dual mode runtime binary - Tests: 13 packages ALL PASS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
156 lines
3.2 KiB
Go
156 lines
3.2 KiB
Go
// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
|
// All rights reserved.
|
|
|
|
// OS/Environment functions: GETENV, HB_GETENV, OS, VERSION, HB_RUN,
|
|
// HB_PROCESSOPEN, HB_FNAMEDIR, HB_FNAMEEXT, HB_FNAMENAME
|
|
|
|
package hbrtl
|
|
|
|
import (
|
|
"five/hbrt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// GETENV(cVarName [, cDefault]) → cValue
|
|
func GetEnv(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
name := t.Local(1).AsString()
|
|
val := os.Getenv(name)
|
|
if val == "" && nParams >= 2 && !t.Local(2).IsNil() {
|
|
val = t.Local(2).AsString()
|
|
}
|
|
t.RetString(val)
|
|
}
|
|
|
|
// HB_GETENV(cVarName [, cDefault]) → cValue (alias)
|
|
func HbGetEnv(t *hbrt.Thread) {
|
|
GetEnv(t)
|
|
}
|
|
|
|
// SETENV(cVarName, cValue) → lSuccess
|
|
func SetEnvFunc(t *hbrt.Thread) {
|
|
t.Frame(2, 0)
|
|
defer t.EndProc()
|
|
name := t.Local(1).AsString()
|
|
val := t.Local(2).AsString()
|
|
err := os.Setenv(name, val)
|
|
t.RetBool(err == nil)
|
|
}
|
|
|
|
// OS() → cOSDescription
|
|
func OSFunc(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
t.RetString(runtime.GOOS + "/" + runtime.GOARCH)
|
|
}
|
|
|
|
// VERSION() → cVersion
|
|
func VersionFunc(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
t.RetString("Five 1.0.0 (Go " + runtime.Version() + ")")
|
|
}
|
|
|
|
// HB_RUN(cCommand) → nExitCode
|
|
// Runs an external command via shell.
|
|
func HbRun(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
|
|
cmdStr := t.Local(1).AsString()
|
|
var cmd *exec.Cmd
|
|
if runtime.GOOS == "windows" {
|
|
cmd = exec.Command("cmd", "/c", cmdStr)
|
|
} else {
|
|
cmd = exec.Command("sh", "-c", cmdStr)
|
|
}
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
cmd.Stdin = os.Stdin
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
t.RetInt(int64(exitErr.ExitCode()))
|
|
return
|
|
}
|
|
t.RetInt(-1)
|
|
return
|
|
}
|
|
t.RetInt(0)
|
|
}
|
|
|
|
// HB_FNAMEDIR(cFilePath) → cDir
|
|
func HbFNameDir(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
t.RetString(filepath.Dir(t.Local(1).AsString()) + string(filepath.Separator))
|
|
}
|
|
|
|
// HB_FNAMEEXT(cFilePath) → cExt (including dot)
|
|
func HbFNameExt(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
t.RetString(filepath.Ext(t.Local(1).AsString()))
|
|
}
|
|
|
|
// HB_FNAMENAME(cFilePath) → cName (without dir and ext)
|
|
func HbFNameName(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
name := filepath.Base(t.Local(1).AsString())
|
|
ext := filepath.Ext(name)
|
|
t.RetString(strings.TrimSuffix(name, ext))
|
|
}
|
|
|
|
// HB_FNAMEMERGE(cDir, cName, cExt) → cFilePath
|
|
func HbFNameMerge(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
dir := ""
|
|
name := ""
|
|
ext := ""
|
|
if nParams >= 1 {
|
|
dir = t.Local(1).AsString()
|
|
}
|
|
if nParams >= 2 {
|
|
name = t.Local(2).AsString()
|
|
}
|
|
if nParams >= 3 {
|
|
ext = t.Local(3).AsString()
|
|
}
|
|
t.RetString(filepath.Join(dir, name+ext))
|
|
}
|
|
|
|
// DIRMAKE(cPath) → nResult (0=success)
|
|
func DirMake(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
err := os.MkdirAll(t.Local(1).AsString(), 0755)
|
|
if err != nil {
|
|
t.RetInt(-1)
|
|
return
|
|
}
|
|
t.RetInt(0)
|
|
}
|
|
|
|
// DIRREMOVE(cPath) → nResult (0=success)
|
|
func DirRemove(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
err := os.Remove(t.Local(1).AsString())
|
|
if err != nil {
|
|
t.RetInt(-1)
|
|
return
|
|
}
|
|
t.RetInt(0)
|
|
}
|