Logo Search packages:      
Sourcecode: maildrop version File versions  Download package

search.C

#include    "search.h"
#include    "message.h"
#include    "messageinfo.h"
#include    "rematchstr.h"
#include    "rematchmsg.h"
#include    "varlist.h"
#include    <string.h>
#include    <ctype.h>
#include    <stdlib.h>

static const char rcsid[]="$Id: search.C,v 1.1 1998/04/16 23:53:22 mrsam Exp $";

int   Search::init(const char *expr, const char *opts)
{
int   dummy;

      match_header=0;
      match_body=0;
      weight1=1;
      weight2=1;
      scoring_match=0;
      score=0;

      if (strchr(opts, 'h'))  match_header=1;
      if (strchr(opts, 'b'))  match_body=1;
      if (!match_header && !match_body)
      {
            match_header=1;
            if (strchr(opts, 'w'))  match_body=1;
      }

      if (regexp.Compile(expr, strchr(opts, 'D') ? 1:0, dummy)) return (-1);
      while (*opts)
      {
            if (*opts == '.' || isdigit(*opts) || *opts == '-' ||
                  *opts == '+')
            {
                  weight1=atof(opts);
                  while (*opts && *opts != ',') ++opts;
                  if (*opts == ',')
                  {
                        ++opts;
                        if (*opts == '.' || isdigit(*opts) ||
                              *opts == '-' || *opts == '+')
                              weight2=atof(opts);
                  }
                  scoring_match=1;
                  break;
            }
            ++opts;
      }
      return (0);
}

int Search::find(Message &msg, MessageInfo &,
      const char *expr, const char *opts, Buffer *foreachp)
{
      if (init(expr, opts))   return (-1);

      msg.Rewind();
      return (strchr(opts, 'w') ? findinsection(msg, expr, foreachp):
            findinline(msg, expr, foreachp));
}

int Search::find(const char *str, const char *expr, const char *opts,
            Buffer *foreachp)
{
      if (init(expr, opts))   return (-1);

      if (VerboseLevel() > 2)
      {
      Buffer      msg;

            msg="Matching /";
            msg.append(expr);
            msg.append("/ against ");
            msg += str;
            msg += '\n';
            msg += '\0';
            merr.write(msg);
      }

      for (;;)
      {
      ReMatchStr match(str);

            if ( regexp.Match(match))     break;

            score += weight1;
            weight1 *= weight2;

            if (!scoring_match || foreachp)
            {
                  match.SetCurrentPos(0);
                  init_match_vars(match, foreachp);
                  if (!foreachp)
                        break;      // No need for more.
            }

      Re *p;
      off_t c=0;

            for (p= &regexp; p; )
                  c += p->MatchCount( &p );
            if (c == 0)
            {
                  if (!*str)  break;
                  ++c;
            }
            str += c;
      }
      return (0);
}

//////////////////////////////////////////////////////////////////////////////
//
// Search individual lines for the pattern (transparently concatenate
// continued headers.
//
//////////////////////////////////////////////////////////////////////////////

