/* Copyright (c) 2001 IBK-Landquart-Switzerland. All rights reserved.
 *
 * Module      :  ZRegular.cpp
 * Application :  IBK Open Class Library
 * Purpose     :  Regular expression searching
 *
 * Date        Description                                 Who
 * --------------------------------------------------------------------------
 * 2001.05.30  First implementation                        P.Koch, IBK
 *
 * OPEN SOURCE LICENSE
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * 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 IBK at info@ibk-software.ch.
 */

#define ZC_BUILDING_ZBASE

#include <ZRegular.hpp>
#include <ZExcept.hpp>

#if ZC_IBM
#include <regex.h>
#elif ZC_UNIXFAM
#include <sys/types.h>
#include <regex.h>
#define __REG_SUBEXP_MAX 9
#else
#include <ZRegEx.h>
#endif

ZExport0 ZRegularExpression::ZRegularExpression (const ZString & aExpression,
                                                 int aOpenFlags)
{
  ZFUNCTRACE_DEVELOP
    ("ZRegularExpression::ZRegularExpression(const ZString& aExpression, int aOpenFlags)");
  iHandle = new regex_t;
  int cflags (0);
  if (aOpenFlags & openExtended)
    cflags |= REG_EXTENDED;
  if (aOpenFlags & openIgnorecase)
    cflags |= REG_ICASE;
  if (aOpenFlags & openNewline)
    cflags |= REG_NEWLINE;
  if (aOpenFlags & openNosubreps)
    cflags |= REG_NOSUB;
  int err = regcomp ((regex_t *) iHandle, aExpression.constBuffer (), cflags);
  if (err)
      {
        char msg[80];
        regerror (err, (regex_t *) iHandle, msg, sizeof (msg));
        regfree ((regex_t *) iHandle);
        delete (regex_t *) iHandle;
        iHandle = 0;
        ZTHROWEXC (msg);
      }                         // if
}                               // ZRegularExpression

ZExport0 ZRegularExpression::~ZRegularExpression ()
{
  ZFUNCTRACE_DEVELOP ("ZRegularExpression::~ZRegularExpression()");
  if (iHandle)
      {
        regfree ((regex_t *) iHandle);
        delete (regex_t *) iHandle;
      }                         // if
}                               // ~ZRegularExpression

ZExport (int) ZRegularExpression::match (const ZString & aString,
                                         int aMaxMatches,
                                         long *aStartpos,
                                         long *aLength, int aMatchFlags)
{
  ZFUNCTRACE_DEVELOP
    ("ZRegularExpression::match(const ZString&, int, long*, long*, int)");
  if (!iHandle)
    ZTHROWEXC ("Invalid regular expression!");

  // check nmatch
  if (aMaxMatches < 0)
    ZTHROWEXC ("match count >= 0");
  if (aMaxMatches > __REG_SUBEXP_MAX)
    ZTHROWEXC ("match count must be <= " + ZString (__REG_SUBEXP_MAX));
  regmatch_t rm[__REG_SUBEXP_MAX];

  int eflags (0);
  if (aMatchFlags & matchNotBol)
    eflags |= REG_NOTBOL;
  if (aMatchFlags & matchNotEol)
    eflags |= REG_NOTEOL;

  // do the matching
  int err = regexec ((regex_t *) iHandle, aString, aMaxMatches, rm, eflags);

  if (err == REG_NOMATCH)
    return 0;

  if (err)
      {
        char msg[80];
        regerror (err, (regex_t *) iHandle, msg, sizeof (msg));
        ZTHROWEXC (msg);
      }                         // if

  // get the results
  for (int x = 0; x < aMaxMatches; x++)
      {
        if (rm[x].rm_so < 0)
          return x;
        aStartpos[x] = rm[x].rm_so + 1;
        aLength[x] = rm[x].rm_eo - rm[x].rm_so;
      }                         // for
  return aMaxMatches;
}                               // match
