changed: update version strings for beta4
[xbmc.git] / xbmc / utils / RegExp.cpp
blob15c6bc206b6dc4394661813c227b395347df1d58
1 /*
2 * Copyright (C) 2005-2008 Team XBMC
3 * http://www.xbmc.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include <stdlib.h>
23 #include <string.h>
24 #include "RegExp.h"
25 #include "StdString.h"
26 #include "log.h"
28 using namespace PCRE;
30 CRegExp::CRegExp(bool caseless)
32 m_re = NULL;
33 m_iOptions = PCRE_DOTALL;
34 if(caseless)
35 m_iOptions |= PCRE_CASELESS;
37 m_bMatched = false;
38 m_iMatchCount = 0;
41 CRegExp::CRegExp(const CRegExp& re)
43 m_re = NULL;
44 m_iOptions = re.m_iOptions;
45 *this = re;
48 const CRegExp& CRegExp::operator=(const CRegExp& re)
50 size_t size;
51 Cleanup();
52 m_pattern = re.m_pattern;
53 if (re.m_re)
55 if (pcre_fullinfo(re.m_re, NULL, PCRE_INFO_SIZE, &size) >= 0)
57 if ((m_re = (pcre*)malloc(size)))
59 memcpy(m_re, re.m_re, size);
60 memcpy(m_iOvector, re.m_iOvector, OVECCOUNT*sizeof(int));
61 m_iMatchCount = re.m_iMatchCount;
62 m_bMatched = re.m_bMatched;
63 m_subject = re.m_subject;
64 m_iOptions = re.m_iOptions;
68 return *this;
71 CRegExp::~CRegExp()
73 Cleanup();
76 CRegExp* CRegExp::RegComp(const char *re)
78 if (!re)
79 return NULL;
81 m_bMatched = false;
82 m_iMatchCount = 0;
83 const char *errMsg = NULL;
84 int errOffset = 0;
86 Cleanup();
88 m_re = pcre_compile(re, m_iOptions, &errMsg, &errOffset, NULL);
89 if (!m_re)
91 m_pattern.clear();
92 CLog::Log(LOGERROR, "PCRE: %s. Compilation failed at offset %d in expression '%s'",
93 errMsg, errOffset, re);
94 return NULL;
97 m_pattern = re;
99 return this;
102 int CRegExp::RegFind(const char* str, int startoffset)
104 m_bMatched = false;
105 m_iMatchCount = 0;
107 if (!m_re)
109 CLog::Log(LOGERROR, "PCRE: Called before compilation");
110 return -1;
113 if (!str)
115 CLog::Log(LOGERROR, "PCRE: Called without a string to match");
116 return -1;
119 m_subject = str;
120 int rc = pcre_exec(m_re, NULL, str, strlen(str), startoffset, 0, m_iOvector, OVECCOUNT);
122 if (rc<1)
124 switch(rc)
126 case PCRE_ERROR_NOMATCH:
127 return -1;
129 case PCRE_ERROR_MATCHLIMIT:
130 CLog::Log(LOGERROR, "PCRE: Match limit reached");
131 return -1;
133 default:
134 CLog::Log(LOGERROR, "PCRE: Unknown error: %d", rc);
135 return -1;
138 m_bMatched = true;
139 m_iMatchCount = rc;
140 return m_iOvector[0];
143 int CRegExp::GetCaptureTotal()
145 int c = -1;
146 if (m_re)
147 pcre_fullinfo(m_re, NULL, PCRE_INFO_CAPTURECOUNT, &c);
148 return c;
151 char* CRegExp::GetReplaceString( const char* sReplaceExp )
153 char *src = (char *)sReplaceExp;
154 char *buf;
155 char c;
156 int no;
157 size_t len;
159 if( sReplaceExp == NULL || !m_bMatched )
160 return NULL;
163 // First compute the length of the string
164 int replacelen = 0;
165 while ((c = *src++) != '\0')
167 if (c == '&')
168 no = 0;
169 else if (c == '\\' && isdigit(*src))
170 no = *src++ - '0';
171 else
172 no = -1;
174 if (no < 0)
176 // Ordinary character.
177 if (c == '\\' && (*src == '\\' || *src == '&'))
178 c = *src++;
179 replacelen++;
181 else if (no < m_iMatchCount && (m_iOvector[no*2]>=0))
183 // Get tagged expression
184 len = m_iOvector[no*2+1] - m_iOvector[no*2];
185 replacelen += len;
189 // Now allocate buf
190 buf = (char *)malloc((replacelen + 1)*sizeof(char));
191 if( buf == NULL )
192 return NULL;
194 char* sReplaceStr = buf;
196 // Add null termination
197 buf[replacelen] = '\0';
199 // Now we can create the string
200 src = (char *)sReplaceExp;
201 while ((c = *src++) != '\0')
203 if (c == '&')
204 no = 0;
205 else if (c == '\\' && isdigit(*src))
206 no = *src++ - '0';
207 else
208 no = -1;
210 if (no < 0)
212 // Ordinary character.
213 if (c == '\\' && (*src == '\\' || *src == '&'))
214 c = *src++;
215 *buf++ = c;
217 else if (no < m_iMatchCount && (m_iOvector[no*2]>=0))
219 // Get tagged expression
220 len = m_iOvector[no*2+1] - m_iOvector[no*2];
221 strncpy(buf, m_subject.c_str()+m_iOvector[no*2], len);
222 buf += len;
226 return sReplaceStr;
229 std::string CRegExp::GetMatch(int iSub /* = 0 */)
231 if (iSub < 0 || iSub > m_iMatchCount)
232 return "";
234 int pos = m_iOvector[(iSub*2)];
235 int len = m_iOvector[(iSub*2)+1] - pos;
236 return m_subject.substr(pos, len);
239 bool CRegExp::GetNamedSubPattern(const char* strName, std::string& strMatch)
241 strMatch.clear();
242 int iSub = pcre_get_stringnumber(m_re, strName);
243 if (iSub < 0)
244 return false;
245 strMatch = GetMatch(iSub);
246 return true;
249 void CRegExp::DumpOvector(int iLog /* = LOGDEBUG */)
251 if (iLog < LOGDEBUG || iLog > LOGNONE)
252 return;
254 CStdString str = "{";
255 int size = GetSubCount(); // past the subpatterns is junk
256 for (int i = 0; i <= size; i++)
258 CStdString t;
259 t.Format("[%i,%i]", m_iOvector[(i*2)], m_iOvector[(i*2)+1]);
260 if (i != size)
261 t += ",";
262 str += t;
264 str += "}";
265 CLog::Log(iLog, "regexp ovector=%s", str.c_str());