From 45c6b6493baf62306a646c2480678bdfc848580d Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 20 Jun 2021 20:55:12 +0300 Subject: [PATCH] v.util: make util.smart_quote use its output string builder directly --- vlib/strings/builder.v | 2 +- vlib/v/util/quote.v | 118 +++++++++++++++++++++++++---------------- 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/vlib/strings/builder.v b/vlib/strings/builder.v index ea0fff5472..1c8bae1ac5 100644 --- a/vlib/strings/builder.v +++ b/vlib/strings/builder.v @@ -45,7 +45,7 @@ pub fn (b &Builder) byte_at(n int) byte { // write appends the string `s` to the buffer [inline] pub fn (mut b Builder) write_string(s string) { - if s == '' { + if s.len == 0 { return } unsafe { b.push_many(s.str, s.len) } diff --git a/vlib/v/util/quote.v b/vlib/v/util/quote.v index a05dadcb2c..1d5ba10020 100644 --- a/vlib/v/util/quote.v +++ b/vlib/v/util/quote.v @@ -2,93 +2,119 @@ module util import strings -const ( - invalid_escapes = ['(', '{', '$', '`', '.'] -) +const invalid_escapes = r'({$`.'.bytes() -[direct_array_access] +const backslash = 92 + +const backslash_r = 13 + +const backslash_n = 10 + +const double_quote = 34 + +const double_escape = '\\\\' + +//[direct_array_access] pub fn smart_quote(str string, raw bool) string { len := str.len if len == 0 { - return str + return '' } mut result := strings.new_builder(len) mut pos := -1 - mut last := '' - // TODO: This should be a single char? - mut next := '' + mut last := byte(0) + mut current := byte(0) + mut next := byte(0) mut skip_next := false for { - pos = pos + 1 + pos++ if skip_next { skip_next = false - pos = pos + 1 + pos++ } if pos >= len { break } if pos + 1 < len { - next = str[pos + 1].ascii_str() - } - mut current := str - mut toadd := str - if len > 1 { - current = str[pos].ascii_str() - toadd = current + next = str[pos + 1] } + current = str[pos] // double quote - if current == '"' { - toadd = '\\"' - current = '' + if current == util.double_quote { + current = 0 + last = current + result.write_b(util.backslash) + result.write_b(util.double_quote) + continue } - if current == '\\' { + if current == util.backslash { if raw { - toadd = '\\\\' + last = current + result.write_string(util.double_escape) + continue } else { // escaped backslash - keep as is - if next == '\\' { - toadd = '\\\\' + if next == util.backslash { skip_next = true - } else if next != '' { + last = current + result.write_string(util.double_escape) + continue + } else if next != 0 { if raw { - toadd = '\\\\' + next skip_next = true - } - // keep all valid escape sequences - else if next !in util.invalid_escapes { - toadd = '\\' + next + 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 { - toadd = next + // keep all valid escape sequences skip_next = true + last = current + result.write_b(current) + result.write_b(next) + continue } } } } // keep newlines in string - if current == '\n' { - toadd = '\\n' - current = '' - } else if current == '\r' && next == '\n' { - toadd = '\r\n' - current = '' + if current == util.backslash_n { + current = 0 + last = current + result.write_b(util.backslash) + result.write_b(`n`) + continue + } else 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 == '\\' { - toadd = r'\$' + if !raw && current == `$` { + if last == util.backslash { + result.write_b(last) + result.write_b(current) + last = current + continue } } // Windows style new line \r\n - if !raw && current == '\r' { - if next == '\n' { - skip_next = true - toadd = '\\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 } - result.write_string(toadd) last = current + result.write_b(current) } return result.str() }