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