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>
14 #include <limits.h>
15 #include <memory>
16 #include <sstream>
17 #include <stdarg.h>
18 #include <string.h>
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 //--
CMIUtilString()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 //--
CMIUtilString(const char * vpData)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 //--
CMIUtilString(const std::string & vrStr)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 //--
operator =(const char * vpRhs)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 //--
operator =(const std::string & vrRhs)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 //--
~CMIUtilString()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 //--
FormatPriv(const CMIUtilString & vrFormat,va_list vArgs)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 //--
Format(const char * vFormating,...)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 //--
FormatValist(const CMIUtilString & vrFormating,va_list vArgs)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 //--
Split(const CMIUtilString & vDelimiter,VecString_t & vwVecSplits) const198 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 //--
SplitConsiderQuotes(const CMIUtilString & vDelimiter,VecString_t & vwVecSplits) const250 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 //--
SplitLines(VecString_t & vwVecSplits) const297 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 //--
StripCREndOfLine() const310 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 //--
StripCRAll() const330 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
FindAndReplace(const CMIUtilString & vFind,const CMIUtilString & vReplaceWith) const346 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 //--
IsNumber() const373 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 return nPos == std::string::npos;
382 }
383
384 //++
385 //------------------------------------------------------------------------------------
386 // Details: Check if *this string is a hexadecimal number.
387 // Type: Method.
388 // Args: None.
389 // Return: bool - True = yes number, false not a number.
390 // Throws: None.
391 //--
IsHexadecimalNumber() const392 bool CMIUtilString::IsHexadecimalNumber() const {
393 // Compare '0x..' prefix
394 if ((strncmp(c_str(), "0x", 2) != 0) && (strncmp(c_str(), "0X", 2) != 0))
395 return false;
396
397 // Skip '0x..' prefix
398 const size_t nPos = find_first_not_of("01234567890ABCDEFabcedf", 2);
399 return nPos == std::string::npos;
400 }
401
402 //++
403 //------------------------------------------------------------------------------------
404 // Details: Extract the number from the string. The number can be either a
405 // hexadecimal or
406 // natural number. It cannot contain other non-numeric characters.
407 // Type: Method.
408 // Args: vwrNumber - (W) Number extracted from the string.
409 // Return: bool - True = yes number, false not a number.
410 // Throws: None.
411 //--
ExtractNumber(MIint64 & vwrNumber) const412 bool CMIUtilString::ExtractNumber(MIint64 &vwrNumber) const {
413 vwrNumber = 0;
414
415 if (!IsNumber()) {
416 return ExtractNumberFromHexadecimal(vwrNumber);
417 }
418
419 std::stringstream ss(const_cast<CMIUtilString &>(*this));
420 ss >> vwrNumber;
421
422 return true;
423 }
424
425 //++
426 //------------------------------------------------------------------------------------
427 // Details: Extract the number from the hexadecimal string..
428 // Type: Method.
429 // Args: vwrNumber - (W) Number extracted from the string.
430 // Return: bool - True = yes number, false not a number.
431 // Throws: None.
432 //--
ExtractNumberFromHexadecimal(MIint64 & vwrNumber) const433 bool CMIUtilString::ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const {
434 vwrNumber = 0;
435
436 const size_t nPos = find_first_not_of("xX01234567890ABCDEFabcedf");
437 if (nPos != std::string::npos)
438 return false;
439
440 errno = 0;
441 const MIuint64 nNum = ::strtoull(this->c_str(), nullptr, 16);
442 if (errno == ERANGE)
443 return false;
444
445 vwrNumber = static_cast<MIint64>(nNum);
446
447 return true;
448 }
449
450 //++
451 //------------------------------------------------------------------------------------
452 // Details: Determine if the text is all valid alpha numeric characters. Letters
453 // can be
454 // either upper or lower case.
455 // Type: Static method.
456 // Args: vpText - (R) The text data to examine.
457 // Return: bool - True = yes all alpha, false = one or more chars is non alpha.
458 // Throws: None.
459 //--
IsAllValidAlphaAndNumeric(const char * vpText)460 bool CMIUtilString::IsAllValidAlphaAndNumeric(const char *vpText) {
461 const size_t len = ::strlen(vpText);
462 if (len == 0)
463 return false;
464
465 for (size_t i = 0; i < len; i++, vpText++) {
466 const char c = *vpText;
467 if (::isalnum((int)c) == 0)
468 return false;
469 }
470
471 return true;
472 }
473
474 //++
475 //------------------------------------------------------------------------------------
476 // Details: Check if two strings share equal contents.
477 // Type: Method.
478 // Args: vrLhs - (R) String A.
479 // vrRhs - (R) String B.
480 // Return: bool - True = yes equal, false - different.
481 // Throws: None.
482 //--
Compare(const CMIUtilString & vrLhs,const CMIUtilString & vrRhs)483 bool CMIUtilString::Compare(const CMIUtilString &vrLhs,
484 const CMIUtilString &vrRhs) {
485 // Check the sizes match
486 if (vrLhs.size() != vrRhs.size())
487 return false;
488
489 return (::strncmp(vrLhs.c_str(), vrRhs.c_str(), vrLhs.size()) == 0);
490 }
491
492 //++
493 //------------------------------------------------------------------------------------
494 // Details: Remove from either end of *this string the following: " \t\n\v\f\r".
495 // Type: Method.
496 // Args: None.
497 // Return: CMIUtilString - Trimmed string.
498 // Throws: None.
499 //--
Trim() const500 CMIUtilString CMIUtilString::Trim() const {
501 CMIUtilString strNew(*this);
502 const char *pWhiteSpace = " \t\n\v\f\r";
503 const size_t nPos = find_last_not_of(pWhiteSpace);
504 if (nPos != std::string::npos) {
505 strNew = substr(0, nPos + 1);
506 }
507 const size_t nPos2 = strNew.find_first_not_of(pWhiteSpace);
508 if (nPos2 != std::string::npos) {
509 strNew = strNew.substr(nPos2);
510 }
511
512 return strNew;
513 }
514
515 //++
516 //------------------------------------------------------------------------------------
517 // Details: Remove from either end of *this string the specified character.
518 // Type: Method.
519 // Args: None.
520 // Return: CMIUtilString - Trimmed string.
521 // Throws: None.
522 //--
Trim(const char vChar) const523 CMIUtilString CMIUtilString::Trim(const char vChar) const {
524 CMIUtilString strNew(*this);
525 const size_t nLen = strNew.length();
526 if (nLen > 1) {
527 if ((strNew[0] == vChar) && (strNew[nLen - 1] == vChar))
528 strNew = strNew.substr(1, nLen - 2);
529 }
530
531 return strNew;
532 }
533
534 //++
535 //------------------------------------------------------------------------------------
536 // Details: Do a printf equivalent for printing a number in binary i.e. "b%llB".
537 // Type: Static method.
538 // Args: vnDecimal - (R) The number to represent in binary.
539 // Return: CMIUtilString - Binary number in text.
540 // Throws: None.
541 //--
FormatBinary(const MIuint64 vnDecimal)542 CMIUtilString CMIUtilString::FormatBinary(const MIuint64 vnDecimal) {
543 CMIUtilString strBinaryNumber;
544
545 const MIuint nConstBits = 64;
546 MIuint nRem[nConstBits + 1];
547 MIint i = 0;
548 MIuint nLen = 0;
549 MIuint64 nNum = vnDecimal;
550 while ((nNum > 0) && (nLen < nConstBits)) {
551 nRem[i++] = nNum % 2;
552 nNum = nNum >> 1;
553 nLen++;
554 }
555 char pN[nConstBits + 1];
556 MIuint j = 0;
557 for (i = nLen; i > 0; --i, j++) {
558 pN[j] = '0' + nRem[i - 1];
559 }
560 pN[j] = 0; // String NUL termination
561
562 strBinaryNumber = CMIUtilString::Format("0b%s", &pN[0]);
563
564 return strBinaryNumber;
565 }
566
567 //++
568 //------------------------------------------------------------------------------------
569 // Details: Remove from a string doubled up characters so only one set left.
570 // Characters
571 // are only removed if the previous character is already a same
572 // character.
573 // Type: Method.
574 // Args: vChar - (R) The character to search for and remove adjacent
575 // duplicates.
576 // Return: CMIUtilString - New version of the string.
577 // Throws: None.
578 //--
RemoveRepeatedCharacters(const char vChar)579 CMIUtilString CMIUtilString::RemoveRepeatedCharacters(const char vChar) {
580 return RemoveRepeatedCharacters(0, vChar);
581 }
582
583 //++
584 //------------------------------------------------------------------------------------
585 // Details: Recursively remove from a string doubled up characters so only one
586 // set left.
587 // Characters are only removed if the previous character is already a
588 // same
589 // character.
590 // Type: Method.
591 // Args: vChar - (R) The character to search for and remove adjacent
592 // duplicates.
593 // vnPos - Character position in the string.
594 // Return: CMIUtilString - New version of the string.
595 // Throws: None.
596 //--
RemoveRepeatedCharacters(size_t vnPos,const char vChar)597 CMIUtilString CMIUtilString::RemoveRepeatedCharacters(size_t vnPos,
598 const char vChar) {
599 const char cQuote = '"';
600
601 // Look for first quote of two
602 const size_t nPos = find(cQuote, vnPos);
603 if (nPos == std::string::npos)
604 return *this;
605
606 const size_t nPosNext = nPos + 1;
607 if (nPosNext > length())
608 return *this;
609
610 if (at(nPosNext) == cQuote) {
611 *this = substr(0, nPos) + substr(nPosNext, length());
612 RemoveRepeatedCharacters(nPosNext, vChar);
613 }
614
615 return *this;
616 }
617
618 //++
619 //------------------------------------------------------------------------------------
620 // Details: Is the text in *this string surrounded by quotes.
621 // Type: Method.
622 // Args: None.
623 // Return: bool - True = Yes string is quoted, false = no quoted.
624 // Throws: None.
625 //--
IsQuoted() const626 bool CMIUtilString::IsQuoted() const {
627 const char cQuote = '"';
628
629 if (at(0) != cQuote)
630 return false;
631
632 const size_t nLen = length();
633 return !((nLen > 0) && (at(nLen - 1) != cQuote));
634 }
635
636 //++
637 //------------------------------------------------------------------------------------
638 // Details: Find first occurrence in *this string which matches the pattern.
639 // Type: Method.
640 // Args: vrPattern - (R) The pattern to search for.
641 // vnPos - The starting position at which to start searching.
642 // (Dflt = 0)
643 // Return: size_t - The position of the first substring that match.
644 // Throws: None.
645 //--
FindFirst(const CMIUtilString & vrPattern,size_t vnPos) const646 size_t CMIUtilString::FindFirst(const CMIUtilString &vrPattern,
647 size_t vnPos /* = 0 */) const {
648 return find(vrPattern, vnPos);
649 }
650
651 //++
652 //------------------------------------------------------------------------------------
653 // Details: Find first occurrence in *this string which matches the pattern and
654 // isn't surrounded by quotes.
655 // Type: Method.
656 // Args: vrPattern - (R) The pattern to search for.
657 // vbSkipQuotedText - (R) True = don't look at quoted text,
658 // false = otherwise.
659 // vrwbNotFoundClosedQuote - (W) True = parsing error: unmatched
660 // quote, false = otherwise.
661 // vnPos - Position of the first character in the
662 // string to be considered in the search. (Dflt = 0)
663 // Return: size_t - The position of the first substring that matches and isn't
664 // quoted.
665 // Throws: None.
666 //--
FindFirst(const CMIUtilString & vrPattern,const bool vbSkipQuotedText,bool & vrwbNotFoundClosedQuote,size_t vnPos) const667 size_t CMIUtilString::FindFirst(const CMIUtilString &vrPattern,
668 const bool vbSkipQuotedText,
669 bool &vrwbNotFoundClosedQuote,
670 size_t vnPos /* = 0 */) const {
671 vrwbNotFoundClosedQuote = false;
672
673 if (!vbSkipQuotedText)
674 return FindFirst(vrPattern, vnPos);
675
676 const size_t nLen(length());
677
678 size_t nPos = vnPos;
679 do {
680 const size_t nQuotePos(FindFirstQuote(nPos));
681 const size_t nPatternPos(FindFirst(vrPattern, nPos));
682 if (nQuotePos == std::string::npos)
683 return nPatternPos;
684
685 const size_t nQuoteClosedPos = FindFirstQuote(nQuotePos + 1);
686 if (nQuoteClosedPos == std::string::npos) {
687 vrwbNotFoundClosedQuote = true;
688 return std::string::npos;
689 }
690
691 if ((nPatternPos == std::string::npos) || (nPatternPos < nQuotePos))
692 return nPatternPos;
693
694 nPos = nQuoteClosedPos + 1;
695 } while (nPos < nLen);
696
697 return std::string::npos;
698 }
699
700 //++
701 //------------------------------------------------------------------------------------
702 // Details: Find first occurrence in *this string which doesn't match the
703 // pattern.
704 // Type: Method.
705 // Args: vrPattern - (R) The pattern to search for.
706 // vnPos - Position of the first character in the string to be
707 // considered in the search. (Dflt = 0)
708 // Return: size_t - The position of the first character that doesn't match.
709 // Throws: None.
710 //--
FindFirstNot(const CMIUtilString & vrPattern,size_t vnPos) const711 size_t CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern,
712 size_t vnPos /* = 0 */) const {
713 const size_t nLen(length());
714 const size_t nPatternLen(vrPattern.length());
715
716 size_t nPatternPos(vnPos);
717 do {
718 const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0);
719 if (!bMatchPattern)
720 return nPatternPos;
721 nPatternPos += nPatternLen;
722 } while (nPatternPos < nLen);
723
724 return std::string::npos;
725 }
726
727 //++
728 //------------------------------------------------------------------------------------
729 // Details: Find first occurrence of not escaped quotation mark in *this string.
730 // Type: Method.
731 // Args: vnPos - Position of the first character in the string to be
732 // considered in the search.
733 // Return: size_t - The position of the quotation mark.
734 // Throws: None.
735 //--
FindFirstQuote(size_t vnPos) const736 size_t CMIUtilString::FindFirstQuote(size_t vnPos) const {
737 const char cBckSlash('\\');
738 const char cQuote('"');
739 const size_t nLen(length());
740
741 size_t nPos = vnPos;
742 do {
743 const size_t nBckSlashPos(find(cBckSlash, nPos));
744 const size_t nQuotePos(find(cQuote, nPos));
745 if ((nBckSlashPos == std::string::npos) || (nQuotePos == std::string::npos))
746 return nQuotePos;
747
748 if (nQuotePos < nBckSlashPos)
749 return nQuotePos;
750
751 // Skip 2 characters: First is '\', second is that which is escaped by '\'
752 nPos = nBckSlashPos + 2;
753 } while (nPos < nLen);
754
755 return std::string::npos;
756 }
757
758 //++
759 //------------------------------------------------------------------------------------
760 // Details: Get escaped string from *this string.
761 // Type: Method.
762 // Args: None.
763 // Return: CMIUtilString - The escaped version of the initial string.
764 // Throws: None.
765 //--
Escape(bool vbEscapeQuotes) const766 CMIUtilString CMIUtilString::Escape(bool vbEscapeQuotes /* = false */) const {
767 const size_t nLen(length());
768 CMIUtilString strNew;
769 strNew.reserve(nLen);
770 for (size_t nIndex(0); nIndex < nLen; ++nIndex) {
771 const char cUnescapedChar((*this)[nIndex]);
772 if (cUnescapedChar == '"' && vbEscapeQuotes)
773 strNew.append("\\\"");
774 else
775 strNew.append(ConvertToPrintableASCII((char)cUnescapedChar));
776 }
777 return strNew;
778 }
779
780 //++
781 //------------------------------------------------------------------------------------
782 // Details: Get string with backslashes in front of double quote '"' and
783 // backslash '\\'
784 // characters.
785 // Type: Method.
786 // Args: None.
787 // Return: CMIUtilString - The wrapped version of the initial string.
788 // Throws: None.
789 //--
AddSlashes() const790 CMIUtilString CMIUtilString::AddSlashes() const {
791 const char cBckSlash('\\');
792 const size_t nLen(length());
793 CMIUtilString strNew;
794 strNew.reserve(nLen);
795
796 size_t nOffset(0);
797 while (nOffset < nLen) {
798 const size_t nUnescapedCharPos(find_first_of("\"\\", nOffset));
799 const bool bUnescapedCharNotFound(nUnescapedCharPos == std::string::npos);
800 if (bUnescapedCharNotFound) {
801 const size_t nAppendAll(std::string::npos);
802 strNew.append(*this, nOffset, nAppendAll);
803 break;
804 }
805 const size_t nAppendLen(nUnescapedCharPos - nOffset);
806 strNew.append(*this, nOffset, nAppendLen);
807 strNew.push_back(cBckSlash);
808 const char cUnescapedChar((*this)[nUnescapedCharPos]);
809 strNew.push_back(cUnescapedChar);
810 nOffset = nUnescapedCharPos + 1;
811 }
812
813 return strNew;
814 }
815
816 //++
817 //------------------------------------------------------------------------------------
818 // Details: Remove backslashes added by CMIUtilString::AddSlashes.
819 // Type: Method.
820 // Args: None.
821 // Return: CMIUtilString - The initial version of wrapped string.
822 // Throws: None.
823 //--
StripSlashes() const824 CMIUtilString CMIUtilString::StripSlashes() const {
825 const char cBckSlash('\\');
826 const size_t nLen(length());
827 CMIUtilString strNew;
828 strNew.reserve(nLen);
829
830 size_t nOffset(0);
831 while (nOffset < nLen) {
832 const size_t nBckSlashPos(find(cBckSlash, nOffset));
833 const bool bBckSlashNotFound(nBckSlashPos == std::string::npos);
834 if (bBckSlashNotFound) {
835 const size_t nAppendAll(std::string::npos);
836 strNew.append(*this, nOffset, nAppendAll);
837 break;
838 }
839 const size_t nAppendLen(nBckSlashPos - nOffset);
840 strNew.append(*this, nOffset, nAppendLen);
841 const bool bBckSlashIsLast(nBckSlashPos == nLen);
842 if (bBckSlashIsLast) {
843 strNew.push_back(cBckSlash);
844 break;
845 }
846 const char cEscapedChar((*this)[nBckSlashPos + 1]);
847 const size_t nEscapedCharPos(std::string("\"\\").find(cEscapedChar));
848 const bool bEscapedCharNotFound(nEscapedCharPos == std::string::npos);
849 if (bEscapedCharNotFound)
850 strNew.push_back(cBckSlash);
851 strNew.push_back(cEscapedChar);
852 nOffset = nBckSlashPos + 2;
853 }
854
855 return strNew;
856 }
857
ConvertToPrintableASCII(const char vChar,bool bEscapeQuotes)858 CMIUtilString CMIUtilString::ConvertToPrintableASCII(const char vChar,
859 bool bEscapeQuotes) {
860 switch (vChar) {
861 case '\a':
862 return "\\a";
863 case '\b':
864 return "\\b";
865 case '\t':
866 return "\\t";
867 case '\n':
868 return "\\n";
869 case '\v':
870 return "\\v";
871 case '\f':
872 return "\\f";
873 case '\r':
874 return "\\r";
875 case '\033':
876 return "\\e";
877 case '\\':
878 return "\\\\";
879 case '"':
880 if (bEscapeQuotes)
881 return "\\\"";
882 LLVM_FALLTHROUGH;
883 default:
884 if (::isprint(vChar))
885 return Format("%c", vChar);
886 else
887 return Format("\\x%02" PRIx8, vChar);
888 }
889 }
890
891 CMIUtilString
ConvertCharValueToPrintableASCII(char vChar,bool bEscapeQuotes)892 CMIUtilString::ConvertCharValueToPrintableASCII(char vChar,
893 bool bEscapeQuotes) {
894 switch (vChar) {
895 case '\a':
896 return "\\a";
897 case '\b':
898 return "\\b";
899 case '\t':
900 return "\\t";
901 case '\n':
902 return "\\n";
903 case '\v':
904 return "\\v";
905 case '\f':
906 return "\\f";
907 case '\r':
908 return "\\r";
909 case '\033':
910 return "\\e";
911 case '\\':
912 return "\\\\";
913 case '"':
914 if (bEscapeQuotes)
915 return "\\\"";
916 LLVM_FALLTHROUGH;
917 default:
918 if (::isprint(vChar))
919 return Format("%c", vChar);
920 else
921 return CMIUtilString();
922 }
923 }
924
ConvertToPrintableASCII(const char16_t vChar16,bool bEscapeQuotes)925 CMIUtilString CMIUtilString::ConvertToPrintableASCII(const char16_t vChar16,
926 bool bEscapeQuotes) {
927 if (vChar16 == (char16_t)(char)vChar16) {
928 // Convert char16_t to char (if possible)
929 CMIUtilString str =
930 ConvertCharValueToPrintableASCII((char)vChar16, bEscapeQuotes);
931 if (str.length() > 0)
932 return str;
933 }
934 return Format("\\u%02" PRIx8 "%02" PRIx8, (vChar16 >> 8) & 0xff,
935 vChar16 & 0xff);
936 }
937
ConvertToPrintableASCII(const char32_t vChar32,bool bEscapeQuotes)938 CMIUtilString CMIUtilString::ConvertToPrintableASCII(const char32_t vChar32,
939 bool bEscapeQuotes) {
940 if (vChar32 == (char32_t)(char)vChar32) {
941 // Convert char32_t to char (if possible)
942 CMIUtilString str =
943 ConvertCharValueToPrintableASCII((char)vChar32, bEscapeQuotes);
944 if (str.length() > 0)
945 return str;
946 }
947 return Format("\\U%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8,
948 (vChar32 >> 24) & 0xff, (vChar32 >> 16) & 0xff,
949 (vChar32 >> 8) & 0xff, vChar32 & 0xff);
950 }
951