/* bobint.c - bytecode interpreter */
/*
        Copyright (c) 1991, by David Michael Betz
        All rights reserved.

        Alterations and additions, 1994, by G.C.Wraith
*/

#include <setjmp.h>
#include <string.h>
#include "bob.h"

#define iszero(x)       ((x)->v_type == DT_INTEGER && (x)->v.v_integer == 0)
#define istrue(x)       ((x)->v_type != DT_NIL && !iszero(x))

#define pushr(x,t,f)     (--spr,spr->v_type = (t), spr->v.f = (x))
#define pushr_integer(x)      pushr(x,DT_INTEGER,v_integer)

/* global variables */
unsigned char *cbase;   /* the base code address */
unsigned char *pc;      /* the program counter */
VECTOR *code;           /* the current code vector */
VALUE *stkbase;         /* the runtime stack */
VALUE *stktop;          /* the top of the stack */
VALUE *sp;              /* the stack pointer */
VALUE *fp;              /* the frame pointer */
int offset;             /* used for in .. put { ... } */
extern int trace;       /* variable to control tracing */

/* external variables */
extern VALUE symbols;
extern jmp_buf error_trap;

/* forward declarations */
#ifdef __STDC__
static void interpret(int);
static void opCALL(void);
static int opRETURN(void);
static void opSEND(void);
static void opVREF(void);
static void opVSET(void);
static void opADD(void);
static void opVECT(int);
static void op_pokew(int,int);
static void op_pokes(int,STRING *);
static int getwoperand(void);
static char *typename(int type);
static int str_lt(struct string *,struct string *);
static int str_le(struct string *,struct string *);
static int str_eq(struct string *,struct string *);
static int str_ne(struct string *,struct string *);
static int str_ge(struct string *,struct string *);
static int str_gt(struct string *,struct string *);
#else
char *typename();
#endif

/* execute - execute a bytecode function */
int execute(char *name)
{
    if (setjmp(error_trap) != 0)
        return (FALSE);
    if (!start_call(name))
        return (FALSE);
    return (execute_call(0));
}

/* start_call - start a function call */
int start_call(char *name)
{
    DICT_ENTRY *sym;
    
    /* lookup the symbol */
    if ((sym = findentry(&symbols,name)) == NULL)
       {
        printf("Cannot find %s\n",name);
        return (FALSE);
       }

    /* setup the stack */
    sp = fp = stktop;
    *--sp = sym->de_value;
    return (TRUE);
}

/* start_send - start a message send */
int start_send(OBJECT *obj,char *selector)
{
    sp = fp = stktop;
    push_object(obj);
    push_string(makestring(selector));
    return (TRUE);
}

/* execute_call - execute a function call */
int execute_call(int n)
{
    switch (sp[n].v_type) {
    case DT_CODE:
        (*sp[n].v.v_code)(n);
        return (TRUE);
    case DT_BYTECODE:
        interpret(n);
        return (TRUE);
    }
    return (FALSE);
}

