Skip to content

Commit 43f1d41

Browse files
authored
Merge pull request #378 from ndeloof/Flood-Resistant-mirror-drill
2 parents e0f9c51 + 71293bc commit 43f1d41

File tree

4 files changed

+42
-38
lines changed

4 files changed

+42
-38
lines changed

dotenv/godotenv.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,13 @@ func Read(filenames ...string) (map[string]string, error) {
111111

112112
// UnmarshalBytesWithLookup parses env file from byte slice of chars, returning a map of keys and values.
113113
func UnmarshalBytesWithLookup(src []byte, lookupFn LookupFn) (map[string]string, error) {
114+
return UnmarshalWithLookup(string(src), lookupFn)
115+
}
116+
117+
// UnmarshalWithLookup parses env file from string, returning a map of keys and values.
118+
func UnmarshalWithLookup(src string, lookupFn LookupFn) (map[string]string, error) {
114119
out := make(map[string]string)
115-
err := newParser().parseBytes(src, out, lookupFn)
120+
err := newParser().parse(src, out, lookupFn)
116121
return out, err
117122
}
118123

dotenv/godotenv_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ func TestLinesToIgnore(t *testing.T) {
465465

466466
for n, c := range cases {
467467
t.Run(n, func(t *testing.T) {
468-
got := string(newParser().getStatementStart([]byte(c.input)))
468+
got := string(newParser().getStatementStart(c.input))
469469
if got != c.want {
470470
t.Errorf("Expected:\t %q\nGot:\t %q", c.want, got)
471471
}

dotenv/parser.go

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dotenv
22

33
import (
4-
"bytes"
54
"errors"
65
"fmt"
76
"regexp"
@@ -31,14 +30,14 @@ func newParser() *parser {
3130
}
3231
}
3332

34-
func (p *parser) parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error {
33+
func (p *parser) parse(src string, out map[string]string, lookupFn LookupFn) error {
3534
cutset := src
3635
if lookupFn == nil {
3736
lookupFn = noLookupFn
3837
}
3938
for {
4039
cutset = p.getStatementStart(cutset)
41-
if cutset == nil {
40+
if cutset == "" {
4241
// reached end of file
4342
break
4443
}
@@ -75,10 +74,10 @@ func (p *parser) parseBytes(src []byte, out map[string]string, lookupFn LookupFn
7574
// getStatementPosition returns position of statement begin.
7675
//
7776
// It skips any comment line or non-whitespace character.
78-
func (p *parser) getStatementStart(src []byte) []byte {
77+
func (p *parser) getStatementStart(src string) string {
7978
pos := p.indexOfNonSpaceChar(src)
8079
if pos == -1 {
81-
return nil
80+
return ""
8281
}
8382

8483
src = src[pos:]
@@ -87,70 +86,69 @@ func (p *parser) getStatementStart(src []byte) []byte {
8786
}
8887

8988
// skip comment section
90-
pos = bytes.IndexFunc(src, isCharFunc('\n'))
89+
pos = strings.IndexFunc(src, isCharFunc('\n'))
9190
if pos == -1 {
92-
return nil
91+
return ""
9392
}
9493
return p.getStatementStart(src[pos:])
9594
}
9695

9796
// locateKeyName locates and parses key name and returns rest of slice
98-
func (p *parser) locateKeyName(src []byte) (string, []byte, bool, error) {
97+
func (p *parser) locateKeyName(src string) (string, string, bool, error) {
9998
var key string
10099
var inherited bool
101100
// trim "export" and space at beginning
102-
src = bytes.TrimLeftFunc(exportRegex.ReplaceAll(src, nil), isSpace)
101+
src = strings.TrimLeftFunc(exportRegex.ReplaceAllString(src, ""), isSpace)
103102

104103
// locate key name end and validate it in single loop
105104
offset := 0
106105
loop:
107-
for i, char := range src {
108-
rchar := rune(char)
109-
if isSpace(rchar) {
106+
for i, rune := range src {
107+
if isSpace(rune) {
110108
continue
111109
}
112110

113-
switch char {
111+
switch rune {
114112
case '=', ':', '\n':
115113
// library also supports yaml-style value declaration
116114
key = string(src[0:i])
117115
offset = i + 1
118-
inherited = char == '\n'
116+
inherited = rune == '\n'
119117
break loop
120118
case '_', '.', '-', '[', ']':
121119
default:
122120
// variable name should match [A-Za-z0-9_.-]
123-
if unicode.IsLetter(rchar) || unicode.IsNumber(rchar) {
121+
if unicode.IsLetter(rune) || unicode.IsNumber(rune) {
124122
continue
125123
}
126124

127-
return "", nil, inherited, fmt.Errorf(
125+
return "", "", inherited, fmt.Errorf(
128126
`line %d: unexpected character %q in variable name`,
129-
p.line, string(char))
127+
p.line, string(rune))
130128
}
131129
}
132130

133-
if len(src) == 0 {
134-
return "", nil, inherited, errors.New("zero length string")
131+
if src == "" {
132+
return "", "", inherited, errors.New("zero length string")
135133
}
136134

137135
// trim whitespace
138136
key = strings.TrimRightFunc(key, unicode.IsSpace)
139-
cutset := bytes.TrimLeftFunc(src[offset:], isSpace)
137+
cutset := strings.TrimLeftFunc(src[offset:], isSpace)
140138
return key, cutset, inherited, nil
141139
}
142140

143141
// extractVarValue extracts variable value and returns rest of slice
144-
func (p *parser) extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (string, []byte, error) {
142+
func (p *parser) extractVarValue(src string, envMap map[string]string, lookupFn LookupFn) (string, string, error) {
145143
quote, isQuoted := hasQuotePrefix(src)
146144
if !isQuoted {
147145
// unquoted value - read until new line
148-
value, rest, _ := bytes.Cut(src, []byte("\n"))
146+
value, rest, _ := strings.Cut(src, "\n")
149147
p.line++
150148

151149
// Remove inline comments on unquoted lines
152-
value, _, _ = bytes.Cut(value, []byte(" #"))
153-
value = bytes.TrimRightFunc(value, unicode.IsSpace)
150+
value, _, _ = strings.Cut(value, " #")
151+
value = strings.TrimRightFunc(value, unicode.IsSpace)
154152
retVal, err := expandVariables(string(value), envMap, lookupFn)
155153
return retVal, rest, err
156154
}
@@ -176,7 +174,7 @@ func (p *parser) extractVarValue(src []byte, envMap map[string]string, lookupFn
176174
// variables on the result
177175
retVal, err := expandVariables(expandEscapes(value), envMap, lookupFn)
178176
if err != nil {
179-
return "", nil, err
177+
return "", "", err
180178
}
181179
value = retVal
182180
}
@@ -185,12 +183,12 @@ func (p *parser) extractVarValue(src []byte, envMap map[string]string, lookupFn
185183
}
186184

187185
// return formatted error if quoted string is not terminated
188-
valEndIndex := bytes.IndexFunc(src, isCharFunc('\n'))
186+
valEndIndex := strings.IndexFunc(src, isCharFunc('\n'))
189187
if valEndIndex == -1 {
190188
valEndIndex = len(src)
191189
}
192190

193-
return "", nil, fmt.Errorf("line %d: unterminated quoted value %s", p.line, src[:valEndIndex])
191+
return "", "", fmt.Errorf("line %d: unterminated quoted value %s", p.line, src[:valEndIndex])
194192
}
195193

196194
func expandEscapes(str string) string {
@@ -225,8 +223,8 @@ func expandEscapes(str string) string {
225223
return out
226224
}
227225

228-
func (p *parser) indexOfNonSpaceChar(src []byte) int {
229-
return bytes.IndexFunc(src, func(r rune) bool {
226+
func (p *parser) indexOfNonSpaceChar(src string) int {
227+
return strings.IndexFunc(src, func(r rune) bool {
230228
if r == '\n' {
231229
p.line++
232230
}
@@ -235,8 +233,8 @@ func (p *parser) indexOfNonSpaceChar(src []byte) int {
235233
}
236234

237235
// hasQuotePrefix reports whether charset starts with single or double quote and returns quote character
238-
func hasQuotePrefix(src []byte) (byte, bool) {
239-
if len(src) == 0 {
236+
func hasQuotePrefix(src string) (byte, bool) {
237+
if src == "" {
240238
return 0, false
241239
}
242240

dotenv/parser_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,21 @@ var testInput = `
1010
a=b
1111
a[1]=c
1212
a.propertyKey=d
13+
árvíztűrő-TÜKÖRFÚRÓGÉP=ÁRVÍZTŰRŐ-tükörfúrógép
1314
`
1415

1516
func TestParseBytes(t *testing.T) {
1617
p := newParser()
1718

18-
var inputBytes = []byte(testInput)
1919
expectedOutput := map[string]string{
20-
"a": "b",
21-
"a[1]": "c",
22-
"a.propertyKey": "d",
20+
"a": "b",
21+
"a[1]": "c",
22+
"a.propertyKey": "d",
23+
"árvíztűrő-TÜKÖRFÚRÓGÉP": "ÁRVÍZTŰRŐ-tükörfúrógép",
2324
}
2425

2526
out := map[string]string{}
26-
err := p.parseBytes([]byte(inputBytes), out, nil)
27+
err := p.parse(testInput, out, nil)
2728

2829
assert.NilError(t, err)
2930
assert.Equal(t, len(expectedOutput), len(out))

0 commit comments

Comments
 (0)