Skip to content

Instantly share code, notes, and snippets.

@as
Created July 8, 2018 08:00
Show Gist options
  • Save as/83d272f1097f0e2a2489b0ee470b45ed to your computer and use it in GitHub Desktop.
Save as/83d272f1097f0e2a2489b0ee470b45ed to your computer and use it in GitHub Desktop.
Go: Using standard I/O, or "Portable Inter-process Communication without Berkeley"
// With no arguments, this program starts the launcher. For every line read from standard input,
// the launcher executes a second copy of itself with in 'calc' mode, and writes the line of input
// to that second process. The 'calc' process parses the data into a simple arithmetic expression
// and evaluates it. Then it writes the successful result back to the launcher, which prints it to
// the standard output or standard error. The calc process is launched once for every line of input
// typed by the user. This is intentional. The more optimal approach would be to run calc only once.
//
// go build pipes.go && pipes
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
"os/exec"
"time"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "calc" {
calc()
} else {
launcher()
}
}
func launcher() {
sc := bufio.NewScanner(os.Stdin)
self, _ := os.Executable()
for sc.Scan() {
func() {
cmd := exec.Command(self, "calc")
cmd.Stderr = os.Stderr
rc, _ := cmd.StdoutPipe()
wc, _ := cmd.StdinPipe()
defer wc.Close()
finread := make(chan bool)
go func() {
defer rc.Close()
fmt.Print("from calc process: ")
io.Copy(os.Stdout, rc)
close(finread)
}()
cmd.Start()
defer cmd.Wait()
fmt.Fprintln(wc, sc.Text())
<-finread
}()
}
}
func calc() {
var (
a, b int
op byte
)
go func() {
time.Sleep(time.Second)
fmt.Println("timeout")
os.Exit(1)
}()
_, err := fmt.Fscanf(os.Stdin, "%d%c%d\n", &a, &op, &b)
if err != nil {
fmt.Println(err)
return
}
switch op {
case '+':
fmt.Println(a + b)
case '-':
fmt.Println(a - b)
case '/':
if b == 0 {
fmt.Println("zero denominator: %d%c%d", a, op, b)
} else {
fmt.Println(a / b)
}
case '%':
if b == 0 {
log.Fatalf("zero denominator: %d%c%d", a, op, b)
} else {
fmt.Println(a % b)
}
case '=':
fmt.Println(a == b)
default:
fmt.Println("bad op: %q", op)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment