1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "RegexExplorer.h"
4 
RegexExplorer(QWidget * p)5 RegexExplorer::RegexExplorer(QWidget* p)
6   : QDialog(p)
7   , m_matched(false)
8 {
9   this->setupUi(this);
10 
11   for (int i = 1; i < cmsys::RegularExpressionMatch::NSUBEXP; ++i) {
12     matchNumber->addItem(QString("Match %1").arg(QString::number(i)),
13                          QVariant(i));
14   }
15   matchNumber->setCurrentIndex(0);
16 }
17 
setStatusColor(QWidget * widget,bool successful)18 void RegexExplorer::setStatusColor(QWidget* widget, bool successful)
19 {
20   QColor color = successful ? QColor(0, 127, 0) : Qt::red;
21 
22   QPalette palette = widget->palette();
23   palette.setColor(QPalette::WindowText, color);
24   widget->setPalette(palette);
25 }
26 
on_regularExpression_textChanged(const QString & text)27 void RegexExplorer::on_regularExpression_textChanged(const QString& text)
28 {
29 #ifdef QT_NO_STL
30   m_regex = text.toAscii().constData();
31 #else
32   m_regex = text.toStdString();
33 #endif
34 
35   bool validExpression =
36     stripEscapes(m_regex) && m_regexParser.compile(m_regex);
37   if (!validExpression) {
38     m_regexParser.set_invalid();
39   }
40 
41   setStatusColor(labelRegexValid, validExpression);
42 
43   on_inputText_textChanged();
44 }
45 
on_inputText_textChanged()46 void RegexExplorer::on_inputText_textChanged()
47 {
48   if (m_regexParser.is_valid()) {
49     QString plainText = inputText->toPlainText();
50 #ifdef QT_NO_STL
51     m_text = plainText.toAscii().constData();
52 #else
53     m_text = plainText.toStdString();
54 #endif
55     m_matched = m_regexParser.find(m_text);
56   } else {
57     m_matched = false;
58   }
59 
60   setStatusColor(labelRegexMatch, m_matched);
61 
62   if (!m_matched) {
63     clearMatch();
64     return;
65   }
66 
67   std::string matchingText;
68 
69   if (matchAll->isChecked()) {
70     const char* p = m_text.c_str();
71     while (m_regexParser.find(p)) {
72       std::string::size_type l = m_regexParser.start();
73       std::string::size_type r = m_regexParser.end();
74       if (r - l == 0) {
75         // matched empty string
76         clearMatch();
77         return;
78       }
79       if (!matchingText.empty()) {
80         matchingText += ";";
81       }
82       matchingText += std::string(p + l, r - l);
83       p += r;
84     }
85   } else {
86     matchingText = m_regexParser.match(0);
87   }
88 
89 #ifdef QT_NO_STL
90   QString matchText = matchingText.c_str();
91 #else
92   QString matchText = QString::fromStdString(matchingText);
93 #endif
94   match0->setPlainText(matchText);
95 
96   on_matchNumber_currentIndexChanged(matchNumber->currentIndex());
97 }
98 
on_matchNumber_currentIndexChanged(int index)99 void RegexExplorer::on_matchNumber_currentIndexChanged(int index)
100 {
101   if (!m_matched) {
102     return;
103   }
104 
105   QVariant itemData = matchNumber->itemData(index);
106   int idx = itemData.toInt();
107 
108   if (idx < 1 || idx >= cmsys::RegularExpressionMatch::NSUBEXP) {
109     return;
110   }
111 
112 #ifdef QT_NO_STL
113   QString match = m_regexParser.match(idx).c_str();
114 #else
115   QString match = QString::fromStdString(m_regexParser.match(idx));
116 #endif
117   matchN->setPlainText(match);
118 }
119 
on_matchAll_toggled(bool checked)120 void RegexExplorer::on_matchAll_toggled(bool checked)
121 {
122   Q_UNUSED(checked);
123 
124   on_inputText_textChanged();
125 }
126 
clearMatch()127 void RegexExplorer::clearMatch()
128 {
129   m_matched = false;
130   match0->clear();
131   matchN->clear();
132 }
133 
stripEscapes(std::string & source)134 bool RegexExplorer::stripEscapes(std::string& source)
135 {
136   const char* in = source.c_str();
137 
138   std::string result;
139   result.reserve(source.size());
140 
141   for (char inc = *in; inc != '\0'; inc = *++in) {
142     if (inc == '\\') {
143       char nextc = in[1];
144       if (nextc == 't') {
145         result.append(1, '\t');
146         in++;
147       } else if (nextc == 'n') {
148         result.append(1, '\n');
149         in++;
150       } else if (isalnum(nextc) || nextc == '\0') {
151         return false;
152       } else {
153         result.append(1, nextc);
154         in++;
155       }
156     } else {
157       result.append(1, inc);
158     }
159   }
160 
161   source = result;
162   return true;
163 }
164