properties.go 23 KB

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