Index: lldb/trunk/test/tools/lldb-mi/symbol/Makefile =================================================================== --- lldb/trunk/test/tools/lldb-mi/symbol/Makefile +++ lldb/trunk/test/tools/lldb-mi/symbol/Makefile @@ -1,5 +1,5 @@ LEVEL = ../../../make -CXX_SOURCES := main.cpp +CXX_SOURCES := main.cpp symbol_list_lines_inline_test.cpp symbol_list_lines_inline_test2.cpp include $(LEVEL)/Makefile.rules Index: lldb/trunk/test/tools/lldb-mi/symbol/TestMiSymbol.py =================================================================== --- lldb/trunk/test/tools/lldb-mi/symbol/TestMiSymbol.py +++ lldb/trunk/test/tools/lldb-mi/symbol/TestMiSymbol.py @@ -39,6 +39,19 @@ self.runCmd("-symbol-list-lines main.cpp") self.expect("\^done,lines=\[\{pc=\"0x0*%x\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"\d+\"\})+\]" % (addr, line)) + # Test that -symbol-list-lines doesn't include lines from other sources + # by checking the first and last line, and making sure the other lines + # are between 30 and 39. + sline = line_number('symbol_list_lines_inline_test2.cpp', '// FUNC_gfunc2') + eline = line_number('symbol_list_lines_inline_test2.cpp', '// END_gfunc2') + self.runCmd("-symbol-list-lines symbol_list_lines_inline_test2.cpp") + self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}\]" % (sline, eline)) + ##FIXME: This doesn't work for symbol_list_lines_inline_test.cpp due to clang bug llvm.org/pr24716 + ##sline = line_number('symbol_list_lines_inline_test.cpp', '// FUNC_gfunc') + ##eline = line_number('symbol_list_lines_inline_test.cpp', '// STRUCT_s') + ##self.runCmd("-symbol-list-lines symbol_list_lines_inline_test.cpp") + ##self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}\]" % (sline, eline)) + # Test that -symbol-list-lines fails when file doesn't exist self.runCmd("-symbol-list-lines unknown_file") self.expect("\^error,message=\"warning: No source filenames matched 'unknown_file'\. error: no source filenames matched any command arguments \"") Index: lldb/trunk/test/tools/lldb-mi/symbol/main.cpp =================================================================== --- lldb/trunk/test/tools/lldb-mi/symbol/main.cpp +++ lldb/trunk/test/tools/lldb-mi/symbol/main.cpp @@ -7,8 +7,12 @@ // //===----------------------------------------------------------------------===// +extern int j; +extern int gfunc(int i); +extern int gfunc2(int i); int -main(int argc, char const *argv[]) +main() { // FUNC_main - return 0; + int i = gfunc(j) + gfunc2(j); + return i == 0; } Index: lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h =================================================================== --- lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h +++ lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h @@ -0,0 +1,24 @@ +namespace ns +{ +inline int +ifunc(int i) +{ + return i; +} +struct S +{ + int a; + int b; + S() + : a(3) + , b(4) + { + } + int + mfunc() + { + return a + b; + } +}; +extern S s; +} Index: lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp =================================================================== --- lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp +++ lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp @@ -0,0 +1,39 @@ +// Skip lines so we can make sure we're not seeing any lines from +// symbol_list_lines_inline_test.h included in -symbol-list-lines +// symbol_list_lines_inline_test.cpp, by checking that all the lines +// are between 30 and 39. +// line 5 +// line 6 +// line 7 +// line 8 +// line 9 +// line 10 +// line 11 +// line 12 +// line 13 +// line 14 +// line 15 +// line 16 +// line 17 +// line 18 +// line 19 +// line 20 +// line 21 +// line 22 +// line 23 +// line 24 +// line 25 +// line 26 +// line 27 +// line 28 +// line 29 +#include "symbol_list_lines_inline_test.h" +int +gfunc(int i) +{ // FUNC_gfunc + return ns::ifunc(i); +} +namespace ns +{ +S s; // STRUCT_s +} Index: lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp =================================================================== --- lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp +++ lldb/trunk/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp @@ -0,0 +1,38 @@ +// Skip lines so we can make sure we're not seeing any lines from +// symbol_list_lines_inline_test.h included in -symbol-list-lines +// symbol_list_lines_inline_test2.cpp, by checking that all the lines +// are between 30 and 39. +// line 5 +// line 6 +// line 7 +// line 8 +// line 9 +// line 10 +// line 11 +// line 12 +// line 13 +// line 14 +// line 15 +// line 16 +// line 17 +// line 18 +// line 19 +// line 20 +// line 21 +// line 22 +// line 23 +// line 24 +// line 25 +// line 26 +// line 27 +// line 28 +// line 29 +#include "symbol_list_lines_inline_test.h" +int j = 2; +int +gfunc2(int i) +{ // FUNC_gfunc2 + i += ns::s.mfunc(); + i += ns::ifunc(i); + return i == 0; // END_gfunc2 +} Index: lldb/trunk/tools/lldb-mi/CMakeLists.txt =================================================================== --- lldb/trunk/tools/lldb-mi/CMakeLists.txt +++ lldb/trunk/tools/lldb-mi/CMakeLists.txt @@ -65,6 +65,7 @@ MIDriverBase.cpp MIDriverMain.cpp MIDriverMgr.cpp + MIUtilParse.cpp MIUtilDateTimeStd.cpp MIUtilDebug.cpp MIUtilFileStd.cpp Index: lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp =================================================================== --- lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp +++ lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp @@ -42,6 +42,7 @@ #include "MICmdArgValConsume.h" #include "MICmnLLDBDebugSessionInfoVarObj.h" #include "MICmnLLDBUtilSBValue.h" +#include "MIUtilParse.h" //++ ------------------------------------------------------------------------------------ // Details: CMICmdCmdDataEvaluateExpression constructor. @@ -1642,6 +1643,53 @@ } //++ ------------------------------------------------------------------------------------ +// Details: Helper function for parsing a line entry returned from lldb for the command: +// target modules lookup -v +// where the line entry is of the format: +// LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/file:3[:1] +// start end file line column(opt) +// Args: input - (R) Input string to parse. +// start - (W) String representing the start address. +// end - (W) String representing the end address. +// file - (W) String representing the file. +// line - (W) String representing the line. +// Return: bool - True = input was parsed successfully, false = input could not be parsed. +// Throws: None. +//-- +static bool +ParseLLDBLineEntry(const char *input, CMIUtilString &start, CMIUtilString &end, + CMIUtilString &file, CMIUtilString &line) +{ + // Note: Ambiguities arise because the column is optional, and + // because : can appear in filenames or as a byte in a multibyte + // UTF8 character. We keep those cases to a minimum by using regex + // to work on the string from both the left and right, so that what + // is remains is assumed to be the filename. + + // Match LineEntry using regex. + static MIUtilParse::CRegexParser g_lineentry_nocol_regex( + "^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$"); + static MIUtilParse::CRegexParser g_lineentry_col_regex( + "^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+):[0-9]+$"); + // ^1=start ^2=end ^3=f ^4=line ^5=:col(opt) + + MIUtilParse::CRegexParser::Match match(6); + + // First try matching the LineEntry with the column, + // then try without the column. + const bool ok = g_lineentry_col_regex.Execute(input, match) || + g_lineentry_nocol_regex.Execute(input, match); + if (ok) + { + start = match.GetMatchAtIndex(1); + end = match.GetMatchAtIndex(2); + file = match.GetMatchAtIndex(3); + line = match.GetMatchAtIndex(4); + } + return ok; +} + +//++ ------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command prepares a MI Record Result // for the work carried out in the Execute(). // Type: Overridden. @@ -1672,58 +1720,25 @@ // String looks like: // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1] const CMIUtilString &rLine(vecLines[i]); + CMIUtilString strStart; + CMIUtilString strEnd; + CMIUtilString strFile; + CMIUtilString strLine; - // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1] - // ^^^^^^^^^ -- property - const size_t nPropertyStartPos = rLine.find_first_not_of(' '); - const size_t nPropertyEndPos = rLine.find(':'); - const size_t nPropertyLen = nPropertyEndPos - nPropertyStartPos; - const CMIUtilString strProperty(rLine.substr(nPropertyStartPos, nPropertyLen).c_str()); - - // Skip all except LineEntry - if (!CMIUtilString::Compare(strProperty, "LineEntry")) + if (!ParseLLDBLineEntry(rLine.c_str(), strStart, strEnd, strFile, strLine)) continue; - // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1] - // ^^^^^^^^^^^^^^^^^^ -- start address - const size_t nStartAddressStartPos = rLine.find('['); - const size_t nStartAddressEndPos = rLine.find('-'); - const size_t nStartAddressLen = nStartAddressEndPos - nStartAddressStartPos - 1; - const CMIUtilString strStartAddress(rLine.substr(nStartAddressStartPos + 1, nStartAddressLen).c_str()); - const CMICmnMIValueConst miValueConst(strStartAddress); + const CMICmnMIValueConst miValueConst(strStart); const CMICmnMIValueResult miValueResult("start", miValueConst); - CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); - - // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1] - // ^^^^^^^^^^^^^^^^^^ -- end address - const size_t nEndAddressEndPos = rLine.find(')'); - const size_t nEndAddressLen = nEndAddressEndPos - nStartAddressEndPos - 1; - const CMIUtilString strEndAddress(rLine.substr(nStartAddressEndPos + 1, nEndAddressLen).c_str()); - const CMICmnMIValueConst miValueConst2(strEndAddress); + CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, + CMICmnMIResultRecord::eResultClass_Done, + miValueResult); + const CMICmnMIValueConst miValueConst2(strEnd); const CMICmnMIValueResult miValueResult2("end", miValueConst2); miRecordResult.Add(miValueResult2); - - // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1] - // ^^^^^^^^^^^^^ -- file - // ^ -- line - // ^ -- column (optional) - const size_t nFileStartPos = rLine.find_first_not_of(' ', nEndAddressEndPos + 2); - const size_t nFileOrLineEndPos = rLine.rfind(':'); - const size_t nFileOrLineStartPos = rLine.rfind(':', nFileOrLineEndPos - 1); - const size_t nFileEndPos = nFileStartPos < nFileOrLineStartPos ? nFileOrLineStartPos : nFileOrLineEndPos; - const size_t nFileLen = nFileEndPos - nFileStartPos; - const CMIUtilString strFile(rLine.substr(nFileStartPos, nFileLen).c_str()); const CMICmnMIValueConst miValueConst3(strFile); const CMICmnMIValueResult miValueResult3("file", miValueConst3); miRecordResult.Add(miValueResult3); - - // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1] - // ^ -- line - const size_t nLineStartPos = nFileEndPos + 1; - const size_t nLineEndPos = rLine.find(':', nLineStartPos); - const size_t nLineLen = nLineEndPos != std::string::npos ? nLineEndPos - nLineStartPos - : std::string::npos; - const CMIUtilString strLine(rLine.substr(nLineStartPos, nLineLen).c_str()); const CMICmnMIValueConst miValueConst4(strLine); const CMICmnMIValueResult miValueResult4("line", miValueConst4); miRecordResult.Add(miValueResult4); Index: lldb/trunk/tools/lldb-mi/MICmdCmdSymbol.cpp =================================================================== --- lldb/trunk/tools/lldb-mi/MICmdCmdSymbol.cpp +++ lldb/trunk/tools/lldb-mi/MICmdCmdSymbol.cpp @@ -19,6 +19,7 @@ #include "MICmnMIResultRecord.h" #include "MICmnMIValueList.h" #include "MICmnMIValueTuple.h" +#include "MIUtilParse.h" //++ ------------------------------------------------------------------------------------ // Details: CMICmdCmdSymbolListLines constructor. @@ -81,6 +82,10 @@ CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile); const CMIUtilString &strFilePath(pArgFile->GetValue()); + // FIXME: this won't work for header files! To try and use existing + // commands to get this to work for header files would be too slow. + // Instead, this code should be rewritten to use APIs and/or support + // should be added to lldb which would work for header files. const CMIUtilString strCmd(CMIUtilString::Format("target modules dump line-table \"%s\"", strFilePath.AddSlashes().c_str())); CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); @@ -91,6 +96,77 @@ } //++ ------------------------------------------------------------------------------------ +// Details: Helper function for parsing the header returned from lldb for the command: +// target modules dump line-table +// where the header is of the format: +// Line table for /path/to/file in `/path/to/module +// Args: input - (R) Input string to parse. +// file - (W) String representing the file. +// Return: bool - True = input was parsed successfully, false = input could not be parsed. +// Throws: None. +//-- +static bool +ParseLLDBLineAddressHeader(const char *input, CMIUtilString &file) +{ + // Match LineEntry using regex. + static MIUtilParse::CRegexParser g_lineentry_header_regex( + "^ *Line table for (.+) in `(.+)$"); + // ^1=file ^2=module + + MIUtilParse::CRegexParser::Match match(3); + + const bool ok = g_lineentry_header_regex.Execute(input, match); + if (ok) + file = match.GetMatchAtIndex(1); + return ok; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Helper function for parsing a line entry returned from lldb for the command: +// target modules dump line-table +// where the line entry is of the format: +// 0x0000000100000e70: /path/to/file:3002[:4] +// addr file line column(opt) +// Args: input - (R) Input string to parse. +// addr - (W) String representing the pc address. +// file - (W) String representing the file. +// line - (W) String representing the line. +// Return: bool - True = input was parsed successfully, false = input could not be parsed. +// Throws: None. +//-- +static bool +ParseLLDBLineAddressEntry(const char *input, CMIUtilString &addr, + CMIUtilString &file, CMIUtilString &line) +{ + // Note: Ambiguities arise because the column is optional, and + // because : can appear in filenames or as a byte in a multibyte + // UTF8 character. We keep those cases to a minimum by using regex + // to work on the string from both the left and right, so that what + // is remains is assumed to be the filename. + + // Match LineEntry using regex. + static MIUtilParse::CRegexParser g_lineentry_nocol_regex( + "^ *(0x[0-9a-fA-F]+): (.+):([0-9]+)$"); + static MIUtilParse::CRegexParser g_lineentry_col_regex( + "^ *(0x[0-9a-fA-F]+): (.+):([0-9]+):[0-9]+$"); + // ^1=addr ^2=f ^3=line ^4=:col(opt) + + MIUtilParse::CRegexParser::Match match(5); + + // First try matching the LineEntry with the column, + // then try without the column. + const bool ok = g_lineentry_col_regex.Execute(input, match) || + g_lineentry_nocol_regex.Execute(input, match); + if (ok) + { + addr = match.GetMatchAtIndex(1); + file = match.GetMatchAtIndex(2); + line = match.GetMatchAtIndex(3); + } + return ok; +} + +//++ ------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command prepares a MI Record Result // for the work carried out in the Execute(). // Type: Overridden. @@ -117,29 +193,43 @@ const CMIUtilString strLldbMsg(m_lldbResult.GetOutput()); const MIuint nLines(strLldbMsg.SplitLines(vecLines)); + // Parse the file from the header. + const CMIUtilString &rWantFile(vecLines[0]); + CMIUtilString strWantFile; + if (!ParseLLDBLineAddressHeader(rWantFile.c_str(), strWantFile)) + { + // Unexpected error - parsing failed. + // MI print "%s^error,msg=\"Command '-symbol-list-lines'. Error: Line address header is absent or has an unknown format.\"" + const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(), "Line address header is absent or has an unknown format.")); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + // Parse the line address entries. CMICmnMIValueList miValueList(true); for (MIuint i = 1; i < nLines; ++i) { // String looks like: // 0x0000000100000e70: /path/to/file:3[:4] const CMIUtilString &rLine(vecLines[i]); + CMIUtilString strAddr; + CMIUtilString strFile; + CMIUtilString strLine; + + if (!ParseLLDBLineAddressEntry(rLine.c_str(), strAddr, strFile, strLine)) + continue; + + // Skip entries which don't match the desired source. + if (strWantFile != strFile) + continue; - // 0x0000000100000e70: /path/to/file:3[:4] - // ^^^^^^^^^^^^^^^^^^ -- pc - const size_t nAddrEndPos = rLine.find(':'); - const CMIUtilString strAddr(rLine.substr(0, nAddrEndPos).c_str()); const CMICmnMIValueConst miValueConst(strAddr); const CMICmnMIValueResult miValueResult("pc", miValueConst); CMICmnMIValueTuple miValueTuple(miValueResult); - // 0x0000000100000e70: /path/to/file:3[:4] - // ^ -- line - const size_t nLineOrColumnStartPos = rLine.rfind(':'); - const CMIUtilString strLineOrColumn(rLine.substr(nLineOrColumnStartPos + 1).c_str()); - const size_t nPathOrLineStartPos = rLine.rfind(':', nLineOrColumnStartPos - 1); - const size_t nPathOrLineLen = nLineOrColumnStartPos - nPathOrLineStartPos - 1; - const CMIUtilString strPathOrLine(rLine.substr(nPathOrLineStartPos + 1, nPathOrLineLen).c_str()); - const CMIUtilString strLine(strPathOrLine.IsNumber() ? strPathOrLine : strLineOrColumn); const CMICmnMIValueConst miValueConst2(strLine); const CMICmnMIValueResult miValueResult2("line", miValueConst2); miValueTuple.Add(miValueResult2); Index: lldb/trunk/tools/lldb-mi/MIUtilParse.h =================================================================== --- lldb/trunk/tools/lldb-mi/MIUtilParse.h +++ lldb/trunk/tools/lldb-mi/MIUtilParse.h @@ -0,0 +1,93 @@ +//===-- MIUtilParse.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#pragma once + +// Third party headers: +#include "../lib/Support/regex_impl.h" + +// In-house headers: +#include "MIUtilString.h" + +namespace MIUtilParse +{ + +//++ ============================================================================ +// Details: MI common code utility class. Used to parse the output +// returned from lldb commands using regex. +//-- +class CRegexParser +{ + public: + // Helper class for keeping track of regex matches. + class Match + { + friend CRegexParser; + public: + /* ctor */ explicit Match(size_t nmatches) + : m_matchStrs(nmatches), m_maxMatches(nmatches) + { + } + size_t + GetMatchCount() const + { + return m_matchStrs.size(); + } + CMIUtilString + GetMatchAtIndex(size_t i) const + { + if (m_matchStrs.size() > i) + return m_matchStrs[i]; + return CMIUtilString(); + } + private: + CMIUtilString::VecString_t m_matchStrs; + const size_t m_maxMatches; + }; + + // Methods: + // Compile the regular expression. + /* ctor */ explicit CRegexParser(const char *regexStr); + + // Free the memory used by the regular expression. + /* dtor */ ~CRegexParser(); + + // No copies + CRegexParser(const CRegexParser&) = delete; + void operator=(CRegexParser&) = delete; + + // Return the match at the index. + int + GetMatchCount(const Match& match) const + { + if (m_isValid) + return match.GetMatchCount(); + return 0; + } + + bool + IsValid() const + { + return m_isValid; + } + + // Match the input against the regular expression. Return an error + // if the number of matches is less than minMatches. If the default + // minMatches value of 0 is passed, an error will be returned if + // the number of matches is less than the maxMatches value used to + // initialize Match. + bool + Execute(const char *input, Match& match, size_t minMatches = 0); + + private: + llvm_regex_t m_emma; + const bool m_isValid; +}; + +} Index: lldb/trunk/tools/lldb-mi/MIUtilParse.cpp =================================================================== --- lldb/trunk/tools/lldb-mi/MIUtilParse.cpp +++ lldb/trunk/tools/lldb-mi/MIUtilParse.cpp @@ -0,0 +1,75 @@ +//===-- MIUtilParse.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Third party headers: +#include + +// In-house headers: +#include "MIUtilParse.h" + +//++ ------------------------------------------------------------------------------------ +// Details: CRegexParser constructor. +// Type: Method. +// Args: regexStr - Pointer to the regular expression to compile. +// Return: None. +// Throws: None. +//-- +MIUtilParse::CRegexParser::CRegexParser(const char *regexStr) + : m_isValid(llvm_regcomp(&m_emma, regexStr, REG_EXTENDED) == 0) +{ +} + +//++ ------------------------------------------------------------------------------------ +// Details: CRegexParser destructor. +// Type: Method. +// Args: None. +// Return: None. +// Throws: None. +//-- +MIUtilParse::CRegexParser::~CRegexParser() +{ + // Free up memory held within regex. + if (m_isValid) + llvm_regfree(&m_emma); +} + +//++ ------------------------------------------------------------------------------------ +// Details: CRegexParser regex executer. +// Match the input against the regular expression. Return an error +// if the number of matches is less than minMatches. If the default +// minMatches value of 0 is passed, an error will be returned if +// the number of matches is less than the maxMatches value used to +// initialize Match. +// Type: Method. +// Args: input (R) - Pointer to UTF8 text data to be parsed. +// match (RW) - Reference to Match class. +// minMatches (R) - Minimum number of regex matches expected. +// Return: bool - True = minimum matches were met, +// false = minimum matches were not met or regex failed. +// Throws: None. +//-- +bool +MIUtilParse::CRegexParser::Execute(const char *input, Match& match, size_t minMatches) +{ + if (!m_isValid) + return false; + + std::unique_ptr matches(new llvm_regmatch_t[match.m_maxMatches]); // Array of matches + + if (llvm_regexec(&m_emma, input, match.m_maxMatches, matches.get(), 0) != 0) + return false; + + size_t i; + for (i = 0; i < match.m_maxMatches && matches[i].rm_so >= 0; i++) + { + const int n = matches[i].rm_eo - matches[i].rm_so; + match.m_matchStrs[i].assign(input + matches[i].rm_so, n); + } + return i >= minMatches; +} Index: lldb/trunk/tools/lldb-mi/MIUtilString.h =================================================================== --- lldb/trunk/tools/lldb-mi/MIUtilString.h +++ lldb/trunk/tools/lldb-mi/MIUtilString.h @@ -44,6 +44,7 @@ /* ctor */ CMIUtilString(); /* ctor */ CMIUtilString(const char *vpData); /* ctor */ CMIUtilString(const char *const *vpData); + /* ctor */ CMIUtilString(const char *vpData, size_t nLen); // bool ExtractNumber(MIint64 &vwrNumber) const; CMIUtilString FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const; Index: lldb/trunk/tools/lldb-mi/MIUtilString.cpp =================================================================== --- lldb/trunk/tools/lldb-mi/MIUtilString.cpp +++ lldb/trunk/tools/lldb-mi/MIUtilString.cpp @@ -55,6 +55,19 @@ } //++ ------------------------------------------------------------------------------------ +// Details: CMIUtilString constructor. +// Type: Method. +// Args: vpData - Pointer to UTF8 text data. +// nLen - Length of string. +// Return: None. +// Throws: None. +//-- +CMIUtilString::CMIUtilString(const char *vpData, size_t nLen) + : std::string(vpData, nLen) +{ +} + +//++ ------------------------------------------------------------------------------------ // Details: CMIUtilString assignment operator. // Type: Method. // Args: vpRhs - Pointer to UTF8 text data.