/* interpret - interpret bytecode instructions */
static void interpret(int argc)
{
    register VALUE *spr;
    register OBJECT *obj;
    register VECTOR *coder;
    register int n;
    int x;
    float z;

    /* make a dummy call frame */
    check(3);
    spr = sp;
    code = coder = spr[argc].v.v_vector;
    pushr_integer(argc);         /* argument count */
    pushr_integer(stktop - fp);  /* old fp */
    pushr_integer(0);            /* old pc */
    cbase = pc = (void *)coder->vec_data[0].v.v_string->str_data;
    fp = (sp = spr);
    
    /* execute each instruction */
    for (;;) {
        if (trace) {
            check(1);
            push_bytecode(code);
            decode_instruction(sp,pc-(unsigned char *)strgetdata(vecgetelement(sp,0)));
            ++sp;
        }
        switch (*pc++) {
        case OP_CALL:   opCALL();       break;
        case OP_RETURN: if (!opRETURN()) return;
                        break;
        case OP_SEND:   opSEND();       break;
        case OP_ADD:    opADD();        break;
        case OP_VREF:   opVREF();       break;
        case OP_VSET:   opVSET();       break;
        case OP_REF:
                *sp = code->vec_data[*pc++].v.v_var->de_value;
                break;
        case OP_SET:
                code->vec_data[*pc++].v.v_var->de_value = *sp;
                break;
        case OP_MREF:
                obj = fp[fp[2].v.v_integer+2].v.v_object;
                *sp = obj->obj_members[*pc++];
                break;
        case OP_MSET:
                obj = fp[fp[2].v.v_integer+2].v.v_object;
                obj->obj_members[*pc++] = *sp;
                break;
        case OP_AREF:
                n = *pc++;
                if (n >= fp[2].v.v_integer)
                    error0("Too few arguments");
                *sp = fp[n+3];
                break;
        case OP_ASET:
                n = *pc++;
                if (n >= fp[2].v.v_integer)
                    error0("Too few arguments");
                fp[n+3] = *sp;
                break;
        case OP_TREF:
                n = *pc++;
                *sp = fp[-n-1];
                break;
        case OP_TSET:
                n = *pc++;
                fp[-n-1] = *sp;
                break;
        case OP_TSPACE:
                n = *pc++;
                check(n);
                while (--n >= 0) {
                    --sp;
                    set_nil(sp);
                }
                break;
        case OP_BRT:
                if (istrue(sp))
                    pc = cbase + getwoperand();
                else
                    pc += 2;
                break;
        case OP_BRF:
                if (istrue(sp))
                    pc += 2;
                else
                    pc = cbase + getwoperand();
                break;
        case OP_BR:
                pc = cbase + getwoperand();
                break;
        case OP_NIL:
                set_nil(sp);
                break;
        case OP_PUSH:
                check(1);
                push_integer(FALSE);
                break;
        case OP_NOT:
                if (istrue(sp))
                    set_integer(sp,FALSE);
                else
                    set_integer(sp,TRUE);
                break;
        case OP_NEG:
                switch(sp[0].v_type)
                {
                 case DT_INTEGER:
                   sp->v.v_integer = -sp->v.v_integer;
                   break;
                 case DT_REAL:
                   sp->v.v_real = -sp->v.v_real;
                   break;
                  default:
                   error0("Not an integer or a real");
                   break;
                  }
                break;
        case OP_SUB:
                switch(sp[0].v_type)
                {
                 case DT_INTEGER:
                  chktype(1,DT_INTEGER);
                  sp[1].v.v_integer -= sp->v.v_integer;
                  ++sp;
                  break;
                 case DT_REAL:
                  chktype(1,DT_REAL);
                  sp[1].v.v_real -= sp->v.v_real;
                  ++sp;
                  break;
                 default:
                  error0("Not an integer or a real");
                  break; 
                }                 
                break;
        case OP_MUL:
                switch(sp[0].v_type)
                {
                 case DT_INTEGER:
                   switch(sp[1].v_type)
                   {
                    case DT_INTEGER:
                      sp[1].v.v_integer *= sp->v.v_integer;
                      ++sp;
                      break;
                    case DT_REAL:
                      sp[1].v.v_real *= sp->v.v_integer;
                      ++sp;
                      break;
                    default:
                     error0("Not an integer or a real");
                     break;
                   }
                   break;
                 case DT_REAL:
                   switch (sp[1].v_type)
                   {
                    case DT_INTEGER:
                     z = sp[1].v.v_integer;
                     sp[1].v.v_real = z*sp->v.v_real;
                     sp[1].v_type = DT_REAL;
                     ++sp;
                     break;
                    case DT_REAL:
                     sp[1].v.v_real *= sp->v.v_real;
                     ++sp;
                     break;
                    default:
                     error0("Not an integer or a real");
                     break;
                   }            
                   break;
                 default:
                  error0("Not an integer or a real");
                  break;

                }            
                break;
        case OP_DIV:
                switch (sp[1].v_type)
                {
                 case DT_INTEGER:
                   chktype(0,DT_INTEGER);
                   x = sp->v.v_integer;
                   if (x != 0) 
                        sp[1].v.v_integer /= x;
                   else
                    error0("Division by zero\n");
                   break;
                 case DT_REAL:
                   switch (sp[0].v_type)
                   {
                    case DT_INTEGER:
                    x = sp->v.v_integer;
                      if (x != 0) 
                        sp[1].v.v_real /= x;
                      else
                        error0("Division by zero\n");
                      break;
                    case DT_REAL:
                      z = sp->v.v_real;
                      if (z != 0.0) 
                        sp[1].v.v_real /= z;
                      else
                        error0("Division by zero\n");
                      break;
                    default:
                       error0("denominator not a number");
                       break;
                   }
                   break;
                 default:
                  error0("numerator not a number");
                  break;
                }    
                ++sp;
                break;
        case OP_REM:
                chktype(0,DT_INTEGER);
                chktype(1,DT_INTEGER);
                if (sp->v.v_integer != 0) {
                    int x=sp->v.v_integer;
                    sp[1].v.v_integer %= x;
                }
                else
                    sp[1].v.v_integer = 0;
                ++sp;
                break;
        case OP_INC:
                chktype(0,DT_INTEGER);
                ++sp->v.v_integer;
                break;
        case OP_DEC:
                chktype(0,DT_INTEGER);
                --sp->v.v_integer;
                break;
        case OP_BAND:
                chktype(0,DT_INTEGER);
                chktype(1,DT_INTEGER);
                sp[1].v.v_integer &= sp->v.v_integer;
                ++sp;
                break;
        case OP_BOR:
                chktype(0,DT_INTEGER);
                chktype(1,DT_INTEGER);
                sp[1].v.v_integer |= sp->v.v_integer;
                ++sp;
                break;
        case OP_XOR:
                chktype(0,DT_INTEGER);
                chktype(1,DT_INTEGER);
                sp[1].v.v_integer ^= sp->v.v_integer;
                ++sp;
                break;
        case OP_BNOT:
                chktype(0,DT_INTEGER);
                sp->v.v_integer = ~sp->v.v_integer;
                break;
        case OP_SHL:
                switch (sp[1].v_type) {
                case DT_INTEGER:
                    chktype(0,DT_INTEGER);
                    sp[1].v.v_integer <<= sp->v.v_integer;
                    break;
                case DT_IOSTREAM:
                    print1(&sp[1],FALSE,&sp[0]);
                    break;
                default:
                    break;
                }
                ++sp;
                break;
        case OP_SHR:
                chktype(0,DT_INTEGER);
                chktype(1,DT_INTEGER);
                sp[1].v.v_integer >>= sp->v.v_integer;
                ++sp;
                break;
        case OP_LT:
                switch(sp[0].v_type)  /* RISC OS */
                  {
                   case DT_INTEGER:
                     chktype(1,DT_INTEGER);
                     n = sp[1].v.v_integer < sp->v.v_integer;
                     break;
                   case DT_REAL:
                     chktype(1,DT_REAL);
                     n = sp[1].v.v_real < sp->v.v_real;
                     break;                     
                   case DT_STRING:
                     chktype(1,DT_STRING);
                     n = str_lt(sp[1].v.v_string,sp->v.v_string);
                     break;
                   default:
                     error0("Not an integer or a string");
                   }
                ++sp;
                set_integer(sp,n ? TRUE : FALSE);
                break;
        case OP_LE:
                switch(sp[0].v_type)  /* RISC OS */
                  {
                   case DT_INTEGER:
                     chktype(1,DT_INTEGER);
                     n = sp[1].v.v_integer <= sp->v.v_integer;
                     break;
                   case DT_REAL:
                     chktype(1,DT_REAL);
                     n = sp[1].v.v_real <= sp->v.v_real;
                     break;
                   case DT_STRING:
                     chktype(1,DT_STRING);
                     n = str_le(sp[1].v.v_string,sp->v.v_string);
                     break;
                   default:
                     error0("Not an integer or a string");
                   }
                ++sp;
                set_integer(sp,n ? TRUE : FALSE);
                break;
        case OP_EQ:
                switch(sp[0].v_type)  /* RISC OS */
                  {
                   case DT_INTEGER:
                     chktype(1,DT_INTEGER);
                     n = sp[1].v.v_integer == sp->v.v_integer;
                     break;
                   case DT_REAL:
                     chktype(1,DT_REAL);
                     n = sp[1].v.v_real == sp->v.v_real;
                     break;
                   case DT_STRING:
                     chktype(1,DT_STRING);
                     n = str_eq(sp[1].v.v_string,sp->v.v_string);
                     break;
                   default:
                     error0("Not an integer or a string");
                   }
                ++sp;
                set_integer(sp,n ? TRUE : FALSE);
                break;
        case OP_NE:
                switch(sp[0].v_type)  /* RISC OS */
                  {
                   case DT_INTEGER:
                     chktype(1,DT_INTEGER);
                     n = sp[1].v.v_integer != sp->v.v_integer;
                     break;
                   case DT_REAL:
                     chktype(1,DT_REAL);
                     n = sp[1].v.v_real != sp->v.v_real;
                     break;
                   case DT_STRING:
                     chktype(1,DT_STRING);
                     n = str_ne(sp[1].v.v_string,sp->v.v_string);
                     break;
                   default:
                     error0("Not an integer or a string");
                   }
                ++sp;
                set_integer(sp,n ? TRUE : FALSE);
                break;
        case OP_GE:
                switch(sp[0].v_type)  /* RISC OS */
                  {
                   case DT_INTEGER:
                     chktype(1,DT_INTEGER);
                     n = sp[1].v.v_integer >= sp->v.v_integer;
                     break;
                   case DT_REAL:
                     chktype(1,DT_REAL);
                     n = sp[1].v.v_real >= sp->v.v_real;
                     break;
                   case DT_STRING:
                     chktype(1,DT_STRING);
                     n = str_ge(sp[1].v.v_string,sp->v.v_string);
                     break;
                   default:
                     error0("Not an integer or a string");
                   }
                ++sp;
                set_integer(sp,n ? TRUE : FALSE);
                break;
        case OP_GT:
                switch(sp[0].v_type)  /* RISC OS */
                  {
                   case DT_INTEGER:
                     chktype(1,DT_INTEGER);
                     n = sp[1].v.v_integer > sp->v.v_integer;
                     break;
                   case DT_REAL:
                     chktype(1,DT_REAL);
                     n = sp[1].v.v_real > sp->v.v_real;
                     break;
                   case DT_STRING:
                     chktype(1,DT_STRING);
                     n = str_gt(sp[1].v.v_string,sp->v.v_string);
                     break;
                   default:
                     error0("Not an integer or a string");
                   }
                ++sp;
                set_integer(sp,n ? TRUE : FALSE);
                break;
        case OP_LIT:
                *sp = code->vec_data[*pc++];
                break;
        case OP_DUP2:
                check(2);
                sp -= 2;
                *sp = sp[2];
                sp[1] = sp[3];
                break;
        case OP_NEW:
                chktype(0,DT_CLASS);
                set_object(sp,newobject(sp));
                break;
        case OP_DUP:
                check(1);
                sp--;
                *sp = sp[1];
                break;
        case OP_DROP:
                if (sp < stktop)
                    sp++;
                else
                     error0("Stack empty");
                break;
        case OP_ADR:
                offset = 0;
                switch(sp->v_type)
                {
                 case DT_STRING:
                    sp->v_type = DT_INTEGER;
                    sp->v.v_integer = (int) sp->v.v_string->str_data;
                    break;
                 case DT_INTEGER:
                    break;
                 default:
                    error0("Expecting a string or an integer\n");
                    break;
                }
                break;
        case OP_PUTNEXT:
                switch(sp->v_type)
                {
                 case DT_INTEGER:
                    op_pokew((&sp[1])->v.v_integer,sp->v.v_integer);
                    break;
                 case DT_STRING:
                    op_pokes((&sp[1])->v.v_integer,sp->v.v_string);
                    break;
                 default:
                    error0("Expecting a string or an integer\n");
                    break;
                }
                break;
        case OP_VECT:
                if ((n = *pc++)<1) error0("No components for vector\n");
                else opVECT(n);
                break;
        default:
                error1d("Bad opcode %02x",pc[-1]);
                break;
        }
    }
}

