// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Eduardo Aguiar
//
// This program 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, or (at your option) any later
// version.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <mobius/regex_impl.h>
#include <mobius/exception.inc>
#include <stdexcept>
#include <memory>

namespace mobius
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief create new regular expression object
//! \param pattern regex pattern
//! \param flags as defined in system's regex.h
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
regex::regex (const std::string& pattern, int flags)
{
  int rc = regcomp (&reg_, pattern.c_str (), flags);
  if (rc)
    {
      char errmsg[256];
      regerror (rc, &reg_, errmsg, sizeof (errmsg));
      throw std::runtime_error (MOBIUS_EXCEPTION_MSG (errmsg));
    }
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief destructor
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
regex::~regex ()
{
  regfree (&reg_);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief return a matched group
//! \param idx group index
//! \return group text
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
std::string
regex::operator[](regex::size_type idx) const
{
  if (idx >= matches_.size ())
    throw std::out_of_range (MOBIUS_EXCEPTION_MSG ("out of range group idx"));

  return matches_[idx];
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief check if text matches with regex
//! \param text text
//! \return true/false if text matched
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool
regex::match (const std::string& text)
{
  std::unique_ptr <regmatch_t[]> pmatch (new regmatch_t[reg_.re_nsub + 1]);

  bool found = !regexec (&reg_, text.c_str (), reg_.re_nsub + 1, pmatch.get (), 0);
  if (found)
    {
      matches_.clear ();
      std::string group;

      for (std::size_t i = 0; i < reg_.re_nsub + 1; i++)
        {
          if (pmatch[i].rm_so != -1)
            group = text.substr (pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so);

          else
            group = std::string ();

          matches_.push_back (group);
        }
    }

  return found;
}

} // namespace mobius
