diff options
Diffstat (limited to 'config/value.go')
| -rw-r--r-- | config/value.go | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/config/value.go b/config/value.go new file mode 100644 index 00000000..3ade9c16 --- /dev/null +++ b/config/value.go @@ -0,0 +1,111 @@ +package config + +import ( + "bytes" + "errors" + "fmt" + "io" +) + +func (p *configParser) parseValue() (string, error) { + var ( + value bytes.Buffer + inQuote bool + inComment bool + ) + + trimLen := 0 + + for { + ch, err := p.nextChar() + if errors.Is(err, io.EOF) { + if inQuote { + return "", errors.New("unexpected EOF in quoted value") + } + + if trimLen > 0 { + return truncateAtNUL(value.String()[:trimLen]), nil + } + + return truncateAtNUL(value.String()), nil + } + + if err != nil { + return "", err + } + + if ch == '\n' { + if inQuote { + return "", errors.New("newline in quoted value") + } + + if trimLen > 0 { + return truncateAtNUL(value.String()[:trimLen]), nil + } + + return truncateAtNUL(value.String()), nil + } + + if inComment { + continue + } + + if isWhitespace(ch) && !inQuote { + if trimLen == 0 && value.Len() > 0 { + trimLen = value.Len() + } + + if value.Len() > 0 { + value.WriteByte(ch) + } + + continue + } + + if !inQuote && (ch == '#' || ch == ';') { + inComment = true + + continue + } + + if trimLen > 0 { + trimLen = 0 + } + + if ch == '\\' { + next, err := p.nextChar() + if errors.Is(err, io.EOF) { + return "", errors.New("unexpected EOF after backslash") + } + + if err != nil { + return "", err + } + + switch next { + case '\n': + continue + case 'n': + value.WriteByte('\n') + case 't': + value.WriteByte('\t') + case 'b': + value.WriteByte('\b') + case '\\', '"': + value.WriteByte(next) + default: + return "", fmt.Errorf("invalid escape sequence: \\%c", next) + } + + continue + } + + if ch == '"' { + inQuote = !inQuote + + continue + } + + value.WriteByte(ch) + } +} |
