Skip to content

Commit

Permalink
Fixed problem with duplicate named groups in regular expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
nickgammon committed Apr 15, 2018
1 parent b9e52a1 commit 39cce14
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 17 deletions.
71 changes: 70 additions & 1 deletion regexp.cpp
Expand Up @@ -4,6 +4,9 @@
#include "MUSHclient.h"
#include "doc.h"
#include "dialogs\RegexpProblemDlg.h"
#include "pcre\config.h"
#include "pcre\pcre.h"
#include "pcre\pcre_internal.h"

#ifdef _DEBUG
#define new DEBUG_NEW
Expand Down Expand Up @@ -146,4 +149,70 @@ pcre * program;
dlg.m_iColumn = erroroffset + 1;
dlg.DoModal ();
return false; // bad
}
}


// returns a named wildcard
string t_regexp::GetWildcard (const string& sName) const
{
int iNumber = PCRE_ERROR_NOSUBSTRING;
if (IsStringNumber (sName))
iNumber = atoi (sName.c_str ());
else
{
if (m_program == NULL)
iNumber = PCRE_ERROR_NOSUBSTRING;
else
{
/* now do named subpatterns */
int namecount;
pcre_fullinfo(m_program, m_extra, PCRE_INFO_NAMECOUNT, &namecount);


if (namecount > 0)
{
unsigned char *name_table;
int name_entry_size;
unsigned char *tabptr;
int ncapt;
int jchanged;
pcre_fullinfo(m_program, m_extra, PCRE_INFO_CAPTURECOUNT, &ncapt);
pcre_fullinfo(m_program, m_extra, PCRE_INFO_NAMETABLE, &name_table);
pcre_fullinfo(m_program, m_extra, PCRE_INFO_NAMEENTRYSIZE, &name_entry_size);
pcre_fullinfo(m_program, m_extra, PCRE_INFO_JCHANGED, &jchanged);
tabptr = name_table;
set<string> found_strings;
for (int i = 0; i < namecount; i++, tabptr += name_entry_size)
{
int n = (tabptr[0] << 8) | tabptr[1];
const unsigned char * name = tabptr + 2;
// if duplicates were possible then ...
if (jchanged)
{
// this code is to ensure that we don't find a match (eg. mob = Kobold)
// and then if duplicates were allowed, replace Kobold with false.

string sName = (LPCTSTR) name;

// for duplicate names, see if we already added this name
if (found_strings.find (sName) != found_strings.end ())
{
// do not replace if this one is out of range or empty
if (n < 0 || n > m_iCount || GetWildcard (n) == "")
continue;
} // end of duplicate
else
found_strings.insert (sName);
}

if (n >= 0 && n <= m_iCount)
iNumber = n;

} // end of wildcard loop
} // end of having named wildcards

} // end of program not NULL

} // end of wanting a named wildcard
return GetWildcard (iNumber);
} // end of t_regexp::GetWildcard
15 changes: 1 addition & 14 deletions regexp.h
Expand Up @@ -74,20 +74,7 @@ class t_regexp
};

// returns a named wildcard
string GetWildcard (const string& sName) const
{
int iNumber;
if (IsStringNumber (sName))
iNumber = atoi (sName.c_str ());
else
{
if (m_program == NULL)
iNumber = PCRE_ERROR_NOSUBSTRING;
else
iNumber = njg_get_first_set (m_program, sName.c_str (), &m_vOffsets [0]);
}
return GetWildcard (iNumber);
}
string GetWildcard (const string& sName) const;

};

Expand Down
6 changes: 4 additions & 2 deletions scripting/lua_scripting.cpp
Expand Up @@ -546,16 +546,18 @@ bool CScriptEngine::ExecuteLua (DISPID & dispid, // dispatch ID, will be set to
pcre_fullinfo(regexp->m_program, regexp->m_extra, PCRE_INFO_NAMECOUNT, &namecount);
if (namecount > 0)
{
int jchanged;
pcre_fullinfo(regexp->m_program, regexp->m_extra, PCRE_INFO_NAMETABLE, &name_table);
pcre_fullinfo(regexp->m_program, regexp->m_extra, PCRE_INFO_NAMEENTRYSIZE, &name_entry_size);
pcre_fullinfo(regexp->m_program, regexp->m_extra, PCRE_INFO_JCHANGED, &jchanged);
tabptr = name_table;
set<string> found_strings;
for (i = 0; i < namecount; i++, tabptr += name_entry_size)
{
int n = (tabptr[0] << 8) | tabptr[1];
const unsigned char * name = tabptr + 2;
// if duplicates were possible then ...
if ((regexp->m_program->options & (PCRE_DUPNAMES | PCRE_JCHANGED)) != 0)
if (jchanged)
{
// this code is to ensure that we don't find a match (eg. mob = Kobold)
// and then if duplicates were allowed, replace Kobold with false.
Expand All @@ -566,7 +568,7 @@ bool CScriptEngine::ExecuteLua (DISPID & dispid, // dispatch ID, will be set to
if (found_strings.find (sName) != found_strings.end ())
{
// do not replace if this one is out of range
if (n < 0 || n > ncapt)
if (n < 0 || n > ncapt || regexp->GetWildcard (n) == "")
continue;
} // end of duplicate
else
Expand Down

0 comments on commit 39cce14

Please sign in to comment.