/* opVECT - make a vector from values on stack */
static void opVECT(int n)
{
 VECTOR *x;
 int i;
 x = newvector(n);
 for(i = 0; i < n ; i++)
    x->vec_data[i] = sp[n-i-1];
 sp += n-1;
 set_vector(sp,x);
}

/* op_pokew - poke a word and increment */
static void op_pokew(int adr, int x)
{
 int *n;
 n = (int *) (adr+offset);
 *n = x;
 offset += 4;
}

/* op_pokes - poke a string and increment */
static void op_pokes(int adr, STRING *x)
{
 int len,i;
 char *n;
 len = x->str_size;
 n = (char *) (adr+offset);
 for(i=0;i<len;i++)
   {
    *(n++) = x->str_data[i];
    offset++;
   }
}

/* opCALL - CALL opcode handler */
static void opCALL(void)
{
    register VALUE *spr;
    register int n;
    register VECTOR *coder;
    spr = sp;
    n = *pc++;  /* get argument count */
    switch (spr[n].v_type) {
    case DT_CODE:
        (*spr[n].v.v_code)(n);
        break;
    case DT_BYTECODE:
        check(3);
        code = coder = spr[n].v.v_vector;
        pushr_integer(n);                /* argument count */
        pushr_integer(stktop - fp);      /* old fp */
        pushr_integer(pc - cbase);       /* old pc */
        cbase = pc = (void *)coder->vec_data[0].v.v_string->str_data;
        fp = (sp = spr);
        break;
    default:
        error1("Call to non-procedure, Type %s",typename(sp[n].v_type));
        break;
    }
}

