From 71523c86a17f06a7d9a9382a4e076ea4eb5c1c75 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 21 Jun 2021 15:02:53 +0300 Subject: [PATCH] v.util: simplify smart_quote more --- vlib/v/util/quote.v | 108 +++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 47 deletions(-) diff --git a/vlib/v/util/quote.v b/vlib/v/util/quote.v index 1d5ba10020..0ee20a2124 100644 --- a/vlib/v/util/quote.v +++ b/vlib/v/util/quote.v @@ -14,13 +14,34 @@ const double_quote = 34 const double_escape = '\\\\' -//[direct_array_access] +[direct_array_access] pub fn smart_quote(str string, raw bool) string { len := str.len if len == 0 { return '' } - mut result := strings.new_builder(len) + if len < 256 { + mut is_pure := true + for i := 0; i < len; i++ { + ch := byte(str[i]) + if (ch >= 37 && ch <= 90) || (ch >= 95 && ch <= 126) + || (ch in [` `, `!`, `#`, `[`, `]`]) { + // safe punctuation + digits + big latin letters, + // small latin letters + more safe punctuation, + // important punctuation exceptions, that are not + // placed conveniently in a consequitive span in + // the ASCII table. + continue + } + is_pure = false + break + } + if is_pure { + return str + } + } + // ensure there is enough space for the potential expansion of several \\ or \n + mut result := strings.new_builder(len + 10) mut pos := -1 mut last := byte(0) mut current := byte(0) @@ -35,85 +56,78 @@ pub fn smart_quote(str string, raw bool) string { if pos >= len { break } + last = current + current = str[pos] if pos + 1 < len { next = str[pos + 1] + } else { + next = 0 } - current = str[pos] - // double quote if current == util.double_quote { current = 0 - last = current result.write_b(util.backslash) result.write_b(util.double_quote) continue } if current == util.backslash { if raw { - last = current result.write_string(util.double_escape) continue - } else { + } + if next == util.backslash { // escaped backslash - keep as is - if next == util.backslash { + skip_next = true + result.write_string(util.double_escape) + continue + } + if next != 0 { + if raw { skip_next = true - last = current result.write_string(util.double_escape) continue - } else if next != 0 { - if raw { - skip_next = true - last = current - result.write_string(util.double_escape) - continue - } else if next in util.invalid_escapes { - skip_next = true - last = current - result.write_b(next) - continue - } else { - // keep all valid escape sequences - skip_next = true - last = current - result.write_b(current) - result.write_b(next) - continue - } } + if next in util.invalid_escapes { + skip_next = true + result.write_b(next) + continue + } + // keep all valid escape sequences + skip_next = true + result.write_b(current) + result.write_b(next) + continue } } - // keep newlines in string if current == util.backslash_n { + // keep newlines in string current = 0 - last = current result.write_b(util.backslash) result.write_b(`n`) continue - } else if current == util.backslash_r && next == util.backslash_n { + } + if current == util.backslash_r && next == util.backslash_n { result.write_b(current) result.write_b(next) current = 0 skip_next = true - last = current continue } - // Dolar sign - if !raw && current == `$` { - if last == util.backslash { - result.write_b(last) - result.write_b(current) - last = current + if !raw { + if current == `$` { + if last == util.backslash { + result.write_b(last) + result.write_b(current) + continue + } + } + if current == util.backslash_r && next == util.backslash_n { + // Windows style new line \r\n + skip_next = true + result.write_b(util.backslash) + result.write_b(`n`) continue } } - // Windows style new line \r\n - if !raw && current == util.backslash_r && next == util.backslash_n { - skip_next = true - result.write_b(util.backslash) - result.write_b(`n`) - last = current - continue - } - last = current result.write_b(current) } return result.str()