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 // ----------------------------------------------------------------------
CEscapeString(const char * src,size_t src_len,char * dest,size_t dest_len)24 static 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 // ----------------------------------------------------------------------
CEscape(const StringPiece & src)68 std::string 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   std::string s = std::string(dest, used);
74   delete[] dest;
75   return s;
76 }
77 
PrefixSuccessor(std::string * prefix)78 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   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 
StringAppendV(std::string * dst,const char * format,va_list ap)95 static void StringAppendV(std::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 
StringPrintf(const char * format,...)140 std::string StringPrintf(const char* format, ...) {
141   va_list ap;
142   va_start(ap, format);
143   std::string result;
144   StringAppendV(&result, format, ap);
145   va_end(ap);
146   return result;
147 }
148 
149 }  // namespace re2
150