/* Search.c -- API routines for searching the DB 
               These routines are for dealing with non-unique columns;
               DB columns for mnemonic, operand, etc will return tens to
               hundreds of results -- thus they are given special
               treatment here.
*/
#include <api/api_main.h>

extern struct DISASM_TGT target;
extern struct DISASM_ENV disasm_env;
extern struct DISASM_PREFS disasm_prefs;

   struct search {
      DB_ADDR curr_rec;      /* current record in DB */
      unsigned char *pos;   /* position in target image */
      long bytes_read;
      int count;            /* total number of records returned */
   };
   typedef struct search *SEARCH;


/* +++ This is just 10 kinds of ugly. Don't say you weren't warned +++ */

   int FindBytes( unsigned char *bytes, int len, int **s){
   /* find sequence of bytes : returns search ptr */
      struct address a;
      int i, pa, found = 0;
   
      if (! *s) {
      /* this is the 'find first' */
         *s = (int *)calloc(sizeof(struct search), 1);
         ((SEARCH)*s)->pos = (unsigned char *) target.image;
      } 
      while( ((SEARCH)*s)->bytes_read < target.size ){
         if ( ((SEARCH)*s)->pos[0] == bytes[0]) {
         /* check for a full match */
            for (i = 0; i < len; i++)
               if ( ((SEARCH)*s)->pos[i] == bytes[i])   found++;
            if (found == len){
            /* lookup addr for this pa and return it */
               if (d_keyfind(PA, &((SEARCH)*s)->bytes_read) 
               == S_OKAY) {
               /* there is a valid program address for this sequence */
                  d_recread(&a);
                  return(a.rva);
               }
            }
         }
         ((SEARCH)*s)->pos++;
         ((SEARCH)*s)->bytes_read++;
      }
      free(*s); /* free search handle if nothing found */
      return(0);
   }

   void PrepDBSearch( int table, struct search **search){
      if (! *search) {
      /* this is the 'find first' */
         *search = (SEARCH) calloc(sizeof(struct search), 1);
         d_recfrst(table);
      } 
      else {
      /* this is a 'find next' -- restore current record in DB */
         (*search)->count++;
         d_crset(&(*search)->curr_rec);
         d_recnext(table);
      }
      return;
   }

   int FindOperand( char *str, int **s) {
      struct code c;
   
      PrepDBSearch( CODE, (SEARCH*)s );
      while( db_status == S_OKAY ){
         d_crget(&((SEARCH)*s)->curr_rec); /* save current record in DB */
         d_recread(&c);
         /* TODO: REWRITE THIS !!! 
         if (! strcmp(c.dest, str)) 
            return(c.rva);
         if (! strcmp(c.src, str)) 
            return(c.rva);
         if (! strcmp(c.aux, str)) 
            return(c.rva);
          */
         d_recnext(CODE);
      }
      free(*s); /* free search handle if nothing found */
      return(0);
   }

   int FindMnemonic( char *str, int **s){
      struct code c;
   
      PrepDBSearch( CODE, (SEARCH*)s );
      while( db_status == S_OKAY ){
         d_crget(&((SEARCH)*s)->curr_rec); /* save current record in DB */
         d_recread(&c);
         if (! strcmp(c.mnemonic, str)) 
            return(c.rva);
         d_recnext(CODE);
      }
      free(*s); /* free search handle if nothing found */
      return(0);
   }

   int FindConstant( long value, int **s){
      struct constant c;
   
      PrepDBSearch( CODE, (SEARCH*)s );
      while( db_status == S_OKAY ){
         d_crget(&((SEARCH)*s)->curr_rec); /* save current record in DB */
         d_recread(&c);
         if (! c.value == value ) 
            return(c.id);
         d_recnext(CODE);
      }
      free(*s); /* free search handle if nothing found */
      return(0);
   }

   int FreeSearchHandle( int **search ){
      int count = 0;
   
      if (*search) {
         count = ((SEARCH)*search)->count;
         free(*search);
      }
      return(count);
   }

   long FindOpTTL( char *operand, long rva, int ttl, int direction, int access){
      int x, *state;
      struct code c;
      int (*next_fn)(unsigned long);

      if (direction == 1) next_fn = d_keynext;
      else next_fn = d_keyprev;

      state = DBSaveState();
      d_keyfind(CODE_RVA, &rva);
      for (x = 0; x < ttl, db_status == S_OKAY; x++){
         if ( next_fn(CODE_RVA)  == S_OKAY) {
            d_recread(&c);
            /* TODO: REWRITE THIS
            if ( (c.destType & access && !(strcmp(c.dest, operand)) )  || 
                 (c.srcType  & access && !(strcmp(c.src,  operand)) )  ||
                 (c.auxType  & access && !(strcmp(c.aux,  operand)) )  ){
                DBRestoreState(state); 
               return(c.rva); 
            }
            */
         }
      }
      DBRestoreState(state);
      return(0);   
   }

   long FindNextOpRead( char *operand, long rva, int ttl ){
      return(FindOpTTL(operand, rva, ttl, 1, OP_R));
   }
   long FindPrevOpRead( char *operand, long rva, int ttl ){
      return(FindOpTTL(operand, rva, ttl, 0, OP_R));
   }
   long FindNextOpWrite( char *operand, long rva, int ttl ){
      return(FindOpTTL(operand, rva, ttl, 1, OP_W));
   }
   long FindPrevOpWrite( char *operand, long rva, int ttl ){
      return(FindOpTTL(operand, rva, ttl, 0, OP_W));
   }
   long FindNextOpExec( char *operand, long rva, int ttl ){
      return(FindOpTTL(operand, rva, ttl, 1, OP_X));
   }
   long FindPrevOpExec( char *operand, long rva, int ttl ){
      return(FindOpTTL(operand, rva, ttl, 0, OP_X));
   }

