2
3
Fork 0
A simple shell with simple goals https://git.rawtext.club/sloum/slosh
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

164 lines
3.0 KiB

package main
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"os/user"
"path/filepath"
"strconv"
"strings"
)
const (
str int = iota
path
command
pipe
redirect
)
type component struct {
value string
kind int
}
func HomeDir() string {
usr, _ := user.Current()
return usr.HomeDir
}
func isFilepath(p string) bool {
if strings.HasPrefix(p, "./") || strings.HasPrefix(p, "~") || strings.HasPrefix(p, "../") || strings.HasPrefix(p, "/") {
return true
}
wd, _ := os.Getwd()
_, err := os.Stat(filepath.Join(wd, p))
if err != nil {
return false
}
return true
}
func ExpandedAbsFilepath(p string) string {
if strings.HasPrefix(p, "~") {
if p == "~" || strings.HasPrefix(p, "~/") {
homedir, _ := os.UserHomeDir()
if len(p) <= 2 {
p = homedir
} else if len(p) > 2 {
p = filepath.Join(homedir, p[2:])
}
} else {
i := strings.IndexRune(p, '/')
var u string
var remainder string
if i < 0 {
u = p[1:]
remainder = ""
} else {
u = p[1:i]
remainder = p[i:]
}
usr, err := user.Lookup(u)
if err != nil {
p = filepath.Join("/home", u, remainder)
} else {
p = filepath.Join(usr.HomeDir, remainder)
}
}
} else if !strings.HasPrefix(p, "/") {
wd, _ := os.Getwd()
p = filepath.Join(wd, p)
}
path, _ := filepath.Abs(p)
return path
}
func Contains(needle string, haystack []string) bool {
var out bool
for _, x := range haystack {
if x == needle {
out = true
break
}
}
return out
}
// Make stderr work properly. It gets eaten up...
func Execute(output_buffer, error_buffer *bytes.Buffer, capture_output bool, stack ...*exec.Cmd) (err error) {
pipe_stack := make([]*io.PipeWriter, len(stack)-1)
i := 0
for ; i < len(stack)-1; i++ {
stdin_pipe, stdout_pipe := io.Pipe()
stack[i].Stdout = stdout_pipe
stack[i].Stderr = error_buffer
stack[i+1].Stdin = stdin_pipe
pipe_stack[i] = stdout_pipe
}
if capture_output {
stack[i].Stdout = output_buffer
stack[i].Stderr = error_buffer
} else {
stack[i].Stdout = os.Stdout
stack[i].Stderr = os.Stderr
}
return call(stack, pipe_stack)
}
func call(stack []*exec.Cmd, pipes []*io.PipeWriter) (err error) {
if stack[0].Process == nil {
if err = stack[0].Start(); err != nil {
os.Setenv("?", "1")
return err
}
}
if len(stack) > 1 {
if err = stack[1].Start(); err != nil {
os.Setenv("?", "1")
return err
}
defer func() {
if err == nil {
pipes[0].Close()
err = call(stack[1:], pipes[1:])
}
}()
}
e := stack[0].Wait()
os.Setenv("?", strconv.Itoa(stack[0].ProcessState.ExitCode()))
return e
}
func promptReplace(c rune, wd string) string {
switch c {
case 'u':
u, err := user.Current()
if err != nil || u.Name == "" {
return os.Getenv("USER")
} else {
return u.Name
}
case 'c':
return filepath.Base(wd)
case 'D':
return wd
case 'd':
s := strings.Split(wd, "/")
if len(s) > 4 {
return fmt.Sprintf("...%s", filepath.Join(s[len(s)-3:]...))
} else {
return wd
}
case 'h':
return Hostname
}
return fmt.Sprintf("%%%c", c)
}