# More Go


Still learning and playing with [Go](http://www.golang.org), I've
rewritten my 
[cat experiment](/2009/november/18/cat_in_go/index.html), to
use a `*bufio.Reader`, which is more correct I think. I'm also slowly
wrapping my mind around the concept of
[Interfaces](http://golang.org/doc/go_spec.html#Interface_types). As a
non-OO programmer (C and non-OO Perl) is starting to see why this is
useful.

So today's exercises:

1. Write a cat implementation in Go. See below.
2. Write a grep implementation in Go. See below. 


# Cat in go

    package main

    // A implementation of cat in Go

    import (
	    "os";
	    "fmt";
	    "bufio";
	    "flag";
    )

    var numberFlag = flag.Bool("n", false, "number each line")

    func cat(r *bufio.Reader) bool {
	    i := 1;
	    for {
		    buf, e := r.ReadBytes('\n');
		    if e == os.EOF {
			    break
		    }
		    if *numberFlag {
			    fmt.Fprintf(os.Stdout, "%5d  %s", i, buf);
			    i++
		    } else {
			    fmt.Fprintf(os.Stdout, "%s", buf)
		    }
	    }
	    return true;
    }

    func main() {
	    flag.Parse();
	    if flag.NArg() == 0 {
		    cat(bufio.NewReader(os.Stdin))
	    }
	    for i := 0; i < flag.NArg(); i++ {
		    f, e := os.Open(flag.Arg(i), os.O_RDONLY, 0);
		    if e != nil {
			    fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
				    os.Args[0], flag.Arg(i), e.String());
			    continue;
		    }
		    if !cat(bufio.NewReader(f)) {
			    os.Exit(1)
		    }
	    }
    }


# Grep in go

    package main

    // A implementation of Unix grep in Go
    // TODO(mg) better error handling

    import (
	    "os";
	    "fmt";
	    "bufio";
	    "regexp";
	    "flag";
    )

    var numberFlag = flag.Bool("n", false, "number each line")
    var filenameFlag = flag.Bool("l", false, "print names of matching files")

    func grep(r *bufio.Reader, reg string) (match bool) {
	    i := 0;
	    for {
		    buf, e := r.ReadBytes('\n');
		    i++;
		    if e == os.EOF {
			    break
		    }
		    if m, _ := regexp.Match(reg, buf); m == true {
			    match = true;
			    if *filenameFlag {
				    return match
			    }
			    if *numberFlag {
				    fmt.Fprintf(os.Stdout, "%5.d:  %s", i, buf)
			    } else {
				    fmt.Fprintf(os.Stdout, "%s", buf)
			    }
		    }
	    }
	    return match;
    }

    func main() {
	    flag.Parse();
	    if flag.NArg() < 1 {
		    fmt.Fprintf(os.Stderr, "%s: missing regexp\n", os.Args[0]);
		    os.Exit(1);
	    }
	    if flag.NArg() == 1 {
		    if grep(bufio.NewReader(os.Stdin), flag.Arg(0)) {
			    if *filenameFlag {
				    fmt.Fprintf(os.Stdout, "(standard input)\n");
			    }
		    }
	    }
	    for i := 1; i < flag.NArg(); i++ {
		    f, e := os.Open(flag.Arg(i), os.O_RDONLY, 0);
		    if e != nil {
			    fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
				    os.Args[0], flag.Arg(i), e.String());
			    continue;
		    }
		    if grep(bufio.NewReader(f), flag.Arg(0)) {
			    if *filenameFlag {
				    fmt.Fprintf(os.Stdout, "%s\n", flag.Arg(i))
			    }
		    }
	    }
    }


