/*
* sliregexp.cc
*
* This file is part of NEST.
*
* Copyright (C) 2004 The NEST Initiative
*
* NEST is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* NEST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NEST. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "sliregexp.h"
#include "integerdatum.h"
#include "doubledatum.h"
#include "arraydatum.h"
#include "dictdatum.h"
#include "stringdatum.h"
#include "lockptrdatum_impl.h"
#include <regex.h>
SLIType RegexpModule::RegexType;
template class lockPTRDatum<Regex, &RegexpModule::RegexType>;
typedef lockPTRDatum<Regex, &RegexpModule::RegexType> RegexDatum;
Regex::Regex(){}
Regex::~Regex()
{
regfree(&r);
}
regex_t* Regex::get(void)
{
return &r;
}
RegexpModule::~RegexpModule()
{
RegexType.deletetypename();
}
void RegexpModule::init(SLIInterpreter *i)
{
Dictionary * regexdict = new Dictionary;
regexdict->insert(REG_NOTBOL_name, new IntegerDatum(REG_NOTBOL) );
regexdict->insert(REG_NOTEOL_name, new IntegerDatum(REG_NOTEOL) );
regexdict->insert(REG_ESPACE_name, new IntegerDatum(REG_ESPACE) );
regexdict->insert(REG_BADPAT_name, new IntegerDatum(REG_BADPAT) );
regexdict->insert(REG_EXTENDED_name, new IntegerDatum(REG_EXTENDED) );
regexdict->insert(REG_ICASE_name, new IntegerDatum(REG_ICASE) );
regexdict->insert(REG_NOSUB_name, new IntegerDatum(REG_NOSUB) );
regexdict->insert(REG_NEWLINE_name, new IntegerDatum(REG_NEWLINE) );
regexdict->insert(REG_ECOLLATE_name, new IntegerDatum(REG_ECOLLATE) );
regexdict->insert(REG_ECTYPE_name, new IntegerDatum(REG_ECTYPE) );
regexdict->insert(REG_EESCAPE_name, new IntegerDatum(REG_EESCAPE) );
regexdict->insert(REG_ESUBREG_name, new IntegerDatum(REG_ESUBREG) );
regexdict->insert(REG_EBRACK_name, new IntegerDatum(REG_EBRACK) );
regexdict->insert(REG_EPAREN_name, new IntegerDatum(REG_EPAREN) );
regexdict->insert(REG_EBRACE_name, new IntegerDatum(REG_EBRACE) );
regexdict->insert(REG_BADBR_name, new IntegerDatum(REG_BADBR) );
regexdict->insert(REG_ERANGE_name, new IntegerDatum(REG_ERANGE) );
regexdict->insert(REG_BADRPT_name, new IntegerDatum(REG_BADRPT) );
i->def( regexdict_name, new DictionaryDatum(regexdict) );
RegexType.settypename("regextype");
RegexType.setdefaultaction(SLIInterpreter::datatypefunction);
i->createcommand("regcomp_", ®compfunction);
i->createcommand("regexec_", ®execfunction);
i->createcommand("regerror_", ®errorfunction);
}
const std::string RegexpModule::name(void) const
{
return std::string("POSIX-Regexp");
}
const std::string RegexpModule::commandstring(void) const
{
return std::string("/regexp /C++ ($Revision: 9952 $) provide-component /regexp /SLI (1.4) require-component");
}
void RegexpModule::RegcompFunction::execute(SLIInterpreter *i) const
{
// string integer regcomp -> Regex true
// Regex integer false
assert(i->OStack.load()>=2);
IntegerDatum *id =dynamic_cast<IntegerDatum *>(i->OStack.pick(0).datum());
StringDatum *sd =dynamic_cast<StringDatum *>(i->OStack.pick(1).datum());
assert(sd != NULL);
assert(id != NULL);
Regex *MyRegex = new Regex;
int e=regcomp(MyRegex->get(),sd->c_str(),id->get());
i->OStack.pop(2);
Token rt(new RegexDatum(MyRegex));
i->OStack.push_move(rt);
if (!e)
{
i->OStack.push(i->baselookup(i->true_name));
}
else
{
Token it(new IntegerDatum(e));
i->OStack.push_move(it);
i->OStack.push(i->baselookup(i->false_name));
};
i->EStack.pop();
}
void RegexpModule::RegerrorFunction::execute(SLIInterpreter *i) const
{
assert(i->OStack.load()>=2);
IntegerDatum *id =dynamic_cast<IntegerDatum *>(i->OStack.pick(0).datum());
RegexDatum *rd =dynamic_cast<RegexDatum *>(i->OStack.pick(1).datum());
assert(rd != NULL);
assert(id != NULL);
char *error_buffer = new char[256];
regerror(id->get(),rd->get()->get(),error_buffer,256);
Token sd(new StringDatum(error_buffer));
delete[](error_buffer);
// The lockPTR rd gets locked when calling the get() function.
// In order to be able to use (delete) this object we need to
// unlock it again.
rd->unlock();
i->OStack.pop(2);
i->OStack.push_move(sd);
i->EStack.pop();
}
void RegexpModule::RegexecFunction::execute(SLIInterpreter *i) const
{
// regex string integer integer regexec -> array integer
// regex string 0 integer regexec -> integer
assert(i->OStack.load()>=4);
RegexDatum *rd = dynamic_cast<RegexDatum *>(i->OStack.pick(3).datum());
StringDatum *sd = dynamic_cast<StringDatum *>(i->OStack.pick(2).datum());
IntegerDatum *sized = dynamic_cast<IntegerDatum *>(i->OStack.pick(1).datum());
IntegerDatum *eflagsd = dynamic_cast<IntegerDatum *>(i->OStack.pick(0).datum());
assert(rd != NULL);
assert(sd != NULL);
assert(sized != NULL);
assert(eflagsd != NULL);
int size=sized->get();
regmatch_t *pm = new regmatch_t[size];
Regex *r = rd->get();
assert(r !=NULL);
rd->unlock();
int e=regexec(r->get(),sd->c_str(),size,pm,eflagsd->get());
Token id(new IntegerDatum(e));
i->OStack.pop(4);
if (size)
{
ArrayDatum* PushArray=new ArrayDatum();
for (int k=0;k<=(size-1);k++)
{
ArrayDatum* ThisEntry=new ArrayDatum();
Token so(new IntegerDatum(pm[k].rm_so));
ThisEntry->push_back_move(so);
Token eo(new IntegerDatum(pm[k].rm_eo));
ThisEntry->push_back_move(eo);
Token entry_token(ThisEntry);
PushArray->push_back_move(entry_token);
};
Token array_token(PushArray);
i->OStack.push_move(array_token);
};
delete[](pm);
i->OStack.push_move(id);
i->EStack.pop();
}