%{
  extern "C" {
    #include <stdio.h>
    #include <string.h>
    #include <time.h>
  }

#include <string>
  
#include "CflowdRawFlow.hh"
#include "flowfilt.tab.h"
  
extern int       flowfiltlval;
extern int       flowfiltparse (void);

static const string rcsid = "@(#) $Name: cflowd-2-1-b1 $ $Id: flowfilt.lex,v 1.5 1999/05/26 11:01:09 dwm Exp $";

static const CflowdRawFlow   *g_cflowdRawFlow;
static const char            *g_expression;
int                           flowfiltparseval;
static int                    charnum = 0;
static struct tm              g_Tm;
void flowfilterror(const char *msg);

%}

%option noyywrap

%x INERROR

%%

all                 {charnum += strlen(yytext);
                     flowfiltlval = 1; return ALL; /*  matches all flows  */}
router              {charnum += strlen(yytext);
		     flowfiltlval = (g_cflowdRawFlow->Index() &
				     CflowdRawFlow::k_routerMask) ?
				     g_cflowdRawFlow->Router() : 0;
		     return FIELDNAME;}
srcaddr             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_srcIpAddrMask) ?
                                 g_cflowdRawFlow->SrcIpAddr() : 0;
                     return FIELDNAME;}
dstaddr             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_dstIpAddrMask) ?
                       g_cflowdRawFlow->DstIpAddr() : 0;
                     return FIELDNAME;}
nexthop             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_ipNextHopMask) ?
                       g_cflowdRawFlow->IpNextHop() : 0;
                     return FIELDNAME;}
srcport             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_srcPortMask) ?
                       g_cflowdRawFlow->SrcPort() : 0;
                     return FIELDNAME;}
dstport             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_dstPortMask) ?
                       g_cflowdRawFlow->DstPort() : 0;
                     return FIELDNAME;}
srcas               {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_srcAsMask) ?
                       g_cflowdRawFlow->SrcAs() : 0;
                     return FIELDNAME;}
dstas               {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_dstAsMask) ?
                       g_cflowdRawFlow->DstAs() : 0;
                     return FIELDNAME;}
srcmask             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_srcMaskLenMask) ?
                       g_cflowdRawFlow->SrcMaskLen() : 0;
                     return FIELDNAME;}
dstmask             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_dstMaskLenMask) ?
                       g_cflowdRawFlow->DstMaskLen() : 0;
                     return FIELDNAME;}
tcpflags            {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_dstMaskLenMask) ?
                       g_cflowdRawFlow->DstMaskLen() : 0;
                     return FIELDNAME;}
protocol            {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_protocolMask) ?
                       g_cflowdRawFlow->Protocol() : 0;
                     return FIELDNAME;}
tos                 {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_tosMask) ?
                       g_cflowdRawFlow->Tos() : 0;
                     return FIELDNAME;}
inputif             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_inputIfIndexMask) ?
                       g_cflowdRawFlow->InputIfIndex() : 0;
                     return FIELDNAME;}
outputif            {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_outputIfIndexMask) ?
                       g_cflowdRawFlow->OutputIfIndex() : 0;
                     return FIELDNAME;}
pkts                {charnum += strlen(yytext);
		     flowfiltlval = (g_cflowdRawFlow->Index() &
				CflowdRawFlow::k_pktsMask) ?
			g_cflowdRawFlow->Pkts() : 0;
		     return FIELDNAME;}
bytes                {charnum += strlen(yytext);
		     flowfiltlval = (g_cflowdRawFlow->Index() &
				CflowdRawFlow::k_bytesMask) ?
			g_cflowdRawFlow->Bytes() : 0;
		     return FIELDNAME;}
starttime           {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_startTimeMask) ?
                       g_cflowdRawFlow->StartTime() : 0;
                     return FIELDNAME;}
endtime             {charnum += strlen(yytext);
                     flowfiltlval = (g_cflowdRawFlow->Index() &
                               CflowdRawFlow::k_endTimeMask) ?
                       g_cflowdRawFlow->EndTime() : 0;
                     return FIELDNAME;}
enginetype          {charnum += strlen(yytext);
		     flowfiltlval = (g_cflowdRawFlow->Index() &
				     CflowdRawFlow::k_engineTypeMask) ?
		       g_cflowdRawFlow->EngineType() : 0;
		     return FIELDNAME;}
engineid            {charnum += strlen(yytext);
		     flowfiltlval = (g_cflowdRawFlow->Index() &
				     CflowdRawFlow::k_engineIdMask) ?
		       g_cflowdRawFlow->EngineId() : 0;
		     return FIELDNAME;}
