processEscapes method

String processEscapes(
  1. String input,
  2. String quote,
  3. bool isAnsiCQuote
)

Implementation

String processEscapes(String input, String quote, bool isAnsiCQuote) {
  if (!isAnsiCQuote && !escapedQuotes.contains(quote)) {
    // This quote type doesn't support escape sequences
    return input;
  }

  // We need to form a regex that matches any of the escape characters,
  // without interpreting any of the characters as a regex special character.
  var anyEscape = '[${escapes.split('').map((c) => '\\$c').join()}]';

  // In regular quoted strings, we can only escape an escape character, and
  // the quote character itself.
  if (!isAnsiCQuote && escapedQuotes.contains(quote)) {
    var re = RegExp('$anyEscape($anyEscape|\\$quote)');
    return input.replaceAllMapped(re, (m) => m[1]!);
  }

  // ANSI C quoted strings support a wide variety of escape sequences
  if (isAnsiCQuote) {
    var patterns = <String, String Function(String)>{
      // Literal characters
      '([\\\\\'"?])': (x) => x,

      // Non-printable ASCII characters
      'a': (x) => '\x07',
      'b': (x) => '\x08',
      'e|E': (x) => '\x1b',
      'f': (x) => '\x0c',
      'n': (x) => '\x0a',
      'r': (x) => '\x0d',
      't': (x) => '\x09',
      'v': (x) => '\x0b',

      // Octal bytes
      '([0-7]{1,3})': (x) => String.fromCharCode(int.parse(x, radix: 8)),

      // Hexadecimal bytes
      'x([0-9a-fA-F]{1,2})': (x) =>
          String.fromCharCode(int.parse(x, radix: 16)),

      // Unicode code units
      'u([0-9a-fA-F]{1,4})': (x) =>
          String.fromCharCode(int.parse(x, radix: 16)),
      'U([0-9a-fA-F]{1,8})': (x) =>
          String.fromCharCode(int.parse(x, radix: 16)),

      // Control characters
      // https://en.wikipedia.org/wiki/Control_character#How_control_characters_map_to_keyboards
      'c(.)': (x) {
        if (x == '?') {
          return '\x7f';
        } else if (x == '@') {
          return '\x00';
        } else {
          return String.fromCharCode(x.codeUnitAt(0) & 31);
        }
      }
    };

    // Construct an uber-RegEx that catches all of the above pattern
    var re = RegExp('$anyEscape(${patterns.keys.join('|')})');

    // For each match, figure out which subpattern matched, and apply the
    // corresponding function
    return input.replaceAllMapped(re, (m) {
      var p1 = m.group(1);
      for (var matched in patterns.keys) {
        var mm = RegExp('^$matched\$').firstMatch(p1!);
        if (mm != null) {
          return patterns[matched]!(mm.groupCount > 0 ? mm.group(1) ?? '' : '');
        }
      }
      return '';
    });
  }

  // Should not get here
  return '';
}