You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

833 lines
22 KiB

  1. // Copyright 2018 Frank Schroeder. 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. package properties
  5. // BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer.
  6. // BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used.
  7. import (
  8. "fmt"
  9. "io"
  10. "log"
  11. "os"
  12. "regexp"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "unicode/utf8"
  17. )
  18. const maxExpansionDepth = 64
  19. // ErrorHandlerFunc defines the type of function which handles failures
  20. // of the MustXXX() functions. An error handler function must exit
  21. // the application after handling the error.
  22. type ErrorHandlerFunc func(error)
  23. // ErrorHandler is the function which handles failures of the MustXXX()
  24. // functions. The default is LogFatalHandler.
  25. var ErrorHandler ErrorHandlerFunc = LogFatalHandler
  26. // LogHandlerFunc defines the function prototype for logging errors.
  27. type LogHandlerFunc func(fmt string, args ...interface{})
  28. // LogPrintf defines a log handler which uses log.Printf.
  29. var LogPrintf LogHandlerFunc = log.Printf
  30. // LogFatalHandler handles the error by logging a fatal error and exiting.
  31. func LogFatalHandler(err error) {
  32. log.Fatal(err)
  33. }
  34. // PanicHandler handles the error by panicking.
  35. func PanicHandler(err error) {
  36. panic(err)
  37. }
  38. // -----------------------------------------------------------------------------
  39. // A Properties contains the key/value pairs from the properties input.
  40. // All values are stored in unexpanded form and are expanded at runtime
  41. type Properties struct {
  42. // Pre-/Postfix for property expansion.
  43. Prefix string
  44. Postfix string
  45. // DisableExpansion controls the expansion of properties on Get()
  46. // and the check for circular references on Set(). When set to
  47. // true Properties behaves like a simple key/value store and does
  48. // not check for circular references on Get() or on Set().
  49. DisableExpansion bool
  50. // Stores the key/value pairs
  51. m map[string]string
  52. // Stores the comments per key.
  53. c map[string][]string
  54. // Stores the keys in order of appearance.
  55. k []string
  56. }
  57. // NewProperties creates a new Properties struct with the default
  58. // configuration for "${key}" expressions.
  59. func NewProperties() *Properties {
  60. return &Properties{
  61. Prefix: "${",
  62. Postfix: "}",
  63. m: map[string]string{},
  64. c: map[string][]string{},
  65. k: []string{},
  66. }
  67. }
  68. // Load reads a buffer into the given Properties struct.
  69. func (p *Properties) Load(buf []byte, enc Encoding) error {
  70. l := &Loader{Encoding: enc, DisableExpansion: p.DisableExpansion}
  71. newProperties, err := l.LoadBytes(buf)
  72. if err != nil {
  73. return err
  74. }
  75. p.Merge(newProperties)
  76. return nil
  77. }
  78. // Get returns the expanded value for the given key if exists.
  79. // Otherwise, ok is false.
  80. func (p *Properties) Get(key string) (value string, ok bool) {
  81. v, ok := p.m[key]
  82. if p.DisableExpansion {
  83. return v, ok
  84. }
  85. if !ok {
  86. return "", false
  87. }
  88. expanded, err := p.expand(key, v)
  89. // we guarantee that the expanded value is free of
  90. // circular references and malformed expressions
  91. // so we panic if we still get an error here.
  92. if err != nil {
  93. ErrorHandler(fmt.Errorf("%s in %q", err, key+" = "+v))
  94. }
  95. return expanded, true
  96. }
  97. // MustGet returns the expanded value for the given key if exists.
  98. // Otherwise, it panics.
  99. func (p *Properties) MustGet(key string) string {
  100. if v, ok := p.Get(key); ok {
  101. return v
  102. }
  103. ErrorHandler(invalidKeyError(key))
  104. panic("ErrorHandler should exit")
  105. }
  106. // ----------------------------------------------------------------------------
  107. // ClearComments removes the comments for all keys.
  108. func (p *Properties) ClearComments() {
  109. p.c = map[string][]string{}
  110. }
  111. // ----------------------------------------------------------------------------
  112. // GetComment returns the last comment before the given key or an empty string.
  113. func (p *Properties) GetComment(key string) string {
  114. comments, ok := p.c[key]
  115. if !ok || len(comments) == 0 {
  116. return ""
  117. }
  118. return comments[len(comments)-1]
  119. }
  120. // ----------------------------------------------------------------------------
  121. // GetComments returns all comments that appeared before the given key or nil.
  122. func (p *Properties) GetComments(key string) []string {
  123. if comments, ok := p.c[key]; ok {
  124. return comments
  125. }
  126. return nil
  127. }
  128. // ----------------------------------------------------------------------------
  129. // SetComment sets the comment for the key.
  130. func (p *Properties) SetComment(key, comment string) {
  131. p.c[key] = []string{comment}
  132. }
  133. // ----------------------------------------------------------------------------
  134. // SetComments sets the comments for the key. If the comments are nil then
  135. // all comments for this key are deleted.
  136. func (p *Properties) SetComments(key string, comments []string) {
  137. if comments == nil {
  138. delete(p.c, key)
  139. return
  140. }
  141. p.c[key] = comments
  142. }
  143. // ----------------------------------------------------------------------------
  144. // GetBool checks if the expanded value is one of '1', 'yes',
  145. // 'true' or 'on' if the key exists. The comparison is case-insensitive.
  146. // If the key does not exist the default value is returned.
  147. func (p *Properties) GetBool(key string, def bool) bool {
  148. v, err := p.getBool(key)
  149. if err != nil {
  150. return def
  151. }
  152. return v
  153. }
  154. // MustGetBool checks if the expanded value is one of '1', 'yes',
  155. // 'true' or 'on' if the key exists. The comparison is case-insensitive.
  156. // If the key does not exist the function panics.
  157. func (p *Properties) MustGetBool(key string) bool {
  158. v, err := p.getBool(key)
  159. if err != nil {
  160. ErrorHandler(err)
  161. }
  162. return v
  163. }
  164. func (p *Properties) getBool(key string) (value bool, err error) {
  165. if v, ok := p.Get(key); ok {
  166. return boolVal(v), nil
  167. }
  168. return false, invalidKeyError(key)
  169. }
  170. func boolVal(v string) bool {
  171. v = strings.ToLower(v)
  172. return v == "1" || v == "true" || v == "yes" || v == "on"
  173. }
  174. // ----------------------------------------------------------------------------
  175. // GetDuration parses the expanded value as an time.Duration (in ns) if the
  176. // key exists. If key does not exist or the value cannot be parsed the default
  177. // value is returned. In almost all cases you want to use GetParsedDuration().
  178. func (p *Properties) GetDuration(key string, def time.Duration) time.Duration {
  179. v, err := p.getInt64(key)
  180. if err != nil {
  181. return def
  182. }
  183. return time.Duration(v)
  184. }
  185. // MustGetDuration parses the expanded value as an time.Duration (in ns) if
  186. // the key exists. If key does not exist or the value cannot be parsed the
  187. // function panics. In almost all cases you want to use MustGetParsedDuration().
  188. func (p *Properties) MustGetDuration(key string) time.Duration {
  189. v, err := p.getInt64(key)
  190. if err != nil {
  191. ErrorHandler(err)
  192. }
  193. return time.Duration(v)
  194. }
  195. // ----------------------------------------------------------------------------
  196. // GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
  197. // If key does not exist or the value cannot be parsed the default
  198. // value is returned.
  199. func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration {
  200. s, ok := p.Get(key)
  201. if !ok {
  202. return def
  203. }
  204. v, err := time.ParseDuration(s)
  205. if err != nil {
  206. return def
  207. }
  208. return v
  209. }
  210. // MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
  211. // If key does not exist or the value cannot be parsed the function panics.
  212. func (p *Properties) MustGetParsedDuration(key string) time.Duration {
  213. s, ok := p.Get(key)
  214. if !ok {
  215. ErrorHandler(invalidKeyError(key))
  216. }
  217. v, err := time.ParseDuration(s)
  218. if err != nil {
  219. ErrorHandler(err)
  220. }
  221. return v
  222. }
  223. // ----------------------------------------------------------------------------
  224. // GetFloat64 parses the expanded value as a float64 if the key exists.
  225. // If key does not exist or the value cannot be parsed the default
  226. // value is returned.
  227. func (p *Properties) GetFloat64(key string, def float64) float64 {
  228. v, err := p.getFloat64(key)
  229. if err != nil {
  230. return def
  231. }
  232. return v
  233. }
  234. // MustGetFloat64 parses the expanded value as a float64 if the key exists.
  235. // If key does not exist or the value cannot be parsed the function panics.
  236. func (p *Properties) MustGetFloat64(key string) float64 {
  237. v, err := p.getFloat64(key)
  238. if err != nil {
  239. ErrorHandler(err)
  240. }
  241. return v
  242. }
  243. func (p *Properties) getFloat64(key string) (value float64, err error) {
  244. if v, ok := p.Get(key); ok {
  245. value, err = strconv.ParseFloat(v, 64)
  246. if err != nil {
  247. return 0, err
  248. }
  249. return value, nil
  250. }
  251. return 0, invalidKeyError(key)
  252. }
  253. // ----------------------------------------------------------------------------
  254. // GetInt parses the expanded value as an int if the key exists.
  255. // If key does not exist or the value cannot be parsed the default
  256. // value is returned. If the value does not fit into an int the
  257. // function panics with an out of range error.
  258. func (p *Properties) GetInt(key string, def int) int {
  259. v, err := p.getInt64(key)
  260. if err != nil {
  261. return def
  262. }
  263. return intRangeCheck(key, v)
  264. }
  265. // MustGetInt parses the expanded value as an int if the key exists.
  266. // If key does not exist or the value cannot be parsed the function panics.
  267. // If the value does not fit into an int the function panics with
  268. // an out of range error.
  269. func (p *Properties) MustGetInt(key string) int {
  270. v, err := p.getInt64(key)
  271. if err != nil {
  272. ErrorHandler(err)
  273. }
  274. return intRangeCheck(key, v)
  275. }
  276. // ----------------------------------------------------------------------------
  277. // GetInt64 parses the expanded value as an int64 if the key exists.
  278. // If key does not exist or the value cannot be parsed the default
  279. // value is returned.
  280. func (p *Properties) GetInt64(key string, def int64) int64 {
  281. v, err := p.getInt64(key)
  282. if err != nil {
  283. return def
  284. }
  285. return v
  286. }
  287. // MustGetInt64 parses the expanded value as an int if the key exists.
  288. // If key does not exist or the value cannot be parsed the function panics.
  289. func (p *Properties) MustGetInt64(key string) int64 {
  290. v, err := p.getInt64(key)
  291. if err != nil {
  292. ErrorHandler(err)
  293. }
  294. return v
  295. }
  296. func (p *Properties) getInt64(key string) (value int64, err error) {
  297. if v, ok := p.Get(key); ok {
  298. value, err = strconv.ParseInt(v, 10, 64)
  299. if err != nil {
  300. return 0, err
  301. }
  302. return value, nil
  303. }
  304. return 0, invalidKeyError(key)
  305. }
  306. // ----------------------------------------------------------------------------
  307. // GetUint parses the expanded value as an uint if the key exists.
  308. // If key does not exist or the value cannot be parsed the default
  309. // value is returned. If the value does not fit into an int the
  310. // function panics with an out of range error.
  311. func (p *Properties) GetUint(key string, def uint) uint {
  312. v, err := p.getUint64(key)
  313. if err != nil {
  314. return def
  315. }
  316. return uintRangeCheck(key, v)
  317. }
  318. // MustGetUint parses the expanded value as an int if the key exists.
  319. // If key does not exist or the value cannot be parsed the function panics.
  320. // If the value does not fit into an int the function panics with
  321. // an out of range error.
  322. func (p *Properties) MustGetUint(key string) uint {
  323. v, err := p.getUint64(key)
  324. if err != nil {
  325. ErrorHandler(err)
  326. }
  327. return uintRangeCheck(key, v)
  328. }
  329. // ----------------------------------------------------------------------------
  330. // GetUint64 parses the expanded value as an uint64 if the key exists.
  331. // If key does not exist or the value cannot be parsed the default
  332. // value is returned.
  333. func (p *Properties) GetUint64(key string, def uint64) uint64 {
  334. v, err := p.getUint64(key)
  335. if err != nil {
  336. return def
  337. }
  338. return v
  339. }
  340. // MustGetUint64 parses the expanded value as an int if the key exists.
  341. // If key does not exist or the value cannot be parsed the function panics.
  342. func (p *Properties) MustGetUint64(key string) uint64 {
  343. v, err := p.getUint64(key)
  344. if err != nil {
  345. ErrorHandler(err)
  346. }
  347. return v
  348. }
  349. func (p *Properties) getUint64(key string) (value uint64, err error) {
  350. if v, ok := p.Get(key); ok {
  351. value, err = strconv.ParseUint(v, 10, 64)
  352. if err != nil {
  353. return 0, err
  354. }
  355. return value, nil
  356. }
  357. return 0, invalidKeyError(key)
  358. }
  359. // ----------------------------------------------------------------------------
  360. // GetString returns the expanded value for the given key if exists or
  361. // the default value otherwise.
  362. func (p *Properties) GetString(key, def string) string {
  363. if v, ok := p.Get(key); ok {
  364. return v
  365. }
  366. return def
  367. }
  368. // MustGetString returns the expanded value for the given key if exists or
  369. // panics otherwise.
  370. func (p *Properties) MustGetString(key string) string {
  371. if v, ok := p.Get(key); ok {
  372. return v
  373. }
  374. ErrorHandler(invalidKeyError(key))
  375. panic("ErrorHandler should exit")
  376. }
  377. // ----------------------------------------------------------------------------
  378. // Filter returns a new properties object which contains all properties
  379. // for which the key matches the pattern.
  380. func (p *Properties) Filter(pattern string) (*Properties, error) {
  381. re, err := regexp.Compile(pattern)
  382. if err != nil {
  383. return nil, err
  384. }
  385. return p.FilterRegexp(re), nil
  386. }
  387. // FilterRegexp returns a new properties object which contains all properties
  388. // for which the key matches the regular expression.
  389. func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties {
  390. pp := NewProperties()
  391. for _, k := range p.k {
  392. if re.MatchString(k) {
  393. // TODO(fs): we are ignoring the error which flags a circular reference.
  394. // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
  395. pp.Set(k, p.m[k])
  396. }
  397. }
  398. return pp
  399. }
  400. // FilterPrefix returns a new properties object with a subset of all keys
  401. // with the given prefix.
  402. func (p *Properties) FilterPrefix(prefix string) *Properties {
  403. pp := NewProperties()
  404. for _, k := range p.k {
  405. if strings.HasPrefix(k, prefix) {
  406. // TODO(fs): we are ignoring the error which flags a circular reference.
  407. // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
  408. pp.Set(k, p.m[k])
  409. }
  410. }
  411. return pp
  412. }
  413. // FilterStripPrefix returns a new properties object with a subset of all keys
  414. // with the given prefix and the prefix removed from the keys.
  415. func (p *Properties) FilterStripPrefix(prefix string) *Properties {
  416. pp := NewProperties()
  417. n := len(prefix)
  418. for _, k := range p.k {
  419. if len(k) > len(prefix) && strings.HasPrefix(k, prefix) {
  420. // TODO(fs): we are ignoring the error which flags a circular reference.
  421. // TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference
  422. // TODO(fs): this function should probably return an error but the signature is fixed
  423. pp.Set(k[n:], p.m[k])
  424. }
  425. }
  426. return pp
  427. }
  428. // Len returns the number of keys.
  429. func (p *Properties) Len() int {
  430. return len(p.m)
  431. }
  432. // Keys returns all keys in the same order as in the input.
  433. func (p *Properties) Keys() []string {
  434. keys := make([]string, len(p.k))
  435. copy(keys, p.k)
  436. return keys
  437. }
  438. // Set sets the property key to the corresponding value.
  439. // If a value for key existed before then ok is true and prev
  440. // contains the previous value. If the value contains a
  441. // circular reference or a malformed expression then
  442. // an error is returned.
  443. // An empty key is silently ignored.
  444. func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
  445. if key == "" {
  446. return "", false, nil
  447. }
  448. // if expansion is disabled we allow circular references
  449. if p.DisableExpansion {
  450. prev, ok = p.Get(key)
  451. p.m[key] = value
  452. if !ok {
  453. p.k = append(p.k, key)
  454. }
  455. return prev, ok, nil
  456. }
  457. // to check for a circular reference we temporarily need
  458. // to set the new value. If there is an error then revert
  459. // to the previous state. Only if all tests are successful
  460. // then we add the key to the p.k list.
  461. prev, ok = p.Get(key)
  462. p.m[key] = value
  463. // now check for a circular reference
  464. _, err = p.expand(key, value)
  465. if err != nil {
  466. // revert to the previous state
  467. if ok {
  468. p.m[key] = prev
  469. } else {
  470. delete(p.m, key)
  471. }
  472. return "", false, err
  473. }
  474. if !ok {
  475. p.k = append(p.k, key)
  476. }
  477. return prev, ok, nil
  478. }
  479. // SetValue sets property key to the default string value
  480. // as defined by fmt.Sprintf("%v").
  481. func (p *Properties) SetValue(key string, value interface{}) error {
  482. _, _, err := p.Set(key, fmt.Sprintf("%v", value))
  483. return err
  484. }
  485. // MustSet sets the property key to the corresponding value.
  486. // If a value for key existed before then ok is true and prev
  487. // contains the previous value. An empty key is silently ignored.
  488. func (p *Properties) MustSet(key, value string) (prev string, ok bool) {
  489. prev, ok, err := p.Set(key, value)
  490. if err != nil {
  491. ErrorHandler(err)
  492. }
  493. return prev, ok
  494. }
  495. // String returns a string of all expanded 'key = value' pairs.
  496. func (p *Properties) String() string {
  497. var s string
  498. for _, key := range p.k {
  499. value, _ := p.Get(key)
  500. s = fmt.Sprintf("%s%s = %s\n", s, key, value)
  501. }
  502. return s
  503. }
  504. // Write writes all unexpanded 'key = value' pairs to the given writer.
  505. // Write returns the number of bytes written and any write error encountered.
  506. func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) {
  507. return p.WriteComment(w, "", enc)
  508. }
  509. // WriteComment writes all unexpanced 'key = value' pairs to the given writer.
  510. // If prefix is not empty then comments are written with a blank line and the
  511. // given prefix. The prefix should be either "# " or "! " to be compatible with
  512. // the properties file format. Otherwise, the properties parser will not be
  513. // able to read the file back in. It returns the number of bytes written and
  514. // any write error encountered.
  515. func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) {
  516. var x int
  517. for _, key := range p.k {
  518. value := p.m[key]
  519. if prefix != "" {
  520. if comments, ok := p.c[key]; ok {
  521. // don't print comments if they are all empty
  522. allEmpty := true
  523. for _, c := range comments {
  524. if c != "" {
  525. allEmpty = false
  526. break
  527. }
  528. }
  529. if !allEmpty {
  530. // add a blank line between entries but not at the top
  531. if len(comments) > 0 && n > 0 {
  532. x, err = fmt.Fprintln(w)
  533. if err != nil {
  534. return
  535. }
  536. n += x
  537. }
  538. for _, c := range comments {
  539. x, err = fmt.Fprintf(w, "%s%s\n", prefix, encode(c, "", enc))
  540. if err != nil {
  541. return
  542. }
  543. n += x
  544. }
  545. }
  546. }
  547. }
  548. x, err = fmt.Fprintf(w, "%s = %s\n", encode(key, " :", enc), encode(value, "", enc))
  549. if err != nil {
  550. return
  551. }
  552. n += x
  553. }
  554. return
  555. }
  556. // Map returns a copy of the properties as a map.
  557. func (p *Properties) Map() map[string]string {
  558. m := make(map[string]string)
  559. for k, v := range p.m {
  560. m[k] = v
  561. }
  562. return m
  563. }
  564. // FilterFunc returns a copy of the properties which includes the values which passed all filters.
  565. func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties {
  566. pp := NewProperties()
  567. outer:
  568. for k, v := range p.m {
  569. for _, f := range filters {
  570. if !f(k, v) {
  571. continue outer
  572. }
  573. pp.Set(k, v)
  574. }
  575. }
  576. return pp
  577. }
  578. // ----------------------------------------------------------------------------
  579. // Delete removes the key and its comments.
  580. func (p *Properties) Delete(key string) {
  581. delete(p.m, key)
  582. delete(p.c, key)
  583. newKeys := []string{}
  584. for _, k := range p.k {
  585. if k != key {
  586. newKeys = append(newKeys, k)
  587. }
  588. }
  589. p.k = newKeys
  590. }
  591. // Merge merges properties, comments and keys from other *Properties into p
  592. func (p *Properties) Merge(other *Properties) {
  593. for k, v := range other.m {
  594. p.m[k] = v
  595. }
  596. for k, v := range other.c {
  597. p.c[k] = v
  598. }
  599. outer:
  600. for _, otherKey := range other.k {
  601. for _, key := range p.k {
  602. if otherKey == key {
  603. continue outer
  604. }
  605. }
  606. p.k = append(p.k, otherKey)
  607. }
  608. }
  609. // ----------------------------------------------------------------------------
  610. // check expands all values and returns an error if a circular reference or
  611. // a malformed expression was found.
  612. func (p *Properties) check() error {
  613. for key, value := range p.m {
  614. if _, err := p.expand(key, value); err != nil {
  615. return err
  616. }
  617. }
  618. return nil
  619. }
  620. func (p *Properties) expand(key, input string) (string, error) {
  621. // no pre/postfix -> nothing to expand
  622. if p.Prefix == "" && p.Postfix == "" {
  623. return input, nil
  624. }
  625. return expand(input, []string{key}, p.Prefix, p.Postfix, p.m)
  626. }
  627. // expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values.
  628. // The function keeps track of the keys that were already expanded and stops if it
  629. // detects a circular reference or a malformed expression of the form '(prefix)key'.
  630. func expand(s string, keys []string, prefix, postfix string, values map[string]string) (string, error) {
  631. if len(keys) > maxExpansionDepth {
  632. return "", fmt.Errorf("expansion too deep")
  633. }
  634. for {
  635. start := strings.Index(s, prefix)
  636. if start == -1 {
  637. return s, nil
  638. }
  639. keyStart := start + len(prefix)
  640. keyLen := strings.Index(s[keyStart:], postfix)
  641. if keyLen == -1 {
  642. return "", fmt.Errorf("malformed expression")
  643. }
  644. end := keyStart + keyLen + len(postfix) - 1
  645. key := s[keyStart : keyStart+keyLen]
  646. // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key)
  647. for _, k := range keys {
  648. if key == k {
  649. return "", fmt.Errorf("circular reference")
  650. }
  651. }
  652. val, ok := values[key]
  653. if !ok {
  654. val = os.Getenv(key)
  655. }
  656. new_val, err := expand(val, append(keys, key), prefix, postfix, values)
  657. if err != nil {
  658. return "", err
  659. }
  660. s = s[:start] + new_val + s[end+1:]
  661. }
  662. return s, nil
  663. }
  664. // encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters.
  665. func encode(s string, special string, enc Encoding) string {
  666. switch enc {
  667. case UTF8:
  668. return encodeUtf8(s, special)
  669. case ISO_8859_1:
  670. return encodeIso(s, special)
  671. default:
  672. panic(fmt.Sprintf("unsupported encoding %v", enc))
  673. }
  674. }
  675. func encodeUtf8(s string, special string) string {
  676. v := ""
  677. for pos := 0; pos < len(s); {
  678. r, w := utf8.DecodeRuneInString(s[pos:])
  679. pos += w
  680. v += escape(r, special)
  681. }
  682. return v
  683. }
  684. func encodeIso(s string, special string) string {
  685. var r rune
  686. var w int
  687. var v string
  688. for pos := 0; pos < len(s); {
  689. switch r, w = utf8.DecodeRuneInString(s[pos:]); {
  690. case r < 1<<8: // single byte rune -> escape special chars only
  691. v += escape(r, special)
  692. case r < 1<<16: // two byte rune -> unicode literal
  693. v += fmt.Sprintf("\\u%04x", r)
  694. default: // more than two bytes per rune -> can't encode
  695. v += "?"
  696. }
  697. pos += w
  698. }
  699. return v
  700. }
  701. func escape(r rune, special string) string {
  702. switch r {
  703. case '\f':
  704. return "\\f"
  705. case '\n':
  706. return "\\n"
  707. case '\r':
  708. return "\\r"
  709. case '\t':
  710. return "\\t"
  711. default:
  712. if strings.ContainsRune(special, r) {
  713. return "\\" + string(r)
  714. }
  715. return string(r)
  716. }
  717. }
  718. func invalidKeyError(key string) error {
  719. return fmt.Errorf("unknown property: %s", key)
  720. }