/* opRETURN - RETURN opcode handler */
static int opRETURN(void)
{
    register VALUE *fpr;
    int pcoff,n;
    VALUE val;
    VALUE *stktopr;
    unsigned char *cbaser;
    val = *sp;
    sp = fpr = fp;
    pcoff = fpr[0].v.v_integer;
    n = fpr[2].v.v_integer;
    fp = fpr = (stktopr = stktop) - fpr[1].v.v_integer;
    if (fpr == stktopr) return (FALSE);
    cbaser = (void *)(code = fpr[fpr[2].v.v_integer+3].v.v_vector)->vec_data[0].v.v_string->str_data;
    pc = (cbase = cbaser) + pcoff;
    sp += n + 3;
    *sp = val;
    return (TRUE);
}

/* opSEND - SEND opcode handler */
static void opSEND(void)
{
    register VALUE *spr;
    register int n;
    register VECTOR *coder;
    char selector[TKNSIZE+1];
    DICT_ENTRY *de;
    VALUE *class;
    n = *pc++;
    chktype(n,DT_OBJECT);
    chktype(n-1,DT_STRING);
    spr = sp;
    class = objgetclass(&spr[n]);
    getcstring(selector,sizeof(selector),&spr[n-1]);
    spr[n-1] = spr[n];
    do {
        if ((de = findentry(clgetfunctions(class),selector)) != NULL) {
            switch (de->de_value.v_type) {
            case DT_CODE:
                (*de->de_value.v.v_code)(n);
                return;
            case DT_BYTECODE:
                check(3);
                code = coder = de->de_value.v.v_vector;
                set_bytecode(&spr[n],code);
                pushr_integer(n);                /* argument count */
                pushr_integer(stktop - fp);      /* old fp */
                pushr_integer(pc - cbase);       /* old pc */
                cbase = pc = (void *)coder->vec_data[0].v.v_string->str_data;
                fp = (sp = spr);
                return;
            default:
                errorsd("Bad method, Selector '%s', Type %d",
                      selector,
                      de->de_value.v_type);
            }
        }
        class = clgetbase(class);
    } while (!isnil(class));
    error1("No method for selector '%s'",selector);
}

