/* doscan - Denial Of Service Capable Auditing of Networks       -*- C++ -*-
 * Copyright (C) 2003 Florian Weimer
 *
 * 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 of the License, 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef RX_H
#define RX_H

#include <string>
#include <vector>

#include <pcre.h>

class rx {
  pcre* regexp;
  int capture_count;

public:
  class error {
    std::string message;
    int m_offset;
  public:
    error(const char*, int);
    const std::string& str() const;
    int offset() const;
  };

  rx(const char*, int options = 0) throw (error);
  ~rx();

  unsigned captures() const;

  struct match {
    match();
    match(std::string::const_iterator, std::string::const_iterator);
    std::string::const_iterator first;
    std::string::const_iterator last;

    std::string data() const;
  };

  class matches {
    friend class rx;

    std::vector<match> array;

    // set() is invoked by rx::exec() to store the result.  clear()
    // empties the array in case of errors.

    void set(const std::string&, int *, int);
    void clear();

  public:
    matches();

    const match& operator[](unsigned pos) const;

    // Constructs a result string by copying from data.

    std::string operator()(unsigned pos, const std::string& data);
  };

  // Thrown by exec() if an error is encountered (besides a non-match).

  class match_error {
    int error_code;
  public:
    match_error(int);
    int code() const;
  };

  // Match the regular expression against data.  Note that the data
  // argument must not be a temporary object if match objects are
  // collected.

  bool exec(const std::string& data,
            unsigned offset = 0, int options = 0) const;
  bool exec(const std::string& data, match&,
            unsigned offset = 0, int options = 0) const;
  bool exec(const std::string& data, matches&,
            unsigned offset = 0, int options = 0) const;
};

// rx

inline unsigned
rx::captures() const
{
  return capture_count;
}

// error

inline
rx::error::error(const char* err, int offset)
  : message(err), m_offset(offset)
{
}

inline const std::string&
rx::error::str() const
{
  return message;
}

inline int
rx::error::offset() const
{
  return m_offset;
}

// match

inline
rx::match::match()
{
}

inline
rx::match::match(std::string::const_iterator f, std::string::const_iterator l)
  : first(f), last(l)
{
}

inline std::string
rx::match::data() const
{
  return std::string(first, last);
}

// matches

inline
rx::matches::matches()
{
}

inline const rx::match&
rx::matches::operator[](unsigned pos) const
{
  if (pos < array.size()) {
    return array[pos];
  } else {
    abort();
  }
}

inline void
rx::matches::clear()
{
  array.clear();
}

// match_error

inline
rx::match_error::match_error(int code)
  : error_code(code)
{
}

inline int
rx::match_error::code() const
{
  return error_code;
}

#endif // RX_H
