bc.go 992 B

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