/******************************************************************************
*
* project name:  TIGCC Tools Suite
* file name:     findstr.c
* initial date:  28/03/2002
* author:        thomas.nussbaumer@gmx.net
*
* description:   bidirectional search function
*
*                Based on the Knuth-Morris-Pratt linear time string matching
*                algorithm. Extended to support backward searching.
*
* $Id$
*
******************************************************************************/

#define USE_TI89
#define OPTIMIZE_ROM_CALLS
#define NO_EXIT_SUPPORT
#define SAVE_SCREEN

#include <tigcclib.h>

#define MAX_XSIZE 30  // maximum length of search "strings"
                      // modify this if you want to search for longer "strings"

#define SEARCH_FORWARD  0
#define SEARCH_BACKWARD 1


//-----------------------------------------------------------------------------
// fill lookup table
// x      ... string we are looking for
// m      ... length of x
// mpnext ... lookup table
//-----------------------------------------------------------------------------
static inline void PreprocessKMP(const unsigned char *x, const short m, short kmpnext[]) {
    short i, j;

    i = 0;
    j = kmpnext[0] = -1;
    while (i < m) {
        while (j > -1 && x[i] != x[j]) j = kmpnext[j];
        i++;
        j++;
        if (x[i] == x[j]) kmpnext[i] = kmpnext[j];
        else              kmpnext[i] = j;
    }
}


//-----------------------------------------------------------------------------
// reverses source into dest
//-----------------------------------------------------------------------------
static inline void Reverse(unsigned char* dest,const unsigned char* source,const short len) {
    short i;
    for (i=0;i<len;i++) {
        dest[i] = source[len-i-1];
    }
}

//-----------------------------------------------------------------------------
// Extended Knuth-Morris-Pratt search algorithm
//
// I call this implementation "Extended", because it features backward
// searching, too (which is not part of the original Knuth-Morris-Pratt
// algorithm)
//
// x         ... string we are looking for
// m         ... length of x
// y         ... buffer to examine (if searching backward y have to point to
//               the last byte of the buffer!!)
// n         ... length of y
// found     ... index where x was found
// direction ... 0 == forward / 1 == backward
//-----------------------------------------------------------------------------
short EKMP_Find(const unsigned char *x, const short m, const unsigned char *y, const long n,long* found,short direction) {
    short i = 0;
    long  j = 0L;
    short kmpnext[MAX_XSIZE];
    unsigned char xtmp[MAX_XSIZE];

    if (!direction) {
        // Searching forward ...
        PreprocessKMP(x, m, kmpnext);
        while (j < n) {
           while (i > -1 && x[i] != y[j]) i = kmpnext[i];
           i++;
           j++;
           if (i >= m) {
               *found = j - i;
               return 1;
           }
        }
        return 0;
    }

    // we are searching backwards ...
    Reverse(xtmp,x,m);
    x = xtmp;

    PreprocessKMP(x, m, kmpnext);
    while (j < n) {
        while (i > -1 && *(x+i) != *(y-j)) i = kmpnext[i];
        i++;
        j++;
        if (i >= m) {
            *found = n-j;
            return 1;
        }
    }
    return 0;
}




void _main(void) {
    const unsigned char find_in[]    = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17};
    const unsigned char find_this[] = {13,14,15,16};

    long                findpos;

    clrscr();
    if (EKMP_Find(find_this,4,find_in,18,&findpos,SEARCH_FORWARD)) {
        printf("forward found at %ld\n",findpos);
    }
    else {
        printf("forward not found\n");
    }

    // if we are searching backward we MUST hand over a pointer to the end of
    // the buffer to examine (NOT a pointer to the start)
    if (EKMP_Find(find_this,4,find_in+17,18,&findpos,SEARCH_BACKWARD)) {
        printf("backward found at %ld\n",findpos);
    }
    else {
        printf("backward not found\n");
    }
    ngetchx();
}




//#############################################################################
// Revision History
//#############################################################################
//
// $Log$
//