int Search::findinline(Message &msg, const char *expr, Buffer *foreachp)
{
      current_line.reset();
      if (msg.appendline(current_line))   return (0); // Empty msg

int   eof;

      for (;;)
      {
      int   c='\n';

            next_line.reset();
            if ((eof=msg.appendline(next_line)) == 0)
            {
                  c=(unsigned char)*(const char *)next_line;

                  if ( isspace( c ) && c != '\n')
                        // Continued header
                  {
                        current_line.pop();
                        current_line += next_line;
                        continue;
                  }
            }
            current_line.pop();

            current_line += '\0';

            if (match_header)
            {
            ReMatchStr match(current_line);

                  if (VerboseLevel() > 2)
                  {
                  Buffer      msg;

                        msg="Matching /";
                        msg.append(expr);
                        msg.append("/ against ");
                        msg += current_line;
                        msg.pop();  // Trailing null byte.
                        msg += '\n';
                        msg += '\0';
                        merr.write(msg);
                  }

                  if (regexp.Match(match) == 0)
                  {
                        score += weight1;
                        weight1 *= weight2;
                        if (!scoring_match || foreachp)
                        {
                              match.SetCurrentPos(0);
                              init_match_vars(match, foreachp);
                              if (!foreachp)
                                    return (0);
                        }
                  }
                  else  if (VerboseLevel() > 2)
                              merr.write("Not matched.\n");
            }
            if ( c == '\n')   break;
            current_line=next_line;
      }
      if (!match_body || eof) return (0);

      while (current_line.reset(), msg.appendline(current_line) == 0)
      {
            current_line.pop();
            current_line += '\0';
      ReMatchStr match(current_line);

            if (VerboseLevel() > 2)
            {
            Buffer      msg;

                  msg="Matching /";
                  msg.append(expr);
                  msg.append("/ against ");
                  msg += current_line;
                  msg.pop();  // Trailing null byte.
                  msg += '\n';
                  msg += '\0';
                  merr.write(msg);
            }

            if (regexp.Match(match) == 0)
            {
                  score += weight1;
                  weight1 *= weight2;
                  if (!scoring_match || foreachp)
                  {
                        match.SetCurrentPos(0);
                        init_match_vars(match, foreachp);
                        if (!foreachp)
                              return (0);
                  }
            }
            else  if (VerboseLevel() > 2)
                        merr.write("Not matched.\n");
      }
      return (0);
}

///////////////////////////////////////////////////////////////////////////
//
// Search anchored in the entire message.
//
///////////////////////////////////////////////////////////////////////////

int Search::findinsection(Message &msg, const char *expr, Buffer *foreachp)
{
      if (!match_header && !match_body)   return (0); // Huh?

      if (VerboseLevel() > 2)
      {
      Buffer      m;

            m="Matching /";
            m.append(expr);
            m.append("/ against");
            if (match_header)
                  m.append(" header");
            if (match_body)
                  m.append(" body");
            m += '\n';
            m += '\0';
            merr.write(m);
      }

      if (!match_header)
      {
      Buffer      dummy;

            do
            {
                  dummy.reset();
                  if (msg.appendline(dummy) < 0)      return (0);
                                    // No message body, give up.
            } while (dummy.Length() != 1 ||
                        *(const char *)dummy != '\n');
      }

off_t start_pos=msg.tell();
ReMatchMsg  match_msg(&msg, !match_body, match_header);

      while ( match_msg.CurrentChar() >= 0 && regexp.Match(match_msg) == 0)
      {
            score += weight1;
            weight1 *= weight2;

            if (!scoring_match || foreachp)
            {
                  match_msg.SetCurrentPos(start_pos);
                  init_match_vars(match_msg, foreachp);
                  if (!foreachp)
                        break;      // No need for more.
            }

      Re *p;
      off_t c=0;

            for (p= &regexp; p; )
                  c += p->MatchCount( &p );
            if (c == 0) ++c;
            start_pos += c;
            match_msg.SetCurrentPos(start_pos);
      }
      return (0);
}

void Search::init_match_vars(ReMatch &m, Buffer *foreachp)
{
Re    *p;
Buffer      buf;
Buffer      varname;
unsigned long varnamecount=1;

      varname="MATCH";
      for (p= &regexp; p; )
      {
      Re    *q=p;
      unsigned    count=p->MatchCount(&p);

            buf.reset();
            while (count)
            {
                  buf.push( m.NextChar() );
                  count--;
            }

            if ( !q->IsDummy())
            {
                  if (foreachp)
                  {
                        *foreachp += buf;
                        *foreachp += '\0';
                  }
                  else
                  {
                        SetVar(varname, buf);
                        ++varnamecount;
                        varname="MATCH";
                        varname.append(varnamecount);
                  }
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index