sitef.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. package sitef
  2. import "os"
  3. import "io"
  4. import "strings"
  5. import "fmt"
  6. import "bytes"
  7. import "bufio"
  8. import "strconv"
  9. import "reflect"
  10. import "errors"
  11. import "github.com/beoran/woe/monolog"
  12. // Sitef format for serialization
  13. // Sitef is a simple text format for serializing data to
  14. // It's intent is to be human readable and easy to
  15. // use for multi line text.
  16. // It is quite similar to recfiles, though not compatible because
  17. // in sitef files the first character on the line determines the meaning,
  18. // and there is no backslash escaping.
  19. //
  20. // Sitef is a line based syntax where the first character on the line
  21. // determines the meaning of the line.
  22. // Several lines together form a record.
  23. // A line that starts with # is a comment. There may be no whitespace
  24. // in front of the comment.
  25. // A newline character by itself (that is, an empty line),
  26. // or a - ends a record.
  27. // A plus character, an escape on the previous line or a tab or
  28. // a space continues a value.
  29. // A Continues value gets a newline inserted only when a space or tab was used.
  30. // + supresses the newline.
  31. // Anything else signifies the beginning of the next key.
  32. // % is allowed for special keys for recfile compatibility.
  33. // However % directives are not implemented.
  34. // Keys may not be nested, however, you could use spaces or dots,
  35. // or array indexes to emulate nexted keys.
  36. // A # at the start optionally after whitespace is a comment
  37. //
  38. type Record map[string]string
  39. func (me * Record) Put(key string, val string) {
  40. (*me)[key] = val
  41. }
  42. func (me * Record) Putf(key string, format string, values ...interface{}) {
  43. me.Put(key, fmt.Sprintf(format, values...))
  44. }
  45. func (me * Record) PutArray(key string, values []string) {
  46. for i, value := range values {
  47. realkey := fmt.Sprintf("%s[%d]", key, i)
  48. me.Put(realkey, value)
  49. }
  50. }
  51. func (me * Record) PutInt(key string, val int) {
  52. me.Putf(key, "%d", val)
  53. }
  54. func (me * Record) PutInt64(key string, val int64) {
  55. me.Putf(key, "%d", val)
  56. }
  57. func (me * Record) PutFloat64(key string, val float64) {
  58. me.Putf(key, "%lf", val)
  59. }
  60. func (me Record) MayGet(key string) (result string, ok bool) {
  61. result, ok = me[key]
  62. return result, ok
  63. }
  64. func (me Record) Get(key string) (result string) {
  65. result= me[key]
  66. return result
  67. }
  68. func (me Record) Getf(key string, format string,
  69. values ...interface{}) (amount int, ok bool) {
  70. val := me.Get(key)
  71. count, err := fmt.Sscanf(val, format, values...)
  72. if err != nil {
  73. return 0, false
  74. }
  75. return count, true
  76. }
  77. func (me Record) GetInt(key string) (val int, err error) {
  78. i, err := strconv.ParseInt(me.Get(key), 0, 0)
  79. return int(i), err
  80. }
  81. func (me Record) GetIntDefault(key string, def int) (val int) {
  82. i, err := strconv.ParseInt(me.Get(key), 0, 0)
  83. if err != nil {
  84. return def;
  85. }
  86. return int(i);
  87. }
  88. func (me Record) GetFloat(key string) (val float64, error error) {
  89. return strconv.ParseFloat(me.Get(key), 64)
  90. }
  91. func (me * Record) convSimple(typ reflect.Type, val reflect.Value) (res string, err error) {
  92. switch val.Kind() {
  93. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  94. return strconv.FormatInt(val.Int(), 10), nil
  95. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  96. return strconv.FormatUint(val.Uint(), 10), nil
  97. case reflect.Float32, reflect.Float64:
  98. return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil
  99. case reflect.String:
  100. return val.String(), nil
  101. case reflect.Bool:
  102. return strconv.FormatBool(val.Bool()), nil
  103. default:
  104. return "", errors.New("Unsupported type")
  105. }
  106. }
  107. func (me Record) PutValue(key string, value reflect.Value) {
  108. switch (value.Kind()) {
  109. case reflect.Int, reflect.Int32, reflect.Int64:
  110. me.Putf(key, "%d", value.Int())
  111. case reflect.Uint, reflect.Uint32, reflect.Uint64:
  112. me.Putf(key, "%d", value.Uint())
  113. case reflect.Float32, reflect.Float64:
  114. me.Putf(key, "%f", value.Float())
  115. case reflect.String:
  116. me.Putf(key, "%s", value.String())
  117. default:
  118. me.Put(key, "???")
  119. }
  120. }
  121. func (me Record) PutStruct(prefix string, structure interface {}) {
  122. st := reflect.TypeOf(structure)
  123. vt := reflect.ValueOf(structure)
  124. monolog.Info("PutStruct: type %v value %v\n", st, vt)
  125. for i:= 0 ; i < st.NumField() ; i++ {
  126. field := st.Field(i)
  127. key := strings.ToLower(field.Name)
  128. value := vt.Field(i).String()
  129. me.Put(prefix + key, value)
  130. }
  131. }
  132. type Error struct {
  133. error string
  134. lineno int
  135. }
  136. func (me Error) Error() string {
  137. return fmt.Sprintf("%d: %s", me.Lineno, me.error)
  138. }
  139. func (me Error) Lineno() int {
  140. return me.lineno
  141. }
  142. type ParserState int
  143. const (
  144. PARSER_STATE_INIT ParserState = iota
  145. PARSER_STATE_KEY
  146. PARSER_STATE_VALUE
  147. )
  148. type RecordList []Record
  149. func ParseReader(read io.Reader) (RecordList, error) {
  150. var records RecordList
  151. var record Record = make(Record)
  152. var err Error
  153. lineno := 0
  154. scanner := bufio.NewScanner(read)
  155. var key bytes.Buffer
  156. var value bytes.Buffer
  157. for scanner.Scan() {
  158. lineno++
  159. line := scanner.Text()
  160. // End of record?
  161. if (len(line) < 1) || line[0] == '-' {
  162. // save the record and make a new one
  163. records = append(records, record)
  164. record = make(Record)
  165. // comment?
  166. } else if line[0] == '#' {
  167. continue;
  168. // continue value?
  169. } else if line[0] == '\t' || line[0] == ' '|| line[0] == '+' {
  170. /* Add a newline unless + is used */
  171. if (line[0] != '+') {
  172. value.WriteRune('\n')
  173. }
  174. // continue the value, skipping the first character
  175. value.WriteString(line[1:])
  176. // new key
  177. } else if strings.ContainsRune(line, ':') {
  178. // save the previous key/value pair if needed
  179. if len(key.String()) > 0 {
  180. record[key.String()] = value.String()
  181. }
  182. key.Reset()
  183. value.Reset()
  184. parts := strings.SplitN(line, ":", 2)
  185. key.WriteString(parts[0])
  186. if len(parts) > 1 {
  187. value.WriteString(parts[1])
  188. }
  189. // Not a key. Be lenient and assume this is a continued value.
  190. } else {
  191. value.WriteString(line)
  192. }
  193. }
  194. // Append last record if needed.
  195. if len(key.String()) > 0 {
  196. record[key.String()] = value.String()
  197. }
  198. if (len(record) > 0) {
  199. records = append(records, record)
  200. }
  201. if serr := scanner.Err(); serr != nil {
  202. err.lineno = lineno
  203. err.error = serr.Error()
  204. return records, err
  205. }
  206. return records, nil
  207. }
  208. func ParseFilename(filename string) (RecordList, error) {
  209. file, err := os.Open(filename)
  210. if err != nil {
  211. return nil, err
  212. }
  213. defer file.Close()
  214. return ParseReader(file)
  215. }
  216. func WriteField(writer io.Writer, key string, value string) {
  217. replacer := strings.NewReplacer("\n", "\n\t")
  218. writer.Write([]byte(key))
  219. writer.Write([]byte{':'})
  220. writer.Write([]byte(replacer.Replace(value)))
  221. writer.Write([]byte{'\n'})
  222. }
  223. func WriteRecord(writer io.Writer, record Record) {
  224. for key, value := range record {
  225. WriteField(writer, key, value);
  226. }
  227. writer.Write([]byte{'-', '-', '-', '-', '\n'})
  228. }
  229. func WriteRecordList(writer io.Writer, records RecordList) {
  230. for _, record := range records {
  231. WriteRecord(writer, record);
  232. }
  233. }
  234. func SaveRecord(filename string, record Record) (error) {
  235. file, err := os.Create(filename)
  236. if err != nil {
  237. return err
  238. }
  239. defer file.Close()
  240. WriteRecord(file, record)
  241. return nil
  242. }
  243. func SaveRecordList(filename string, records RecordList) (error) {
  244. file, err := os.Create(filename)
  245. if err != nil {
  246. return err
  247. }
  248. defer file.Close()
  249. WriteRecordList(file, records)
  250. return nil
  251. }
  252. /*
  253. func ParseFile(file)
  254. lineno = 0
  255. results = []
  256. errors = []
  257. record = {}
  258. key = nil
  259. value = nil
  260. until file.eof?
  261. lineno += 1
  262. line = file.gets(256)
  263. break if line.nil?
  264. next if line.empty?
  265. // new record
  266. if line[0,2] == '--'
  267. // Store last key used if any.
  268. if key
  269. record[key] = value.chomp
  270. key = nil
  271. end
  272. results << record
  273. record = {}
  274. elsif line[0] == '//'
  275. // Comments start with //
  276. elsif line[0] == ':'
  277. // a key/value pair
  278. key, value = line[1,line.size].split(':', 2)
  279. record[key] = value.chomp
  280. key = value = nil
  281. elsif line[0, 2] == '..'
  282. // end of multiline value
  283. record[key] = value.chomp
  284. key = value = nil
  285. elsif (line[0] == '.') && key.nil?
  286. // Multiline key/value starts here (but is ignored
  287. // until .. is encountered)
  288. key = line[1, line.size]
  289. key.chomp!
  290. value = ""
  291. // multiline value
  292. elsif key
  293. if line[0] == '\\'
  294. // remove any escapes
  295. line.slice!(0)
  296. end
  297. // continue the value
  298. value << line
  299. else
  300. // Not in a key, sntax error.
  301. errors << "//{lineno}: Don't know how to process line"
  302. end
  303. end
  304. // Store last key used if any.
  305. if key
  306. record[key] = value.chomp
  307. end
  308. // store last record
  309. results << record unless record.empty?
  310. return results, errors
  311. end
  312. func load_filename(filename)
  313. results, errors = nil, nil, nil;
  314. file = File.open(filename, 'rt') rescue nil
  315. return nil, ["Could not open //{filename}"] unless file
  316. begin
  317. results, errors = parse_file(file)
  318. ensure
  319. file.close
  320. end
  321. return results, errors
  322. end
  323. // Loads a Sitef fileas obejcts. Uses the ruby_klass atribute to load the object
  324. // If that is missing, uses defklass
  325. func load_objects(filename, defklass=nil)
  326. results, errors = load_filename(filename)
  327. p filename, results, errors
  328. unless errors.nil? || errors.empty?
  329. return nil, errors
  330. end
  331. objres = []
  332. results.each do | result |
  333. klassname = result['ruby_class'] || defklass
  334. return nil unless klassname
  335. klass = klassname.split('::').inject(Kernel) { |klass, name| klass.const_get(name) rescue nil }
  336. return nil unless klass
  337. if klass.respond_to? :from_sitef
  338. objres << klass.from_sitef(result)
  339. else
  340. objres << klass.new(result)
  341. end
  342. end
  343. return objres, errors
  344. end
  345. // Saves a single field to a file in Sitef format.
  346. func save_field(file, key, value)
  347. if value.is_a? String
  348. sval = value.dup
  349. else
  350. sval = value.to_s
  351. end
  352. if sval["\n"]
  353. file.puts(".//{key}\n")
  354. // Escape everything that could be misinterpreted with a \\
  355. sval.gsub!(/\n([\.\-\:\//\\]+)/, "\n\\\\\\1")
  356. sval.gsub!(/\A([\.\-\:\//\\]+)/, "\\\\\\1")
  357. file.printf("%s", sval)
  358. file.printf("\n..\n")
  359. else
  360. file.printf("://{key}://{sval}\n")
  361. end
  362. end
  363. func save_object(file, object, *fields)
  364. save_field(file, :ruby_class, object.class.to_s)
  365. fields.each do | field |
  366. value = object.send(field.to_sym)
  367. save_field(file, field, value)
  368. end
  369. end
  370. func save_record(file, record, *fields)
  371. record.each do | key, value |
  372. next if fields && !fields.empty? && !fields.member?(key)
  373. save_field(file, key, value)
  374. end
  375. end
  376. func save_file(file, records, *fields)
  377. records.each do | record |
  378. if record.is_a? Hash
  379. save_record(file, record, *fields)
  380. else
  381. save_object(file, record, *fields)
  382. end
  383. file.puts("--\n")
  384. end
  385. end
  386. func save_filename(filename, records, *fields)
  387. results , errors = nil, nil
  388. file = File.open(filename, 'wt')
  389. return false, ["Could not open //{filename}"] unless file
  390. begin
  391. save_file(file, records, *fields)
  392. ensure
  393. file.close
  394. end
  395. return true, []
  396. end
  397. end
  398. */