1
0
mirror of https://github.com/golang/go synced 2024-11-23 04:00:03 -07:00
go/usr/gri/pretty/template.go
Robert Griesemer ec77e75e5d daily snapshot:
- various parser fixes to match updated spec (&&, &^=, label decls, const decls)
- using html template for directory and error page in doc server
- show compile errors inplace in the source
- cleanups

R=rsc
OCL=26287
CL=26287
2009-03-13 16:59:51 -07:00

124 lines
2.3 KiB
Go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package template
import (
"os";
"io";
)
type Template struct {
template []byte;
}
func (T *Template) Init(filename string) *os.Error {
f, err0 := os.Open(filename, os.O_RDONLY, 0);
defer f.Close();
if err0 != nil {
return err0;
}
var buf io.ByteBuffer;
len, err1 := io.Copy(f, &buf);
if err1 == io.ErrEOF {
err1 = nil;
}
if err1 != nil {
return err1;
}
T.template = buf.Data();
return nil;
}
// Returns true if buf starts with s, returns false otherwise.
//
func match(buf []byte, s string) bool {
if len(buf) < len(s) {
return false;
}
for i := 0; i < len(s); i++ {
if buf[i] != s[i] {
return false;
}
}
return true;
}
// Find the position of string s in buf, starting at i.
// Returns a value < 0 if not found.
//
func find(buf []byte, s string, i int) int {
if s == "" {
return i;
}
L: for ; i + len(s) <= len(buf); i++ {
for k := 0; k < len(s); k++ {
if buf[i+k] != s[k] {
continue L;
}
}
return i;
}
return -1
}
type Substitution map [string] func()
func (T *Template) Apply(w io.Write, prefix string, subs Substitution) *os.Error {
i0 := 0; // position from which to write from the template
i1 := 0; // position from which to look for the next prefix
for {
// look for a prefix
i2 := find(T.template, prefix, i1); // position of prefix, if any
if i2 < 0 {
// no prefix found, we are done
break;
}
// we have a prefix, look for a matching key
i1 = i2 + len(prefix);
for key, action := range subs {
if match(T.template[i1 : len(T.template)], key) {
// found a match
i1 += len(key); // next search starting pos
len, err := w.Write(T.template[i0 : i2]); // TODO handle errors
i0 = i1; // skip placeholder
action();
break;
}
}
}
// write the rest of the template
len, err := w.Write(T.template[i0 : len(T.template)]); // TODO handle errors
return err;
}
func NewTemplate(filename string) *Template {
t := new(Template);
if t.Init(filename) != nil {
return nil;
}
return t;
}
func NewTemplateOrDie(filename string) *Template {
t := NewTemplate(filename);
if t == nil {
panic("could not read template");
}
return t;
}