/* opVREF - VREF opcode handler */
static void opVREF(void)
{
    VECTOR *vect;
    STRING *str;
    int i;
    chktype(0,DT_INTEGER);
    switch (sp[1].v_type) {
    case DT_VECTOR:
        vect = sp[1].v.v_vector;
        i = sp[0].v.v_integer;
        if (i < 0 || i >= vect->vec_size)
            error1d("subscript out of bounds: %d",i);
        sp[1] = vect->vec_data[i];
        break;
    case DT_STRING:
        str = sp[1].v.v_string;
        i = sp[0].v.v_integer;
        if (i < 0 || i >= str->str_size)
            error1d("subscript out of bounds: %d",i);
        set_integer(&sp[1],str->str_data[i]);
        break;
    default:
        badtype(1,DT_VECTOR);
        break;
    }
    ++sp;
}

/* opVSET - VSET opcode handler */
static void opVSET(void)
{
    VECTOR *vect;
    STRING *str;
    int i;
    chktype(1,DT_INTEGER);
    switch (sp[2].v_type) {
    case DT_VECTOR:
        vect = sp[2].v.v_vector;
        i = sp[1].v.v_integer;
        if (i < 0 || i >= vect->vec_size)
            error1d("subscript out of bounds: %d",i);
        vect->vec_data[i] = sp[2] = *sp;
        break;
    case DT_STRING:
        chktype(0,DT_INTEGER);
        str = sp[2].v.v_string;
        i = sp[1].v.v_integer;
        if (i < 0 || i >= str->str_size)
            error1d("subscript out of bounds: %d",i);
        str->str_data[i] = sp[0].v.v_integer;
        set_integer(&sp[2],str->str_data[i]);
        break;
    default:
        badtype(1,DT_VECTOR);
        break;
    }
    sp += 2;
}

