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