static int evaluate_double(grib_expression *g,grib_handle* h,double* dres)
{
    double v1=0.0;
    double v2=0.0;
    int ret;

    grib_expression_binop* e = (grib_expression_binop*)g;

#if 0 /* DEBUGGING */
    {
        int typeLeft, typeRight;
        const char* nameLeft;
        const char* nameRight;
        typeLeft = grib_expression_native_type(h, e->left);
        typeRight = grib_expression_native_type(h, e->right);
        nameLeft = grib_expression_get_name(e->left);
        nameRight= grib_expression_get_name(e->right);
        printf("eval_dbl nameLeft=%s (type=%d), nameRight=%s (type=%d)\n",nameLeft,typeLeft, nameRight,typeRight);
        grib_expression_print(h->context, g, h);
        printf("\n");
    }
#endif

    ret = grib_expression_evaluate_double(h,e->left,&v1);
    if (ret != GRIB_SUCCESS) return ret;

    ret = grib_expression_evaluate_double(h,e->right,&v2);
    if (ret != GRIB_SUCCESS) return ret;

    *dres = e->double_func ? e->double_func(v1,v2) : e->long_func(v1,v2);

    return GRIB_SUCCESS;
}
static void init(grib_accessor* a,const long l, grib_arguments* c)
{
    grib_accessor_bits* self = (grib_accessor_bits*)a;
    grib_expression* e=NULL;
    int n = 0;

    self->argument = grib_arguments_get_name(grib_handle_of_accessor(a),c,n++);
    self->start    = grib_arguments_get_long(grib_handle_of_accessor(a),c,n++);
    self->len    = grib_arguments_get_long(grib_handle_of_accessor(a),c,n++);
    e=grib_arguments_get_expression(grib_handle_of_accessor(a),c,n++);
    if (e) {
        grib_expression_evaluate_double(grib_handle_of_accessor(a),e,&(self->referenceValue));
        self->referenceValuePresent=1;
    } else {
        self->referenceValuePresent=0;
    }
    self->scale = 1;
    if (self->referenceValuePresent) {
        self->scale=grib_arguments_get_double(grib_handle_of_accessor(a),c,n++);
    }

    Assert(self->len <= sizeof(long)*8);

    a->length=0;
}
static int evaluate_double(grib_expression* g,grib_handle* h,double* dres)
{
	int ret;
	double v=0;
	grib_expression_unop* e = (grib_expression_unop*)g;
	ret = grib_expression_evaluate_double(h,e->exp,&v);
	if (ret != GRIB_SUCCESS) return ret;
	*dres = e->double_func ? e->double_func(v) :  e->long_func(v);
	return GRIB_SUCCESS;

}
static void init(grib_accessor* a, const long len, grib_arguments* params) {
  int n=0;
  grib_accessor_codetable* self  = (grib_accessor_codetable*)a;
  grib_action* act=(grib_action*)(a->creator);

  self->tablename = grib_arguments_get_string(a->parent->h,params,n++);
  self->masterDir = grib_arguments_get_name(a->parent->h,params,n++);
  self->localDir = grib_arguments_get_name(a->parent->h,params,n++);

  /*if (a->flags & GRIB_ACCESSOR_FLAG_STRING_TYPE)
    printf("-------- %s type string (%ld)\n",a->name,a->flags);*/

  if (a->flags & GRIB_ACCESSOR_FLAG_TRANSIENT) {
    a->length = 0;
	if (!a->vvalue) 
		a->vvalue = grib_context_malloc_clear(a->parent->h->context,sizeof(grib_virtual_value));
    a->vvalue->type=grib_accessor_get_native_type(a);
    a->vvalue->length=len;
    if (act->default_value!=NULL) {
      const char* p = 0;
      size_t len = 1;
      long l;
      int ret=0;
      double d;
      char tmp[1024];
      grib_expression* expression=grib_arguments_get_expression(a->parent->h,act->default_value,0);
      int type = grib_expression_native_type(a->parent->h,expression);
      switch(type) {
        case GRIB_TYPE_DOUBLE:
          grib_expression_evaluate_double(a->parent->h,expression,&d);
          grib_pack_double(a,&d,&len);
          break;

        case GRIB_TYPE_LONG:
          grib_expression_evaluate_long(a->parent->h,expression,&l);
          grib_pack_long(a,&l,&len);
          break;

        default:
          len = sizeof(tmp);
          p = grib_expression_evaluate_string(a->parent->h,expression,tmp,&len,&ret);
          if (ret != GRIB_SUCCESS) {
			  grib_context_log(a->parent->h->context,GRIB_LOG_FATAL,
							   "unable to evaluate %s as string",a->name);
          }
          len = strlen(p)+1;
          pack_string(a,p,&len);
          break;
      }
    }
  } else
    a->length = len;

}
static void index_add_conditions(grib_concept_index* index,grib_concept_condition* condition) {
	grib_concept_condition* c=condition;
	char s[512]={0,};
	grib_concept_index_entry* e;;
	grib_concept_index_entry* entry=index_entry_new(index->context,index->keys);;

	while (c) {
		size_t size=512;
		int type;
		e=entry;
		type = grib_expression_native_type(0,c->expression);
		switch(type)
		{
			case GRIB_TYPE_LONG:
			  grib_expression_evaluate_long(0,c->expression,&lres);
			  sprintf(s,"%ld",lres);
			  break;

			case GRIB_TYPE_DOUBLE:
			  grib_expression_evaluate_double(0,c->expression,&dres);
			  sprintf(s,"%g",dres);
			  break;

			case GRIB_TYPE_STRING:
			  grib_expression_evaluate_string(0,c->expression,s,&size,&err);
			  break;

			default:
			  Assert(0);
			  break;
		}

		while (e->name && strcmp(e->name,c->name)) 
			e=e->next;

		e->type=type;
		e->value=grib_context_strdup(index->context,s);
		if (!e->name) {
			e->name=grib_context_strdup(index->context,c->name);
			e->next=grib_context_malloc_clear_persistent(index->context,sizeof(grib_concept_index_entry));
			if (!e->next) 
				grib_context_log(index->context,GRIB_LOG_FATAL,"index_add_conditions unable to allocate");
		} 

		c=c->next;
	}

	index_insert_entry(index,entry,condition->name);

	index_entry_delete(index->context,entry);
}
static int execute(grib_action* act, grib_handle *h)
{
    grib_action_if* a = (grib_action_if*)act;
    grib_action* next = NULL;
    int ret = 0;
    long lres=0;

    /* See GRIB-394 */
    int type = grib_expression_native_type(h, a->expression);
    if (type != GRIB_TYPE_DOUBLE) {
        if ((ret=grib_expression_evaluate_long(h,a->expression,&lres)) != GRIB_SUCCESS) {
            if (ret == GRIB_NOT_FOUND) lres=0;
            else return ret;
        }
    }
    else {
        double dres = 0.0;
        ret = grib_expression_evaluate_double(h, a->expression, &dres);
        lres = (long)dres;
        if ( ret != GRIB_SUCCESS ) {
            if (ret == GRIB_NOT_FOUND) lres=0;
            else return ret;
        }
    }

    if(lres)
        next = a->block_true;
    else
        next = a->block_false;

    while(next){
        ret = grib_action_execute(next, h);
        if(ret != GRIB_SUCCESS) return ret;
        next= next->next;
    }

    return GRIB_SUCCESS;
}
static int pack_string(grib_accessor* a, const char* buffer, size_t *len)
{
  grib_accessor_codetable* self = (grib_accessor_codetable*)a;
  grib_codetable*          table ;

  long i;
  size_t size = 1;

  typedef int (*cmpproc)(const char*, const char*);

  cmpproc cmp = a->flags | GRIB_ACCESSOR_FLAG_LOWERCASE ? strcasecmp : strcmp;

  if(!self->table) self->table = load_table(self);
  table=self->table;

  if(!table)
    return GRIB_ENCODING_ERROR;

  if (a->set) {
	  int err=grib_set_string(a->parent->h,a->set,buffer,len);
	  if (err!=0) return err;
  }

  for(i = 0 ; i < table->size; i++)
    if(table->entries[i].abbreviation)
		  if(cmp(table->entries[i].abbreviation,buffer) == 0)
        return grib_pack_long(a,&i,&size);

  if (a->flags & GRIB_ACCESSOR_FLAG_NO_FAIL) {
	  grib_action* act=(grib_action*)(a->creator);
	  if (act->default_value!=NULL) {
		  const char* p = 0;
		  size_t len = 1;
		  long l;
		  int ret=0;
		  double d;
		  char tmp[1024];
		  grib_expression* expression=grib_arguments_get_expression(a->parent->h,act->default_value,0);
		  int type = grib_expression_native_type(a->parent->h,expression);
		  switch(type) {
			  case GRIB_TYPE_DOUBLE:
				  grib_expression_evaluate_double(a->parent->h,expression,&d);
				  grib_pack_double(a,&d,&len);
				  break;

			  case GRIB_TYPE_LONG:
				  grib_expression_evaluate_long(a->parent->h,expression,&l);
				  grib_pack_long(a,&l,&len);
				  break;

			  default:
				  len = sizeof(tmp);
				  p = grib_expression_evaluate_string(a->parent->h,expression,tmp,&len,&ret);
				  if (ret != GRIB_SUCCESS) {
					  grib_context_log(a->parent->h->context,GRIB_LOG_FATAL,
									   "unable to evaluate %s as string",a->name);
					  return ret;
				  }
				  len = strlen(p)+1;
				  pack_string(a,p,&len);
				  break;
		  }
		  return GRIB_SUCCESS;
	  }
	
  }
  return GRIB_ENCODING_ERROR;
}
static int execute(grib_action* act, grib_handle *h) {
    grib_action_switch* a = (grib_action_switch*)act;
    grib_case* c=a->Case;
    grib_action* next = a->Default;
    grib_arguments* args=a->args;
    grib_arguments* values;
    grib_expression* e;
    grib_expression* value;
    int ret = 0;
    long lres=0;
    double dres=0;
    long lval=0;
    double dval=0;
    int type=0;
    int  ok=0;
    const char *cval;
    const char *cres;
    char buf[80];
    char tmp[80];
    size_t len = sizeof(buf);
    size_t size=sizeof(tmp);
    int err=0;

    Assert(args);

    while (c) {
        e=args->expression;
        values=c->values;
        value=values->expression;
        ok=0;
        while (e && value) {
            if (!strcmp(value->cclass->name,"true"))  ok=1;
            else {
                type=grib_expression_native_type(h,value);

                switch(type) {
                case GRIB_TYPE_LONG:
                    ok= ( grib_expression_evaluate_long(h,value,&lres) == GRIB_SUCCESS) &&
                    ( grib_expression_evaluate_long(h,e,&lval) == GRIB_SUCCESS) &&
                    (lval == lres);
                    break;

                case GRIB_TYPE_DOUBLE:
                    ok = ( grib_expression_evaluate_double(h,value,&dres) == GRIB_SUCCESS) &&
                    ( grib_expression_evaluate_double(h,e,&dval) == GRIB_SUCCESS) &&
                    (dval == dres);
                    break;

                case GRIB_TYPE_STRING:
                    len = sizeof(buf);
                    size=sizeof(tmp);
                    ok = ((cres=grib_expression_evaluate_string(h,e,buf,&len,&err)) != NULL ) &&
                            (err==0) && ((cval = grib_expression_evaluate_string(h,value,tmp,&size,&err)) != NULL) &&
                            (err==0) && ((strcmp(buf,cval) == 0) || (strcmp(cval,"*")==0));
                    break;

                default:
                    /* TODO: */
                    break;
                }
            }
            if (!ok) break;

            args=args->next;
            if (args) e=args->expression;
            else e=NULL;

            values=values->next;
            if (values) value=values->expression;
            else value=NULL;
        }

        if(ok) { next=c->action; break; }

        c=c->next;
    }

    if (!next) return GRIB_SWITCH_NO_MATCH;

    while(next){
        ret = grib_action_execute(next, h);
        if(ret != GRIB_SUCCESS) return ret;
        next= next->next;
    }

    return GRIB_SUCCESS;
}