gotosocial/vendor/codeberg.org/gruf/go-kv/util.go
dependabot[bot] 0a864623f3
[chore]: Bump codeberg.org/gruf/go-kv from 1.6.0 to 1.6.1 (#1619)
Bumps codeberg.org/gruf/go-kv from 1.6.0 to 1.6.1.

---
updated-dependencies:
- dependency-name: codeberg.org/gruf/go-kv
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-13 07:52:13 +00:00

176 lines
4.1 KiB
Go

package kv
import (
"strconv"
"strings"
"codeberg.org/gruf/go-byteutil"
"codeberg.org/gruf/go-kv/format"
)
// AppendQuoteString will append (and escape/quote where necessary) a field string.
func AppendQuoteString(buf *byteutil.Buffer, str string) {
switch {
case len(str) == 0:
// Append empty quotes.
buf.B = append(buf.B, `""`...)
return
case len(str) == 1:
// Append quote single byte.
appendQuoteByte(buf, str[0])
return
case len(str) > format.SingleTermLine || !format.IsSafeASCII(str):
// Long line or contains non-ascii chars.
buf.B = strconv.AppendQuote(buf.B, str)
return
case !isQuoted(str):
// Not single/double quoted already.
if format.ContainsSpaceOrTab(str) {
// Quote un-enclosed spaces.
buf.B = append(buf.B, '"')
buf.B = append(buf.B, str...)
buf.B = append(buf.B, '"')
return
}
if format.ContainsDoubleQuote(str) {
// Contains double quote, double quote
// and append escaped existing.
buf.B = append(buf.B, '"')
buf.B = format.AppendEscape(buf.B, str)
buf.B = append(buf.B, '"')
return
}
}
// Double quoted, enclosed in braces, or
// literally anything else: append as-is.
buf.B = append(buf.B, str...)
return
}
// AppendQuoteValue will append (and escape/quote where necessary) a formatted value string.
func AppendQuoteValue(buf *byteutil.Buffer, str string) {
switch {
case len(str) == 0:
// Append empty quotes.
buf.B = append(buf.B, `""`...)
return
case len(str) == 1:
// Append quote single byte.
appendQuoteByte(buf, str[0])
return
case len(str) > format.SingleTermLine || !format.IsSafeASCII(str):
// Long line or contains non-ascii chars.
buf.B = strconv.AppendQuote(buf.B, str)
return
case !isQuoted(str):
// Not single/double quoted already.
// Get space / tab indices (if any).
s := strings.IndexByte(str, ' ')
t := strings.IndexByte(str, '\t')
// Find first whitespace.
sp0 := smallest(s, t)
if sp0 < 0 {
break
}
// Check if str is enclosed by braces.
// (but without any key-value separator).
if (enclosedBy(str, sp0, '{', '}') ||
enclosedBy(str, sp0, '[', ']') ||
enclosedBy(str, sp0, '(', ')')) &&
strings.IndexByte(str, '=') < 0 {
break
}
if format.ContainsDoubleQuote(str) {
// Contains double quote, double quote
// and append escaped existing.
buf.B = append(buf.B, '"')
buf.B = format.AppendEscape(buf.B, str)
buf.B = append(buf.B, '"')
return
}
// Quote un-enclosed spaces.
buf.B = append(buf.B, '"')
buf.B = append(buf.B, str...)
buf.B = append(buf.B, '"')
return
}
// Double quoted, enclosed in braces, or
// literally anything else: append as-is.
buf.B = append(buf.B, str...)
return
}
// appendEscapeByte will append byte to buffer, quoting and escaping where necessary.
func appendQuoteByte(buf *byteutil.Buffer, c byte) {
switch c {
// Double quote space.
case ' ':
buf.B = append(buf.B, '"', c, '"')
// Escape + double quote.
case '\a':
buf.B = append(buf.B, '"', '\\', 'a', '"')
case '\b':
buf.B = append(buf.B, '"', '\\', 'b', '"')
case '\f':
buf.B = append(buf.B, '"', '\\', 'f', '"')
case '\n':
buf.B = append(buf.B, '"', '\\', 'n', '"')
case '\r':
buf.B = append(buf.B, '"', '\\', 'r', '"')
case '\t':
buf.B = append(buf.B, '"', '\\', 't', '"')
case '\v':
buf.B = append(buf.B, '"', '\\', 'v', '"')
// Append as-is.
default:
buf.B = append(buf.B, c)
}
}
// isQuoted checks if string is single or double quoted.
func isQuoted(str string) bool {
return (str[0] == '"' && str[len(str)-1] == '"') ||
(str[0] == '\'' && str[len(str)-1] == '\'')
}
// smallest attempts to return the smallest positive value of those given.
func smallest(i1, i2 int) int {
if i1 >= 0 && (i2 < 0 || i1 < i2) {
return i1
}
return i2
}
// enclosedBy will check if given string is enclosed by end, and at least non-whitespace up to start.
func enclosedBy(str string, sp int, start, end byte) bool {
// Check for ending char in string.
if str[len(str)-1] != end {
return false
}
// Check for starting char in string.
i := strings.IndexByte(str, start)
if i < 0 {
return false
}
// Check before space.
return i < sp
}