diff --git a/fixtures/unquoted.env b/fixtures/unquoted.env new file mode 100644 index 0000000..f83a4b6 --- /dev/null +++ b/fixtures/unquoted.env @@ -0,0 +1,5 @@ +OPTION_A = "some quoted phrase" +OPTION_B=first one with an unquoted phrase +OPTION_C = then another one with an unquoted phrase +OPTION_D = then another one with an unquoted phrase special è char +OPTION_E = "then another one quoted phrase" diff --git a/godotenv_test.go b/godotenv_test.go index 39abf92..ad46519 100644 --- a/godotenv_test.go +++ b/godotenv_test.go @@ -199,6 +199,19 @@ and so on`, loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets) } +func TestLoadUnquotedEnv(t *testing.T) { + envFileName := "fixtures/unquoted.env" + expectedValues := map[string]string{ + "OPTION_A": "some quoted phrase", + "OPTION_B": "first one with an unquoted phrase", + "OPTION_C": "then another one with an unquoted phrase", + "OPTION_D": "then another one with an unquoted phrase special è char", + "OPTION_E": "then another one quoted phrase", + } + + loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets) +} + func TestSubstitutions(t *testing.T) { envFileName := "fixtures/substitutions.env" expectedValues := map[string]string{ diff --git a/parser.go b/parser.go index dd8c4b5..1d144de 100644 --- a/parser.go +++ b/parser.go @@ -127,15 +127,21 @@ loop: // extractVarValue extracts variable value and returns rest of slice func extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (value string, rest []byte, err error) { - quote, hasPrefix := hasQuotePrefix(src) - if !hasPrefix { - // unquoted value - read until whitespace - end := bytes.IndexFunc(src, unicode.IsSpace) - if end == -1 { - return expandVariables(string(src), envMap, lookupFn), nil, nil + quote, isQuoted := hasQuotePrefix(src) + if !isQuoted { + // unquoted value - read until new line + end := bytes.IndexFunc(src, isNewLine) + var rest []byte + var value string + if end < 0 { + value := strings.TrimRightFunc(string(src), unicode.IsSpace) + rest = nil + return expandVariables(value, envMap, lookupFn), rest, nil } - return expandVariables(string(src[0:end]), envMap, lookupFn), src[end:], nil + value = strings.TrimRightFunc(string(src[0:end]), unicode.IsSpace) + rest = src[end:] + return expandVariables(value, envMap, lookupFn), rest, nil } // lookup quoted string terminator @@ -192,7 +198,7 @@ func indexOfNonSpaceChar(src []byte) int { } // hasQuotePrefix reports whether charset starts with single or double quote and returns quote character -func hasQuotePrefix(src []byte) (prefix byte, isQuored bool) { +func hasQuotePrefix(src []byte) (quote byte, isQuoted bool) { if len(src) == 0 { return 0, false } @@ -221,3 +227,9 @@ func isSpace(r rune) bool { } return false } + + +// isNewLine reports whether the rune is a new line character +func isNewLine(r rune) bool { + return r == '\n' +}