mirror of
https://codeberg.org/scip/tablizer.git
synced 2025-12-18 13:01:11 +01:00
126 lines
2.9 KiB
Go
126 lines
2.9 KiB
Go
package zygo
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
var ShellCmd string = "/bin/bash"
|
|
|
|
func init() {
|
|
SetShellCmd()
|
|
}
|
|
|
|
// set ShellCmd as used by SystemFunction
|
|
func SetShellCmd() {
|
|
if runtime.GOOS == "windows" {
|
|
ShellCmd = os.Getenv("COMSPEC")
|
|
return
|
|
}
|
|
try := []string{"/usr/bin/bash"}
|
|
if !FileExists(ShellCmd) {
|
|
for i := range try {
|
|
b := try[i]
|
|
if FileExists(b) {
|
|
ShellCmd = b
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// sys is a builder. shell out, return the combined output.
|
|
func SystemBuilder(env *Zlisp, name string, args []Sexp) (Sexp, error) {
|
|
//P("SystemBuilder called with args='%#v'", args)
|
|
return SystemFunction(env, name, args)
|
|
}
|
|
|
|
func SystemFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
|
|
if len(args) == 0 {
|
|
return SexpNull, WrongNargs
|
|
}
|
|
|
|
flat, err := flattenToWordsHelper(args)
|
|
if err != nil {
|
|
return SexpNull, fmt.Errorf("flatten on '%#v' failed with error '%s'", args, err)
|
|
}
|
|
if len(flat) == 0 {
|
|
return SexpNull, WrongNargs
|
|
}
|
|
|
|
joined := strings.Join(flat, " ")
|
|
cmd := ShellCmd
|
|
|
|
var out []byte
|
|
if runtime.GOOS == "windows" {
|
|
out, err = exec.Command(cmd, "/c", joined).CombinedOutput()
|
|
} else {
|
|
out, err = exec.Command(cmd, "-c", joined).CombinedOutput()
|
|
}
|
|
if err != nil {
|
|
return SexpNull, fmt.Errorf("error from command: '%s'. Output:'%s'", err, string(Chomp(out)))
|
|
}
|
|
return &SexpStr{S: string(Chomp(out))}, nil
|
|
}
|
|
|
|
// given strings/lists of strings with possible whitespace
|
|
// flatten out to a array of SexpStr with no internal whitespace,
|
|
// suitable for passing along to (system) / exec.Command()
|
|
func FlattenToWordsFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
|
|
if len(args) == 0 {
|
|
return SexpNull, WrongNargs
|
|
}
|
|
stringArgs, err := flattenToWordsHelper(args)
|
|
if err != nil {
|
|
return SexpNull, err
|
|
}
|
|
|
|
// Now convert to []Sexp{SexpStr}
|
|
res := make([]Sexp, len(stringArgs))
|
|
for i := range stringArgs {
|
|
res[i] = &SexpStr{S: stringArgs[i]}
|
|
}
|
|
return env.NewSexpArray(res), nil
|
|
}
|
|
|
|
func flattenToWordsHelper(args []Sexp) ([]string, error) {
|
|
stringArgs := []string{}
|
|
|
|
for i := range args {
|
|
switch c := args[i].(type) {
|
|
case *SexpStr:
|
|
many := strings.Split(c.S, " ")
|
|
stringArgs = append(stringArgs, many...)
|
|
case *SexpSymbol:
|
|
stringArgs = append(stringArgs, c.name)
|
|
case *SexpPair:
|
|
carry, err := ListToArray(c)
|
|
if err != nil {
|
|
return []string{}, fmt.Errorf("tried to convert list of strings to array but failed with error '%s'. Input was type %T / val = '%#v'", err, c, c)
|
|
}
|
|
moreWords, err := flattenToWordsHelper(carry)
|
|
if err != nil {
|
|
return []string{}, err
|
|
}
|
|
stringArgs = append(stringArgs, moreWords...)
|
|
default:
|
|
return []string{}, fmt.Errorf("arguments to system must be strings; instead we have %T / val = '%#v'", c, c)
|
|
}
|
|
} // end i over args
|
|
// INVAR: stringArgs has our flattened list.
|
|
return stringArgs, nil
|
|
}
|
|
|
|
func Chomp(by []byte) []byte {
|
|
if len(by) > 0 {
|
|
n := len(by)
|
|
if by[n-1] == '\n' {
|
|
return by[:n-1]
|
|
}
|
|
}
|
|
return by
|
|
}
|