/* opADD - ADD opcode handler */
static void opADD(void)
{
    STRING *s1,*s2,*sn;
    switch (sp[1].v_type) {
    case DT_INTEGER:
        switch (sp[0].v_type) {
        case DT_INTEGER:
            sp[1].v.v_integer += sp->v.v_integer;
            break;
        case DT_STRING:
            sn = newstring(1 + sp[0].v.v_string->str_size);
            s2 = sp[0].v.v_string;
            sn->str_data[0] = sp[1].v.v_integer;
            memcpy(&sn->str_data[1],
                   s2->str_data,
                   s2->str_size);
                   set_string(&sp[1],sn);
                   break;
        default:
            break;
        }
        break;
    case DT_STRING:
        switch (sp[0].v_type) {
        case DT_INTEGER:
            sn = newstring(sp[1].v.v_string->str_size + 1);
            s1 = sp[1].v.v_string;
            memcpy(sn->str_data,
                   s1->str_data,
                   s1->str_size);
                   sn->str_data[s1->str_size] = sp[0].v.v_integer;
            set_string(&sp[1],sn);
            break;
        case DT_STRING:
            sn = newstring(sp[1].v.v_string->str_size
                         + sp[0].v.v_string->str_size);
            s1 = sp[1].v.v_string;
            s2 = sp[0].v.v_string;
            memcpy(sn->str_data,
                   s1->str_data,s1->str_size);
            memcpy(&sn->str_data[s1->str_size],
                   s2->str_data,s2->str_size);
            set_string(&sp[1],sn);
            break;
        default:
            break;
        }
        break;
    case DT_REAL:
       switch (sp[0].v_type) {
         case DT_REAL:
            sp[1].v.v_real += sp->v.v_real;
           break;
         default:
            badtype(0,DT_REAL);
            break;
       }
    default:
        break;
    }
    ++sp;
}

/* getwoperand - get data word */
static int getwoperand(void)
{
    int b;
    b = *pc++;
    return ((*pc++ << 8) | b);
}

/* type names */
static char *tnames[] = {
"NIL","CLASS","OBJECT","VECTOR","INTEGER","STRING","BYTECODE",
"CODE","DICTIONARY","VAR","FILE","REAL"
};

/* typename - get the name of a type */
static char *typename(int type)
{
    static char buf[20];
    if (type >= _DTMIN && type <= _DTMAX)
        return (tnames[type]);
    sprintf(buf,"(%d)",type);
    return (buf);
}

/* badtype - report a bad operand type */
void badtype(int off,int type)
{
    char tn1[20];
    strcpy(tn1,typename(sp[off].v_type));
    infodss("PC: %04x, Offset %d, Type %s, Expected %s",
         pc-cbase,off,tn1,typename(type));
    error0("Bad argument type");
}

/* stackover - report a stack overflow error */
void stackover(void)
{
    error0("Stack overflow");
}

/* String compare functions for RISC OS version */
static int str_lt(struct string * a,struct string *b)
{
 int a_len = a->str_size;
 if (a_len > b->str_size) return(FALSE);
 return (strncmp(a->str_data,b->str_data,a_len)<0);
}
 
static int str_le(struct string *a,struct string *b)
{
 int a_len = a->str_size;
 if (a_len > b->str_size) return(FALSE);
 return (strncmp(a->str_data,b->str_data,a_len)<=0);
}

static int str_eq(struct string *a,struct string *b)
{
 int a_len = a->str_size;
 if (a_len != b->str_size) return(FALSE);
 return (strncmp(a->str_data,b->str_data,a_len)==0);
}

static int str_ne(struct string *a,struct string *b)
{
 int a_len = a->str_size;
 if (a_len != b->str_size) return(TRUE);
 return (strncmp(a->str_data,b->str_data,a_len)!=0);
}

static int str_ge(struct string *a,struct string *b)
{
 int b_len = b->str_size;
 if (b_len > a->str_size) return(FALSE);
 return (strncmp(a->str_data,b->str_data,b_len)>=0);
}

static int str_gt(struct string *a,struct string *b)
{
 int b_len = b->str_size;
 if (b_len > a->str_size) return(FALSE);
 return (strncmp(a->str_data,b->str_data,b_len)>0);
}
