OSDN Git Service

libgo: Update to weekly.2011-12-06.
[pf3gnuchains/gcc-fork.git] / libgo / go / html / template / template.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package template
6
7 import (
8         "fmt"
9         "io"
10         "io/ioutil"
11         "path/filepath"
12         "sync"
13         "text/template"
14         "text/template/parse"
15 )
16
17 // Template is a specialized template.Template that produces a safe HTML
18 // document fragment.
19 type Template struct {
20         escaped bool
21         // We could embed the text/template field, but it's safer not to because
22         // we need to keep our version of the name space and the underlying
23         // template's in sync.
24         text       *template.Template
25         *nameSpace // common to all associated templates
26 }
27
28 // nameSpace is the data structure shared by all templates in an association.
29 type nameSpace struct {
30         mu  sync.Mutex
31         set map[string]*Template
32 }
33
34 // Execute applies a parsed template to the specified data object,
35 // writing the output to wr.
36 func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
37         t.nameSpace.mu.Lock()
38         if !t.escaped {
39                 if err = escapeTemplates(t, t.Name()); err != nil {
40                         t.escaped = true
41                 }
42         }
43         t.nameSpace.mu.Unlock()
44         if err != nil {
45                 return
46         }
47         return t.text.Execute(wr, data)
48 }
49
50 // ExecuteTemplate applies the template associated with t that has the given
51 // name to the specified data object and writes the output to wr.
52 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) (err error) {
53         t.nameSpace.mu.Lock()
54         tmpl := t.set[name]
55         if (tmpl == nil) != (t.text.Lookup(name) == nil) {
56                 panic("html/template internal error: template escaping out of sync")
57         }
58         if tmpl != nil && !tmpl.escaped {
59                 err = escapeTemplates(tmpl, name)
60         }
61         t.nameSpace.mu.Unlock()
62         if err != nil {
63                 return
64         }
65         return t.text.ExecuteTemplate(wr, name, data)
66 }
67
68 // Parse parses a string into a template. Nested template definitions
69 // will be associated with the top-level template t. Parse may be
70 // called multiple times to parse definitions of templates to associate
71 // with t. It is an error if a resulting template is non-empty (contains
72 // content other than template definitions) and would replace a
73 // non-empty template with the same name.  (In multiple calls to Parse
74 // with the same receiver template, only one call can contain text
75 // other than space, comments, and template definitions.)
76 func (t *Template) Parse(src string) (*Template, error) {
77         t.nameSpace.mu.Lock()
78         t.escaped = false
79         t.nameSpace.mu.Unlock()
80         ret, err := t.text.Parse(src)
81         if err != nil {
82                 return nil, err
83         }
84         // In general, all the named templates might have changed underfoot.
85         // Regardless, some new ones may have been defined.
86         // The template.Template set has been updated; update ours.
87         t.nameSpace.mu.Lock()
88         defer t.nameSpace.mu.Unlock()
89         for _, v := range ret.Templates() {
90                 name := v.Name()
91                 tmpl := t.set[name]
92                 if tmpl == nil {
93                         tmpl = t.new(name)
94                 }
95                 tmpl.escaped = false
96                 tmpl.text = v
97         }
98         return t, nil
99 }
100
101 // AddParseTree is unimplemented.
102 func (t *Template) AddParseTree(name string, tree *parse.Tree) error {
103         return fmt.Errorf("html/template: AddParseTree unimplemented")
104 }
105
106 // Clone is unimplemented.
107 func (t *Template) Clone(name string) error {
108         return fmt.Errorf("html/template: Clone unimplemented")
109 }
110
111 // New allocates a new HTML template with the given name.
112 func New(name string) *Template {
113         tmpl := &Template{
114                 false,
115                 template.New(name),
116                 &nameSpace{
117                         set: make(map[string]*Template),
118                 },
119         }
120         tmpl.set[name] = tmpl
121         return tmpl
122 }
123
124 // New allocates a new HTML template associated with the given one
125 // and with the same delimiters. The association, which is transitive,
126 // allows one template to invoke another with a {{template}} action.
127 func (t *Template) New(name string) *Template {
128         t.nameSpace.mu.Lock()
129         defer t.nameSpace.mu.Unlock()
130         return t.new(name)
131 }
132
133 // new is the implementation of New, without the lock.
134 func (t *Template) new(name string) *Template {
135         tmpl := &Template{
136                 false,
137                 t.text.New(name),
138                 t.nameSpace,
139         }
140         tmpl.set[name] = tmpl
141         return tmpl
142 }
143
144 // Name returns the name of the template.
145 func (t *Template) Name() string {
146         return t.text.Name()
147 }
148
149 // Funcs adds the elements of the argument map to the template's function map.
150 // It panics if a value in the map is not a function with appropriate return
151 // type. However, it is legal to overwrite elements of the map. The return
152 // value is the template, so calls can be chained.
153 func (t *Template) Funcs(funcMap template.FuncMap) *Template {
154         t.text.Funcs(funcMap)
155         return t
156 }
157
158 // Delims sets the action delimiters to the specified strings, to be used in
159 // subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
160 // definitions will inherit the settings. An empty delimiter stands for the
161 // corresponding default: {{ or }}.
162 // The return value is the template, so calls can be chained.
163 func (t *Template) Delims(left, right string) *Template {
164         t.text.Delims(left, right)
165         return t
166 }
167
168 // Lookup returns the template with the given name that is associated with t,
169 // or nil if there is no such template.
170 func (t *Template) Lookup(name string) *Template {
171         t.nameSpace.mu.Lock()
172         defer t.nameSpace.mu.Unlock()
173         return t.set[name]
174 }
175
176 // Must panics if err is non-nil in the same way as template.Must.
177 func Must(t *Template, err error) *Template {
178         t.text = template.Must(t.text, err)
179         return t
180 }
181
182 // ParseFiles creates a new Template and parses the template definitions from
183 // the named files. The returned template's name will have the (base) name and
184 // (parsed) contents of the first file. There must be at least one file.
185 // If an error occurs, parsing stops and the returned *Template is nil.
186 func ParseFiles(filenames ...string) (*Template, error) {
187         return parseFiles(nil, filenames...)
188 }
189
190 // ParseFiles parses the named files and associates the resulting templates with
191 // t. If an error occurs, parsing stops and the returned template is nil;
192 // otherwise it is t. There must be at least one file.
193 func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
194         return parseFiles(t, filenames...)
195 }
196
197 // parseFiles is the helper for the method and function. If the argument
198 // template is nil, it is created from the first file.
199 func parseFiles(t *Template, filenames ...string) (*Template, error) {
200         if len(filenames) == 0 {
201                 // Not really a problem, but be consistent.
202                 return nil, fmt.Errorf("template: no files named in call to ParseFiles")
203         }
204         for _, filename := range filenames {
205                 b, err := ioutil.ReadFile(filename)
206                 if err != nil {
207                         return nil, err
208                 }
209                 s := string(b)
210                 name := filepath.Base(filename)
211                 // First template becomes return value if not already defined,
212                 // and we use that one for subsequent New calls to associate
213                 // all the templates together. Also, if this file has the same name
214                 // as t, this file becomes the contents of t, so
215                 //  t, err := New(name).Funcs(xxx).ParseFiles(name)
216                 // works. Otherwise we create a new template associated with t.
217                 var tmpl *Template
218                 if t == nil {
219                         t = New(name)
220                 }
221                 if name == t.Name() {
222                         tmpl = t
223                 } else {
224                         tmpl = t.New(name)
225                 }
226                 _, err = tmpl.Parse(s)
227                 if err != nil {
228                         return nil, err
229                 }
230         }
231         return t, nil
232 }
233
234 // ParseGlob creates a new Template and parses the template definitions from the
235 // files identified by the pattern, which must match at least one file. The
236 // returned template will have the (base) name and (parsed) contents of the
237 // first file matched by the pattern. ParseGlob is equivalent to calling
238 // ParseFiles with the list of files matched by the pattern.
239 func ParseGlob(pattern string) (*Template, error) {
240         return parseGlob(nil, pattern)
241 }
242
243 // ParseGlob parses the template definitions in the files identified by the
244 // pattern and associates the resulting templates with t. The pattern is
245 // processed by filepath.Glob and must match at least one file. ParseGlob is
246 // equivalent to calling t.ParseFiles with the list of files matched by the
247 // pattern.
248 func (t *Template) ParseGlob(pattern string) (*Template, error) {
249         return parseGlob(t, pattern)
250 }
251
252 // parseGlob is the implementation of the function and method ParseGlob.
253 func parseGlob(t *Template, pattern string) (*Template, error) {
254         filenames, err := filepath.Glob(pattern)
255         if err != nil {
256                 return nil, err
257         }
258         if len(filenames) == 0 {
259                 return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
260         }
261         return parseFiles(t, filenames...)
262 }