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
15namespace 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// ----------------------------------------------------------------------
24static size_t CEscapeString(const char* src, size_t src_len,
25 char* dest, size_t dest_len) {
26 const char* src_end = src + src_len;
27 size_t used = 0;
28
29 for (; src < src_end; src++) {
30 if (dest_len - used < 2) // space for two-character escape
31 return (size_t)-1;
32
33 unsigned char c = *src;
34 switch (c) {
35 case '\n': dest[used++] = '\\'; dest[used++] = 'n'; break;
36 case '\r': dest[used++] = '\\'; dest[used++] = 'r'; break;
37 case '\t': dest[used++] = '\\'; dest[used++] = 't'; break;
38 case '\"': dest[used++] = '\\'; dest[used++] = '\"'; break;
39 case '\'': dest[used++] = '\\'; dest[used++] = '\''; break;
40 case '\\': dest[used++] = '\\'; dest[used++] = '\\'; break;
41 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 if (c < ' ' || c > '~') {
46 if (dest_len - used < 5) // space for four-character escape + \0
47 return (size_t)-1;
48 snprintf(dest + used, 5, "\\%03o", c);
49 used += 4;
50 } else {
51 dest[used++] = c; break;
52 }
53 }
54 }
55
56 if (dest_len - used < 1) // make sure that there is room for \0
57 return (size_t)-1;
58
59 dest[used] = '\0'; // doesn't count towards return value though
60 return used;
61}
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// ----------------------------------------------------------------------
68string CEscape(const StringPiece& src) {
69 const size_t dest_len = src.size() * 4 + 1; // Maximum possible expansion
70 char* dest = new char[dest_len];
71 const size_t used = CEscapeString(src.data(), src.size(),
72 dest, dest_len);
73 string s = string(dest, used);
74 delete[] dest;
75 return s;
76}
77
78void PrefixSuccessor(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 while (!prefix->empty()) {
85 char& c = prefix->back();
86 if (c == '\xff') { // char literal avoids signed/unsigned.
87 prefix->pop_back();
88 } else {
89 ++c;
90 break;
91 }
92 }
93}
94
95static void StringAppendV(string* dst, const char* format, va_list ap) {
96 // First try with a small fixed size buffer
97 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 va_list backup_ap;
103 va_copy(backup_ap, ap);
104 int result = vsnprintf(space, sizeof(space), format, backup_ap);
105 va_end(backup_ap);
106
107 if ((result >= 0) && (static_cast<size_t>(result) < sizeof(space))) {
108 // It fit
109 dst->append(space, result);
110 return;
111 }
112
113 // Repeatedly increase buffer size until it fits
114 int length = sizeof(space);
115 while (true) {
116 if (result < 0) {
117 // Older behavior: just try doubling the buffer size
118 length *= 2;
119 } else {
120 // We need exactly "result+1" characters
121 length = result+1;
122 }
123 char* buf = new char[length];
124
125 // Restore the va_list before we use it again
126 va_copy(backup_ap, ap);
127 result = vsnprintf(buf, length, format, backup_ap);
128 va_end(backup_ap);
129
130 if ((result >= 0) && (result < length)) {
131 // It fit
132 dst->append(buf, result);
133 delete[] buf;
134 return;
135 }
136 delete[] buf;
137 }
138}
139
140string StringPrintf(const char* format, ...) {
141 va_list ap;
142 va_start(ap, format);
143 string result;
144 StringAppendV(&result, format, ap);
145 va_end(ap);
146 return result;
147}
148
149void SStringPrintf(string* dst, const char* format, ...) {
150 va_list ap;
151 va_start(ap, format);
152 dst->clear();
153 StringAppendV(dst, format, ap);
154 va_end(ap);
155}
156
157void StringAppendF(string* dst, const char* format, ...) {
158 va_list ap;
159 va_start(ap, format);
160 StringAppendV(dst, format, ap);
161 va_end(ap);
162}
163
164} // namespace re2
165