src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/cli/examples/e3bc/bc/bc.go (about) 1 package bc 2 3 import ( 4 "io" 5 "log" 6 "os" 7 "os/exec" 8 ) 9 10 type Bc interface { 11 Exec(string) error 12 Quit() 13 } 14 15 type bc struct { 16 cmd *exec.Cmd 17 stdin io.WriteCloser 18 stdout io.ReadCloser 19 } 20 21 func Start() Bc { 22 cmd := exec.Command("bc") 23 stdin, err := cmd.StdinPipe() 24 if err != nil { 25 log.Fatal(err) 26 } 27 stdout, err := cmd.StdoutPipe() 28 if err != nil { 29 log.Fatal(err) 30 } 31 cmd.Stderr = os.Stderr 32 cmd.Start() 33 return &bc{cmd, stdin, stdout} 34 } 35 36 // TODO: Use a more robust marker 37 var inputSuffix = []byte("\n\"\x04\"\n") 38 39 func (bc *bc) Exec(code string) error { 40 bc.stdin.Write([]byte(code)) 41 bc.stdin.Write(inputSuffix) 42 for { 43 b, err := readByte(bc.stdout) 44 if err != nil { 45 return err 46 } 47 if b == 0x04 { 48 break 49 } 50 os.Stdout.Write([]byte{b}) 51 } 52 return nil 53 } 54 55 func readByte(r io.Reader) (byte, error) { 56 var buf [1]byte 57 _, err := r.Read(buf[:]) 58 if err != nil { 59 return 0, err 60 } 61 return buf[0], nil 62 } 63 64 func (bc *bc) Quit() { 65 bc.stdin.Close() 66 bc.cmd.Wait() 67 bc.stdout.Close() 68 }