aboutsummaryrefslogtreecommitdiff
path: root/config/value.go
diff options
context:
space:
mode:
Diffstat (limited to 'config/value.go')
-rw-r--r--config/value.go111
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)
+ }
+}