You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2015/11/21 01:42:42 UTC
[17/42] incubator-mynewt-newt git commit: Move newt source into a
"newt" subdirectory.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/kr/text/indent.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/kr/text/indent.go b/newt/Godeps/_workspace/src/github.com/kr/text/indent.go
new file mode 100644
index 0000000..4ebac45
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/kr/text/indent.go
@@ -0,0 +1,74 @@
+package text
+
+import (
+ "io"
+)
+
+// Indent inserts prefix at the beginning of each non-empty line of s. The
+// end-of-line marker is NL.
+func Indent(s, prefix string) string {
+ return string(IndentBytes([]byte(s), []byte(prefix)))
+}
+
+// IndentBytes inserts prefix at the beginning of each non-empty line of b.
+// The end-of-line marker is NL.
+func IndentBytes(b, prefix []byte) []byte {
+ var res []byte
+ bol := true
+ for _, c := range b {
+ if bol && c != '\n' {
+ res = append(res, prefix...)
+ }
+ res = append(res, c)
+ bol = c == '\n'
+ }
+ return res
+}
+
+// Writer indents each line of its input.
+type indentWriter struct {
+ w io.Writer
+ bol bool
+ pre [][]byte
+ sel int
+ off int
+}
+
+// NewIndentWriter makes a new write filter that indents the input
+// lines. Each line is prefixed in order with the corresponding
+// element of pre. If there are more lines than elements, the last
+// element of pre is repeated for each subsequent line.
+func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer {
+ return &indentWriter{
+ w: w,
+ pre: pre,
+ bol: true,
+ }
+}
+
+// The only errors returned are from the underlying indentWriter.
+func (w *indentWriter) Write(p []byte) (n int, err error) {
+ for _, c := range p {
+ if w.bol {
+ var i int
+ i, err = w.w.Write(w.pre[w.sel][w.off:])
+ w.off += i
+ if err != nil {
+ return n, err
+ }
+ }
+ _, err = w.w.Write([]byte{c})
+ if err != nil {
+ return n, err
+ }
+ n++
+ w.bol = c == '\n'
+ if w.bol {
+ w.off = 0
+ if w.sel < len(w.pre)-1 {
+ w.sel++
+ }
+ }
+ }
+ return n, nil
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/kr/text/indent_test.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/kr/text/indent_test.go b/newt/Godeps/_workspace/src/github.com/kr/text/indent_test.go
new file mode 100644
index 0000000..5c723ee
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/kr/text/indent_test.go
@@ -0,0 +1,119 @@
+package text
+
+import (
+ "bytes"
+ "testing"
+)
+
+type T struct {
+ inp, exp, pre string
+}
+
+var tests = []T{
+ {
+ "The quick brown fox\njumps over the lazy\ndog.\nBut not quickly.\n",
+ "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\nxxxBut not quickly.\n",
+ "xxx",
+ },
+ {
+ "The quick brown fox\njumps over the lazy\ndog.\n\nBut not quickly.",
+ "xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\n\nxxxBut not quickly.",
+ "xxx",
+ },
+}
+
+func TestIndent(t *testing.T) {
+ for _, test := range tests {
+ got := Indent(test.inp, test.pre)
+ if got != test.exp {
+ t.Errorf("mismatch %q != %q", got, test.exp)
+ }
+ }
+}
+
+type IndentWriterTest struct {
+ inp, exp string
+ pre []string
+}
+
+var ts = []IndentWriterTest{
+ {
+ `
+The quick brown fox
+jumps over the lazy
+dog.
+But not quickly.
+`[1:],
+ `
+xxxThe quick brown fox
+xxxjumps over the lazy
+xxxdog.
+xxxBut not quickly.
+`[1:],
+ []string{"xxx"},
+ },
+ {
+ `
+The quick brown fox
+jumps over the lazy
+dog.
+But not quickly.
+`[1:],
+ `
+xxaThe quick brown fox
+xxxjumps over the lazy
+xxxdog.
+xxxBut not quickly.
+`[1:],
+ []string{"xxa", "xxx"},
+ },
+ {
+ `
+The quick brown fox
+jumps over the lazy
+dog.
+But not quickly.
+`[1:],
+ `
+xxaThe quick brown fox
+xxbjumps over the lazy
+xxcdog.
+xxxBut not quickly.
+`[1:],
+ []string{"xxa", "xxb", "xxc", "xxx"},
+ },
+ {
+ `
+The quick brown fox
+jumps over the lazy
+dog.
+
+But not quickly.`[1:],
+ `
+xxaThe quick brown fox
+xxxjumps over the lazy
+xxxdog.
+xxx
+xxxBut not quickly.`[1:],
+ []string{"xxa", "xxx"},
+ },
+}
+
+func TestIndentWriter(t *testing.T) {
+ for _, test := range ts {
+ b := new(bytes.Buffer)
+ pre := make([][]byte, len(test.pre))
+ for i := range test.pre {
+ pre[i] = []byte(test.pre[i])
+ }
+ w := NewIndentWriter(b, pre...)
+ if _, err := w.Write([]byte(test.inp)); err != nil {
+ t.Error(err)
+ }
+ if got := b.String(); got != test.exp {
+ t.Errorf("mismatch %q != %q", got, test.exp)
+ t.Log(got)
+ t.Log(test.exp)
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/kr/text/mc/Readme
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/kr/text/mc/Readme b/newt/Godeps/_workspace/src/github.com/kr/text/mc/Readme
new file mode 100644
index 0000000..519ddc0
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/kr/text/mc/Readme
@@ -0,0 +1,9 @@
+Command mc prints in multiple columns.
+
+ Usage: mc [-] [-N] [file...]
+
+Mc splits the input into as many columns as will fit in N
+print positions. If the output is a tty, the default N is
+the number of characters in a terminal line; otherwise the
+default N is 80. Under option - each input line ending in
+a colon ':' is printed separately.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/kr/text/mc/mc.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/kr/text/mc/mc.go b/newt/Godeps/_workspace/src/github.com/kr/text/mc/mc.go
new file mode 100644
index 0000000..00169a3
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/kr/text/mc/mc.go
@@ -0,0 +1,62 @@
+// Command mc prints in multiple columns.
+//
+// Usage: mc [-] [-N] [file...]
+//
+// Mc splits the input into as many columns as will fit in N
+// print positions. If the output is a tty, the default N is
+// the number of characters in a terminal line; otherwise the
+// default N is 80. Under option - each input line ending in
+// a colon ':' is printed separately.
+package main
+
+import (
+ "github.com/kr/pty"
+ "github.com/kr/text/colwriter"
+ "io"
+ "log"
+ "os"
+ "strconv"
+)
+
+func main() {
+ var width int
+ var flag uint
+ args := os.Args[1:]
+ for len(args) > 0 && len(args[0]) > 0 && args[0][0] == '-' {
+ if len(args[0]) > 1 {
+ width, _ = strconv.Atoi(args[0][1:])
+ } else {
+ flag |= colwriter.BreakOnColon
+ }
+ args = args[1:]
+ }
+ if width < 1 {
+ _, width, _ = pty.Getsize(os.Stdout)
+ }
+ if width < 1 {
+ width = 80
+ }
+
+ w := colwriter.NewWriter(os.Stdout, width, flag)
+ if len(args) > 0 {
+ for _, s := range args {
+ if f, err := os.Open(s); err == nil {
+ copyin(w, f)
+ f.Close()
+ } else {
+ log.Println(err)
+ }
+ }
+ } else {
+ copyin(w, os.Stdin)
+ }
+}
+
+func copyin(w *colwriter.Writer, r io.Reader) {
+ if _, err := io.Copy(w, r); err != nil {
+ log.Println(err)
+ }
+ if err := w.Flush(); err != nil {
+ log.Println(err)
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/kr/text/wrap.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/kr/text/wrap.go b/newt/Godeps/_workspace/src/github.com/kr/text/wrap.go
new file mode 100644
index 0000000..1c85cd2
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/kr/text/wrap.go
@@ -0,0 +1,86 @@
+package text
+
+import (
+ "bytes"
+ "math"
+)
+
+var (
+ nl = []byte{'\n'}
+ sp = []byte{' '}
+)
+
+const defaultPenalty = 1e5
+
+// Wrap wraps s into a paragraph of lines of length lim, with minimal
+// raggedness.
+func Wrap(s string, lim int) string {
+ return string(WrapBytes([]byte(s), lim))
+}
+
+// WrapBytes wraps b into a paragraph of lines of length lim, with minimal
+// raggedness.
+func WrapBytes(b []byte, lim int) []byte {
+ words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
+ var lines [][]byte
+ for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
+ lines = append(lines, bytes.Join(line, sp))
+ }
+ return bytes.Join(lines, nl)
+}
+
+// WrapWords is the low-level line-breaking algorithm, useful if you need more
+// control over the details of the text wrapping process. For most uses, either
+// Wrap or WrapBytes will be sufficient and more convenient.
+//
+// WrapWords splits a list of words into lines with minimal "raggedness",
+// treating each byte as one unit, accounting for spc units between adjacent
+// words on each line, and attempting to limit lines to lim units. Raggedness
+// is the total error over all lines, where error is the square of the
+// difference of the length of the line and lim. Too-long lines (which only
+// happen when a single word is longer than lim units) have pen penalty units
+// added to the error.
+func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
+ n := len(words)
+
+ length := make([][]int, n)
+ for i := 0; i < n; i++ {
+ length[i] = make([]int, n)
+ length[i][i] = len(words[i])
+ for j := i + 1; j < n; j++ {
+ length[i][j] = length[i][j-1] + spc + len(words[j])
+ }
+ }
+
+ nbrk := make([]int, n)
+ cost := make([]int, n)
+ for i := range cost {
+ cost[i] = math.MaxInt32
+ }
+ for i := n - 1; i >= 0; i-- {
+ if length[i][n-1] <= lim {
+ cost[i] = 0
+ nbrk[i] = n
+ } else {
+ for j := i + 1; j < n; j++ {
+ d := lim - length[i][j-1]
+ c := d*d + cost[j]
+ if length[i][j-1] > lim {
+ c += pen // too-long lines get a worse penalty
+ }
+ if c < cost[i] {
+ cost[i] = c
+ nbrk[i] = j
+ }
+ }
+ }
+ }
+
+ var lines [][][]byte
+ i := 0
+ for i < n {
+ lines = append(lines, words[i:nbrk[i]])
+ i = nbrk[i]
+ }
+ return lines
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/kr/text/wrap_test.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/kr/text/wrap_test.go b/newt/Godeps/_workspace/src/github.com/kr/text/wrap_test.go
new file mode 100644
index 0000000..90f065c
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/kr/text/wrap_test.go
@@ -0,0 +1,44 @@
+package text
+
+import (
+ "bytes"
+ "testing"
+)
+
+var text = "The quick brown fox jumps over the lazy dog."
+
+func TestWrap(t *testing.T) {
+ exp := [][]string{
+ {"The", "quick", "brown", "fox"},
+ {"jumps", "over", "the", "lazy", "dog."},
+ }
+ words := bytes.Split([]byte(text), sp)
+ got := WrapWords(words, 1, 24, defaultPenalty)
+ if len(exp) != len(got) {
+ t.Fail()
+ }
+ for i := range exp {
+ if len(exp[i]) != len(got[i]) {
+ t.Fail()
+ }
+ for j := range exp[i] {
+ if exp[i][j] != string(got[i][j]) {
+ t.Fatal(i, exp[i][j], got[i][j])
+ }
+ }
+ }
+}
+
+func TestWrapNarrow(t *testing.T) {
+ exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog."
+ if Wrap(text, 5) != exp {
+ t.Fail()
+ }
+}
+
+func TestWrapOneLine(t *testing.T) {
+ exp := "The quick brown fox jumps over the lazy dog."
+ if Wrap(text, 500) != exp {
+ t.Fail()
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/.gitignore
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/.gitignore b/newt/Godeps/_workspace/src/github.com/magiconair/properties/.gitignore
new file mode 100644
index 0000000..0e379c5
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/.gitignore
@@ -0,0 +1,2 @@
+*.sublime-project
+*.sublime-workspace
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/.travis.yml
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/.travis.yml b/newt/Godeps/_workspace/src/github.com/magiconair/properties/.travis.yml
new file mode 100644
index 0000000..407127c
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/.travis.yml
@@ -0,0 +1,5 @@
+language: go
+go:
+ - release
+install: go get gopkg.in/check.v1
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/LICENSE
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/LICENSE b/newt/Godeps/_workspace/src/github.com/magiconair/properties/LICENSE
new file mode 100644
index 0000000..7eab43b
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/LICENSE
@@ -0,0 +1,25 @@
+goproperties - properties file decoder for Go
+
+Copyright (c) 2013-2014 - Frank Schroeder
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/README.md
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/README.md b/newt/Godeps/_workspace/src/github.com/magiconair/properties/README.md
new file mode 100644
index 0000000..d05d86b
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/README.md
@@ -0,0 +1,121 @@
+Overview [![Build Status](https://travis-ci.org/magiconair/properties.png?branch=master)](https://travis-ci.org/magiconair/properties)
+========
+
+properties is a Go library for reading and writing properties files.
+
+It supports reading from multiple files and Spring style recursive property
+expansion of expressions like `${key}` to their corresponding value.
+Value expressions can refer to other keys like in `${key}` or to
+environment variables like in `${USER}`.
+Filenames can also contain environment variables like in
+`/home/${USER}/myapp.properties`.
+
+Comments and the order of keys are preserved. Comments can be modified
+and can be written to the output.
+
+The properties library supports both ISO-8859-1 and UTF-8 encoded data.
+
+Starting from version 1.3.0 the behavior of the MustXXX() functions is
+configurable by providing a custom `ErrorHandler` function. The default has
+changed from `panic` to `log.Fatal` but this is configurable and custom
+error handling functions can be provided. See the package documentation for
+details.
+
+Getting Started
+---------------
+
+```go
+import "github.com/magiconair/properties"
+
+func main() {
+ p := properties.MustLoadFile("${HOME}/config.properties", properties.UTF8)
+ host := p.MustGetString("host")
+ port := p.GetInt("port", 8080)
+}
+
+```
+
+Read the full documentation on [GoDoc](https://godoc.org/github.com/magiconair/properties) [![GoDoc](https://godoc.org/github.com/magiconair/properties?status.png)](https://godoc.org/github.com/magiconair/properties)
+
+Installation and Upgrade
+------------------------
+
+```
+$ go get -u github.com/magiconair/properties
+```
+
+For testing and debugging you need the [go-check](https://github.com/go-check/check) library
+
+```
+$ go get -u gopkg.in/check.v1
+```
+
+History
+-------
+
+v1.5.3, 02 Jun 2015
+-------------------
+ * [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp)
+
+v1.5.2, 10 Apr 2015
+-------------------
+ * [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty
+ * Add clickable links to README
+
+v1.5.1, 08 Dec 2014
+-------------------
+ * Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with
+ [time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration).
+
+v1.5.0, 18 Nov 2014
+-------------------
+ * Added support for single and multi-line comments (reading, writing and updating)
+ * The order of keys is now preserved
+ * Calling [Set()](http://godoc.org/github.com/magiconair/properties#Properties.Set) with an empty key now silently ignores the call and does not create a new entry
+ * Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method
+ * Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1)
+
+v1.4.2, 15 Nov 2014
+-------------------
+ * [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one
+
+v1.4.1, 13 Nov 2014
+-------------------
+ * [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string
+
+v1.4.0, 23 Sep 2014
+-------------------
+ * Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys
+ * Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties
+
+v1.3.0, 18 Mar 2014
+-------------------
+* Added support for time.Duration
+* Made MustXXX() failure behavior configurable (log.Fatal, panic, custom)
+* Changed default of MustXXX() failure from panic to log.Fatal
+
+v1.2.0, 05 Mar 2014
+-------------------
+* Added MustGet... functions
+* Added support for int and uint with range checks on 32 bit platforms
+
+v1.1.0, 20 Jan 2014
+-------------------
+* Renamed from goproperties to properties
+* Added support for expansion of environment vars in
+ filenames and value expressions
+* Fixed bug where value expressions were not at the
+ start of the string
+
+v1.0.0, 7 Jan 2014
+------------------
+* Initial release
+
+License
+-------
+
+2 clause BSD license. See [LICENSE](https://github.com/magiconair/properties/blob/master/LICENSE) file for details.
+
+ToDo
+----
+* Dump contents with passwords and secrets obscured
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/benchmark_test.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/benchmark_test.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/benchmark_test.go
new file mode 100644
index 0000000..b2019e1
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/benchmark_test.go
@@ -0,0 +1,22 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+ "fmt"
+ "testing"
+)
+
+// Benchmarks the decoder by creating a property file with 1000 key/value pairs.
+func BenchmarkLoad(b *testing.B) {
+ input := ""
+ for i := 0; i < 1000; i++ {
+ input += fmt.Sprintf("key%d=value%d\n", i, i)
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Load([]byte(input), ISO_8859_1)
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/doc.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/doc.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/doc.go
new file mode 100644
index 0000000..69cf2e8
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/doc.go
@@ -0,0 +1,135 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package properties provides functions for reading and writing
+// ISO-8859-1 and UTF-8 encoded .properties files and has
+// support for recursive property expansion.
+//
+// Java properties files are ISO-8859-1 encoded and use Unicode
+// literals for characters outside the ISO character set. Unicode
+// literals can be used in UTF-8 encoded properties files but
+// aren't necessary.
+//
+// To load a single properties file use MustLoadFile():
+//
+// p := properties.MustLoadFile(filename, properties.UTF8)
+//
+// To load multiple properties files use MustLoadFiles()
+// which loads the files in the given order and merges the
+// result. Missing properties files can be ignored if the
+// 'ignoreMissing' flag is set to true.
+//
+// Filenames can contain environment variables which are expanded
+// before loading.
+//
+// f1 := "/etc/myapp/myapp.conf"
+// f2 := "/home/${USER}/myapp.conf"
+// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true)
+//
+// All of the different key/value delimiters ' ', ':' and '=' are
+// supported as well as the comment characters '!' and '#' and
+// multi-line values.
+//
+// ! this is a comment
+// # and so is this
+//
+// # the following expressions are equal
+// key value
+// key=value
+// key:value
+// key = value
+// key : value
+// key = val\
+// ue
+//
+// Properties stores all comments preceding a key and provides
+// GetComments() and SetComments() methods to retrieve and
+// update them. The convenience functions GetComment() and
+// SetComment() allow access to the last comment. The
+// WriteComment() method writes properties files including
+// the comments and with the keys in the original order.
+// This can be used for sanitizing properties files.
+//
+// Property expansion is recursive and circular references
+// and malformed expressions are not allowed and cause an
+// error. Expansion of environment variables is supported.
+//
+// # standard property
+// key = value
+//
+// # property expansion: key2 = value
+// key2 = ${key}
+//
+// # recursive expansion: key3 = value
+// key3 = ${key2}
+//
+// # circular reference (error)
+// key = ${key}
+//
+// # malformed expression (error)
+// key = ${ke
+//
+// # refers to the users' home dir
+// home = ${HOME}
+//
+// # local key takes precendence over env var: u = foo
+// USER = foo
+// u = ${USER}
+//
+// The default property expansion format is ${key} but can be
+// changed by setting different pre- and postfix values on the
+// Properties object.
+//
+// p := properties.NewProperties()
+// p.Prefix = "#["
+// p.Postfix = "]#"
+//
+// Properties provides convenience functions for getting typed
+// values with default values if the key does not exist or the
+// type conversion failed.
+//
+// # Returns true if the value is either "1", "on", "yes" or "true"
+// # Returns false for every other value and the default value if
+// # the key does not exist.
+// v = p.GetBool("key", false)
+//
+// # Returns the value if the key exists and the format conversion
+// # was successful. Otherwise, the default value is returned.
+// v = p.GetInt64("key", 999)
+// v = p.GetUint64("key", 999)
+// v = p.GetFloat64("key", 123.0)
+// v = p.GetString("key", "def")
+// v = p.GetDuration("key", 999)
+//
+// Properties provides several MustXXX() convenience functions
+// which will terminate the app if an error occurs. The behavior
+// of the failure is configurable and the default is to call
+// log.Fatal(err). To have the MustXXX() functions panic instead
+// of logging the error set a different ErrorHandler before
+// you use the Properties package.
+//
+// properties.ErrorHandler = properties.PanicHandler
+//
+// # Will panic instead of logging an error
+// p := properties.MustLoadFile("config.properties")
+//
+// You can also provide your own ErrorHandler function. The only requirement
+// is that the error handler function must exit after handling the error.
+//
+// properties.ErrorHandler = func(err error) {
+// fmt.Println(err)
+// os.Exit(1)
+// }
+//
+// # Will write to stdout and then exit
+// p := properties.MustLoadFile("config.properties")
+//
+// The following documents provide a description of the properties
+// file format.
+//
+// http://en.wikipedia.org/wiki/.properties
+//
+// http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29
+//
+package properties
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/example_test.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/example_test.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/example_test.go
new file mode 100644
index 0000000..38bf04f
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/example_test.go
@@ -0,0 +1,93 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+ "fmt"
+ "log"
+)
+
+func ExampleLoad_iso88591() {
+ buf := []byte("key = ISO-8859-1 value with unicode literal \\u2318 and umlaut \xE4") // 0xE4 == ä
+ p, _ := Load(buf, ISO_8859_1)
+ v, ok := p.Get("key")
+ fmt.Println(ok)
+ fmt.Println(v)
+ // Output:
+ // true
+ // ISO-8859-1 value with unicode literal ⌘ and umlaut ä
+}
+
+func ExampleLoad_utf8() {
+ p, _ := Load([]byte("key = UTF-8 value with unicode character ⌘ and umlaut ä"), UTF8)
+ v, ok := p.Get("key")
+ fmt.Println(ok)
+ fmt.Println(v)
+ // Output:
+ // true
+ // UTF-8 value with unicode character ⌘ and umlaut ä
+}
+
+func ExampleProperties_GetBool() {
+ var input = `
+ key=1
+ key2=On
+ key3=YES
+ key4=true`
+ p, _ := Load([]byte(input), ISO_8859_1)
+ fmt.Println(p.GetBool("key", false))
+ fmt.Println(p.GetBool("key2", false))
+ fmt.Println(p.GetBool("key3", false))
+ fmt.Println(p.GetBool("key4", false))
+ fmt.Println(p.GetBool("keyX", false))
+ // Output:
+ // true
+ // true
+ // true
+ // true
+ // false
+}
+
+func ExampleProperties_GetString() {
+ p, _ := Load([]byte("key=value"), ISO_8859_1)
+ v := p.GetString("another key", "default value")
+ fmt.Println(v)
+ // Output:
+ // default value
+}
+
+func Example() {
+ // Decode some key/value pairs with expressions
+ p, err := Load([]byte("key=value\nkey2=${key}"), ISO_8859_1)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Get a valid key
+ if v, ok := p.Get("key"); ok {
+ fmt.Println(v)
+ }
+
+ // Get an invalid key
+ if _, ok := p.Get("does not exist"); !ok {
+ fmt.Println("invalid key")
+ }
+
+ // Get a key with a default value
+ v := p.GetString("does not exist", "some value")
+ fmt.Println(v)
+
+ // Dump the expanded key/value pairs of the Properties
+ fmt.Println("Expanded key/value pairs")
+ fmt.Println(p)
+
+ // Output:
+ // value
+ // invalid key
+ // some value
+ // Expanded key/value pairs
+ // key = value
+ // key2 = value
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/lex.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/lex.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/lex.go
new file mode 100644
index 0000000..1ae7a45
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/lex.go
@@ -0,0 +1,409 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Parts of the lexer are from the template/text/parser package
+// For these parts the following applies:
+//
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file of the go 1.2
+// distribution.
+
+package properties
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+ typ itemType // The type of this item.
+ pos int // The starting position, in bytes, of this item in the input string.
+ val string // The value of this item.
+}
+
+func (i item) String() string {
+ switch {
+ case i.typ == itemEOF:
+ return "EOF"
+ case i.typ == itemError:
+ return i.val
+ case len(i.val) > 10:
+ return fmt.Sprintf("%.10q...", i.val)
+ }
+ return fmt.Sprintf("%q", i.val)
+}
+
+// itemType identifies the type of lex items.
+type itemType int
+
+const (
+ itemError itemType = iota // error occurred; value is text of error
+ itemEOF
+ itemKey // a key
+ itemValue // a value
+ itemComment // a comment
+)
+
+// defines a constant for EOF
+const eof = -1
+
+// permitted whitespace characters space, FF and TAB
+const whitespace = " \f\t"
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+ input string // the string being scanned
+ state stateFn // the next lexing function to enter
+ pos int // current position in the input
+ start int // start position of this item
+ width int // width of last rune read from input
+ lastPos int // position of most recent item returned by nextItem
+ runes []rune // scanned runes for this item
+ items chan item // channel of scanned items
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() rune {
+ if int(l.pos) >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+ r, w := utf8.DecodeRuneInString(l.input[l.pos:])
+ l.width = w
+ l.pos += l.width
+ return r
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() rune {
+ r := l.next()
+ l.backup()
+ return r
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+ l.pos -= l.width
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+ item := item{t, l.start, string(l.runes)}
+ l.items <- item
+ l.start = l.pos
+ l.runes = l.runes[:0]
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+ l.start = l.pos
+}
+
+// appends the rune to the current value
+func (l *lexer) appendRune(r rune) {
+ l.runes = append(l.runes, r)
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+ if strings.IndexRune(valid, l.next()) >= 0 {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+ for strings.IndexRune(valid, l.next()) >= 0 {
+ }
+ l.backup()
+}
+
+// acceptRunUntil consumes a run of runes up to a terminator.
+func (l *lexer) acceptRunUntil(term rune) {
+ for term != l.next() {
+ }
+ l.backup()
+}
+
+// hasText returns true if the current parsed text is not empty.
+func (l *lexer) isNotEmpty() bool {
+ return l.pos > l.start
+}
+
+// lineNumber reports which line we're on, based on the position of
+// the previous item returned by nextItem. Doing it this way
+// means we don't have to worry about peek double counting.
+func (l *lexer) lineNumber() int {
+ return 1 + strings.Count(l.input[:l.lastPos], "\n")
+}
+
+// errorf returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.nextItem.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
+ return nil
+}
+
+// nextItem returns the next item from the input.
+func (l *lexer) nextItem() item {
+ item := <-l.items
+ l.lastPos = item.pos
+ return item
+}
+
+// lex creates a new scanner for the input string.
+func lex(input string) *lexer {
+ l := &lexer{
+ input: input,
+ items: make(chan item),
+ runes: make([]rune, 0, 32),
+ }
+ go l.run()
+ return l
+}
+
+// run runs the state machine for the lexer.
+func (l *lexer) run() {
+ for l.state = lexBeforeKey(l); l.state != nil; {
+ l.state = l.state(l)
+ }
+}
+
+// state functions
+
+// lexBeforeKey scans until a key begins.
+func lexBeforeKey(l *lexer) stateFn {
+ switch r := l.next(); {
+ case isEOF(r):
+ l.emit(itemEOF)
+ return nil
+
+ case isEOL(r):
+ l.ignore()
+ return lexBeforeKey
+
+ case isComment(r):
+ return lexComment
+
+ case isWhitespace(r):
+ l.acceptRun(whitespace)
+ l.ignore()
+ return lexKey
+
+ default:
+ l.backup()
+ return lexKey
+ }
+}
+
+// lexComment scans a comment line. The comment character has already been scanned.
+func lexComment(l *lexer) stateFn {
+ l.acceptRun(whitespace)
+ l.ignore()
+ for {
+ switch r := l.next(); {
+ case isEOF(r):
+ l.ignore()
+ l.emit(itemEOF)
+ return nil
+ case isEOL(r):
+ l.emit(itemComment)
+ return lexBeforeKey
+ default:
+ l.appendRune(r)
+ }
+ }
+}
+
+// lexKey scans the key up to a delimiter
+func lexKey(l *lexer) stateFn {
+ var r rune
+
+Loop:
+ for {
+ switch r = l.next(); {
+
+ case isEscape(r):
+ err := l.scanEscapeSequence()
+ if err != nil {
+ return l.errorf(err.Error())
+ }
+
+ case isEndOfKey(r):
+ l.backup()
+ break Loop
+
+ case isEOF(r):
+ break Loop
+
+ default:
+ l.appendRune(r)
+ }
+ }
+
+ if len(l.runes) > 0 {
+ l.emit(itemKey)
+ }
+
+ if isEOF(r) {
+ l.emit(itemEOF)
+ return nil
+ }
+
+ return lexBeforeValue
+}
+
+// lexBeforeValue scans the delimiter between key and value.
+// Leading and trailing whitespace is ignored.
+// We expect to be just after the key.
+func lexBeforeValue(l *lexer) stateFn {
+ l.acceptRun(whitespace)
+ l.accept(":=")
+ l.acceptRun(whitespace)
+ l.ignore()
+ return lexValue
+}
+
+// lexValue scans text until the end of the line. We expect to be just after the delimiter.
+func lexValue(l *lexer) stateFn {
+ for {
+ switch r := l.next(); {
+ case isEscape(r):
+ r := l.peek()
+ if isEOL(r) {
+ l.next()
+ l.acceptRun(whitespace)
+ } else {
+ err := l.scanEscapeSequence()
+ if err != nil {
+ return l.errorf(err.Error())
+ }
+ }
+
+ case isEOL(r):
+ l.emit(itemValue)
+ l.ignore()
+ return lexBeforeKey
+
+ case isEOF(r):
+ l.emit(itemValue)
+ l.emit(itemEOF)
+ return nil
+
+ default:
+ l.appendRune(r)
+ }
+ }
+}
+
+// scanEscapeSequence scans either one of the escaped characters
+// or a unicode literal. We expect to be after the escape character.
+func (l *lexer) scanEscapeSequence() error {
+ switch r := l.next(); {
+
+ case isEscapedCharacter(r):
+ l.appendRune(decodeEscapedCharacter(r))
+ return nil
+
+ case atUnicodeLiteral(r):
+ return l.scanUnicodeLiteral()
+
+ case isEOF(r):
+ return fmt.Errorf("premature EOF")
+
+ // silently drop the escape character and append the rune as is
+ default:
+ l.appendRune(r)
+ return nil
+ }
+}
+
+// scans a unicode literal in the form \uXXXX. We expect to be after the \u.
+func (l *lexer) scanUnicodeLiteral() error {
+ // scan the digits
+ d := make([]rune, 4)
+ for i := 0; i < 4; i++ {
+ d[i] = l.next()
+ if d[i] == eof || !strings.ContainsRune("0123456789abcdefABCDEF", d[i]) {
+ return fmt.Errorf("invalid unicode literal")
+ }
+ }
+
+ // decode the digits into a rune
+ r, err := strconv.ParseInt(string(d), 16, 0)
+ if err != nil {
+ return err
+ }
+
+ l.appendRune(rune(r))
+ return nil
+}
+
+// decodeEscapedCharacter returns the unescaped rune. We expect to be after the escape character.
+func decodeEscapedCharacter(r rune) rune {
+ switch r {
+ case 'f':
+ return '\f'
+ case 'n':
+ return '\n'
+ case 'r':
+ return '\r'
+ case 't':
+ return '\t'
+ default:
+ return r
+ }
+}
+
+// atUnicodeLiteral reports whether we are at a unicode literal.
+// The escape character has already been consumed.
+func atUnicodeLiteral(r rune) bool {
+ return r == 'u'
+}
+
+// isComment reports whether we are at the start of a comment.
+func isComment(r rune) bool {
+ return r == '#' || r == '!'
+}
+
+// isEndOfKey reports whether the rune terminates the current key.
+func isEndOfKey(r rune) bool {
+ return strings.ContainsRune(" \f\t\r\n:=", r)
+}
+
+// isEOF reports whether we are at EOF.
+func isEOF(r rune) bool {
+ return r == eof
+}
+
+// isEOL reports whether we are at a new line character.
+func isEOL(r rune) bool {
+ return r == '\n' || r == '\r'
+}
+
+// isEscape reports whether the rune is the escape character which
+// prefixes unicode literals and other escaped characters.
+func isEscape(r rune) bool {
+ return r == '\\'
+}
+
+// isEscapedCharacter reports whether we are at one of the characters that need escaping.
+// The escape character has already been consumed.
+func isEscapedCharacter(r rune) bool {
+ return strings.ContainsRune(" :=fnrt", r)
+}
+
+// isWhitespace reports whether the rune is a whitespace character.
+func isWhitespace(r rune) bool {
+ return strings.ContainsRune(whitespace, r)
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/load.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/load.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/load.go
new file mode 100644
index 0000000..431d462
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/load.go
@@ -0,0 +1,124 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+
+// Encoding specifies encoding of the input data.
+type Encoding uint
+
+const (
+ // UTF8 interprets the input data as UTF-8.
+ UTF8 Encoding = 1 << iota
+
+ // ISO_8859_1 interprets the input data as ISO-8859-1.
+ ISO_8859_1
+)
+
+// Load reads a buffer into a Properties struct.
+func Load(buf []byte, enc Encoding) (*Properties, error) {
+ return loadBuf(buf, enc)
+}
+
+// LoadFile reads a file into a Properties struct.
+func LoadFile(filename string, enc Encoding) (*Properties, error) {
+ return loadFiles([]string{filename}, enc, false)
+}
+
+// LoadFiles reads multiple files in the given order into
+// a Properties struct. If 'ignoreMissing' is true then
+// non-existent files will not be reported as error.
+func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
+ return loadFiles(filenames, enc, ignoreMissing)
+}
+
+// MustLoadFile reads a file into a Properties struct and
+// panics on error.
+func MustLoadFile(filename string, enc Encoding) *Properties {
+ return mustLoadFiles([]string{filename}, enc, false)
+}
+
+// MustLoadFiles reads multiple files in the given order into
+// a Properties struct and panics on error. If 'ignoreMissing'
+// is true then non-existent files will not be reported as error.
+func MustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties {
+ return mustLoadFiles(filenames, enc, ignoreMissing)
+}
+
+// ----------------------------------------------------------------------------
+
+func loadBuf(buf []byte, enc Encoding) (*Properties, error) {
+ p, err := parse(convert(buf, enc))
+ if err != nil {
+ return nil, err
+ }
+
+ return p, p.check()
+}
+
+func loadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
+ buff := make([]byte, 0, 4096)
+
+ for _, filename := range filenames {
+ f, err := expandFilename(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ buf, err := ioutil.ReadFile(f)
+ if err != nil {
+ if ignoreMissing && os.IsNotExist(err) {
+ // TODO(frank): should we log that we are skipping the file?
+ continue
+ }
+ return nil, err
+ }
+
+ // concatenate the buffers and add a new line in case
+ // the previous file didn't end with a new line
+ buff = append(append(buff, buf...), '\n')
+ }
+
+ return loadBuf(buff, enc)
+}
+
+func mustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties {
+ p, err := loadFiles(filenames, enc, ignoreMissing)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return p
+}
+
+// expandFilename expands ${ENV_VAR} expressions in a filename.
+// If the environment variable does not exist then it will be replaced
+// with an empty string. Malformed expressions like "${ENV_VAR" will
+// be reported as error.
+func expandFilename(filename string) (string, error) {
+ return expand(filename, make(map[string]bool), "${", "}", make(map[string]string))
+}
+
+// Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string.
+// For ISO-8859-1 we can convert each byte straight into a rune since the
+// first 256 unicode code points cover ISO-8859-1.
+func convert(buf []byte, enc Encoding) string {
+ switch enc {
+ case UTF8:
+ return string(buf)
+ case ISO_8859_1:
+ runes := make([]rune, len(buf))
+ for i, b := range buf {
+ runes[i] = rune(b)
+ }
+ return string(runes)
+ default:
+ ErrorHandler(fmt.Errorf("unsupported encoding %v", enc))
+ }
+ panic("ErrorHandler should exit")
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/load_test.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/load_test.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/load_test.go
new file mode 100644
index 0000000..9d1e3b6
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/load_test.go
@@ -0,0 +1,137 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ . "gopkg.in/check.v1"
+)
+
+type LoadSuite struct {
+ tempFiles []string
+}
+
+var (
+ _ = Suite(&LoadSuite{})
+)
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TestLoadFailsWithNotExistingFile(c *C) {
+ _, err := LoadFile("doesnotexist.properties", ISO_8859_1)
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, "open.*no such file or directory")
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TestLoadFilesFailsOnNotExistingFile(c *C) {
+ _, err := LoadFiles([]string{"doesnotexist.properties"}, ISO_8859_1, false)
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, "open.*no such file or directory")
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TestLoadFilesDoesNotFailOnNotExistingFileAndIgnoreMissing(c *C) {
+ p, err := LoadFiles([]string{"doesnotexist.properties"}, ISO_8859_1, true)
+ c.Assert(err, IsNil)
+ c.Assert(p.Len(), Equals, 0)
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TestLoad(c *C) {
+ filename := s.makeFile(c, "key=value")
+ p := MustLoadFile(filename, ISO_8859_1)
+
+ c.Assert(p.Len(), Equals, 1)
+ assertKeyValues(c, "", p, "key", "value")
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TestLoadFiles(c *C) {
+ filename := s.makeFile(c, "key=value")
+ filename2 := s.makeFile(c, "key2=value2")
+ p := MustLoadFiles([]string{filename, filename2}, ISO_8859_1, false)
+ assertKeyValues(c, "", p, "key", "value", "key2", "value2")
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TestLoadExpandedFile(c *C) {
+ filename := s.makeFilePrefix(c, os.Getenv("USER"), "key=value")
+ filename = strings.Replace(filename, os.Getenv("USER"), "${USER}", -1)
+ p := MustLoadFile(filename, ISO_8859_1)
+ assertKeyValues(c, "", p, "key", "value")
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TestLoadFilesAndIgnoreMissing(c *C) {
+ filename := s.makeFile(c, "key=value")
+ filename2 := s.makeFile(c, "key2=value2")
+ p := MustLoadFiles([]string{filename, filename + "foo", filename2, filename2 + "foo"}, ISO_8859_1, true)
+ assertKeyValues(c, "", p, "key", "value", "key2", "value2")
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) SetUpSuite(c *C) {
+ s.tempFiles = make([]string, 0)
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) TearDownSuite(c *C) {
+ for _, path := range s.tempFiles {
+ err := os.Remove(path)
+ if err != nil {
+ fmt.Printf("os.Remove: %v", err)
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) makeFile(c *C, data string) string {
+ return s.makeFilePrefix(c, "properties", data)
+}
+
+// ----------------------------------------------------------------------------
+
+func (s *LoadSuite) makeFilePrefix(c *C, prefix, data string) string {
+ f, err := ioutil.TempFile("", prefix)
+ if err != nil {
+ fmt.Printf("ioutil.TempFile: %v", err)
+ c.FailNow()
+ }
+
+ // remember the temp file so that we can remove it later
+ s.tempFiles = append(s.tempFiles, f.Name())
+
+ n, err := fmt.Fprint(f, data)
+ if err != nil {
+ fmt.Printf("fmt.Fprintln: %v", err)
+ c.FailNow()
+ }
+ if n != len(data) {
+ fmt.Printf("Data size mismatch. expected=%d wrote=%d\n", len(data), n)
+ c.FailNow()
+ }
+
+ err = f.Close()
+ if err != nil {
+ fmt.Printf("f.Close: %v", err)
+ c.FailNow()
+ }
+
+ return f.Name()
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/parser.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/parser.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/parser.go
new file mode 100644
index 0000000..bb71fb9
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/parser.go
@@ -0,0 +1,95 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+ "fmt"
+ "runtime"
+)
+
+type parser struct {
+ lex *lexer
+}
+
+func parse(input string) (properties *Properties, err error) {
+ p := &parser{lex: lex(input)}
+ defer p.recover(&err)
+
+ properties = NewProperties()
+ key := ""
+ comments := []string{}
+
+ for {
+ token := p.expectOneOf(itemComment, itemKey, itemEOF)
+ switch token.typ {
+ case itemEOF:
+ goto done
+ case itemComment:
+ comments = append(comments, token.val)
+ continue
+ case itemKey:
+ key = token.val
+ if _, ok := properties.m[key]; !ok {
+ properties.k = append(properties.k, key)
+ }
+ }
+
+ token = p.expectOneOf(itemValue, itemEOF)
+ if len(comments) > 0 {
+ properties.c[key] = comments
+ comments = []string{}
+ }
+ switch token.typ {
+ case itemEOF:
+ properties.m[key] = ""
+ goto done
+ case itemValue:
+ properties.m[key] = token.val
+ }
+ }
+
+done:
+ return properties, nil
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+ format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format)
+ panic(fmt.Errorf(format, args...))
+}
+
+func (p *parser) expect(expected itemType) (token item) {
+ token = p.lex.nextItem()
+ if token.typ != expected {
+ p.unexpected(token)
+ }
+ return token
+}
+
+func (p *parser) expectOneOf(expected ...itemType) (token item) {
+ token = p.lex.nextItem()
+ for _, v := range expected {
+ if token.typ == v {
+ return token
+ }
+ }
+ p.unexpected(token)
+ panic("unexpected token")
+}
+
+func (p *parser) unexpected(token item) {
+ p.errorf(token.String())
+}
+
+// recover is the handler that turns panics into returns from the top level of Parse.
+func (p *parser) recover(errp *error) {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ *errp = e.(error)
+ }
+ return
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/e95057f4/newt/Godeps/_workspace/src/github.com/magiconair/properties/properties.go
----------------------------------------------------------------------
diff --git a/newt/Godeps/_workspace/src/github.com/magiconair/properties/properties.go b/newt/Godeps/_workspace/src/github.com/magiconair/properties/properties.go
new file mode 100644
index 0000000..edcaccc
--- /dev/null
+++ b/newt/Godeps/_workspace/src/github.com/magiconair/properties/properties.go
@@ -0,0 +1,698 @@
+// Copyright 2013-2014 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+// BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer.
+// BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used.
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+)
+
+// ErrorHandlerFunc defines the type of function which handles failures
+// of the MustXXX() functions. An error handler function must exit
+// the application after handling the error.
+type ErrorHandlerFunc func(error)
+
+// ErrorHandler is the function which handles failures of the MustXXX()
+// functions. The default is LogFatalHandler.
+var ErrorHandler = LogFatalHandler
+
+// LogFatalHandler handles the error by logging a fatal error and exiting.
+func LogFatalHandler(err error) {
+ log.Fatal(err)
+}
+
+// PanicHandler handles the error by panicking.
+func PanicHandler(err error) {
+ panic(err)
+}
+
+// -----------------------------------------------------------------------------
+
+// A Properties contains the key/value pairs from the properties input.
+// All values are stored in unexpanded form and are expanded at runtime
+type Properties struct {
+ // Pre-/Postfix for property expansion.
+ Prefix string
+ Postfix string
+
+ // Stores the key/value pairs
+ m map[string]string
+
+ // Stores the comments per key.
+ c map[string][]string
+
+ // Stores the keys in order of appearance.
+ k []string
+}
+
+// NewProperties creates a new Properties struct with the default
+// configuration for "${key}" expressions.
+func NewProperties() *Properties {
+ return &Properties{
+ Prefix: "${",
+ Postfix: "}",
+ m: map[string]string{},
+ c: map[string][]string{},
+ k: []string{},
+ }
+}
+
+// Get returns the expanded value for the given key if exists.
+// Otherwise, ok is false.
+func (p *Properties) Get(key string) (value string, ok bool) {
+ v, ok := p.m[key]
+ if !ok {
+ return "", false
+ }
+
+ expanded, err := p.expand(v)
+
+ // we guarantee that the expanded value is free of
+ // circular references and malformed expressions
+ // so we panic if we still get an error here.
+ if err != nil {
+ ErrorHandler(fmt.Errorf("%s in %q", err, key+" = "+v))
+ }
+
+ return expanded, true
+}
+
+// MustGet returns the expanded value for the given key if exists.
+// Otherwise, it panics.
+func (p *Properties) MustGet(key string) string {
+ if v, ok := p.Get(key); ok {
+ return v
+ }
+ ErrorHandler(invalidKeyError(key))
+ panic("ErrorHandler should exit")
+}
+
+// ----------------------------------------------------------------------------
+
+// ClearComments removes the comments for all keys.
+func (p *Properties) ClearComments() {
+ p.c = map[string][]string{}
+}
+
+// ----------------------------------------------------------------------------
+
+// GetComment returns the last comment before the given key or an empty string.
+func (p *Properties) GetComment(key string) string {
+ comments, ok := p.c[key]
+ if !ok || len(comments) == 0 {
+ return ""
+ }
+ return comments[len(comments)-1]
+}
+
+// ----------------------------------------------------------------------------
+
+// GetComments returns all comments that appeared before the given key or nil.
+func (p *Properties) GetComments(key string) []string {
+ if comments, ok := p.c[key]; ok {
+ return comments
+ }
+ return nil
+}
+
+// ----------------------------------------------------------------------------
+
+// SetComment sets the comment for the key.
+func (p *Properties) SetComment(key, comment string) {
+ p.c[key] = []string{comment}
+}
+
+// ----------------------------------------------------------------------------
+
+// SetComments sets the comments for the key. If the comments are nil then
+// all comments for this key are deleted.
+func (p *Properties) SetComments(key string, comments []string) {
+ if comments == nil {
+ delete(p.c, key)
+ return
+ }
+ p.c[key] = comments
+}
+
+// ----------------------------------------------------------------------------
+
+// GetBool checks if the expanded value is one of '1', 'yes',
+// 'true' or 'on' if the key exists. The comparison is case-insensitive.
+// If the key does not exist the default value is returned.
+func (p *Properties) GetBool(key string, def bool) bool {
+ v, err := p.getBool(key)
+ if err != nil {
+ return def
+ }
+ return v
+}
+
+// MustGetBool checks if the expanded value is one of '1', 'yes',
+// 'true' or 'on' if the key exists. The comparison is case-insensitive.
+// If the key does not exist the function panics.
+func (p *Properties) MustGetBool(key string) bool {
+ v, err := p.getBool(key)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return v
+}
+
+func (p *Properties) getBool(key string) (value bool, err error) {
+ if v, ok := p.Get(key); ok {
+ v = strings.ToLower(v)
+ return v == "1" || v == "true" || v == "yes" || v == "on", nil
+ }
+ return false, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetDuration parses the expanded value as an time.Duration (in ns) if the
+// key exists. If key does not exist or the value cannot be parsed the default
+// value is returned. In almost all cases you want to use GetParsedDuration().
+func (p *Properties) GetDuration(key string, def time.Duration) time.Duration {
+ v, err := p.getInt64(key)
+ if err != nil {
+ return def
+ }
+ return time.Duration(v)
+}
+
+// MustGetDuration parses the expanded value as an time.Duration (in ns) if
+// the key exists. If key does not exist or the value cannot be parsed the
+// function panics. In almost all cases you want to use MustGetParsedDuration().
+func (p *Properties) MustGetDuration(key string) time.Duration {
+ v, err := p.getInt64(key)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return time.Duration(v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration {
+ s, ok := p.Get(key)
+ if !ok {
+ return def
+ }
+ v, err := time.ParseDuration(s)
+ if err != nil {
+ return def
+ }
+ return v
+}
+
+// MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetParsedDuration(key string) time.Duration {
+ s, ok := p.Get(key)
+ if !ok {
+ ErrorHandler(invalidKeyError(key))
+ }
+ v, err := time.ParseDuration(s)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return v
+}
+
+// ----------------------------------------------------------------------------
+
+// GetFloat64 parses the expanded value as a float64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetFloat64(key string, def float64) float64 {
+ v, err := p.getFloat64(key)
+ if err != nil {
+ return def
+ }
+ return v
+}
+
+// MustGetFloat64 parses the expanded value as a float64 if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetFloat64(key string) float64 {
+ v, err := p.getFloat64(key)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return v
+}
+
+func (p *Properties) getFloat64(key string) (value float64, err error) {
+ if v, ok := p.Get(key); ok {
+ value, err = strconv.ParseFloat(v, 64)
+ if err != nil {
+ return 0, err
+ }
+ return value, nil
+ }
+ return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetInt parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned. If the value does not fit into an int the
+// function panics with an out of range error.
+func (p *Properties) GetInt(key string, def int) int {
+ v, err := p.getInt64(key)
+ if err != nil {
+ return def
+ }
+ return intRangeCheck(key, v)
+}
+
+// MustGetInt parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+// If the value does not fit into an int the function panics with
+// an out of range error.
+func (p *Properties) MustGetInt(key string) int {
+ v, err := p.getInt64(key)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return intRangeCheck(key, v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetInt64 parses the expanded value as an int64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetInt64(key string, def int64) int64 {
+ v, err := p.getInt64(key)
+ if err != nil {
+ return def
+ }
+ return v
+}
+
+// MustGetInt64 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetInt64(key string) int64 {
+ v, err := p.getInt64(key)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return v
+}
+
+func (p *Properties) getInt64(key string) (value int64, err error) {
+ if v, ok := p.Get(key); ok {
+ value, err = strconv.ParseInt(v, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ return value, nil
+ }
+ return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetUint parses the expanded value as an uint if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned. If the value does not fit into an int the
+// function panics with an out of range error.
+func (p *Properties) GetUint(key string, def uint) uint {
+ v, err := p.getUint64(key)
+ if err != nil {
+ return def
+ }
+ return uintRangeCheck(key, v)
+}
+
+// MustGetUint parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+// If the value does not fit into an int the function panics with
+// an out of range error.
+func (p *Properties) MustGetUint(key string) uint {
+ v, err := p.getUint64(key)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return uintRangeCheck(key, v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetUint64 parses the expanded value as an uint64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetUint64(key string, def uint64) uint64 {
+ v, err := p.getUint64(key)
+ if err != nil {
+ return def
+ }
+ return v
+}
+
+// MustGetUint64 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetUint64(key string) uint64 {
+ v, err := p.getUint64(key)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return v
+}
+
+func (p *Properties) getUint64(key string) (value uint64, err error) {
+ if v, ok := p.Get(key); ok {
+ value, err = strconv.ParseUint(v, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ return value, nil
+ }
+ return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetString returns the expanded value for the given key if exists or
+// the default value otherwise.
+func (p *Properties) GetString(key, def string) string {
+ if v, ok := p.Get(key); ok {
+ return v
+ }
+ return def
+}
+
+// MustGetString returns the expanded value for the given key if exists or
+// panics otherwise.
+func (p *Properties) MustGetString(key string) string {
+ if v, ok := p.Get(key); ok {
+ return v
+ }
+ ErrorHandler(invalidKeyError(key))
+ panic("ErrorHandler should exit")
+}
+
+// ----------------------------------------------------------------------------
+
+// Filter returns a new properties object which contains all properties
+// for which the key matches the pattern.
+func (p *Properties) Filter(pattern string) (*Properties, error) {
+ re, err := regexp.Compile(pattern)
+ if err != nil {
+ return nil, err
+ }
+
+ return p.FilterRegexp(re), nil
+}
+
+// FilterRegexp returns a new properties object which contains all properties
+// for which the key matches the regular expression.
+func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties {
+ pp := NewProperties()
+ for _, k := range p.k {
+ if re.MatchString(k) {
+ pp.Set(k, p.m[k])
+ }
+ }
+ return pp
+}
+
+// FilterPrefix returns a new properties object which contains all properties
+// for which the key starts with the prefix.
+func (p *Properties) FilterPrefix(prefix string) *Properties {
+ pp := NewProperties()
+ for _, k := range p.k {
+ if strings.HasPrefix(k, prefix) {
+ pp.Set(k, p.m[k])
+ }
+ }
+ return pp
+}
+
+// Len returns the number of keys.
+func (p *Properties) Len() int {
+ return len(p.m)
+}
+
+// Keys returns all keys in the same order as in the input.
+func (p *Properties) Keys() []string {
+ keys := make([]string, len(p.k))
+ for i, k := range p.k {
+ keys[i] = k
+ }
+ return keys
+}
+
+// Set sets the property key to the corresponding value.
+// If a value for key existed before then ok is true and prev
+// contains the previous value. If the value contains a
+// circular reference or a malformed expression then
+// an error is returned.
+// An empty key is silently ignored.
+func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
+ if key == "" {
+ return "", false, nil
+ }
+
+ // to check for a circular reference we temporarily need
+ // to set the new value. If there is an error then revert
+ // to the previous state. Only if all tests are successful
+ // then we add the key to the p.k list.
+ prev, ok = p.Get(key)
+ p.m[key] = value
+
+ // now check for a circular reference
+ _, err = p.expand(value)
+ if err != nil {
+
+ // revert to the previous state
+ if ok {
+ p.m[key] = prev
+ } else {
+ delete(p.m, key)
+ }
+
+ return "", false, err
+ }
+
+ if !ok {
+ p.k = append(p.k, key)
+ }
+
+ return prev, ok, nil
+}
+
+// MustSet sets the property key to the corresponding value.
+// If a value for key existed before then ok is true and prev
+// contains the previous value. An empty key is silently ignored.
+func (p *Properties) MustSet(key, value string) (prev string, ok bool) {
+ prev, ok, err := p.Set(key, value)
+ if err != nil {
+ ErrorHandler(err)
+ }
+ return prev, ok
+}
+
+// String returns a string of all expanded 'key = value' pairs.
+func (p *Properties) String() string {
+ var s string
+ for _, key := range p.k {
+ value, _ := p.Get(key)
+ s = fmt.Sprintf("%s%s = %s\n", s, key, value)
+ }
+ return s
+}
+
+// Write writes all unexpanded 'key = value' pairs to the given writer.
+// Write returns the number of bytes written and any write error encountered.
+func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) {
+ return p.WriteComment(w, "", enc)
+}
+
+// WriteComment writes all unexpanced 'key = value' pairs to the given writer.
+// If prefix is not empty then comments are written with a blank line and the
+// given prefix. The prefix should be either "# " or "! " to be compatible with
+// the properties file format. Otherwise, the properties parser will not be
+// able to read the file back in. It returns the number of bytes written and
+// any write error encountered.
+func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) {
+ var x int
+
+ for _, key := range p.k {
+ value := p.m[key]
+
+ if prefix != "" {
+ if comments, ok := p.c[key]; ok {
+ // don't print comments if they are all empty
+ allEmpty := true
+ for _, c := range comments {
+ if c != "" {
+ allEmpty = false
+ break
+ }
+ }
+
+ if !allEmpty {
+ // add a blank line between entries but not at the top
+ if len(comments) > 0 && n > 0 {
+ x, err = fmt.Fprintln(w)
+ if err != nil {
+ return
+ }
+ n += x
+ }
+
+ for _, c := range comments {
+ x, err = fmt.Fprintf(w, "%s%s\n", prefix, encode(c, "", enc))
+ if err != nil {
+ return
+ }
+ n += x
+ }
+ }
+ }
+ }
+
+ x, err = fmt.Fprintf(w, "%s = %s\n", encode(key, " :", enc), encode(value, "", enc))
+ if err != nil {
+ return
+ }
+ n += x
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+
+// check expands all values and returns an error if a circular reference or
+// a malformed expression was found.
+func (p *Properties) check() error {
+ for _, value := range p.m {
+ if _, err := p.expand(value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p *Properties) expand(input string) (string, error) {
+ // no pre/postfix -> nothing to expand
+ if p.Prefix == "" && p.Postfix == "" {
+ return input, nil
+ }
+
+ return expand(input, make(map[string]bool), p.Prefix, p.Postfix, p.m)
+}
+
+// expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values.
+// The function keeps track of the keys that were already expanded and stops if it
+// detects a circular reference or a malformed expression of the form '(prefix)key'.
+func expand(s string, keys map[string]bool, prefix, postfix string, values map[string]string) (string, error) {
+ start := strings.Index(s, prefix)
+ if start == -1 {
+ return s, nil
+ }
+
+ keyStart := start + len(prefix)
+ keyLen := strings.Index(s[keyStart:], postfix)
+ if keyLen == -1 {
+ return "", fmt.Errorf("malformed expression")
+ }
+
+ end := keyStart + keyLen + len(postfix) - 1
+ key := s[keyStart : keyStart+keyLen]
+
+ // 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)
+
+ if _, ok := keys[key]; ok {
+ return "", fmt.Errorf("circular reference")
+ }
+
+ val, ok := values[key]
+ if !ok {
+ val = os.Getenv(key)
+ }
+
+ // remember that we've seen the key
+ keys[key] = true
+
+ return expand(s[:start]+val+s[end+1:], keys, prefix, postfix, values)
+}
+
+// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters.
+func encode(s string, special string, enc Encoding) string {
+ switch enc {
+ case UTF8:
+ return encodeUtf8(s, special)
+ case ISO_8859_1:
+ return encodeIso(s, special)
+ default:
+ panic(fmt.Sprintf("unsupported encoding %v", enc))
+ }
+}
+
+func encodeUtf8(s string, special string) string {
+ v := ""
+ for pos := 0; pos < len(s); {
+ r, w := utf8.DecodeRuneInString(s[pos:])
+ pos += w
+ v += escape(r, special)
+ }
+ return v
+}
+
+func encodeIso(s string, special string) string {
+ var r rune
+ var w int
+ var v string
+ for pos := 0; pos < len(s); {
+ switch r, w = utf8.DecodeRuneInString(s[pos:]); {
+ case r < 1<<8: // single byte rune -> escape special chars only
+ v += escape(r, special)
+ case r < 1<<16: // two byte rune -> unicode literal
+ v += fmt.Sprintf("\\u%04x", r)
+ default: // more than two bytes per rune -> can't encode
+ v += "?"
+ }
+ pos += w
+ }
+ return v
+}
+
+func escape(r rune, special string) string {
+ switch r {
+ case '\f':
+ return "\\f"
+ case '\n':
+ return "\\n"
+ case '\r':
+ return "\\r"
+ case '\t':
+ return "\\t"
+ default:
+ if strings.ContainsRune(special, r) {
+ return "\\" + string(r)
+ }
+ return string(r)
+ }
+}
+
+func invalidKeyError(key string) error {
+ return fmt.Errorf("unknown property: %s", key)
+}