/* SHS: Syntactically Homogeneous Shell * Copyright (C) 2019 Aidan Hahn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package stdlib import ( "os" "fmt" "bytes" "os/exec" "git.callpipe.com/aidan/shs/ast" "git.callpipe.com/aidan/shs/log" ) var bgProcs = make([]*exec.Cmd, 0) func call(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { if in == nil { return nil } path, err := exec.LookPath(in.Inner.(string)) if err != nil { log.Log(log.ERR, "Couldnt exec " + in.Inner.(string) + ", file not found", "call") return nil } args := []string{} for i := in.Next; i != nil; i = i.Next { if i.Tag == ast.LIST { log.Log(log.ERR, "Couldnt exec " + path + ", element in arguments is a list", "call") return nil } args = append(args, i.Inner.(string)) } var cmd *exec.Cmd if len(args) > 0 { cmd = exec.Command(path, args...) } else { cmd = exec.Command(path) } cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin exit := 0 err = cmd.Run() if err != nil { if exitError, ok := err.(*exec.ExitError); ok { exit = exitError.ExitCode() } else { log.Log(log.ERR, "Execution step returned unparsable error: " + err.Error(), "call") } } return &ast.Token{Tag: ast.NUMBER, Inner: fmt.Sprintf("%d", exit)} } func bgcall(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { if in == nil { return nil } path, err := exec.LookPath(in.Inner.(string)) if err != nil { log.Log(log.ERR, "Couldnt exec " + in.Inner.(string) + ", file not found", "call") return nil } args := []string{} for i := in.Next; i != nil; i = i.Next { if i.Tag == ast.LIST { log.Log(log.ERR, "Couldnt exec " + path + ", element in arguments is a list", "call") return nil } args = append(args, i.Inner.(string)) } var cmd *exec.Cmd if len(args) > 0 { cmd = exec.Command(path, args...) } else { cmd = exec.Command(path) } cmd.Stderr = os.Stderr bgProcs = append(bgProcs, cmd) cmd.Start() return nil } func fg(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { if len(bgProcs) < 1 { return nil } cmd := bgProcs[0] bgProcs = bgProcs[1:] cmd.Stdout = os.Stdout cmd.Stdin = os.Stdin exit := 0 err := cmd.Wait() if err != nil { if exitError, ok := err.(*exec.ExitError); ok { exit = exitError.ExitCode() } else { log.Log(log.ERR, "Execution step returned unparsable error: " + err.Error(), "call") } } return &ast.Token{Tag: ast.NUMBER, Inner: fmt.Sprintf("%d", exit)} } func read_cmd(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { if in == nil { return nil } var out bytes.Buffer path, err := exec.LookPath(in.Inner.(string)) if err != nil { log.Log(log.ERR, "Couldnt exec " + in.Inner.(string) + ", file not found", "call") return nil } args := []string{} for i := in.Next; i != nil; i = i.Next { if i.Tag == ast.LIST { log.Log(log.ERR, "Couldnt exec " + path + ", element in arguments is a list", "call") return nil } args = append(args, i.Inner.(string)) } var cmd *exec.Cmd if len(args) > 0 { cmd = exec.Command(path, args...) } else { cmd = exec.Command(path) } cmd.Stdout = &out cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin err = cmd.Run() if err != nil { log.Log(log.ERR, err.Error(), "$") } return &ast.Token{Tag: ast.STRING, Inner: out.String()} }