#include "most.h"
#include "externs.h"
#include "buffer.h"
#include "line.h"

int CASE_SENSITIVE = 0;
char SEARCH_STR[80];
int SEARCH_DIR = 1;

#define upcase(ch) ((!CASE_SENSITIVE && (ch <= 'z') && (ch >= 'a')) ? ch &= 0xDF : ch)

/* This routine returns the 1 + position of first match of key in str.
   key is modified to match the case of str. */
/* We should try to optimize this routine */
/* searches from beg up to but not including end */
unsigned char *forw_search_region(unsigned char *beg,unsigned char *end, unsigned char *key)
{
    char ch, ch2,char1,work[80];
    unsigned char *pos;
    int key_len,j, str_len;

    if (CASE_SENSITIVE)
      {
          strcpy(work,key);
          key_len = strlen(key);
      }
    else
      {
          /* upcase key */
          key_len = 0;
          while (ch = key[key_len],ch != '\0')
            {
                ch = upcase(ch);
                work[key_len++] = ch;        /* null char is ok */
            }
      }
    
    str_len = (int) (end - beg);
    if (str_len < key_len) return (EOB);
    str_len = str_len - key_len; /* effective length */
    end -= key_len;
          
    char1 = work[0];
    
    while(1)
      {
          while (ch = *beg, ch = upcase(ch), ch != char1)
            {
                if (beg > end) return(EOB);
                beg++;
            }
          beg++;
          /* so we have a position of possible match */

          j = 1;
          pos = beg;  /* save this position so we start from here again */
          while(ch = *beg++, ch = upcase(ch),
                ch2 = work[j++], (ch == ch2) && (j <= key_len));

          if (j > key_len)
            {
                /* make key match 'key' in beg */
                beg = pos - 1;  /* skip back to beginning of match */
                for (j = 0; j < key_len; j++) key[j] = *beg++;
                return(pos - 1);
            }
          
          else beg = pos;
      }
}


unsigned char *back_search_region(unsigned char *beg,unsigned char *end, unsigned char *key)
{
    char ch, ch2,char1,work[80];
    unsigned char *pos;
    int key_len,j, str_len;

    if (CASE_SENSITIVE)
      {
          strcpy(work,key);
          key_len = strlen(key);
      }
    else
      {
          /* upcase key */
          key_len = 0;
          while (ch = key[key_len],ch != '\0')
            {
                ch = upcase(ch);
                work[key_len++] = ch;        /* null char is ok */
            }
      }
    
    str_len = (int) (end - beg);
    if (str_len < key_len) return (EOB);
    str_len = str_len - key_len; /* effective length */
    beg += key_len;
          
    char1 = work[key_len - 1];
    
    while(1)
      {
          while (ch = *end, ch = upcase(ch), ch != char1)
            {
                if (beg > end) return(EOB);
                end--;
            }
          end--;
          /* so we have a position of possible match */

          j = key_len - 2;
          pos = end;  /* save this position so we start from here again */
          while(ch = *end--, ch = upcase(ch),
                ch2 = work[j], (ch == ch2) && (j >= 0)) j--;

          if (j < 0)
            {
                /* make key match 'key' in beg */
                end = pos +  1;  /* skip back to beginning of match */
                for (j = key_len; j > 0; j--) key[j - 1] = *end--;
                return(end + 1);
            }
          
          else end = pos;
      }
}



int search(unsigned char *from, int repeat, int *col)
{
    /* return the line match was found as well as line number,
       search from i on; assume that line_array match the i so we need
       no initial lookup */

    int test,j,save_line, the_col, row;
    char ch, string[80];
    unsigned char *pos, *save_pos, *found_at;

    if ((from < BEG) || (from > EOB)) return(-1);
    save_pos = C_POS;
    save_line = C_LINE;
    found_at = EOB;
    *col = 0;

    pos = from;
    if (SEARCH_STR[0] != '\0')
      {
          test = repeat && (pos < EOB) && (pos >= BEG);
          while(test)
            {
                if (SEARCH_DIR == 1)
                  pos = forw_search_region(pos,EOB,(unsigned char*) SEARCH_STR);
                else
                  pos = back_search_region(BEG,pos,(unsigned char*) SEARCH_STR);
                
                
                if (pos < EOB)
                  {
                      repeat--;
                      found_at = pos;
                      if (SEARCH_DIR == 1)
                        pos += strlen(SEARCH_STR);
                      else pos--;
                  }
                test = repeat && (pos < EOB) && (pos >= BEG);
            }
      }
    
    if (repeat) /* not found */
      {
          *col = 0;
          if (SEARCH_STR[0] == '\0')
            message("Search string not specified.",1);
          else
            {
                (void) sprintf(string,"%s NOT FOUND.",SEARCH_STR);
                message(string,1);
            }
          
          row = -1;
      }
    else /* if ( !MOST_T_OPT && !MOST_B_OPT) */   /* expand tabs to get col correct */
      {
          find_row_column(found_at,&row,&the_col);
          *col = apparant_distance(found_at);
      }
    C_POS = save_pos;
    C_LINE = save_line;
    if (row > 0) CURS_POS = found_at;
    return( row );
}

