Coverage Report

Created: 2024-06-09 08:58

/src/re2/util/strutil.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 1999-2005 The RE2 Authors.  All Rights Reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
5
#include <stdarg.h>
6
#include <stdio.h>
7
8
#include "util/strutil.h"
9
10
#ifdef _WIN32
11
#define snprintf _snprintf
12
#define vsnprintf _vsnprintf
13
#endif
14
15
namespace re2 {
16
17
// ----------------------------------------------------------------------
18
// CEscapeString()
19
//    Copies 'src' to 'dest', escaping dangerous characters using
20
//    C-style escape sequences.  'src' and 'dest' should not overlap.
21
//    Returns the number of bytes written to 'dest' (not including the \0)
22
//    or (size_t)-1 if there was insufficient space.
23
// ----------------------------------------------------------------------
24
static size_t CEscapeString(const char* src, size_t src_len,
25
0
                            char* dest, size_t dest_len) {
26
0
  const char* src_end = src + src_len;
27
0
  size_t used = 0;
28
29
0
  for (; src < src_end; src++) {
30
0
    if (dest_len - used < 2)   // space for two-character escape
31
0
      return (size_t)-1;
32
33
0
    unsigned char c = *src;
34
0
    switch (c) {
35
0
      case '\n': dest[used++] = '\\'; dest[used++] = 'n';  break;
36
0
      case '\r': dest[used++] = '\\'; dest[used++] = 'r';  break;
37
0
      case '\t': dest[used++] = '\\'; dest[used++] = 't';  break;
38
0
      case '\"': dest[used++] = '\\'; dest[used++] = '\"'; break;
39
0
      case '\'': dest[used++] = '\\'; dest[used++] = '\''; break;
40
0
      case '\\': dest[used++] = '\\'; dest[used++] = '\\'; break;
41
0
      default:
42
        // Note that if we emit \xNN and the src character after that is a hex
43
        // digit then that digit must be escaped too to prevent it being
44
        // interpreted as part of the character code by C.
45
0
        if (c < ' ' || c > '~') {
46
0
          if (dest_len - used < 5)   // space for four-character escape + \0
47
0
            return (size_t)-1;
48
0
          snprintf(dest + used, 5, "\\%03o", c);
49
0
          used += 4;
50
0
        } else {
51
0
          dest[used++] = c; break;
52
0
        }
53
0
    }
54
0
  }
55
56
0
  if (dest_len - used < 1)   // make sure that there is room for \0
57
0
    return (size_t)-1;
58
59
0
  dest[used] = '\0';   // doesn't count towards return value though
60
0
  return used;
61
0
}
62
63
// ----------------------------------------------------------------------
64
// CEscape()
65
//    Copies 'src' to result, escaping dangerous characters using
66
//    C-style escape sequences.  'src' and 'dest' should not overlap.
67
// ----------------------------------------------------------------------
68
0
std::string CEscape(const StringPiece& src) {
69
0
  const size_t dest_len = src.size() * 4 + 1; // Maximum possible expansion
70
0
  char* dest = new char[dest_len];
71
0
  const size_t used = CEscapeString(src.data(), src.size(),
72
0
                                    dest, dest_len);
73
0
  std::string s = std::string(dest, used);
74
0
  delete[] dest;
75
0
  return s;
76
0
}
77
78
0
void PrefixSuccessor(std::string* prefix) {
79
  // We can increment the last character in the string and be done
80
  // unless that character is 255, in which case we have to erase the
81
  // last character and increment the previous character, unless that
82
  // is 255, etc. If the string is empty or consists entirely of
83
  // 255's, we just return the empty string.
84
0
  while (!prefix->empty()) {
85
0
    char& c = prefix->back();
86
0
    if (c == '\xff') {  // char literal avoids signed/unsigned.
87
0
      prefix->pop_back();
88
0
    } else {
89
0
      ++c;
90
0
      break;
91
0
    }
92
0
  }
93
0
}
94
95
0
static void StringAppendV(std::string* dst, const char* format, va_list ap) {
96
  // First try with a small fixed size buffer
97
0
  char space[1024];
98
99
  // It's possible for methods that use a va_list to invalidate
100
  // the data in it upon use.  The fix is to make a copy
101
  // of the structure before using it and use that copy instead.
102
0
  va_list backup_ap;
103
0
  va_copy(backup_ap, ap);
104
0
  int result = vsnprintf(space, sizeof(space), format, backup_ap);
105
0
  va_end(backup_ap);
106
107
0
  if ((result >= 0) && (static_cast<size_t>(result) < sizeof(space))) {
108
    // It fit
109
0
    dst->append(space, result);
110
0
    return;
111
0
  }
112
113
  // Repeatedly increase buffer size until it fits
114
0
  int length = sizeof(space);
115
0
  while (true) {
116
0
    if (result < 0) {
117
      // Older behavior: just try doubling the buffer size
118
0
      length *= 2;
119
0
    } else {
120
      // We need exactly "result+1" characters
121
0
      length = result+1;
122
0
    }
123
0
    char* buf = new char[length];
124
125
    // Restore the va_list before we use it again
126
0
    va_copy(backup_ap, ap);
127
0
    result = vsnprintf(buf, length, format, backup_ap);
128
0
    va_end(backup_ap);
129
130
0
    if ((result >= 0) && (result < length)) {
131
      // It fit
132
0
      dst->append(buf, result);
133
0
      delete[] buf;
134
0
      return;
135
0
    }
136
0
    delete[] buf;
137
0
  }
138
0
}
139
140
0
std::string StringPrintf(const char* format, ...) {
141
0
  va_list ap;
142
0
  va_start(ap, format);
143
0
  std::string result;
144
0
  StringAppendV(&result, format, ap);
145
0
  va_end(ap);
146
0
  return result;
147
0
}
148
149
}  // namespace re2