/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2004 rzyjontko

   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; version 2.

   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.  

   ----------------------------------------------------------------------

*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include <string.h>
#include <ctype.h>

#include "search.h"
#include "xmalloc.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/

#define MAX_MISTAKES    9
#define MAX_PATTERN_LEN (8 * sizeof (unsigned))

/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/
/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/
/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/


search_t *
search_create (int flags, int mistakes)
{
        search_t *search;

        search           = xcalloc (1, sizeof (search_t));
        search->mistakes = (mistakes > MAX_MISTAKES) ? MAX_MISTAKES : mistakes;
        search->flags    = flags;
        search->pattern  = str_create_size (MAX_PATTERN_LEN + 1);

        return search;
}



void
search_destroy (search_t *search)
{
        str_destroy (search->pattern);
        xfree (search);
}



int
search_add_char (search_t *search, unsigned char c)
{
        int len = search->pattern->len;
        
        if (len >= MAX_PATTERN_LEN)
                return 1;
        
        str_put_char (search->pattern, c);

        if ((search->flags & SEARCH_INSENSITIVE) && isalpha (c)){
                search->tab[(int) tolower (c)] |= 1 << len;
                search->tab[(int) toupper (c)] |= 1 << len;
        }
        else {
                search->tab[(int) c] |= 1 << len;
        }

        return 0;
}



void
search_chop (search_t *search)
{
        int           len = search->pattern->len - 1;
        unsigned char c   = search->pattern->str[len];
        
        if ((search->flags & SEARCH_INSENSITIVE) && isalpha (c)){
                search->tab[(int) tolower (c)] &= ~ (1 << len);
                search->tab[(int) toupper (c)] &= ~ (1 << len);
        }
        else {
                search->tab[(int) c] &= ~ (1 << len);
        }

        str_chop (search->pattern);
}



int
search_perform (search_t *search, const unsigned char *str)
{
        unsigned base[1 + MAX_MISTAKES] = {0, 1, 3, 7, 15, 31, 63, 127, 255, 511};
        unsigned tab[1 + MAX_MISTAKES]  = {0, 1, 3, 7, 15, 31, 63, 127, 255, 511};
        int      len;
        int      i, j;
        int      mistakes = search->mistakes;

        if (search == NULL)
                return -1;
        
        len = strlen (str);

        for (i = 0; i < len; i++){
                for (j = mistakes; j > 0; j--){
                        tab[j] = base[j] | (tab[j - 1] << 1)
                                | ((1 | tab[j] << 1)
                                   & search->tab[(int) str[i]]);
                }
                tab[0] = (1 | tab[0] << 1) & search->tab[(int) str[i]];
                if (tab[mistakes] & (1 << (search->pattern->len - 1)))
                        return i;
        }

        return -1;
}


/****************************************************************************
 *    INTERFACE CLASS BODIES
 ****************************************************************************/
/****************************************************************************
 *
 *    END MODULE search.c
 *
 ****************************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1