strutil.cc 4.7 KB

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