now                 {charnum += strlen(yytext);
                     flowfiltlval = time((time_t *)0);
                     return INTEGER;}

[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+  {charnum += strlen(yytext);
                                    flowfiltlval = inet_addr(yytext);
                                    return INTEGER;}

  /*  Match a date and time of the form 'MM/DD/YY hh:mm:ss', convert to  *
   *  an integer of seconds since UNIX epoch.                            */
[0-9]+[/][0-9]+[/][0-9]+[ ]+[0-9]+[\:][0-9][0-9][\:][0-9][0-9]  {
  charnum += strlen(yytext); memset(&g_Tm,0,sizeof(g_Tm));
  if (sscanf(yytext,
             "%d/%d/%d %d:%02d:%02d",&g_Tm.tm_mon,&g_Tm.tm_mday,
             &g_Tm.tm_year,&g_Tm.tm_hour,&g_Tm.tm_min,&g_Tm.tm_sec) != 6) 
  {
    flowfilterror("bad date format");
    exit(1);
  }
  else
  {
    g_Tm.tm_mon --;
    g_Tm.tm_isdst = -1;
    if (g_Tm.tm_year >= 1900)
      g_Tm.tm_year -= 1900;
    flowfiltlval = mktime(&g_Tm);
    return INTEGER;
  }
}

[0-9]+          {charnum += strlen(yytext); flowfiltlval = atoi(yytext); 
                 return INTEGER;}
0x[0-9a-fA-F]+  {charnum += strlen(yytext); 
                 flowfiltlval = strtoul(yytext,(char **)NULL,16);
                 return INTEGER;}
[ \t]+          {charnum += strlen(yytext);  /* skip whitespace  */ }
[!][=]          {charnum += 2; return(NE);       /* not equal */ }
[=][=]          {charnum += 2; return(EQ);       /* equal  */ }
[<]             {charnum++; return(LT);          /* less than  */ }
[>]             {charnum++; return(GT);          /* greater than  */ }
[<][=]          {charnum += 2; return(LE);       /* less than or equal  */ }
[>][=]          {charnum += 2; return(GE);       /* greater than or equal */ }
[=]             {charnum++; return(EQ);          /* equal */ }
[\&][\&]        {charnum += 2; return(AND);      /* and */ }
[\&]            {charnum++; return(BITAND);      /* bitwise and */ }
[\|][\|]        {charnum += 2; return(LOGOR);    /* logical or */ }
[\|]            {charnum++; return(BITOR);       /* bitwise or */ }
[\(]            {charnum++; return(LPAREN);      /* left paren */ }
[\)]            {charnum++; return(RPAREN);      /* right paren */ }
[/]             {charnum++; return(DIV);         /* divide */ }
[*]             {charnum++; return(MUL);         /* multiply */ }
[+]             {charnum++; return(ADD);         /* add */ }
[-]             {charnum++; return(SUB);         /* subtract */ }
[%]             {charnum++; return(MOD);         /* modulo */ }
[~]             {charnum++; return(BITNOT);      /* bitwise not */ }
[!]             {charnum++; return(LOGNOT);      /* logical not */ }
\n              {charnum++; return(0);}
<<EOF>>         {return(0);}
<INITIAL>.      {charnum++; BEGIN(INERROR); yyless(0);}
<INERROR>[a-zA-Z]+  {return(1);}
<INERROR>[^a-zA-Z]* {return(1);}

%%

//-------------------------------------------------------------------------
//                   void flowfilterror(const char *msg)
//.........................................................................
//  
//-------------------------------------------------------------------------
void flowfilterror(const char *msg)
{
  char fmtString[10];
  
  fprintf(stderr,"[E] %s at '%s':\n",msg,yytext);
  fprintf(stderr,"%s\n",g_expression);
  sprintf(fmtString,"%%%ds\n",charnum);
  fprintf(stderr,fmtString,"^");
  exit(1);
  
  return;
}

//-------------------------------------------------------------------------
//  bool FlowMatches(const char *expression, const CflowdRawFlow *rawFlow) 
//.........................................................................
//  
//-------------------------------------------------------------------------
bool FlowMatches(const char *expression, const CflowdRawFlow *rawFlow)
{
  YY_BUFFER_STATE      bufferState;
  int                  rc;

  g_cflowdRawFlow = rawFlow;
  
  g_expression = expression;
  bufferState = yy_scan_string(expression);
  rc = flowfiltparse();
  if (rc) {
    yy_delete_buffer(bufferState);
    return(false);
  }

  if (flowfiltparseval) {
    yy_delete_buffer(bufferState);
    return(true);
  }

  yy_delete_buffer(bufferState);
  
  return(false);
}
