/*  -*- Mode: C;  -*- */

/******************************************************************************
*                                                                             *
*   Copyright 2005 University of Cambridge Computer Laboratory.               *
*                                                                             *
*   This file is part of Nprobe.                                              *
*                                                                             *
*   Nprobe 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.                                       *
*                                                                             *
*   Nprobe 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 Nprobe; if not, write to the Free Software                     *
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
*                                                                             *
******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#ifdef __alpha__
#include <sys/mbuf.h>
#endif
#include <net/route.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#undef __STDC__
#include <netinet/ip.h>

#ifdef __alpha__
#include <netinet/ip_var.h>
#endif 
#include <netinet/tcp.h>
#include <netinet/if_ether.h>

#include "list.h"
#include "pkt.h"
#include "interface.h"
#include "flows.h"
#include "http.h"
#include "tcp.h"
#include "seq.h"

/*
 * Return ptr. to char c in sequence s of length len - as strchr()
 */

char *
seqchr(char *s, char c, int len)
{
#if 0
  char *endp = s+len;
  s--;
  while (s < endp)
    if (*++s == c)
      return s;

  return NULL;
#endif

  return memchr(s, c, len);

}

/*
 * As seqchr() but char c always l.c. and insensitive to case of s
 */

char *
ci_seqchr(char *s, char c, int len)
{
  char *endp = s+len;
  while (s < endp)
    {
      if (*s == c || tolower(*s) == c)
	return s;
      s++;
    }

  return NULL;
}

/* 
 * Compare s1, s2, insensitive to case in s1 
 * **s2 MUST be all LC and NULL terminated** 
 * s1 need not be null terminated - but should probably check len is >= s2
 *
 * Return 0 if match, else non zero
 */

int 
ci_seqstrcmp(char *s1, char *s2)
{
  char c1, c2;

  do 
    {
      c1 = tolower(*s1++);
      c2 = *s2++;
      if (c2 == '\0')
	return 0;
    } while (c1 == c2);

  return 1;
}

/*
 * Compare at most n bytes of sequence s1, string s2, insensitive to case 
 * of s1 
 * **s2 MUST be all LC and NULL terminated**
 * **if s1 not known to be len >= s2 then n should be len s1
 *
 * NB return len s2 if equal, 0 if unequal, -len of s2 matched if n exhausted
 */

int 
ci_seqstrncmp(char *s1, char *s2, int n)
{
  char c1, c2;
  int len = 0;
  char *start = s2;

  if (n >= 4)
    {
      size_t n4 = n >> 2;
      do
        {
          c1 = tolower(*s1++);
          c2 = *s2++;
          if (c2 == '\0')
	    return len;
	  if (c1 != c2)
            return 0;
          c1 = tolower(*s1++);
          c2 = *s2++;
          if (c2 == '\0')
	    return len + 1;
	  if (c1 != c2)
            return 0;
          c1 = tolower(*s1++);
          c2 = *s2++;
          if (c2 == '\0')
	    return len + 2;
	  if (c1 != c2)
            return 0;
          c1 = tolower(*s1++);
          c2 = *s2++;
          if (c2 == '\0')
	    return len + 3;
	  if (c1 != c2)
            return 0;
	  len += 4;
        } while (--n4 > 0);
      n &= 3;
    }

  while (n > 0)
    {
      c1 = tolower(*s1++);
      c2 = *s2++;
      if (c2 == '\0')
	return len;
	//return (len + 3) -n;
      if (c1 != c2)
	return 0;
      n--;
      len++;
    }

  if (n == 0)
    return start - s2;

  /* NOT REACHED */
  return 0;
}


/* 
 * Return the first ocurrence of NEEDLE in HAYSTACK of length len 
 * - as strstr()  
 */

char *
seqstr_l(const char *haystack,  const char *needle, size_t len)
{
  const char * needle_end = strchr(needle, '\0');
  const char *haystack_end = haystack + len;
  const size_t needle_len = needle_end - needle;
  const size_t needle_last = needle_len - 1;
  const char *begin;

  if (needle_len == 0)
    return (char *) haystack;   /* ANSI 4.11.5.7, line 25.  */
  if ((size_t) (haystack_end - haystack) < needle_len)
    return NULL;

  for (begin = &haystack[needle_last]; begin < haystack_end; ++begin)
    {
      const char *n = &needle[needle_last];
      const char *h = begin;

      do
        if (*h != *n)
          goto loop;            /* continue for loop */
      while (--n >= needle && --h >= haystack);

      return (char *) h;

    loop:;
    }

  return NULL;
}

/* 
 * Return the first ocurrence of NEEDLE in HAYSTACK delimited by delim 
 * - as strstr()
 *
 * CAUTION: Must be sure that delim exists in H 
 *  (which may not be a handy NULL terminated string) 
 */

char *
seqstr_d(const char *haystack,  const char *needle, char delim)
{
  const char * needle_end = strchr(needle, '\0');
  const char *haystack_end = strchr(haystack, delim);
  const size_t needle_len = needle_end - needle;
  const size_t needle_last = needle_len - 1;
  const char *begin;

  if (needle_len == 0)
    return (char *) haystack;   /* ANSI 4.11.5.7, line 25.  */
  if ((size_t) (haystack_end - haystack) < needle_len)
    return NULL;

  for (begin = &haystack[needle_last]; begin < haystack_end; ++begin)
    {
      const char *n = &needle[needle_last];
      const char *h = begin;

      do
        if (*h != *n)
          goto loop;            /* continue for loop */
      while (--n >= needle && --h >= haystack);

      return (char *) h;

    loop:;
    }

  return NULL;
}

/* 
 * Return the first ocurrence of NEEDLE in HAYSTACK delimited by delim 
 * and of length len, NULL if not found.
 * 
 */

char *
seqstr_dl(const char *haystack,  const char *needle, char delim, int len)
{
  const char * needle_end = strchr(needle, '\0');
  const char *haystack_end = seqchr((char *)haystack, delim, len);
  const size_t needle_len = needle_end - needle;
  const size_t needle_last = needle_len - 1;
  const char *begin;

  if (needle_len == 0)
    return (char *) haystack;   /* ANSI 4.11.5.7, line 25.  */
  if ((size_t) (haystack_end - haystack) < needle_len)
    return NULL;

  for (begin = &haystack[needle_last]; begin < haystack_end; ++begin)
    {
      const char *n = &needle[needle_last];
      const char *h = begin;

      do
        if (*h != *n)
          goto loop;            /* continue for loop */
      while (--n >= needle && --h >= haystack);

      return (char *) h;

    loop:;
    }

  return NULL;
}


/*
 * end seq.c 
 */
