Index: /trunk/zs.go
===================================================================
--- /trunk/zs.go	(revision 4)
+++ /trunk/zs.go	(revision 5)
@@ -47,30 +47,28 @@
 
 func render(s string, vars map[string]string, eval EvalFn) (string, error) {
-	b := []byte(s)
-	delim_open := []byte("{{")
-	delim_close := []byte("}}")
+	delim_open := "{{"
+	delim_close := "}}"
 
 	out := bytes.NewBuffer(nil)
 	for {
-		if from := bytes.Index(b, delim_open); from == -1 {
-			out.Write(b)
+		if from := strings.Index(s, delim_open); from == -1 {
+			out.WriteString(s)
 			return out.String(), nil
 		} else {
-			to := bytes.Index(b, delim_close)
-			if to == -1 {
+			if to := strings.Index(s, delim_close); to == -1 {
 				return "", fmt.Errorf("Close delim not found")
 			} else {
-				out.Write(b[:from])
-				cmd := b[from+len(delim_open) : to]
-				b = b[to+len(delim_close):]
-				m := strings.Fields(string(cmd))
+				out.WriteString(s[:from])
+				cmd := s[from+len(delim_open) : to]
+				s = s[to+len(delim_close):]
+				m := strings.Fields(cmd)
 				if len(m) == 1 {
 					if v, ok := vars[m[0]]; ok {
-						out.Write([]byte(v))
+						out.WriteString(v)
 						continue
 					}
 				}
 				if res, err := eval(m, vars); err == nil {
-					out.Write([]byte(res))
+					out.WriteString(res)
 				} else {
 					log.Println(err) // silent
@@ -81,26 +79,42 @@
 }
 
-func eval(cmd []string, vars map[string]string) (string, error) {
-	var outbuf, errbuf bytes.Buffer
-	c := exec.Command(path.Join(ZSDIR, cmd[0]), cmd[1:]...)
+func env(vars map[string]string) []string {
 	env := []string{"ZS=" + os.Args[0]}
+	env = append(env, os.Environ()...)
 	for k, v := range vars {
 		env = append(env, "ZS_"+strings.ToUpper(k)+"="+v)
 	}
-	c.Env = append(c.Env, env...)
-	c.Stdout = &outbuf
+	return env
+}
+
+func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
+	var errbuf bytes.Buffer
+	c := exec.Command(cmd, args...)
+	c.Env = env(vars)
+	c.Stdout = output
 	c.Stderr = &errbuf
-	if err := c.Run(); err != nil {
-		log.Println(err)
-		c := exec.Command(path.Join(cmd[0]), cmd[1:]...)
-		c.Env = append(c.Env, env...)
-		c.Stdout = &outbuf
-		c.Stderr = &errbuf
-		if err := c.Run(); err != nil {
-			return "", err
-		}
-	}
+
+	err := c.Run()
+
 	if errbuf.Len() > 0 {
 		log.Println(errbuf.String())
+	}
+
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func eval(cmd []string, vars map[string]string) (string, error) {
+	outbuf := bytes.NewBuffer(nil)
+	err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
+	if err != nil {
+		log.Println(err)
+		outbuf = bytes.NewBuffer(nil)
+		err := run(cmd[0], cmd[1:], vars, outbuf)
+		if err != nil {
+			return "", err
+		}
 	}
 	return outbuf.String(), nil
@@ -248,9 +262,6 @@
 		}
 	default:
-		cmd := exec.Command(path.Join(ZSDIR, cmd), args...)
-		cmd.Env = append(cmd.Env, "ZS="+os.Args[0])
-		cmd.Stdout = os.Stdout
-		cmd.Stderr = os.Stderr
-		if err := cmd.Run(); err != nil {
+		err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
+		if err != nil {
 			log.Println(err)
 		}
Index: /trunk/zs_test.go
===================================================================
--- /trunk/zs_test.go	(revision 4)
+++ /trunk/zs_test.go	(revision 5)
@@ -1,5 +1,12 @@
 package main
 
-import "testing"
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"os"
+	"strings"
+	"testing"
+)
 
 func TestSplit2(t *testing.T) {
@@ -76,3 +83,51 @@
 		t.Error()
 	}
+	// Test error case
+	if s, err := render("a {{greet text ", vars, eval); err == nil || len(s) != 0 {
+		t.Error()
+	}
 }
+
+func TestEnv(t *testing.T) {
+	e := env(map[string]string{"foo": "bar", "baz": "hello world"})
+	mustHave := []string{"ZS=" + os.Args[0], "ZS_FOO=bar", "ZS_BAZ=hello world", "PATH="}
+	for _, s := range mustHave {
+		found := false
+		for _, v := range e {
+			if strings.HasPrefix(v, s) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			t.Error("Missing", s)
+		}
+	}
+}
+
+func TestRun(t *testing.T) {
+	out := bytes.NewBuffer(nil)
+	err := run("some_unbelievable_command_name", []string{}, map[string]string{}, out)
+	if err == nil {
+		t.Error()
+	}
+
+	out = bytes.NewBuffer(nil)
+	err = run(os.Args[0], []string{"-test.run=TestHelperProcess"},
+		map[string]string{"helper": "1", "out": "foo", "err": "bar"}, out)
+	if err != nil {
+		t.Error(err)
+	}
+	if out.String() != "foo\n" {
+		t.Error(out.String())
+	}
+}
+
+func TestHelperProcess(*testing.T) {
+	if os.Getenv("ZS_HELPER") != "1" {
+		return
+	}
+	defer os.Exit(0)                 // TODO check exit code
+	log.Println(os.Getenv("ZS_ERR")) // stderr
+	fmt.Println(os.Getenv("ZS_OUT")) // stdout
+}
