]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.cpp
MFV r353613: 10731 zfs: NULL pointer errors
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / tools / lldb-mi / MIUtilString.cpp
1 //===-- MIUtilString.cpp ----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // Third party headers
10 #include "llvm/Support/Compiler.h"
11 #include <cstdlib>
12 #include <inttypes.h>
13 #include <limits.h>
14 #include <memory>
15 #include <sstream>
16 #include <stdarg.h>
17 #include <string.h>
18
19 // In-house headers:
20 #include "MIUtilString.h"
21
22 //++
23 // Details: CMIUtilString constructor.
24 // Type:    Method.
25 // Args:    None.
26 // Return:  None.
27 // Throws:  None.
28 //--
29 CMIUtilString::CMIUtilString() : std::string() {}
30
31 //++
32 // Details: CMIUtilString constructor.
33 // Type:    Method.
34 // Args:    vpData  - Pointer to UTF8 text data.
35 // Return:  None.
36 // Throws:  None.
37 //--
38 CMIUtilString::CMIUtilString(const char *vpData)
39   : std::string(WithNullAsEmpty(vpData)) {}
40
41 //++
42 // Details: CMIUtilString constructor.
43 // Type:    Method.
44 // Args:    vpStr  - Text data.
45 // Return:  None.
46 // Throws:  None.
47 //--
48 CMIUtilString::CMIUtilString(const std::string &vrStr) : std::string(vrStr) {}
49
50 //++
51 // Details: CMIUtilString assignment operator.
52 // Type:    Method.
53 // Args:    vpRhs   - Pointer to UTF8 text data.
54 // Return:  CMIUtilString & - *this string.
55 // Throws:  None.
56 //--
57 CMIUtilString &CMIUtilString::operator=(const char *vpRhs) {
58   assign(WithNullAsEmpty(vpRhs));
59   return *this;
60 }
61
62 //++
63 // Details: CMIUtilString assignment operator.
64 // Type:    Method.
65 // Args:    vrRhs   - The other string to copy from.
66 // Return:  CMIUtilString & - *this string.
67 // Throws:  None.
68 //--
69 CMIUtilString &CMIUtilString::operator=(const std::string &vrRhs) {
70   assign(vrRhs);
71   return *this;
72 }
73
74 //++
75 // Details: CMIUtilString destructor.
76 // Type:    Method.
77 // Args:    None.
78 // Return:  None.
79 // Throws:  None.
80 //--
81 CMIUtilString::~CMIUtilString() {}
82
83 //++
84 // Details: Perform a snprintf format style on a string data. A new string
85 // object is
86 //          created and returned.
87 // Type:    Static method.
88 // Args:    vrFormat      - (R) Format string data instruction.
89 //          vArgs         - (R) Var list args of any type.
90 // Return:  CMIUtilString - Number of splits found in the string data.
91 // Throws:  None.
92 //--
93 CMIUtilString CMIUtilString::FormatPriv(const CMIUtilString &vrFormat,
94                                         va_list vArgs) {
95   CMIUtilString strResult;
96   MIint nFinal = 0;
97   MIint n = vrFormat.size();
98
99   // IOR: mysterious crash in this function on some windows builds not able to
100   // duplicate but found article which may be related. Crash occurs in
101   // vsnprintf() or va_copy().
102   // Duplicate vArgs va_list argument pointer to ensure that it can be safely
103   // used in a new frame.
104   // http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
105   va_list argsDup;
106   va_copy(argsDup, vArgs);
107
108   // Create a copy va_list to reset when we spin
109   va_list argsCpy;
110   va_copy(argsCpy, argsDup);
111
112   if (n == 0)
113     return strResult;
114
115   n = n << 4; // Reserve 16 times as much the length of the vrFormat
116
117   std::unique_ptr<char[]> pFormatted;
118   while (1) {
119     pFormatted.reset(new char[n + 1]); // +1 for safety margin
120     ::strncpy(&pFormatted[0], vrFormat.c_str(), n);
121
122     // We need to restore the variable argument list pointer to the start again
123     // before running vsnprintf() more then once
124     va_copy(argsDup, argsCpy);
125
126     nFinal = ::vsnprintf(&pFormatted[0], n, vrFormat.c_str(), argsDup);
127     if ((nFinal < 0) || (nFinal >= n))
128       n += abs(nFinal - n + 1);
129     else
130       break;
131   }
132
133   va_end(argsCpy);
134   va_end(argsDup);
135
136   strResult = pFormatted.get();
137
138   return strResult;
139 }
140
141 //++
142 // Details: Perform a snprintf format style on a string data. A new string
143 // object is
144 //          created and returned.
145 // Type:    Static method.
146 // Args:    vFormat       - (R) Format string data instruction.
147 //          ...           - (R) Var list args of any type.
148 // Return:  CMIUtilString - Number of splits found in the string data.
149 // Throws:  None.
150 //--
151 CMIUtilString CMIUtilString::Format(const char *vFormating, ...) {
152   va_list args;
153   va_start(args, vFormating);
154   CMIUtilString strResult =
155       CMIUtilString::FormatPriv(WithNullAsEmpty(vFormating), args);
156   va_end(args);
157
158   return strResult;
159 }
160
161 //++
162 // Details: Perform a snprintf format style on a string data. A new string
163 // object is
164 //          created and returned.
165 // Type:    Static method.
166 // Args:    vrFormat      - (R) Format string data instruction.
167 //          vArgs         - (R) Var list args of any type.
168 // Return:  CMIUtilString - Number of splits found in the string data.
169 // Throws:  None.
170 //--
171 CMIUtilString CMIUtilString::FormatValist(const CMIUtilString &vrFormating,
172                                           va_list vArgs) {
173   return CMIUtilString::FormatPriv(vrFormating, vArgs);
174 }
175
176 //++
177 // Details: Splits string into array of strings using delimiter. If multiple
178 // delimiter
179 //          are found in sequence then they are not added to the list of splits.
180 // Type:    Method.
181 // Args:    vData       - (R) String data to be split up.
182 //          vDelimiter  - (R) Delimiter char or text.
183 //          vwVecSplits - (W) Container of splits found in string data.
184 // Return:  size_t - Number of splits found in the string data.
185 // Throws:  None.
186 //--
187 size_t CMIUtilString::Split(const CMIUtilString &vDelimiter,
188                             VecString_t &vwVecSplits) const {
189   vwVecSplits.clear();
190
191   if (this->empty() || vDelimiter.empty())
192     return 0;
193
194   const size_t nLen(length());
195   size_t nOffset(0);
196   do {
197     // Find first occurrence which doesn't match to the delimiter
198     const size_t nSectionPos(FindFirstNot(vDelimiter, nOffset));
199     if (nSectionPos == std::string::npos)
200       break;
201
202     // Find next occurrence of the delimiter after section
203     size_t nNextDelimiterPos(FindFirst(vDelimiter, nSectionPos));
204     if (nNextDelimiterPos == std::string::npos)
205       nNextDelimiterPos = nLen;
206
207     // Extract string between delimiters
208     const size_t nSectionLen(nNextDelimiterPos - nSectionPos);
209     const std::string strSection(substr(nSectionPos, nSectionLen));
210     vwVecSplits.push_back(strSection);
211
212     // Next
213     nOffset = nNextDelimiterPos + 1;
214   } while (nOffset < nLen);
215
216   return vwVecSplits.size();
217 }
218
219 //++
220 // Details: Splits string into array of strings using delimiter. However the
221 // string is
222 //          also considered for text surrounded by quotes. Text with quotes
223 //          including the
224 //          delimiter is treated as a whole. If multiple delimiter are found in
225 //          sequence
226 //          then they are not added to the list of splits. Quotes that are
227 //          embedded in
228 //          the string as string formatted quotes are ignored (proceeded by a
229 //          '\\') i.e.
230 //          "\"MI GDB local C++.cpp\":88".
231 // Type:    Method.
232 // Args:    vData       - (R) String data to be split up.
233 //          vDelimiter  - (R) Delimiter char or text.
234 //          vwVecSplits - (W) Container of splits found in string data.
235 // Return:  size_t - Number of splits found in the string data.
236 // Throws:  None.
237 //--
238 size_t CMIUtilString::SplitConsiderQuotes(const CMIUtilString &vDelimiter,
239                                           VecString_t &vwVecSplits) const {
240   vwVecSplits.clear();
241
242   if (this->empty() || vDelimiter.empty())
243     return 0;
244
245   const size_t nLen(length());
246   size_t nOffset(0);
247   do {
248     // Find first occurrence which doesn't match to the delimiter
249     const size_t nSectionPos(FindFirstNot(vDelimiter, nOffset));
250     if (nSectionPos == std::string::npos)
251       break;
252
253     // Find next occurrence of the delimiter after (quoted) section
254     const bool bSkipQuotedText(true);
255     bool bUnmatchedQuote(false);
256     size_t nNextDelimiterPos(
257         FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos));
258     if (bUnmatchedQuote) {
259       vwVecSplits.clear();
260       return 0;
261     }
262     if (nNextDelimiterPos == std::string::npos)
263       nNextDelimiterPos = nLen;
264
265     // Extract string between delimiters
266     const size_t nSectionLen(nNextDelimiterPos - nSectionPos);
267     const std::string strSection(substr(nSectionPos, nSectionLen));
268     vwVecSplits.push_back(strSection);
269
270     // Next
271     nOffset = nNextDelimiterPos + 1;
272   } while (nOffset < nLen);
273
274   return vwVecSplits.size();
275 }
276
277 //++
278 // Details: Split string into lines using \n and return an array of strings.
279 // Type:    Method.
280 // Args:    vwVecSplits - (W) Container of splits found in string data.
281 // Return:  size_t - Number of splits found in the string data.
282 // Throws:  None.
283 //--
284 size_t CMIUtilString::SplitLines(VecString_t &vwVecSplits) const {
285   return Split("\n", vwVecSplits);
286 }
287
288 //++
289 // Details: Remove '\n' from the end of string if found. It does not alter
290 //          *this string.
291 // Type:    Method.
292 // Args:    None.
293 // Return:  CMIUtilString - New version of the string.
294 // Throws:  None.
295 //--
296 CMIUtilString CMIUtilString::StripCREndOfLine() const {
297   const size_t nPos = rfind('\n');
298   if (nPos == std::string::npos)
299     return *this;
300
301   const CMIUtilString strNew(substr(0, nPos));
302
303   return strNew;
304 }
305
306 //++
307 // Details: Remove all '\n' from the string and replace with a space. It does
308 // not alter
309 //          *this string.
310 // Type:    Method.
311 // Args:    None.
312 // Return:  CMIUtilString - New version of the string.
313 // Throws:  None.
314 //--
315 CMIUtilString CMIUtilString::StripCRAll() const {
316   return FindAndReplace("\n", " ");
317 }
318
319 //++
320 // Details: Find and replace all matches of a sub string with another string. It
321 // does not
322 //          alter *this string.
323 // Type:    Method.
324 // Args:    vFind         - (R) The string to look for.
325 //          vReplaceWith  - (R) The string to replace the vFind match.
326 // Return:  CMIUtilString - New version of the string.
327 // Throws:  None.
328 //--
329 CMIUtilString
330 CMIUtilString::FindAndReplace(const CMIUtilString &vFind,
331                               const CMIUtilString &vReplaceWith) const {
332   if (vFind.empty() || this->empty())
333     return *this;
334
335   size_t nPos = find(vFind);
336   if (nPos == std::string::npos)
337     return *this;
338
339   CMIUtilString strNew(*this);
340   while (nPos != std::string::npos) {
341     strNew.replace(nPos, vFind.length(), vReplaceWith);
342     nPos += vReplaceWith.length();
343     nPos = strNew.find(vFind, nPos);
344   }
345
346   return strNew;
347 }
348
349 //++
350 // Details: Check if *this string is a decimal number.
351 // Type:    Method.
352 // Args:    None.
353 // Return:  bool - True = yes number, false not a number.
354 // Throws:  None.
355 //--
356 bool CMIUtilString::IsNumber() const {
357   if (empty())
358     return false;
359
360   if ((at(0) == '-') && (length() == 1))
361     return false;
362
363   const size_t nPos = find_first_not_of("-.0123456789");
364   return nPos == std::string::npos;
365 }
366
367 //++
368 // Details: Check if *this string is a hexadecimal number.
369 // Type:    Method.
370 // Args:    None.
371 // Return:  bool - True = yes number, false not a number.
372 // Throws:  None.
373 //--
374 bool CMIUtilString::IsHexadecimalNumber() const {
375   // Compare '0x..' prefix
376   if ((strncmp(c_str(), "0x", 2) != 0) && (strncmp(c_str(), "0X", 2) != 0))
377     return false;
378
379   // Skip '0x..' prefix
380   const size_t nPos = find_first_not_of("01234567890ABCDEFabcedf", 2);
381   return nPos == std::string::npos;
382 }
383
384 //++
385 // Details: Extract the number from the string. The number can be either a
386 // hexadecimal or
387 //          natural number. It cannot contain other non-numeric characters.
388 // Type:    Method.
389 // Args:    vwrNumber   - (W) Number extracted from the string.
390 // Return:  bool - True = yes number, false not a number.
391 // Throws:  None.
392 //--
393 bool CMIUtilString::ExtractNumber(MIint64 &vwrNumber) const {
394   vwrNumber = 0;
395
396   if (!IsNumber()) {
397     return ExtractNumberFromHexadecimal(vwrNumber);
398   }
399
400   std::stringstream ss(const_cast<CMIUtilString &>(*this));
401   ss >> vwrNumber;
402
403   return true;
404 }
405
406 //++
407 // Details: Extract the number from the hexadecimal string..
408 // Type:    Method.
409 // Args:    vwrNumber   - (W) Number extracted from the string.
410 // Return:  bool - True = yes number, false not a number.
411 // Throws:  None.
412 //--
413 bool CMIUtilString::ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const {
414   vwrNumber = 0;
415
416   const size_t nPos = find_first_not_of("xX01234567890ABCDEFabcedf");
417   if (nPos != std::string::npos)
418     return false;
419
420   errno = 0;
421   const MIuint64 nNum = ::strtoull(this->c_str(), nullptr, 16);
422   if (errno == ERANGE)
423     return false;
424
425   vwrNumber = static_cast<MIint64>(nNum);
426
427   return true;
428 }
429
430 //++
431 // Details: Determine if the text is all valid alpha numeric characters. Letters
432 // can be
433 //          either upper or lower case.
434 // Type:    Static method.
435 // Args:    vpText  - (R) The text data to examine.
436 // Return:  bool - True = yes all alpha, false = one or more chars is non alpha.
437 // Throws:  None.
438 //--
439 bool CMIUtilString::IsAllValidAlphaAndNumeric(const char *vpText) {
440   const size_t len = ::strlen(WithNullAsEmpty(vpText));
441   if (len == 0)
442     return false;
443
444   for (size_t i = 0; i < len; i++, vpText++) {
445     const char c = *vpText;
446     if (::isalnum((int)c) == 0)
447       return false;
448   }
449
450   return true;
451 }
452
453 //++
454 // Details: Check if two strings share equal contents.
455 // Type:    Method.
456 // Args:    vrLhs   - (R) String A.
457 //          vrRhs   - (R) String B.
458 // Return:  bool - True = yes equal, false - different.
459 // Throws:  None.
460 //--
461 bool CMIUtilString::Compare(const CMIUtilString &vrLhs,
462                             const CMIUtilString &vrRhs) {
463   // Check the sizes match
464   if (vrLhs.size() != vrRhs.size())
465     return false;
466
467   return (::strncmp(vrLhs.c_str(), vrRhs.c_str(), vrLhs.size()) == 0);
468 }
469
470 //++
471 // Details: Remove from either end of *this string the following: " \t\n\v\f\r".
472 // Type:    Method.
473 // Args:    None.
474 // Return:  CMIUtilString - Trimmed string.
475 // Throws:  None.
476 //--
477 CMIUtilString CMIUtilString::Trim() const {
478   CMIUtilString strNew(*this);
479   const char *pWhiteSpace = " \t\n\v\f\r";
480   const size_t nPos = find_last_not_of(pWhiteSpace);
481   if (nPos != std::string::npos) {
482     strNew = substr(0, nPos + 1);
483   }
484   const size_t nPos2 = strNew.find_first_not_of(pWhiteSpace);
485   if (nPos2 != std::string::npos) {
486     strNew = strNew.substr(nPos2);
487   }
488
489   return strNew;
490 }
491
492 //++
493 // Details: Remove from either end of *this string the specified character.
494 // Type:    Method.
495 // Args:    None.
496 // Return:  CMIUtilString - Trimmed string.
497 // Throws:  None.
498 //--
499 CMIUtilString CMIUtilString::Trim(const char vChar) const {
500   CMIUtilString strNew(*this);
501   const size_t nLen = strNew.length();
502   if (nLen > 1) {
503     if ((strNew[0] == vChar) && (strNew[nLen - 1] == vChar))
504       strNew = strNew.substr(1, nLen - 2);
505   }
506
507   return strNew;
508 }
509
510 //++
511 // Details: Do a printf equivalent for printing a number in binary i.e. "b%llB".
512 // Type:    Static method.
513 // Args:    vnDecimal   - (R) The number to represent in binary.
514 // Return:  CMIUtilString - Binary number in text.
515 // Throws:  None.
516 //--
517 CMIUtilString CMIUtilString::FormatBinary(const MIuint64 vnDecimal) {
518   CMIUtilString strBinaryNumber;
519
520   const MIuint nConstBits = 64;
521   MIuint nRem[nConstBits + 1];
522   MIint i = 0;
523   MIuint nLen = 0;
524   MIuint64 nNum = vnDecimal;
525   while ((nNum > 0) && (nLen < nConstBits)) {
526     nRem[i++] = nNum % 2;
527     nNum = nNum >> 1;
528     nLen++;
529   }
530   char pN[nConstBits + 1];
531   MIuint j = 0;
532   for (i = nLen; i > 0; --i, j++) {
533     pN[j] = '0' + nRem[i - 1];
534   }
535   pN[j] = 0; // String NUL termination
536
537   strBinaryNumber = CMIUtilString::Format("0b%s", &pN[0]);
538
539   return strBinaryNumber;
540 }
541
542 //++
543 // Details: Remove from a string doubled up characters so only one set left.
544 // Characters
545 //          are only removed if the previous character is already a same
546 //          character.
547 // Type:    Method.
548 // Args:    vChar   - (R) The character to search for and remove adjacent
549 // duplicates.
550 // Return:  CMIUtilString - New version of the string.
551 // Throws:  None.
552 //--
553 CMIUtilString CMIUtilString::RemoveRepeatedCharacters(const char vChar) {
554   return RemoveRepeatedCharacters(0, vChar);
555 }
556
557 //++
558 // Details: Recursively remove from a string doubled up characters so only one
559 // set left.
560 //          Characters are only removed if the previous character is already a
561 //          same
562 //          character.
563 // Type:    Method.
564 // Args:    vChar   - (R) The character to search for and remove adjacent
565 // duplicates.
566 //          vnPos   - Character position in the string.
567 // Return:  CMIUtilString - New version of the string.
568 // Throws:  None.
569 //--
570 CMIUtilString CMIUtilString::RemoveRepeatedCharacters(size_t vnPos,
571                                                       const char vChar) {
572   const char cQuote = '"';
573
574   // Look for first quote of two
575   const size_t nPos = find(cQuote, vnPos);
576   if (nPos == std::string::npos)
577     return *this;
578
579   const size_t nPosNext = nPos + 1;
580   if (nPosNext > length())
581     return *this;
582
583   if (at(nPosNext) == cQuote) {
584     *this = substr(0, nPos) + substr(nPosNext, length());
585     RemoveRepeatedCharacters(nPosNext, vChar);
586   }
587
588   return *this;
589 }
590
591 //++
592 // Details: Is the text in *this string surrounded by quotes.
593 // Type:    Method.
594 // Args:    None.
595 // Return:  bool - True = Yes string is quoted, false = no quoted.
596 // Throws:  None.
597 //--
598 bool CMIUtilString::IsQuoted() const {
599   const char cQuote = '"';
600
601   if (at(0) != cQuote)
602     return false;
603
604   const size_t nLen = length();
605   return !((nLen > 0) && (at(nLen - 1) != cQuote));
606 }
607
608 //++
609 // Details: Find first occurrence in *this string which matches the pattern.
610 // Type:    Method.
611 // Args:    vrPattern   - (R) The pattern to search for.
612 //          vnPos       - The starting position at which to start searching.
613 //          (Dflt = 0)
614 // Return:  size_t - The position of the first substring that match.
615 // Throws:  None.
616 //--
617 size_t CMIUtilString::FindFirst(const CMIUtilString &vrPattern,
618                                 size_t vnPos /* = 0 */) const {
619   return find(vrPattern, vnPos);
620 }
621
622 //++
623 // Details: Find first occurrence in *this string which matches the pattern and
624 // isn't surrounded by quotes.
625 // Type:    Method.
626 // Args:    vrPattern                 - (R) The pattern to search for.
627 //          vbSkipQuotedText          - (R) True = don't look at quoted text,
628 //          false = otherwise.
629 //          vrwbNotFoundClosedQuote   - (W) True = parsing error: unmatched
630 //          quote, false = otherwise.
631 //          vnPos                     - Position of the first character in the
632 //          string to be considered in the search. (Dflt = 0)
633 // Return:  size_t - The position of the first substring that matches and isn't
634 // quoted.
635 // Throws:  None.
636 //--
637 size_t CMIUtilString::FindFirst(const CMIUtilString &vrPattern,
638                                 const bool vbSkipQuotedText,
639                                 bool &vrwbNotFoundClosedQuote,
640                                 size_t vnPos /* = 0 */) const {
641   vrwbNotFoundClosedQuote = false;
642
643   if (!vbSkipQuotedText)
644     return FindFirst(vrPattern, vnPos);
645
646   const size_t nLen(length());
647
648   size_t nPos = vnPos;
649   do {
650     const size_t nQuotePos(FindFirstQuote(nPos));
651     const size_t nPatternPos(FindFirst(vrPattern, nPos));
652     if (nQuotePos == std::string::npos)
653       return nPatternPos;
654
655     const size_t nQuoteClosedPos = FindFirstQuote(nQuotePos + 1);
656     if (nQuoteClosedPos == std::string::npos) {
657       vrwbNotFoundClosedQuote = true;
658       return std::string::npos;
659     }
660
661     if ((nPatternPos == std::string::npos) || (nPatternPos < nQuotePos))
662       return nPatternPos;
663
664     nPos = nQuoteClosedPos + 1;
665   } while (nPos < nLen);
666
667   return std::string::npos;
668 }
669
670 //++
671 // Details: Find first occurrence in *this string which doesn't match the
672 // pattern.
673 // Type:    Method.
674 // Args:    vrPattern   - (R) The pattern to search for.
675 //          vnPos       - Position of the first character in the string to be
676 //          considered in the search. (Dflt = 0)
677 // Return:  size_t - The position of the first character that doesn't match.
678 // Throws:  None.
679 //--
680 size_t CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern,
681                                    size_t vnPos /* = 0 */) const {
682   const size_t nLen(length());
683   const size_t nPatternLen(vrPattern.length());
684
685   size_t nPatternPos(vnPos);
686   do {
687     const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0);
688     if (!bMatchPattern)
689       return nPatternPos;
690     nPatternPos += nPatternLen;
691   } while (nPatternPos < nLen);
692
693   return std::string::npos;
694 }
695
696 //++
697 // Details: Find first occurrence of not escaped quotation mark in *this string.
698 // Type:    Method.
699 // Args:    vnPos   - Position of the first character in the string to be
700 // considered in the search.
701 // Return:  size_t - The position of the quotation mark.
702 // Throws:  None.
703 //--
704 size_t CMIUtilString::FindFirstQuote(size_t vnPos) const {
705   const char cBckSlash('\\');
706   const char cQuote('"');
707   const size_t nLen(length());
708
709   size_t nPos = vnPos;
710   do {
711     const size_t nBckSlashPos(find(cBckSlash, nPos));
712     const size_t nQuotePos(find(cQuote, nPos));
713     if ((nBckSlashPos == std::string::npos) || (nQuotePos == std::string::npos))
714       return nQuotePos;
715
716     if (nQuotePos < nBckSlashPos)
717       return nQuotePos;
718
719     // Skip 2 characters: First is '\', second is that which is escaped by '\'
720     nPos = nBckSlashPos + 2;
721   } while (nPos < nLen);
722
723   return std::string::npos;
724 }
725
726 //++
727 // Details: Get escaped string from *this string.
728 // Type:    Method.
729 // Args:    None.
730 // Return:  CMIUtilString - The escaped version of the initial string.
731 // Throws:  None.
732 //--
733 CMIUtilString CMIUtilString::Escape(bool vbEscapeQuotes /* = false */) const {
734   const size_t nLen(length());
735   CMIUtilString strNew;
736   strNew.reserve(nLen);
737   for (size_t nIndex(0); nIndex < nLen; ++nIndex) {
738     const char cUnescapedChar((*this)[nIndex]);
739     if (cUnescapedChar == '"' && vbEscapeQuotes)
740       strNew.append("\\\"");
741     else
742       strNew.append(ConvertToPrintableASCII((char)cUnescapedChar));
743   }
744   return strNew;
745 }
746
747 //++
748 // Details: Get string with backslashes in front of double quote '"' and
749 // backslash '\\'
750 //          characters.
751 // Type:    Method.
752 // Args:    None.
753 // Return:  CMIUtilString - The wrapped version of the initial string.
754 // Throws:  None.
755 //--
756 CMIUtilString CMIUtilString::AddSlashes() const {
757   const char cBckSlash('\\');
758   const size_t nLen(length());
759   CMIUtilString strNew;
760   strNew.reserve(nLen);
761
762   size_t nOffset(0);
763   while (nOffset < nLen) {
764     const size_t nUnescapedCharPos(find_first_of("\"\\", nOffset));
765     const bool bUnescapedCharNotFound(nUnescapedCharPos == std::string::npos);
766     if (bUnescapedCharNotFound) {
767       const size_t nAppendAll(std::string::npos);
768       strNew.append(*this, nOffset, nAppendAll);
769       break;
770     }
771     const size_t nAppendLen(nUnescapedCharPos - nOffset);
772     strNew.append(*this, nOffset, nAppendLen);
773     strNew.push_back(cBckSlash);
774     const char cUnescapedChar((*this)[nUnescapedCharPos]);
775     strNew.push_back(cUnescapedChar);
776     nOffset = nUnescapedCharPos + 1;
777   }
778
779   return strNew;
780 }
781
782 //++
783 // Details: Remove backslashes added by CMIUtilString::AddSlashes.
784 // Type:    Method.
785 // Args:    None.
786 // Return:  CMIUtilString - The initial version of wrapped string.
787 // Throws:  None.
788 //--
789 CMIUtilString CMIUtilString::StripSlashes() const {
790   const char cBckSlash('\\');
791   const size_t nLen(length());
792   CMIUtilString strNew;
793   strNew.reserve(nLen);
794
795   size_t nOffset(0);
796   while (nOffset < nLen) {
797     const size_t nBckSlashPos(find(cBckSlash, nOffset));
798     const bool bBckSlashNotFound(nBckSlashPos == std::string::npos);
799     if (bBckSlashNotFound) {
800       const size_t nAppendAll(std::string::npos);
801       strNew.append(*this, nOffset, nAppendAll);
802       break;
803     }
804     const size_t nAppendLen(nBckSlashPos - nOffset);
805     strNew.append(*this, nOffset, nAppendLen);
806     const bool bBckSlashIsLast(nBckSlashPos == nLen);
807     if (bBckSlashIsLast) {
808       strNew.push_back(cBckSlash);
809       break;
810     }
811     const char cEscapedChar((*this)[nBckSlashPos + 1]);
812     const size_t nEscapedCharPos(std::string("\"\\").find(cEscapedChar));
813     const bool bEscapedCharNotFound(nEscapedCharPos == std::string::npos);
814     if (bEscapedCharNotFound)
815       strNew.push_back(cBckSlash);
816     strNew.push_back(cEscapedChar);
817     nOffset = nBckSlashPos + 2;
818   }
819
820   return strNew;
821 }
822
823 CMIUtilString CMIUtilString::ConvertToPrintableASCII(const char vChar,
824                                                      bool bEscapeQuotes) {
825   switch (vChar) {
826   case '\a':
827     return "\\a";
828   case '\b':
829     return "\\b";
830   case '\t':
831     return "\\t";
832   case '\n':
833     return "\\n";
834   case '\v':
835     return "\\v";
836   case '\f':
837     return "\\f";
838   case '\r':
839     return "\\r";
840   case '\033':
841     return "\\e";
842   case '\\':
843     return "\\\\";
844   case '"':
845     if (bEscapeQuotes)
846       return "\\\"";
847     LLVM_FALLTHROUGH;
848   default:
849     if (::isprint(vChar))
850       return Format("%c", vChar);
851     else
852       return Format("\\x%02" PRIx8, vChar);
853   }
854 }
855
856 CMIUtilString
857 CMIUtilString::ConvertCharValueToPrintableASCII(char vChar,
858                                                 bool bEscapeQuotes) {
859   switch (vChar) {
860   case '\a':
861     return "\\a";
862   case '\b':
863     return "\\b";
864   case '\t':
865     return "\\t";
866   case '\n':
867     return "\\n";
868   case '\v':
869     return "\\v";
870   case '\f':
871     return "\\f";
872   case '\r':
873     return "\\r";
874   case '\033':
875     return "\\e";
876   case '\\':
877     return "\\\\";
878   case '"':
879     if (bEscapeQuotes)
880       return "\\\"";
881     LLVM_FALLTHROUGH;
882   default:
883     if (::isprint(vChar))
884       return Format("%c", vChar);
885     else
886       return CMIUtilString();
887   }
888 }
889
890 CMIUtilString CMIUtilString::ConvertToPrintableASCII(const char16_t vChar16,
891                                                      bool bEscapeQuotes) {
892   if (vChar16 == (char16_t)(char)vChar16) {
893     // Convert char16_t to char (if possible)
894     CMIUtilString str =
895         ConvertCharValueToPrintableASCII((char)vChar16, bEscapeQuotes);
896     if (str.length() > 0)
897       return str;
898   }
899   return Format("\\u%02" PRIx8 "%02" PRIx8, (vChar16 >> 8) & 0xff,
900                 vChar16 & 0xff);
901 }
902
903 CMIUtilString CMIUtilString::ConvertToPrintableASCII(const char32_t vChar32,
904                                                      bool bEscapeQuotes) {
905   if (vChar32 == (char32_t)(char)vChar32) {
906     // Convert char32_t to char (if possible)
907     CMIUtilString str =
908         ConvertCharValueToPrintableASCII((char)vChar32, bEscapeQuotes);
909     if (str.length() > 0)
910       return str;
911   }
912   return Format("\\U%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8,
913                 (vChar32 >> 24) & 0xff, (vChar32 >> 16) & 0xff,
914                 (vChar32 >> 8) & 0xff, vChar32 & 0xff);
915 }