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