PageRenderTime 33ms CodeModel.GetById 14ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/util/util.go

https://code.google.com/p/gopages/
Go | 308 lines | 230 code | 31 blank | 47 comment | 48 complexity | 035b666809edcfee2b6189735b01705a MD5 | raw file
  1// Copyright 2010 Abiola Ibrahim <abiola89@gmail.com>. All rights reserved.
  2// Use of this source code is governed by New BSD License
  3// http://www.opensource.org/licenses/bsd-license.php
  4// The content and logo is governed by Creative Commons Attribution 3.0
  5// The mascott is a property of Go governed by Creative Commons Attribution 3.0
  6// http://creativecommons.org/licenses/by/3.0/
  7
  8package util
  9
 10import (
 11	"encoding/json"
 12	"errors"
 13	"io/ioutil"
 14	"os"
 15	"path"
 16	"strings"
 17)
 18
 19//StringBuilder type like StringBuilder in java
 20type StringBuilder struct {
 21	String string
 22}
 23
 24//Creates an instance of StringBuilder
 25func NewStringBuilder(s string) *StringBuilder {
 26	sBuilder := new(StringBuilder)
 27	sBuilder.String = s
 28	return sBuilder
 29}
 30
 31//Retrieves the string Content
 32func (this *StringBuilder) Content() string {
 33	return this.String
 34}
 35
 36//Appends string to the end of the string content
 37func (this *StringBuilder) Append(s string) {
 38	this.String = this.String + s
 39}
 40
 41//Deletes string from start index to end
 42func (this *StringBuilder) Delete(start, end int) {
 43	part1 := this.String[0:start]
 44	part2 := this.String[end:]
 45	this.String = part1 + part2
 46}
 47
 48//Deletes the remaining string from index start
 49func (this *StringBuilder) DeleteTillEnd(start int) {
 50	this.String = this.String[0:start]
 51}
 52
 53//Empties the string content
 54func (this *StringBuilder) Reset() {
 55	this.String = ""
 56}
 57
 58//Returns the index of the first occurence of a particular string
 59func (this *StringBuilder) Index(s string) int {
 60	return strings.Index(this.Content(), s)
 61}
 62
 63//Returns the length of the string content
 64func (this *StringBuilder) Len() int {
 65	return len(this.Content())
 66}
 67
 68//Returns the substring from start to end index
 69func (this *StringBuilder) Sub(start, end int) string {
 70	return this.Content()[start:end]
 71}
 72
 73//Returns the remaining string from the start index
 74func (this *StringBuilder) SubEnd(start int) string {
 75	return this.Content()[start:]
 76}
 77
 78//QuoteParser to parse quotes e.g. { } or <?go ?>
 79type QuoteParser struct {
 80	buffer, static   *StringBuilder
 81	outer, inner     []string
 82	opening, closing string
 83}
 84
 85//Creates a new QuoteParser with string s, opening and closing string
 86func NewQuoteParser(s, opening, closing string) *QuoteParser {
 87	parser := new(QuoteParser)
 88	parser.buffer, parser.static = NewStringBuilder(s), NewStringBuilder(s)
 89	parser.opening, parser.closing = opening, closing
 90	//parser.inner, parser.outer = new(vector.StringVector), new(vector.StringVector)
 91	return parser
 92}
 93
 94//Parses the string content in it
 95func (this *QuoteParser) Parse() (err error) {
 96	for this.HasNext() {
 97		_, _, err = this.Next()
 98		if err != nil {
 99			return
100		}
101	}
102	_, _, err = this.Next()
103	return
104}
105
106//Returns the array of contents embedded in the quotes
107func (this *QuoteParser) Parsed() []string {
108	return this.inner
109}
110
111//Returns the array of contents outside the quotes
112func (this *QuoteParser) Outer() []string {
113	return this.outer
114}
115
116//Parses the next set and returns the embedded and outer strings with an error if any
117//This method deletes the parsed string from the content
118//If there is still need to parse whole content, use Reset()
119func (this *QuoteParser) Next() (inner, outer string, err error) {
120	start := this.buffer.Index(this.opening)
121	if start >= 0 {
122		start += len(this.opening)
123	}
124	end := -1
125	if start >= 0 {
126		end = strings.Index(this.buffer.SubEnd(start), this.closing)
127		if end >= 0 {
128			end += start
129		}
130	}
131	//	end := this.buffer.Index(this.closing)
132	if end < 0 && start >= 0 {
133		err = errors.New("no closing string '" + this.closing + "' found near " + this.buffer.SubEnd(start-len(this.opening)))
134		return
135	}
136	if start >= end && end > -1 {
137		err = errors.New("no matching closing string '" + this.closing + "' found near " + this.buffer.SubEnd(start-len(this.opening)))
138		return
139	}
140	if this.HasNext() {
141		inner = this.buffer.Sub(start, end)
142	}
143	//if len(this.opening) > 4 {
144	//	println(start, end, this.closing, inner)
145	//}
146	//println(this.opening)
147	if this.buffer.Len() > 0 {
148		l := this.buffer.Index(this.opening)
149		if l < 0 {
150			l = this.buffer.Len()
151		}
152		outer = this.buffer.Sub(0, l)
153		if start >= 0 {
154			l = end + len(this.closing)
155		}
156		this.buffer.Delete(0, l)
157		this.inner = append(this.inner, inner)
158		this.outer = append(this.outer, outer)
159	}
160	return
161}
162
163//Resets the content to its state before parsing
164func (this *QuoteParser) Reset() {
165	this.buffer = this.static
166	this.outer = []string{}
167	this.inner = []string{}
168}
169
170//Checks whether there is next set of data to parse
171func (this *QuoteParser) HasNext() (res bool) {
172	start := this.buffer.Index(this.opening)
173	end := -1
174	if start >= 0 {
175		end = strings.Index(this.buffer.SubEnd(start), this.closing)
176		if end >= 0 {
177			end += start
178		}
179	}
180	//end := this.buffer.Index(this.closing)
181	return (start >= 0 && end >= 0 && start < end)
182}
183
184//Returns the remaining content in the buffer being used
185func (this *QuoteParser) String() string {
186	return this.buffer.Content()
187}
188
189//public variable to store settings
190var Config map[string][]string
191
192const (
193	SETTINGS   = "pages.json"
194	PATHS_FILE = "pages/.pages"
195)
196
197//Settings file type
198type Settings struct {
199	Data map[string][]string
200}
201
202//loads settings from pages.settings
203func LoadSettings() (s *Settings, err error) {
204	s = new(Settings)
205	err = s.parse()
206	return
207}
208
209//parse the informations in the settings file
210func (this *Settings) parse() (err error) {
211	settings, err := ioutil.ReadFile(SETTINGS)
212	config := make(map[string]string)
213	if err == nil {
214		err = json.Unmarshal(settings, &config)
215		if err != nil {
216			return
217		}
218	}
219	this.Data = make(map[string][]string)
220	if _, ok := config["extensions"]; !ok {
221		this.Data["extensions"] = []string{"ghtml"}
222	} else {
223		this.Data["extensions"] = strings.Split(config["extensions"], " ")
224	}
225	if _, ok := config["folders"]; !ok {
226		this.Data["folders"] = []string{"."}
227	} else {
228		this.Data["folders"] = strings.Split(config["folders"], " ")
229	}
230	err = this.GeneratePages()
231	return
232}
233
234//generates all .go source files
235func (this *Settings) GeneratePages() (err error) {
236	if len(this.Data["extensions"]) == 0 {
237		return
238	}
239	var pages []string
240	for i := 0; i < len(this.Data["folders"]); i++ {
241		pages, err = this.iterFiles(this.Data["folders"][i], pages)
242		if err != nil {
243			break
244			return
245		}
246	}
247	this.Data["pages"] = pages
248	//if len(pages) > 0 {
249	//	AddHandlers(pages)
250	//}
251	return
252}
253
254//loops through root and subfolders to locate files with
255//extensions specified in settings file
256func (this *Settings) iterFiles(f string, pages []string) ([]string, error) {
257	file, err := os.Open(f)
258	if err != nil {
259		println(err.Error())
260		return nil, err
261	}
262	stat, er := file.Stat()
263	if er != nil {
264		err = er
265		return nil, err
266	}
267	if stat.IsDir() {
268		dirs, err := file.Readdir(-1)
269		if err != nil {
270			return nil, err
271		}
272		for _, d := range dirs {
273			pages, err = this.iterFiles(path.Join(file.Name(), d.Name()), pages)
274		}
275	} else {
276		if hasExt(file.Name(), this.Data["extensions"]) {
277			err = generate(file.Name())
278			if err != nil {
279				println(err.Error())
280				return nil, err
281			}
282			pages = append(pages, file.Name())
283		}
284		file.Close()
285	}
286	return pages, err
287}
288
289//check if the file has the extension
290func hasExt(filename string, ext []string) bool {
291	extn := path.Ext(filename)
292	for _, e := range ext {
293		if "."+e == extn {
294			return true
295		}
296	}
297	return false
298}
299
300//direct function to generate .go source file
301func generate(page string) (err error) {
302	p, err := NewPage(page)
303	if err != nil {
304		return
305	}
306	err = p.ParseToFile()
307	return
308}