#include<stdio.h>
#include<hdf5.h>
#include<HE5_HdfEosDef.h>
#include "ruby.h"
#include "narray.h"
#include<string.h>

/* for compatibility with ruby 1.6 */
#ifndef RARRAY_PTR
#define RARRAY_PTR(a) (RARRAY(a)->ptr)
#endif
#ifndef RARRAY_LEN
#define RARRAY_LEN(a) (RARRAY(a)->len)
#endif
#ifndef RSTRING_PTR
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
#endif
#ifndef SafeStringValue
#define SafeStringValue(s) Check_SafeStr(s)
#endif

extern int   check_numbertype(char *);
extern int   change_numbertype(char *);
extern int   change_entrycode(char *);
extern int   change_projcode(char *);
extern int   change_compmethod(char *);
extern int   change_tilingcode(char *);
extern int   change_gridorigincode(char *);
extern int   change_pixelregistcode(char *);
extern int   change_mergeflag(char *);
extern int   change_groupcode(char *);
extern void  HE5Wrap_make_NArray1D_or_str(int, size_t, VALUE *, void **);
extern void  HE5Wrap_store_NArray1D_or_str(int,  VALUE , void **);
extern void  change_chartype(hid_t, char *);
extern void  change_projtype(hid_t, char *);
extern void  change_gridorigintype(hid_t, char *);
extern void  change_pixelregisttype(hid_t, char *);
extern void  change_tilingtype(hid_t, char *);
extern void  change_comptype(hid_t, char *);

extern int     *hdfeos5_obj2cintary(VALUE);
extern long    *hdfeos5_obj2clongary(VALUE);
extern float   *hdfeos5_obj2cfloatary(VALUE);
extern signed long long   *hdfeos5_obj2csint64ary(VALUE);
extern unsigned long long *hdfeos5_obj2cunsint64ary(VALUE);

extern VALUE hdfeos5_ccharary2obj(char *, int, int);
extern VALUE hdfeos5_cintary2obj(int *, int, int, int *);
extern VALUE hdfeos5_clongary2obj(long *, int, int, int *);
extern VALUE hdfeos5_cunsint64ary2obj(unsigned long long *, int, int, int *);

extern void hdfeos5_freecintary(int *);
extern void hdfeos5_freeclongary(long *);
extern void hdfeos5_freecfloatary(float *);
extern void hdfeos5_freecsint64ary(signed long long *);
extern void hdfeos5_freecunsint64ary(unsigned long long *);

VALUE hdfeos5_gdwritefield_char(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdwritefield_short(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdwritefield_int(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdwritefield_long(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdwritefield_float(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdwritefield_double(VALUE, VALUE, VALUE, VALUE, VALUE);

VALUE hdfeos5_gdreadfield_char(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdreadfield_short(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdreadfield_int(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdreadfield_long(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdreadfield_float(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_gdreadfield_double(VALUE, VALUE, VALUE, VALUE);

#define Cbyte_to_NArray(v, rank, shape, up) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_BYTE, rank, shape, cNArray); \
    GetNArray(v,ary); \
    up = (unsigned char *)ary->ptr; \
}
#define Cshort_to_NArray(v, rank, shape, lp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_SINT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    lp = (short *)ary->ptr; \
}
#define Cint_to_NArray(v, rank, shape, lp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_LINT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    lp = (int *)ary->ptr; \
}
#define Clong_to_NArray(v, rank, shape, lp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_LINT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    lp = (long *)ary->ptr; \
}
#define Cfloat_to_NArray(v, rank, shape, fp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_SFLOAT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    fp = (float *)ary->ptr; \
}
#define Cdouble_to_NArray(v, rank, shape, dp); \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_DFLOAT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    dp = (double *)ary->ptr; \
}

/* Array or NArray to pointer and length (with no new allocation) */
#define Array_to_Cfloat_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_SFLOAT); \
    GetNArray(obj, na); \
    ptr = (float *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cdouble_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_DFLOAT); \
    GetNArray(obj, na); \
    ptr = (double *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cbyte_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_BYTE); \
    GetNArray(obj, na); \
    ptr = (u_int8_t *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cshort_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_SINT); \
    GetNArray(obj, na); \
    ptr = (int16_t *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cint_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_LINT); \
    GetNArray(obj, na); \
    ptr = (int32_t *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Clong_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_LINT); \
    GetNArray(obj, na); \
    ptr = (long *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}

#define maxcharsize  3000

static VALUE rb_eHE5Error;
static VALUE mNumRu = 0;
static VALUE cHE5;
static VALUE cHE5Gd;
static VALUE cHE5GdField;

struct HE5{
  hid_t fid;
  char *name;
  int closed;
};

struct HE5Gd{
  hid_t gdid;
  char *name;
  char *fname;
  hid_t fid;
  VALUE file;
};

struct HE5GdField{
  char *name;
  hid_t gdid;
  VALUE grid;
};

static struct HE5Gd *
HE5Gd_init(hid_t gdid, char *name, hid_t fid, VALUE file)
{
  struct HE5Gd *HE5Grid;
  HE5Grid=xmalloc(sizeof(struct HE5Gd));
  HE5Grid->gdid=gdid;
  HE5Grid->fid=fid;
  HE5Grid->name=xmalloc((strlen(name)+1)*sizeof(char));
  strcpy(HE5Grid->name,name);
  HE5Grid->file=file;
  return(HE5Grid);
}

static struct HE5GdField *
HE5GdField_init(char *name,hid_t gdid,VALUE grid)
{
  struct HE5GdField *HE5Gd_Field;
  HE5Gd_Field=xmalloc(sizeof(struct HE5GdField));
  HE5Gd_Field->gdid=gdid;
  HE5Gd_Field->grid=grid;
  HE5Gd_Field->name=xmalloc((strlen(name)+1)*sizeof(char));
  strcpy(HE5Gd_Field->name,name);
  return(HE5Gd_Field);
}

void
HE5Gd_free(struct HE5Gd *HE5_Grid)
{
  free(HE5_Grid->name);
  free(HE5_Grid);
}

void
HE5GdField_free(struct HE5GdField *HE5Gd_Field)
{
  free(HE5Gd_Field->name);
  free(HE5Gd_Field);
}

static void
he5gdfield_mark_obj(struct HE5GdField *he5fld)
{
    VALUE ptr;

    ptr = he5fld->grid;
    rb_gc_mark(ptr);
}

static void
he5gd_mark_obj(struct HE5Gd *he5gd)
{
    VALUE ptr;

    ptr = he5gd->file;
    rb_gc_mark(ptr);
}

VALUE
HE5Gd_clone(VALUE grid)
{
    VALUE clone;
    struct HE5Gd *he5gd1, *he5gd2;

    Data_Get_Struct(grid, struct HE5Gd, he5gd1);
    he5gd2 = HE5Gd_init(he5gd1->gdid, he5gd1->name, he5gd1->fid, he5gd1->file);
    clone = Data_Wrap_Struct(cHE5Gd, he5gd_mark_obj, HE5Gd_free, he5gd2);
    CLONESETUP(clone, grid);
    return clone;
}

VALUE
HE5GdField_clone(VALUE field)
{
    VALUE clone;
    struct HE5GdField *he5fld1, *he5fld2;

    Data_Get_Struct(field, struct HE5GdField, he5fld1);
    he5fld2 = HE5GdField_init(he5fld1->name, he5fld1->gdid, he5fld1->grid);
    clone = Data_Wrap_Struct(cHE5GdField, he5gdfield_mark_obj, HE5GdField_free, he5fld2);
    CLONESETUP(clone, field);
    return clone;
}

long
gdnentries_count(hid_t i_gridid, VALUE entrycode)
{
    char *c_entrycode;
    long o_strbufsize=FAIL;
    long o_count;

    Check_Type(entrycode,T_STRING);
    SafeStringValue(entrycode);
    c_entrycode = RSTRING_PTR(entrycode);

    o_count = HE5_GDnentries(i_gridid, change_entrycode(c_entrycode), &o_strbufsize);
    if (o_count < 0 ) return  Qfalse ;
    return(o_count);
}

long
gdnentries_strbuf(hid_t i_gridid, VALUE entrycode)
{
    char *c_entrycode;
    long o_strbufsize=FAIL;
    long o_count;

    Check_Type(entrycode,T_STRING);
    SafeStringValue(entrycode);
    c_entrycode = RSTRING_PTR(entrycode);

    o_count = HE5_GDnentries(i_gridid, change_entrycode(c_entrycode), &o_strbufsize);
    if (o_count < 0 ) return  Qfalse ;
    return(o_strbufsize);
}

VALUE
hdfeos5_gdcreate(VALUE mod, VALUE gridname, VALUE xdimsize, VALUE ydimsize, VALUE upleftpt, VALUE lowrightpt)
{
    hid_t i_fid;
    hid_t gdid;
    long i_xdimsize;
    long i_ydimsize;
    float *i_upleftpt;
    float *i_lowrightpt;
    char* i_gridname;
    struct HE5 *he5file;
    struct HE5Gd *he5grid;
    char*  file;
    VALUE Grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_fid=he5file->fid;
    file=he5file->name;

    Check_Type(gridname,T_STRING);
    SafeStringValue(gridname);
    i_gridname = RSTRING_PTR(gridname);
    Check_Type(xdimsize,T_FIXNUM);
    i_xdimsize = NUM2INT(xdimsize);
    Check_Type(ydimsize,T_FIXNUM);
    i_ydimsize = NUM2INT(ydimsize);
    if (TYPE(upleftpt) == T_FLOAT) {
      upleftpt = rb_Array(upleftpt);
    }
    i_upleftpt = hdfeos5_obj2cfloatary(upleftpt);
    if (TYPE(lowrightpt) == T_FLOAT) {
      lowrightpt = rb_Array(lowrightpt);
    }
    i_lowrightpt = hdfeos5_obj2cfloatary(lowrightpt);

    gdid = HE5_GDcreate(i_fid, i_gridname, i_xdimsize, i_ydimsize, (double*)i_upleftpt, (double*)i_lowrightpt);
    if(gdid == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    hdfeos5_freecfloatary(i_upleftpt);
    hdfeos5_freecfloatary(i_lowrightpt);
    he5grid = HE5Gd_init(gdid, i_gridname, i_fid, mod);
    Grid = Data_Wrap_Struct(cHE5Gd, he5gd_mark_obj, HE5Gd_free, he5grid);
    return(Grid);
}

VALUE
hdfeos5_gdattach(VALUE mod, VALUE gridname)
{
    hid_t i_fid;
    hid_t gdid;
    char *i_gridname, *i_fname;
    struct HE5 *he5file;
    struct HE5Gd *he5grid;
    VALUE Grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_fid=he5file->fid;
    i_fname=he5file->name;

    Check_Type(gridname,T_STRING);
    SafeStringValue(gridname);
    i_gridname = RSTRING_PTR(gridname);

    gdid = HE5_GDattach(i_fid, i_gridname);
    if(gdid == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    he5grid = HE5Gd_init(gdid, i_gridname, i_fid, mod);
    Grid = Data_Wrap_Struct(cHE5Gd, he5gd_mark_obj, HE5Gd_free, he5grid);
    return(Grid);
}

VALUE
hdfeos5_gddefdim(VALUE mod, VALUE dimname, VALUE dim)
{
    hid_t i_gridid;
    char *i_dimname;
    unsigned long long i_dim;
    herr_t o_rtn_val;
    VALUE rtn_val;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;
    Check_Type(dimname,T_STRING);
    SafeStringValue(dimname);
    Check_Type(dim,T_FIXNUM);
    i_dimname = RSTRING_PTR(dimname);
    i_dim = NUM2LONG(dim);
    o_rtn_val = HE5_GDdefdim(i_gridid, i_dimname, i_dim);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(dimname);
}

VALUE
hdfeos5_gddefproj(VALUE mod, VALUE projcode, VALUE zonecode, VALUE spherecode, VALUE projparm)
{
    hid_t i_gridid;
    int i_projcode;
    int i_zonecode;
    int i_spherecode;
    double *i_projparm;
    herr_t o_rtn_val;
    VALUE rtn_val;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;
    Check_Type(projcode,T_STRING);
    SafeStringValue(projcode);
    Check_Type(zonecode,T_FIXNUM);
    Check_Type(spherecode,T_FIXNUM);
    if (TYPE(projparm) == T_FLOAT) {
      projparm = rb_Array(projparm);
    }
    i_projcode = change_projcode(RSTRING_PTR(projcode));
    i_zonecode = NUM2INT(zonecode);
    i_spherecode = NUM2INT(spherecode);
    i_projparm = (double*)hdfeos5_obj2cfloatary(projparm);
    o_rtn_val = HE5_GDdefproj(i_gridid, i_projcode, i_zonecode, i_spherecode, i_projparm);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);
}

VALUE
hdfeos5_gdblksomoffset(VALUE mod, VALUE offset, VALUE count, VALUE code)
{
    hid_t i_gridid;
    char *i_code;
    long *i_offset;
    unsigned long long *i_count;
    herr_t o_rtn_val;
    VALUE rtn_val;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;
    Check_Type(code,T_STRING);
    SafeStringValue(code);
    Check_Type(offset,T_FIXNUM);
    Check_Type(count,T_FIXNUM);
    i_code = RSTRING_PTR(code);
    if ((TYPE(offset) == T_BIGNUM) || (TYPE(offset) == T_FIXNUM)) {
      offset = rb_Array(offset);
    }
    i_offset = hdfeos5_obj2clongary(offset);
    if ((TYPE(count) == T_BIGNUM) || (TYPE(count) == T_FIXNUM)) {
      count = rb_Array(count);
    }
    i_count = hdfeos5_obj2cunsint64ary(count);

    o_rtn_val = HE5_GDblkSOMoffset(i_gridid, i_offset, i_count, i_code);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);
}

VALUE
hdfeos5_gddefcomp(VALUE mod, VALUE compcode, VALUE compparm)
{
    hid_t i_gridid;
    int i_compcode;
    int *i_compparm;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(compcode,T_STRING);
    SafeStringValue(compcode);
    if ((TYPE(compparm) == T_BIGNUM) || (TYPE(compparm) == T_FIXNUM)) {
      compparm = rb_Array(compparm);
    }
    i_compcode = change_compmethod(RSTRING_PTR(compcode));
    i_compparm = hdfeos5_obj2cintary(compparm);

    o_rtn_val = HE5_GDdefcomp(i_gridid, i_compcode, i_compparm);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecintary(i_compparm);
    return(rtn_val);
}

VALUE
hdfeos5_gddeftile(VALUE mod, VALUE tilecode, VALUE tilerank, VALUE tiledims)
{
    hid_t i_gridid;
    int i_tilecode;
    int i_tilerank;
    unsigned long long *i_tiledims;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(tilecode,T_STRING);
    SafeStringValue(tilecode);
    i_tilecode = change_tilingcode(RSTRING_PTR(tilecode));

    Check_Type(tilerank,T_FIXNUM);
    i_tilerank = NUM2INT(tilerank);
    if ((TYPE(tiledims) == T_BIGNUM) || (TYPE(tiledims) == T_FIXNUM)) {
      tiledims = rb_Array(tiledims);
    }
    i_tiledims = hdfeos5_obj2cunsint64ary(tiledims);

    o_rtn_val = HE5_GDdeftile(i_gridid, i_tilecode, i_tilerank, i_tiledims);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecunsint64ary(i_tiledims);
    return(rtn_val);
}

VALUE
hdfeos5_gddefcomtile(VALUE mod, VALUE compcode, VALUE compparm, VALUE tilerank, VALUE tiledims)
{
    hid_t i_gridid;
    int i_compcode;
    int *i_compparm;
    int i_tilerank;
    unsigned long long *i_tiledims;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(compcode,T_STRING);
    SafeStringValue(compcode);
    if ((TYPE(compparm) == T_BIGNUM) || (TYPE(compparm) == T_FIXNUM)) {
      compparm = rb_Array(compparm);
    }
    i_compcode = change_compmethod(RSTRING_PTR(compcode));
    i_compparm = hdfeos5_obj2cintary(compparm);

    Check_Type(tilerank,T_FIXNUM);
    i_tilerank = NUM2INT(tilerank);
    if ((TYPE(tiledims) == T_BIGNUM) || (TYPE(tiledims) == T_FIXNUM)) {
      tiledims = rb_Array(tiledims);
    }
    i_tiledims = hdfeos5_obj2cunsint64ary(tiledims);

    o_rtn_val = HE5_GDdefcomtile(i_gridid, i_compcode, i_compparm, i_tilerank, i_tiledims);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecintary(i_compparm);
    hdfeos5_freecunsint64ary(i_tiledims);
    return(rtn_val);
}

VALUE
hdfeos5_gddeforigin(VALUE mod, VALUE origincode)
{
    hid_t i_gridid;
    int i_origincode;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(origincode,T_STRING);
    SafeStringValue(origincode);
    i_origincode = change_gridorigincode(RSTRING_PTR(origincode));

    o_rtn_val = HE5_GDdeforigin(i_gridid, i_origincode);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);
}

VALUE
hdfeos5_gddefpixreg(VALUE mod, VALUE pixregcode)
{
    hid_t i_gridid;
    int i_pixregcode;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(pixregcode,T_STRING);
    SafeStringValue(pixregcode);
    i_pixregcode = change_pixelregistcode(RSTRING_PTR(pixregcode));

    o_rtn_val = HE5_GDdefpixreg(i_gridid, i_pixregcode);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);
}

VALUE
hdfeos5_gddiminfo(VALUE mod, VALUE dimname)
{
    hid_t i_gridid;
    char *i_dimname;
    unsigned long long o_ndim;
    VALUE ndim;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(dimname,T_STRING);
    SafeStringValue(dimname);
    i_dimname = RSTRING_PTR(dimname);

    o_ndim = HE5_GDdiminfo(i_gridid, i_dimname);
    ndim = LONG2NUM(o_ndim);
    return(ndim);
}

VALUE
hdfeos5_gdgridinfo(VALUE mod)
{
    hid_t i_gridid;
    int   pt=2;
    long  o_xdimsize;
    long  o_ydimsize;
    void *o_datbuf1;
    void *o_datbuf2;
    herr_t o_rtn_val;
    VALUE xdimsize;
    VALUE ydimsize;
    VALUE upleftpt;
    VALUE lowrightpt;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_DOUBLE, pt, &upleftpt,   &o_datbuf1); 
    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_DOUBLE, pt, &lowrightpt, &o_datbuf2); 
    o_rtn_val = HE5_GDgridinfo(i_gridid, &o_xdimsize, &o_ydimsize, o_datbuf1, o_datbuf2);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    xdimsize = LONG2NUM(o_xdimsize);
    ydimsize = LONG2NUM(o_ydimsize);
    return rb_ary_new3(4, xdimsize, ydimsize, upleftpt, lowrightpt);
}

VALUE
hdfeos5_gdprojinfo(VALUE mod)
{
    hid_t i_gridid;
    int o_projcode;
    int o_zonecode;
    int o_spherecode;
    void *o_projparm;
    char str[maxcharsize];
    herr_t o_rtn_val;
    VALUE projcode;
    VALUE zonecode;
    VALUE spherecode;
    VALUE projparm;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_FLOAT, maxcharsize, &projparm, &o_projparm); 
    o_rtn_val = HE5_GDprojinfo(i_gridid, &o_projcode, &o_zonecode, &o_spherecode, o_projparm);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    change_projtype(o_projcode,str);
    projcode =rb_str_new2(str);
    zonecode = INT2NUM(o_zonecode);
    spherecode = INT2NUM(o_spherecode);
    return rb_ary_new3(4, projcode, zonecode, spherecode, projparm);
}

VALUE
hdfeos5_gdorigininfo(VALUE mod)
{
    hid_t i_gridid;
    int o_origincode;
    herr_t o_rtn_val;
    char str[maxcharsize];
    VALUE origincode;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    o_rtn_val = HE5_GDorigininfo(i_gridid, &o_origincode);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    change_gridorigintype(o_origincode,str);
    origincode = rb_str_new2(str);
    return(origincode);
}

VALUE
hdfeos5_gdpixreginfo(VALUE mod)
{
    hid_t i_gridid;
    int o_pixregcode;
    herr_t o_rtn_val;
    char str[maxcharsize];
    VALUE pixregcode;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    o_rtn_val = HE5_GDpixreginfo(i_gridid, &o_pixregcode);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    change_gridorigintype(o_pixregcode,str);
    pixregcode =rb_str_new2(str);

    return(pixregcode);
}

VALUE
hdfeos5_gdcompinfo(VALUE mod)
{
    hid_t i_gridid;
    char *i_fldname;
    int o_compcode;
    int ncomplevel=32;  /* Set compression level: value 0,1,2,3,4,5,6,7,8,9,10,16, or 32 */
    void *o_compparm;
    herr_t o_rtn_val;
    char str[maxcharsize];
    VALUE compcode;
    VALUE compparm;
    VALUE rtn_val;
    struct HE5GdField *he5field;
                  

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_INT, ncomplevel, &compparm, &o_compparm); 
    o_rtn_val = HE5_GDcompinfo(i_gridid, i_fldname, &o_compcode, o_compparm);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    change_comptype(o_compcode,str);
    compcode =rb_str_new2(str);

    return rb_ary_new3(2, compcode, compparm);
}

VALUE
hdfeos5_gdfieldinfo(VALUE mod)
{
    hid_t i_gridid;
    char *i_fldname;
    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    char str[maxcharsize];
    herr_t o_rtn_val;
    VALUE rank;
    VALUE dims;
    VALUE ntype;
    VALUE dimlist;
    struct HE5GdField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    o_rtn_val = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    rank = INT2NUM(i_rank);
    dims = hdfeos5_cunsint64ary2obj(hs_dims, i_rank, 1, &i_rank);
    change_chartype(i_ntype, str);
    ntype =rb_str_new2(str);
    dimlist = rb_str_new2(o_dimlist);

    return rb_ary_new3(4, rank, dims, ntype, dimlist);
}

VALUE
hdfeos5_gdtileinfo(VALUE mod)
{
    hid_t i_gridid;
    char *i_fldname;
    int o_tilecode;
    int o_tilerank;
    unsigned long long o_tiledims[maxcharsize];
    herr_t o_rtn_val;
    char str[maxcharsize];
    VALUE tilecode;
    VALUE tilerank;
    VALUE tiledims;
    struct HE5GdField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    o_rtn_val = HE5_GDtileinfo(i_gridid, i_fldname, &o_tilecode, &o_tilerank, o_tiledims);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    change_tilingtype(o_tilecode,str);
    tilecode =rb_str_new2(str);
    tilerank = INT2NUM(o_tilerank);
    tiledims =  hdfeos5_cunsint64ary2obj(o_tiledims, o_tilerank, 1, &o_tilerank);

    return rb_ary_new3(3, tilecode, tilerank, tiledims);
}

VALUE
hdfeos5_gddeffield(VALUE file, VALUE fieldname, VALUE dimlist, VALUE maxdimlist, VALUE numbertype, VALUE merge)
{
    hid_t i_gridid;
    char *i_fieldname;
    char *i_dimlist;
    char *i_maxdimlist;
    hid_t i_numbertype;
    int i_merge;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5GdField *he5field;
    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(file, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    Check_Type(dimlist,T_STRING);
    SafeStringValue(dimlist);
    Check_Type(maxdimlist,T_STRING);
    SafeStringValue(maxdimlist);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    Check_Type(merge,T_FIXNUM);

    i_fieldname = RSTRING_PTR(fieldname);
    i_dimlist = RSTRING_PTR(dimlist);
    i_maxdimlist = RSTRING_PTR(maxdimlist);
    i_numbertype = change_numbertype(RSTRING_PTR(numbertype));
    i_merge = NUM2INT(merge);

    if(strcmp(i_maxdimlist,"NULL")==0)  i_maxdimlist = NULL;
    o_rtn_val = HE5_GDdeffield(i_gridid, i_fieldname, i_dimlist, i_maxdimlist, i_numbertype, i_merge);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;

    he5field = HE5GdField_init(i_fieldname, i_gridid, file);
    return(Data_Wrap_Struct(cHE5GdField, he5gdfield_mark_obj, HE5GdField_free, he5field));
}

VALUE
hdfeos5_gdwritefieldmeta(VALUE mod, VALUE dimlist, VALUE numbertype)
{
    hid_t i_gridid;
    char *i_fieldname;
    char *i_dimlist;
    hid_t i_numbertype;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;

    Check_Type(dimlist,T_STRING);
    SafeStringValue(dimlist);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);

    i_dimlist = RSTRING_PTR(dimlist);
    i_numbertype = change_numbertype(RSTRING_PTR(numbertype));

    o_rtn_val = HE5_GDwritefieldmeta(i_gridid, i_fieldname, i_dimlist, i_numbertype);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);
}

VALUE
hdfeos5_gdwritefield(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE data, VALUE ntype)
{
    char *chk_ntype;
    Check_Type(ntype,T_STRING);
    SafeStringValue(ntype);
    chk_ntype = RSTRING_PTR(ntype);

    switch (check_numbertype(chk_ntype)){
    case  HE5T_NATIVE_CHAR:
    case  HE5T_NATIVE_SCHAR:
    case  HE5T_NATIVE_UCHAR:
    case  HE5T_CHARSTRING:
        return hdfeos5_gdwritefield_char(mod,  start,  stride,  edge,  data);
	break;

    case  HE5T_NATIVE_INT8:
    case  HE5T_NATIVE_UINT8:
        return hdfeos5_gdwritefield_char(mod,  start,  stride,  edge,  data);
	break;

    case  HE5T_NATIVE_SHORT:
    case  HE5T_NATIVE_USHORT:
    case  HE5T_NATIVE_INT16:
    case  HE5T_NATIVE_UINT16:
        return hdfeos5_gdwritefield_short(mod,  start,  stride,  edge,  data);
	break;

    case  HE5T_NATIVE_INT:
    case  HE5T_NATIVE_UINT:
    case  HE5T_NATIVE_INT32:
    case  HE5T_NATIVE_UINT32:
        return hdfeos5_gdwritefield_int(mod,  start,  stride,  edge,  data);
	break;

    case  HE5T_NATIVE_LONG:
        return hdfeos5_gdwritefield_long(mod,  start,  stride,  edge,  data);
	break;

    case  HE5T_NATIVE_FLOAT:
        return hdfeos5_gdwritefield_float(mod,  start,  stride,  edge,  data);
	break;

    case  HE5T_NATIVE_DOUBLE:
        return hdfeos5_gdwritefield_double(mod,  start,  stride,  edge,  data);
	break;
    default:
	rb_raise(rb_eHE5Error, "not match data type [%s:%d]",__FILE__,__LINE__);
    }
}

VALUE
hdfeos5_gdreadfield(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE ntype)
{
    char *chk_ntype;
    Check_Type(ntype,T_STRING);
    SafeStringValue(ntype);
    chk_ntype = RSTRING_PTR(ntype);

    switch (check_numbertype(chk_ntype)){
    case  HE5T_NATIVE_CHAR:
    case  HE5T_NATIVE_SCHAR:
    case  HE5T_NATIVE_UCHAR:
    case  HE5T_CHARSTRING:
        return hdfeos5_gdreadfield_char(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_INT8:
    case  HE5T_NATIVE_UINT8:
        return hdfeos5_gdreadfield_char(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_SHORT:
    case  HE5T_NATIVE_USHORT:
    case  HE5T_NATIVE_INT16:
    case  HE5T_NATIVE_UINT16:
        return hdfeos5_gdreadfield_short(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_INT:
    case  HE5T_NATIVE_UINT:
    case  HE5T_NATIVE_INT32:
    case  HE5T_NATIVE_UINT32:
        return hdfeos5_gdreadfield_int(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_LONG:
        return hdfeos5_gdreadfield_long(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_FLOAT:
        return hdfeos5_gdreadfield_float(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_DOUBLE:
        return hdfeos5_gdreadfield_double(mod,  start,  stride,  edge);
	break;
    default:
	rb_raise(rb_eHE5Error, "not match data type [%s:%d]",__FILE__,__LINE__);
    }
}

VALUE
hdfeos5_gdwriteattr(VALUE mod, VALUE attrname, VALUE numbertype, VALUE count, VALUE datbuf)
{
    hid_t i_gridid;
    char *i_attrname;
    hid_t i_numbertype;
    hid_t i_numbertypechk;
    unsigned long long *i_count;
    void *i_datbuf;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    count = rb_Array(count);

    i_attrname = RSTRING_PTR(attrname);
    i_numbertype    = change_numbertype(RSTRING_PTR(numbertype));
    i_numbertypechk = check_numbertype(RSTRING_PTR(numbertype));
    i_count = hdfeos5_obj2cunsint64ary(count);

    HE5Wrap_store_NArray1D_or_str(i_numbertypechk, datbuf, &i_datbuf); 
    o_rtn_val = HE5_GDwriteattr(i_gridid, i_attrname, i_numbertype, i_count, i_datbuf);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecunsint64ary(i_count);
    return(rtn_val);
}

VALUE
hdfeos5_gd_get_att(VALUE mod, VALUE attrname)
{
    VALUE result;
    hid_t i_gridid;
    char *i_attrname;
    hid_t o_ntype;
    void *o_datbuf;
    unsigned long long o_count;
    herr_t o_rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    i_attrname = RSTRING_PTR(attrname);

    o_rtn_val = HE5_GDattrinfo(i_gridid, i_attrname, &o_ntype, &o_count);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    HE5Wrap_make_NArray1D_or_str(o_ntype, o_count, &result, &o_datbuf); 
    o_rtn_val = HE5_GDreadattr(i_gridid, i_attrname, o_datbuf);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    return result;
}

VALUE
hdfeos5_gdinqgrid(VALUE mod)
{
    char *i_filename;
    char *o_gridlist;
    long o_strbufsize;
    long o_nGrid;
    VALUE nGrid;
    VALUE gridlist;
    VALUE strbufsize;

    struct HE5 *he5file;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_filename=he5file->name;

    o_nGrid = HE5_GDinqgrid(i_filename, NULL, &o_strbufsize);
    if (o_nGrid <= 0 ) return  Qfalse ;

    o_gridlist = ALLOCA_N(char, (o_strbufsize + 1));
    o_nGrid = HE5_GDinqgrid(i_filename, o_gridlist, &o_strbufsize);
    if (o_nGrid <= 0 ) return  Qfalse ;
    else               nGrid = LONG2NUM(o_nGrid);
    gridlist = rb_str_new(o_gridlist,o_strbufsize);
    strbufsize = LONG2NUM(o_strbufsize);

    return rb_ary_new3(3, nGrid, gridlist, strbufsize);
}

VALUE
hdfeos5_gdsetfillvalue(VALUE mod, VALUE fieldname, VALUE numbertype, VALUE fillval)
{
    hid_t i_gridid;
    char *i_fieldname;
    hid_t i_numbertype;
    void *i_fillval;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    i_fieldname = RSTRING_PTR(fieldname);
    i_numbertype = change_numbertype(RSTRING_PTR(numbertype));

    if (TYPE(fillval) == T_FLOAT) {
      fillval = rb_Array(fillval);
      i_fillval = hdfeos5_obj2cfloatary(fillval);
    }
    if (TYPE(fillval) == T_STRING) {
      Check_Type(fillval,T_STRING);
      SafeStringValue(fillval);
      i_fillval = RSTRING_PTR(fillval);
    }

    i_fillval = (void*)malloc(HE5_BLKSIZE);
    o_rtn_val = HE5_GDsetfillvalue(i_gridid, i_fieldname, i_numbertype, i_fillval);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecfloatary(i_fillval);
    return(rtn_val);
}

VALUE
hdfeos5_gdgetfillvalue(VALUE mod,VALUE fieldname)
{
    hid_t i_gridid;
    char *i_fieldname;
    void *o_fillval;
    herr_t o_rtn_val;
    VALUE fillval;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    i_fieldname = RSTRING_PTR(fieldname);

    o_fillval = (void*)malloc(HE5_BLKSIZE);
    o_rtn_val = HE5_GDgetfillvalue(i_gridid, i_fieldname, o_fillval);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    fillval = rb_str_new2(o_fillval);

    return(fillval);
}

VALUE
hdfeos5_gdinqdatatype(VALUE mod, VALUE fieldname, VALUE attrname, VALUE group)
{
    hid_t i_gridid;
    char *i_fieldname;
    char *i_attrname;
    int   i_group;
    hid_t  i_datatype;
    H5T_class_t o_classid;
    H5T_order_t o_order;
    size_t o_size;
    herr_t o_rtn_val;
    VALUE classid;
    VALUE order;
    VALUE size;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(group,T_STRING);
    SafeStringValue(group);

    i_fieldname = RSTRING_PTR(fieldname);
    i_attrname = RSTRING_PTR(attrname);
    i_group = change_groupcode(RSTRING_PTR(group));

    if(strcmp(i_attrname,"NULL")==0)  i_attrname = NULL;
    o_rtn_val = HE5_GDinqdatatype(i_gridid, i_fieldname, i_attrname, i_group, &i_datatype, &o_classid, &o_order, &o_size);
    if(o_rtn_val == FAIL) return Qfalse;
    classid = INT2NUM(o_classid);
    order = INT2NUM(o_order);
    size = INT2NUM(o_size);

    return rb_ary_new3(3, classid, order, size);
}

VALUE
hdfeos5_gdnentries(VALUE mod, VALUE entrycode)
{
    hid_t i_gridid;
    int i_entrycode;
    long o_strbufsize;
    long o_count;
    VALUE count;
    VALUE strbufsize;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(entrycode,T_STRING);
    SafeStringValue(entrycode);
    i_entrycode = change_entrycode(RSTRING_PTR(entrycode));

    o_count = HE5_GDnentries(i_gridid, i_entrycode, &o_strbufsize);
    if (o_count < 0 ) return  Qfalse ;
    else              count = LONG2NUM(o_count);
    strbufsize = LONG2NUM(o_strbufsize);

    return rb_ary_new3(2, count, strbufsize);
}

VALUE
hdfeos5_gdinqdims(VALUE mod, VALUE entrycode)
{
    hid_t i_gridid;
    int i_count;
    long i_strbufsize;
    char *o_dimnames;
    unsigned long long *hs_dims;
    long o_ndims;
    VALUE ndims;
    VALUE dimnames;
    VALUE dims;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    i_count = gdnentries_count(i_gridid, entrycode);
    i_strbufsize = gdnentries_strbuf(i_gridid, entrycode);

    hs_dims = ALLOCA_N(unsigned long long,  i_count);
    o_dimnames = ALLOCA_N(char,(i_strbufsize + 1));
    
    o_ndims = HE5_GDinqdims(i_gridid, o_dimnames, hs_dims);
    if(o_ndims < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    ndims = LONG2NUM(o_ndims);
    dimnames = rb_str_new(o_dimnames,i_strbufsize);
    dims = hdfeos5_cunsint64ary2obj(hs_dims, i_count, 1, &i_count);

    return rb_ary_new3(3, ndims, dimnames, dims);
}

VALUE
hdfeos5_gdinqattrs(VALUE mod)
{
    hid_t i_gridid;
    char *o_attrnames;
    long  o_strbufsize;
    long  o_number;
    VALUE nattr;
    VALUE attrnames;
    VALUE strbufsize;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    o_number = HE5_GDinqattrs(i_gridid, NULL, &o_strbufsize);
    if(o_number < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    o_attrnames = ALLOCA_N(char, (o_strbufsize + 1));

    o_number = HE5_GDinqattrs(i_gridid, o_attrnames, &o_strbufsize);
    if(o_number < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    nattr = LONG2NUM(o_number);
    attrnames = rb_str_new(o_attrnames,o_strbufsize);
    strbufsize = INT2NUM(o_strbufsize);

    return rb_ary_new3(3, nattr, attrnames, strbufsize);
}

VALUE
hdfeos5_gdinqfields(VALUE mod, VALUE entrycode)
{
    hid_t i_gridid;
    char  *o_fieldlist;
    int   *o_rank;
    hid_t *o_ntype;
    long   o_nflds;
    int  i_count;
    long i_strbufsize;
    VALUE nflds;
    VALUE fieldlist;
    VALUE rank;
    VALUE ntype;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    i_count = gdnentries_count(i_gridid, entrycode);
    i_strbufsize = gdnentries_strbuf(i_gridid, entrycode);

    o_rank = ALLOCA_N(int, i_count);
    o_fieldlist = ALLOCA_N(char, (i_strbufsize + 1));

    o_nflds = HE5_GDinqfields(i_gridid, o_fieldlist, o_rank, NULL);
    if (o_nflds < 0 ) return  Qfalse ;

    o_ntype = ALLOCA_N(hid_t, (o_nflds + 1)); 
    o_nflds = HE5_GDinqfields(i_gridid, o_fieldlist, o_rank, o_ntype);
    if (o_nflds < 0 ) return  Qfalse ;
    else              nflds = LONG2NUM(o_nflds);
    fieldlist = rb_str_new(o_fieldlist,i_strbufsize);
 
    i_count = (int)o_nflds;
    rank = hdfeos5_cintary2obj(o_rank, i_count, 1, &i_count);
    ntype = hdfeos5_cintary2obj(o_ntype, i_count, 1, &i_count);

    return rb_ary_new3(4, nflds, fieldlist, rank, ntype);
}

VALUE
hdfeos5_gddetach(VALUE mod)
{
    hid_t i_gridid;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    o_rtn_val = HE5_GDdetach(i_gridid);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);
}

VALUE
hdfeos5_gdrs2ll(VALUE mod, VALUE projcode, VALUE projparm, VALUE xdimsize, VALUE ydimsize, VALUE upleft, VALUE lowright, VALUE npnts, VALUE r, VALUE s, VALUE pixcen, VALUE pixcnr)
{
    hid_t i_gridid;
    int i_projcode;
    int i_npnts;
    int i_pixcen;
    int i_pixcnr;
    long i_xdimsize;
    long i_ydimsize;
    float *i_projparm;
    float *i_upleft;
    float *i_lowright;
    float *i_r;
    float *i_s;
    void  *o_latitude;
    void *o_longitude;
    herr_t o_rtn_val;
    VALUE rtn_val;
    VALUE longitude;
    VALUE latitude;
    struct HE5Gd *he5grid;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(projcode,T_STRING);
    SafeStringValue(projcode);
    i_projcode = change_projcode(RSTRING_PTR(projcode));
    Check_Type(xdimsize,T_FIXNUM);
    i_xdimsize = NUM2INT(xdimsize);
    Check_Type(ydimsize,T_FIXNUM);
    i_ydimsize = NUM2INT(ydimsize);
    Check_Type(npnts,T_FIXNUM);
    i_npnts = NUM2INT(npnts);
    Check_Type(pixcen,T_FIXNUM);
    i_pixcen = NUM2INT(pixcen);
    Check_Type(pixcnr,T_FIXNUM);
    i_pixcnr = NUM2INT(pixcnr);
    if (TYPE(projparm) == T_FLOAT) {
      projparm = rb_Array(projparm);
    }
    i_projparm = hdfeos5_obj2cfloatary(projparm);
    if (TYPE(upleft) == T_FLOAT) {
      upleft = rb_Array(upleft);
    }
    i_upleft = hdfeos5_obj2cfloatary(upleft);
    if (TYPE(lowright) == T_FLOAT) {
      lowright = rb_Array(lowright);
    }
    i_lowright = hdfeos5_obj2cfloatary(lowright);
    if (TYPE(r) == T_FLOAT) {
      r = rb_Array(r);
    }
    i_r = hdfeos5_obj2cfloatary(r);
    if (TYPE(s) == T_FLOAT) {
      s = rb_Array(s);
    }
    i_s = hdfeos5_obj2cfloatary(s);

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_FLOAT, i_npnts, &longitude, &o_longitude); 
    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_FLOAT, i_npnts, &latitude, &o_latitude); 
    o_rtn_val = HE5_GDrs2ll(i_projcode, (double*)i_projparm, i_xdimsize, i_ydimsize, (double*)i_upleft, (double*)i_lowright, i_npnts, (double*)i_r, (double*)i_s, o_longitude, o_latitude, i_pixcen, i_pixcnr);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;

    hdfeos5_freecfloatary(i_projparm);
    hdfeos5_freecfloatary(i_lowright);
    hdfeos5_freecfloatary(i_upleft);
    hdfeos5_freecfloatary(i_r);
    hdfeos5_freecfloatary(i_s);

    return rb_ary_new3(2, longitude, latitude);
}


VALUE
hdfeos5_gddefboxregion(VALUE mod, VALUE cornerlon, VALUE cornerlat)
{
    hid_t i_gridid;
    float *i_cornerlon;
    float *i_cornerlat;
    hid_t o_regionID;
    VALUE regionID;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    if (TYPE(cornerlon) == T_FLOAT) {
      cornerlon = rb_Array(cornerlon);
    }
    if (TYPE(cornerlat) == T_FLOAT) {
      cornerlat = rb_Array(cornerlat);
    }
    i_cornerlon = hdfeos5_obj2cfloatary(cornerlon);
    i_cornerlat = hdfeos5_obj2cfloatary(cornerlat);

    o_regionID = HE5_GDdefboxregion(i_gridid, (double *)i_cornerlon, (double *)i_cornerlat);
    regionID = INT2NUM(o_regionID);
    hdfeos5_freecfloatary(i_cornerlon);
    hdfeos5_freecfloatary(i_cornerlat);
    return(regionID);
}

VALUE
hdfeos5_gdregioninfo(VALUE mod, VALUE regionid)
{
    hid_t i_gridid;
    hid_t i_regionid;
    char *i_fieldname;
    hid_t o_ntype;
    int o_rank=0;
    long o_size=0;
    int i_npt=2;
    unsigned long long o_dims[maxcharsize];
    void *o_upleftpt;
    void *o_lowrightpt;
    herr_t o_rtn_val;
    char str[maxcharsize];
    VALUE ntype;
    VALUE rank;
    VALUE dims;
    VALUE size;
    VALUE upleftpt;
    VALUE lowrightpt;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;

    Check_Type(regionid,T_FIXNUM);
    i_regionid = NUM2INT(regionid);

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_INT, i_npt, &upleftpt, &o_upleftpt); 
    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_INT, i_npt, &lowrightpt, &o_lowrightpt); 
    o_rtn_val = HE5_GDregioninfo(i_gridid, i_regionid, i_fieldname, &o_ntype, &o_rank, o_dims, &o_size, o_upleftpt, o_lowrightpt);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    change_chartype(o_ntype, str);
    ntype =rb_str_new2(str);
    rank = INT2NUM(o_rank);
    dims = hdfeos5_cunsint64ary2obj(o_dims, o_rank, 1, &o_rank);
    size = INT2NUM(o_size);

    return rb_ary_new3(6, ntype, rank, dims, size, upleftpt, lowrightpt);
}

VALUE
hdfeos5_gdextractregion(VALUE mod, VALUE regionid)
{
    hid_t i_gridid;
    hid_t i_regionid;
    char *i_fieldname;
    void *o_buffer;
    herr_t o_rtn_val;
    VALUE buffer;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;

    Check_Type(regionid,T_FIXNUM);
    i_regionid = NUM2INT(regionid);

    o_buffer = (void*)malloc(HE5_BLKSIZE);
    o_rtn_val = HE5_GDextractregion(i_gridid, i_regionid, i_fieldname, o_buffer);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    buffer = rb_str_new2(o_buffer);

    return(buffer);

}

VALUE
hdfeos5_gddupregion(VALUE mod, VALUE oldregionid)
{
    hid_t i_oldregionid;
    hid_t o_newRegionid;
    VALUE newRegionid;

    Check_Type(oldregionid,T_FIXNUM);
    i_oldregionid = NUM2INT(oldregionid);

    o_newRegionid = HE5_GDdupregion(i_oldregionid);
    newRegionid = INT2NUM(o_newRegionid);
    return(newRegionid);
}

VALUE
hdfeos5_gddefvrtregion(VALUE mod, VALUE regionid, VALUE vertobj, VALUE range)
{
    hid_t i_gridid;
    hid_t i_regionid;
    char *i_vertobj;
    float *i_range;
    hid_t o_rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(regionid,T_FIXNUM);
    Check_Type(vertobj,T_STRING);
    SafeStringValue(vertobj);
    if (TYPE(range) == T_FLOAT) {
      range = rb_Array(range);
    }
    i_regionid = NUM2INT(regionid);
    i_vertobj = RSTRING_PTR(vertobj);
    i_range = hdfeos5_obj2cfloatary(range);

    o_rtn_val = HE5_GDdefvrtregion(i_gridid, i_regionid, i_vertobj, (double*)i_range);
    regionid = INT2NUM(o_rtn_val);
    hdfeos5_freecfloatary(i_range);

    return(regionid);
}

VALUE
hdfeos5_gddeftimeperiod(VALUE mod, VALUE periodid, VALUE starttime, VALUE stoptime)
{
    hid_t i_gridid;
    hid_t i_periodid;
    double i_starttime;
    double i_stoptime;
    hid_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    if (TYPE(starttime) != T_FLOAT) {
      starttime = rb_funcall(starttime, rb_intern("to_f"), 0);
    }
    if (TYPE(stoptime) != T_FLOAT) {
      stoptime = rb_funcall(stoptime, rb_intern("to_f"), 0);
    }

    i_periodid = NUM2INT(periodid);
    i_starttime = (double)NUM2DBL(starttime);
    i_stoptime = (double)NUM2DBL(stoptime);

    o_rtn_val = HE5_GDdeftimeperiod(i_gridid, i_periodid, i_starttime, i_stoptime);
    rtn_val = INT2NUM(o_rtn_val);
    return(rtn_val);
}

VALUE
hdfeos5_gdgetpixels(VALUE mod, VALUE nlonlat, VALUE lonval, VALUE latval)
{
    hid_t i_gridid;
    long  i_nlonlat;
    float *i_lonval;
    float *i_latval;
    void *o_pixrow;
    void *o_pixval;
    hid_t o_rtn_val;
    VALUE pixrow;
    VALUE pixval;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(nlonlat,T_FIXNUM);
    i_nlonlat = NUM2INT(nlonlat);
    if (TYPE(lonval) == T_FLOAT) {
      lonval = rb_Array(lonval);
    }
    i_lonval = hdfeos5_obj2cfloatary(lonval);
    if (TYPE(latval) == T_FLOAT) {
      latval = rb_Array(latval);
    }
    i_latval = hdfeos5_obj2cfloatary(latval);

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_LONG, i_nlonlat, &pixrow, &o_pixrow); 
    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_LONG, i_nlonlat, &pixval, &o_pixval); 
    o_rtn_val = HE5_GDgetpixels(i_gridid, i_nlonlat, (double*)i_lonval, (double*)i_latval, o_pixrow, o_pixval);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",
                   __FILE__,__LINE__);
    hdfeos5_freecfloatary(i_lonval);
    hdfeos5_freecfloatary(i_latval);
    return rb_ary_new3(2, pixrow, pixval);
}

VALUE
hdfeos5_gdgetpixvalues(VALUE mod, VALUE npixels, VALUE pixrow, VALUE pixcol)
{
    hid_t i_gridid;
    char  *i_fieldname;
    long   i_npixels;
    long   *i_pixrow;
    long   *i_pixcol;
    void *o_buffer;
    hid_t o_rtn_val;
    VALUE rtn_val;
    VALUE buffer;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;

    Check_Type(npixels,T_FIXNUM);
    i_npixels = NUM2INT(npixels);
    pixrow = rb_Array(pixrow);
    i_pixrow = hdfeos5_obj2clongary(pixrow);
    pixcol = rb_Array(pixcol);
    i_pixcol = hdfeos5_obj2clongary(pixcol);

    o_buffer = (void*)malloc(HE5_BLKSIZE);
    o_rtn_val = HE5_GDgetpixvalues(i_gridid, i_npixels, i_pixrow, i_pixcol, i_fieldname, o_buffer);
    hdfeos5_freeclongary(i_pixrow);
    hdfeos5_freeclongary(i_pixcol);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    buffer = rb_str_new2(o_buffer);

    return rb_ary_new3(2, rtn_val, buffer);
}

VALUE
hdfeos5_gdinterpolate(VALUE mod, VALUE nvalues, VALUE lonval, VALUE latval)
{
    hid_t i_gridid;
    char  *i_fieldname;
    long   i_nvalues;
    double *i_lonval;
    double *i_latval;
    void *o_interpval;
    hid_t o_rtn_val;
    VALUE interpval;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;

    Check_Type(nvalues,T_FIXNUM);
    i_nvalues = NUM2INT(nvalues);
    if (TYPE(lonval) == T_FLOAT) {
      lonval = rb_Array(lonval);
    }
    i_lonval = (double*)hdfeos5_obj2cfloatary(latval);
    if (TYPE(latval) == T_FLOAT) {
      latval = rb_Array(latval);
    }
    i_latval = (double*)hdfeos5_obj2cfloatary(latval);

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_DOUBLE, i_nvalues, &interpval, &o_interpval); 
    o_rtn_val = HE5_GDinterpolate(i_gridid, i_nvalues, i_lonval, i_latval, i_fieldname, o_interpval);
    hdfeos5_freecfloatary((float*)i_lonval);
    hdfeos5_freecfloatary((float*)i_latval);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",
                   __FILE__,__LINE__);
    return (interpval);
}

VALUE
hdfeos5_gdwritelocattr(VALUE mod, VALUE attrname, VALUE numbertype, VALUE count, VALUE datbuf)
{
    hid_t i_gridid;
    char *i_fieldname;
    char *i_attrname;
    hid_t i_numbertype;
    hid_t i_numbertypechk;
    unsigned long long *i_count;
    void *i_datbuf;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    count = rb_Array(count);

    i_attrname = RSTRING_PTR(attrname);
    i_numbertype    = change_numbertype(RSTRING_PTR(numbertype));
    i_numbertypechk = check_numbertype(RSTRING_PTR(numbertype));
    i_count = hdfeos5_obj2cunsint64ary(count);

    HE5Wrap_store_NArray1D_or_str(i_numbertypechk, datbuf, &i_datbuf); 
    o_rtn_val = HE5_GDwritelocattr(i_gridid, i_fieldname, i_attrname, i_numbertype, i_count, i_datbuf);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecunsint64ary(i_count);
    return rtn_val;
}

VALUE
hdfeos5_gdfield_get_att(VALUE mod,VALUE  attrname)
{
    VALUE result;
    hid_t i_gridid;
    char *i_fieldname;
    char *i_attrname;
    void *o_datbuf;
    herr_t o_rtn_val;
    hid_t  o_ntype;
    unsigned long long o_count;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;
    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    i_attrname = RSTRING_PTR(attrname);

    o_rtn_val = HE5_GDlocattrinfo(i_gridid, i_fieldname, i_attrname, 
                  &o_ntype, &o_count);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",
                   __FILE__,__LINE__);

    HE5Wrap_make_NArray1D_or_str(o_ntype, o_count, &result, &o_datbuf);
    o_rtn_val = HE5_GDreadlocattr(i_gridid, i_fieldname,i_attrname, o_datbuf);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",
                   __FILE__,__LINE__);
    return result;
}

VALUE
hdfeos5_gdinqlocattrs(VALUE mod)
{
    hid_t i_gridid;
    char *i_fieldname;
    char *o_attrnames;
    long o_strbufsize;
    long o_nattr;
    VALUE nattr;
    VALUE attrname;
    VALUE strbufsize;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;
    i_gridid=he5field->gdid;

    o_nattr = HE5_GDinqlocattrs(i_gridid, i_fieldname, NULL, &o_strbufsize);
    if(o_nattr < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
 
    o_attrnames = ALLOCA_N(char, (o_strbufsize + 1));
    o_nattr = HE5_GDinqlocattrs(i_gridid, i_fieldname, o_attrnames, &o_strbufsize);
    if(o_nattr < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    nattr = LONG2NUM(o_nattr);
    attrname = rb_str_new(o_attrnames,o_strbufsize);
    strbufsize = LONG2NUM(o_strbufsize);
    return rb_ary_new3(3, nattr, attrname, strbufsize);
}

VALUE
hdfeos5_gdwritegrpattr(VALUE mod, VALUE attrname, VALUE numbertype, VALUE count, VALUE datbuf)
{
    hid_t i_gridid;
    char *i_attrname;
    hid_t i_numbertype;
    hid_t i_numbertypechk;
    unsigned long long *i_count;
    void *i_datbuf;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    count = rb_Array(count);

    i_attrname = RSTRING_PTR(attrname);
    i_numbertype    = change_numbertype(RSTRING_PTR(numbertype));
    i_numbertypechk = check_numbertype(RSTRING_PTR(numbertype));
    i_count = hdfeos5_obj2cunsint64ary(count);
    i_datbuf = hdfeos5_obj2cfloatary(datbuf);

    HE5Wrap_store_NArray1D_or_str(i_numbertypechk, datbuf, &i_datbuf); 
    o_rtn_val = HE5_GDwritegrpattr(i_gridid, i_attrname, i_numbertype, i_count, i_datbuf);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecunsint64ary(i_count);
    return(rtn_val);
}

VALUE
hdfeos5_gd_get_grpatt(VALUE mod, VALUE attrname)
{
    VALUE result;
    hid_t i_gridid;
    char *i_attrname;
    hid_t o_ntype;
    void *o_datbuf;
    unsigned long long o_count;
    herr_t o_rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    i_attrname = RSTRING_PTR(attrname);

    o_rtn_val = HE5_GDgrpattrinfo(i_gridid, i_attrname, &o_ntype, &o_count);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    HE5Wrap_make_NArray1D_or_str(o_ntype, o_count, &result, &o_datbuf);
    o_rtn_val = HE5_GDreadgrpattr(i_gridid, i_attrname, o_datbuf);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    return result;
}

VALUE
hdfeos5_gdsetextdata(VALUE mod, VALUE filelist, VALUE offset, VALUE size)
{
    hid_t i_gridid;
    char  *i_filelist;
    off_t *i_offset;
    unsigned long long *i_size;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(filelist,T_STRING);
    SafeStringValue(filelist);
    if ((TYPE(offset) == T_BIGNUM) || (TYPE(offset) == T_FIXNUM)) {
      offset = rb_Array(offset);
    }
    if ((TYPE(size) == T_BIGNUM) || (TYPE(size) == T_FIXNUM)) {
      size = rb_Array(size);
    }
    i_filelist = RSTRING_PTR(filelist);
    i_offset = hdfeos5_obj2clongary(offset);
    i_size = hdfeos5_obj2cunsint64ary(size);

    o_rtn_val = HE5_GDsetextdata(i_gridid, i_filelist, i_offset, i_size);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freeclongary(i_offset);
    hdfeos5_freecunsint64ary(i_size);
    return rtn_val;
}

VALUE
hdfeos5_gdgetextdata(VALUE mod, VALUE fieldname)
{
    hid_t i_gridid;
    char *i_fieldname;
    size_t o_namelength=0;
    char  o_filelist[maxcharsize];
    off_t o_offset[maxcharsize];
    unsigned long long o_size[maxcharsize];
    int o_nfiles;
    VALUE nfiles;
    VALUE namelength;
    VALUE filelist;
    VALUE offset;
    VALUE size;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);

    i_fieldname = RSTRING_PTR(fieldname);

    o_nfiles = HE5_GDgetextdata(i_gridid, i_fieldname, o_namelength, o_filelist, o_offset, o_size);
    nfiles = INT2NUM(o_nfiles);
    
    namelength = hdfeos5_cintary2obj((int*)o_namelength,o_nfiles,1,&o_nfiles);
    filelist = hdfeos5_ccharary2obj(o_filelist,o_nfiles,o_nfiles);
    offset = hdfeos5_clongary2obj(o_offset,o_nfiles,1,&o_nfiles);
    size = hdfeos5_cunsint64ary2obj(o_size,o_nfiles,1,&o_nfiles);

    return rb_ary_new3(5,nfiles, namelength, filelist, offset, size);
}

VALUE
hdfeos5_gdsetalias(VALUE mod, VALUE fieldname)
{
    hid_t i_gridid;
    char *i_fieldname;
    char o_aliaslist[maxcharsize]="";
    herr_t o_rtn_val;
    VALUE aliaslist;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    i_fieldname = RSTRING_PTR(fieldname);

    o_rtn_val = HE5_GDsetalias(i_gridid, i_fieldname, o_aliaslist);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    aliaslist = rb_str_new2(o_aliaslist);
    return aliaslist;
}

VALUE
hdfeos5_gddropalias(VALUE mod, VALUE fldgroup, VALUE aliasname)
{
    hid_t i_gridid;
    int i_fldgroup;
    char *i_aliasname;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    Check_Type(aliasname,T_STRING);
    SafeStringValue(aliasname);

    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));
    i_aliasname = RSTRING_PTR(aliasname);

    o_rtn_val = HE5_GDdropalias(i_gridid, i_fldgroup, i_aliasname);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return rtn_val;
}

VALUE
hdfeos5_gdaliasinfo(VALUE mod, VALUE fldgroup, VALUE aliasname)
{
    hid_t i_gridid;
    int i_fldgroup;
    char *i_aliasname;
    int o_length;
    char o_buffer[maxcharsize]="";
    long o_rtn_val;
    VALUE rtn_val;
    VALUE length;
    VALUE buffer;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    Check_Type(aliasname,T_STRING);
    SafeStringValue(aliasname);

    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));
    i_aliasname = RSTRING_PTR(aliasname);

    o_rtn_val = HE5_GDaliasinfo(i_gridid, i_fldgroup, i_aliasname, &o_length, o_buffer);
    rtn_val = LONG2NUM(o_rtn_val);
    length = INT2NUM(o_length);
    buffer = rb_str_new2(o_buffer);
    return rb_ary_new3(3, rtn_val, length, buffer);
}


VALUE
hdfeos5_gdinqfldalias(VALUE mod)
{
    hid_t i_gridid;
    char *o_fldalias="";
/*   ·³io_fldalias)
    */
    long o_strbufsize;
    long o_nfldalias;
    VALUE nfldalias;
    VALUE fldalias;
    VALUE strbufsize;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    o_nfldalias = HE5_GDinqfldalias(i_gridid, o_fldalias, &o_strbufsize);
    if(o_nfldalias < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    nfldalias = LONG2NUM(o_nfldalias);
    fldalias = rb_str_new2(o_fldalias);
    strbufsize = LONG2NUM(o_strbufsize);
    return rb_ary_new3(3, nfldalias, fldalias, strbufsize);
}

VALUE
hdfeos5_gdgetaliaslist(VALUE mod, VALUE fldgroup)
{
    hid_t i_gridid;
    int i_fldgroup;
    char o_aliaslist[maxcharsize]="";
    long o_strbufsize;
    long o_nalias;
    VALUE nalias;
    VALUE aliaslist;
    VALUE strbufsize;

    struct HE5Gd *he5grid;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));

    o_nalias = HE5_GDgetaliaslist(i_gridid, i_fldgroup, o_aliaslist, &o_strbufsize);
    nalias = LONG2NUM(o_nalias);
    aliaslist = rb_str_new2(o_aliaslist);
    strbufsize = INT2NUM(o_strbufsize);
    return rb_ary_new3(3, nalias, aliaslist, strbufsize);
}

VALUE
hdfeos5_swchkgrid(VALUE mod)
{
    char *i_filename;
    long o_strbufsize;
    long o_rtn_val;

    struct HE5 *he5file;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_filename=he5file->name;

    o_rtn_val = HE5_GDinqgrid(i_filename, NULL, &o_strbufsize);
    if( o_rtn_val <= 0) return Qfalse;
    return Qtrue;
}

VALUE
hdfeos5_swchkgridname(VALUE mod)
{
    char *i_filename;
    char *o_gridlist;
    long o_strbufsize;
    long o_rtn_val;
    VALUE rstr;

    struct HE5 *he5file;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_filename=he5file->name;

    o_rtn_val = HE5_GDinqgrid(i_filename, NULL, &o_strbufsize);
    if( o_rtn_val <= 0) return Qfalse;
    o_gridlist = ALLOCA_N(char, (o_strbufsize + 1));

    o_rtn_val = HE5_GDinqgrid(i_filename, o_gridlist, &o_strbufsize);
    if( o_rtn_val <= 0) return Qfalse;
    rstr = rb_str_new(o_gridlist, o_strbufsize);
    return rstr;
}

VALUE
hdfeos5_gdsetfield(VALUE mod,VALUE fieldname)
{
    int i_gridid;
    char *i_fieldname;
    struct HE5Gd *he5grid;
    struct HE5GdField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Gd, he5grid);
    i_gridid=he5grid->gdid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    i_fieldname = RSTRING_PTR(fieldname);
    
    he5field = HE5GdField_init(i_fieldname, i_gridid, mod);
    return(Data_Wrap_Struct(cHE5GdField, he5gdfield_mark_obj, HE5GdField_free, he5field));
}

VALUE
hdfeos5_gdgetfield(VALUE mod)
{
    char *i_fieldname;
    struct HE5GdField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fieldname=he5field->name;

    return rb_str_new2(i_fieldname);
}

VALUE 
hdfeos5_grid_whether_in_define_mode(VALUE gd)
{
    int fid;
    hid_t HDFfid = FAIL;
    hid_t gid = FAIL;
    uintn access = 0;
    int status;
    struct HE5Gd *he5grid;
  
    Data_Get_Struct(gd, struct HE5Gd, he5grid);
    fid=he5grid->fid;

    status = HE5_EHchkfid(fid, "HE5_GDcreate", &HDFfid,  &gid, &access);
    if(status != FAIL){
      return Qtrue;
    }else {
      status = HE5_EHchkfid(fid, "HE5_GDattach", &HDFfid,  &gid, &access);
      if(status != FAIL){
        return Qtrue;
      } else {
        return Qnil;
      }
    }
}

VALUE
hdfeos5_gd_path(VALUE gd)
{
    char *i_name;
    struct HE5Gd *he5grid;
  
    Data_Get_Struct(gd, struct HE5Gd, he5grid);

    i_name=he5grid->name;
    return rb_str_new2(i_name);
}

VALUE
hdfeos5_gd_inqname(VALUE gd)
{
    char *i_name;
    struct HE5Gd *he5grid;
  
    Data_Get_Struct(gd, struct HE5Gd, he5grid);

    i_name=he5grid->name;
    return rb_str_new2(i_name);
}

VALUE
hdfeos5_gd_file(VALUE gd)
{
    struct HE5Gd *he5grid;
  
    rb_secure(4);
    Data_Get_Struct(gd, struct HE5Gd, he5grid);
    return(he5grid->file);
}

VALUE
hdfeos5_gdfld_grid(VALUE field)
{
    struct HE5GdField *he5field;

    rb_secure(4);
    Data_Get_Struct(field, struct HE5GdField, he5field);
    return(he5field->grid);
}

VALUE
hdfeos5_gdfld_inqname(VALUE field)
{
    char *i_name;
    struct HE5GdField *he5field;

    rb_secure(4);
    Data_Get_Struct(field, struct HE5GdField, he5field);

    i_name=he5field->name;
    return rb_str_new2(i_name);
}

VALUE
hdfeos5_gdwritefield_char(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE data)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_edge_all=1;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    unsigned char  scalar,*i_data;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }

    Array_to_Cbyte_len_shape(data,i_data,len,shape);
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=shape[i];
      }
      c_edge_all=len;
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
        c_edge_all=c_edge[i]*c_edge_all;
      }
      if(len == 1 && len != c_edge_all){
    scalar = *i_data;
    i_data = ALLOCA_N(unsigned char,c_edge_all);
    for(i=0;i<c_edge_all;i++){i_data[i]=scalar;}
      } else if(len != c_edge_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_GDwritefield(i_gridid, i_fldname, c_start, c_stride, c_edge, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_gdwritefield_short(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE data)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_edge_all=1;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    short scalar,*i_data;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }

    Array_to_Cshort_len_shape(data,i_data,len,shape);
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=shape[i];
      }
      c_edge_all=len;
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i]);
        if(l_edge < 0) {
	  l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
        c_edge_all=c_edge[i]*c_edge_all;
      }
      if(len == 1 && len != c_edge_all){
	scalar = *i_data;
	i_data = ALLOCA_N(short,c_edge_all);
	for(i=0;i<c_edge_all;i++){i_data[i]=scalar;}
      } else if(len != c_edge_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_GDwritefield(i_gridid, i_fldname, c_start, c_stride, c_edge, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_gdwritefield_int(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE data)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_edge_all=1;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    int scalar,*i_data;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }

    Array_to_Cint_len_shape(data,i_data,len,shape);
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=shape[i];
      }
      c_edge_all=len;
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
        c_edge_all=c_edge[i]*c_edge_all;
      }
      if(len == 1 && len != c_edge_all){
    scalar = *i_data;
    i_data = ALLOCA_N(int,c_edge_all);
    for(i=0;i<c_edge_all;i++){i_data[i]=scalar;}
      } else if(len != c_edge_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_GDwritefield(i_gridid, i_fldname, c_start, c_stride, c_edge, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_gdwritefield_long(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE data)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_edge_all=1;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    long scalar,*i_data;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }

    Array_to_Clong_len_shape(data,i_data,len,shape);
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=shape[i];
      }
      c_edge_all=len;
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
        c_edge_all=c_edge[i]*c_edge_all;
      }
      if(len == 1 && len != c_edge_all){
    scalar = *i_data;
    i_data = ALLOCA_N(long,c_edge_all);
    for(i=0;i<c_edge_all;i++){i_data[i]=scalar;}
      } else if(len != c_edge_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_GDwritefield(i_gridid, i_fldname, c_start, c_stride, c_edge, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_gdwritefield_float(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE data)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_edge_all=1;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    float scalar,*i_data;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }

    Array_to_Cfloat_len_shape(data,i_data,len,shape);
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=shape[i];
      }
      c_edge_all=len;
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
        c_edge_all=c_edge[i]*c_edge_all;
      }
      if(len == 1 && len != c_edge_all){
    scalar = *i_data;
    i_data = ALLOCA_N(float,c_edge_all);
    for(i=0;i<c_edge_all;i++){i_data[i]=scalar;}
      } else if(len != c_edge_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_GDwritefield(i_gridid, i_fldname, c_start, c_stride, c_edge, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_gdwritefield_double(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE data)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_edge_all=1;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    double scalar,*i_data;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }

    Array_to_Cdouble_len_shape(data,i_data,len,shape);
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=shape[i];
      }
      c_edge_all=len;
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
        c_edge_all=c_edge[i]*c_edge_all;
      }
      if(len == 1 && len != c_edge_all){
    scalar = *i_data;
    i_data = ALLOCA_N(double,c_edge_all);
    for(i=0;i<c_edge_all;i++){i_data[i]=scalar;}
      } else if(len != c_edge_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }
    status = HE5_GDwritefield(i_gridid, i_fldname, c_start, c_stride, c_edge, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_gdreadfield_char(VALUE mod, VALUE start, VALUE stride, VALUE edge)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
           __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
           __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i_rank-1-i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_edge[i];
    }
    Cbyte_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_GDreadfield(i_gridid, i_fldname, c_start, c_stride, c_edge, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_gdreadfield_short(VALUE mod, VALUE start, VALUE stride, VALUE edge)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
           __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
           __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i_rank-1-i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_edge[i];
    }
    Cshort_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_GDreadfield(i_gridid, i_fldname, c_start, c_stride, c_edge, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_gdreadfield_int(VALUE mod, VALUE start, VALUE stride, VALUE edge)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
           __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
           __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i_rank-1-i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_edge[i];
    }
    Cint_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_GDreadfield(i_gridid, i_fldname, c_start, c_stride, c_edge, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_gdreadfield_long(VALUE mod, VALUE start, VALUE stride, VALUE edge)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
           __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
           __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i_rank-1-i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_edge[i];
    }
    Clong_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_GDreadfield(i_gridid, i_fldname, c_start, c_stride, c_edge, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_gdreadfield_float(VALUE mod, VALUE start, VALUE stride, VALUE edge)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
           __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
           __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i_rank-1-i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_edge[i];
    }
    Cfloat_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_GDreadfield(i_gridid, i_fldname, c_start, c_stride, c_edge, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_gdreadfield_double(VALUE mod, VALUE start, VALUE stride, VALUE edge)
{
    hid_t i_gridid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_edge;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_edge;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5GdField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5GdField, he5field);
    i_fldname=he5field->name;
    i_gridid=he5field->gdid;

    status = HE5_GDfieldinfo(i_gridid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
           __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);    
      if(l_start < 0) {
    l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
      c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
           __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
    c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
    if(c_stride[i]==0) {
      rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
    }
      }
    }
    c_edge=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(edge)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_edge[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(edge,T_ARRAY);
      if(RARRAY_LEN(edge) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_edge= NUM2INT(RARRAY_PTR(edge)[i_rank-1-i]);
        if(l_edge < 0) {
      l_edge +=hs_dims[i];
        }
        c_edge[i]=(l_edge-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_edge[i];
    }

    Cdouble_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_GDreadfield(i_gridid, i_fldname, c_start, c_stride, c_edge, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

void
init_hdfeos5gd_wrap(void)
{
    mNumRu = rb_define_module("NumRu");

    /* Difinitions of the classes */;
    cHE5 = rb_define_class_under(mNumRu, "HE5",rb_cObject);
    cHE5Gd = rb_define_class_under(mNumRu, "HE5Gd",rb_cObject);
    cHE5GdField = rb_define_class_under(mNumRu, "HE5GdField",rb_cObject);
    rb_eHE5Error = rb_define_class("HE5Error",rb_eStandardError);

    /* Class Constants Definition */
    /* Difinitions of the HE5 Class */;
    rb_define_method(cHE5, "gdcreate", hdfeos5_gdcreate, 5);
    rb_define_method(cHE5, "gdattach", hdfeos5_gdattach, 1);
    rb_define_method(cHE5, "inqgrid", hdfeos5_gdinqgrid, 0);

    /* Original of the HE5 Class */;
    rb_define_method(cHE5, "chkgrid", hdfeos5_swchkgrid, 0);
    rb_define_method(cHE5, "chkgridname", hdfeos5_swchkgridname, 0);

    /* Difinitions of the HE5 Grid Class */
    rb_define_method(cHE5Gd, "defdim", hdfeos5_gddefdim, 2);
    rb_define_method(cHE5Gd, "defproj", hdfeos5_gddefproj, 4);
    rb_define_method(cHE5Gd, "blksomoffset", hdfeos5_gdblksomoffset, 3);
    rb_define_method(cHE5Gd, "defcomp", hdfeos5_gddefcomp, 2);
    rb_define_method(cHE5Gd, "deftile", hdfeos5_gddeftile, 3);
    rb_define_method(cHE5Gd, "defcomtile", hdfeos5_gddefcomtile, 4);
    rb_define_method(cHE5Gd, "deforigin", hdfeos5_gddeforigin, 1);
    rb_define_method(cHE5Gd, "defpixreg", hdfeos5_gddefpixreg, 1);
    rb_define_method(cHE5Gd, "diminfo", hdfeos5_gddiminfo, 1);
    rb_define_method(cHE5Gd, "gridinfo", hdfeos5_gdgridinfo, 0);
    rb_define_method(cHE5Gd, "projinfo", hdfeos5_gdprojinfo, 0);
    rb_define_method(cHE5Gd, "origininfo", hdfeos5_gdorigininfo, 0);
    rb_define_method(cHE5Gd, "pixreginfo", hdfeos5_gdpixreginfo, 0);
    rb_define_method(cHE5Gd, "deffield", hdfeos5_gddeffield, 5);
    rb_define_method(cHE5Gd, "writefieldmeta", hdfeos5_gdwritefieldmeta, 2);
    rb_define_method(cHE5Gd, "writeattr", hdfeos5_gdwriteattr, 4);
    rb_define_method(cHE5Gd, "setfillvalue", hdfeos5_gdsetfillvalue, 3);
    rb_define_method(cHE5Gd, "getfillvalue", hdfeos5_gdgetfillvalue, 1);
    rb_define_method(cHE5Gd, "inqdatatype", hdfeos5_gdinqdatatype, 3);
    rb_define_method(cHE5Gd, "nentries", hdfeos5_gdnentries, 1);
    rb_define_method(cHE5Gd, "gddetach", hdfeos5_gddetach, 0);
    rb_define_method(cHE5Gd, "inqdims", hdfeos5_gdinqdims, 1);
    rb_define_method(cHE5Gd, "inqattrs", hdfeos5_gdinqattrs, 0);
    rb_define_method(cHE5Gd, "inqfields", hdfeos5_gdinqfields, 1);
    rb_define_method(cHE5Gd, "rs2ll", hdfeos5_gdrs2ll, 11);
    rb_define_method(cHE5Gd, "defboxregion", hdfeos5_gddefboxregion, 2);
    rb_define_method(cHE5Gd, "regioninfo", hdfeos5_gdregioninfo, 1);
    rb_define_method(cHE5Gd, "extractregion", hdfeos5_gdextractregion, 1);
    rb_define_method(cHE5Gd, "dupregion", hdfeos5_gddupregion, 1);
    rb_define_method(cHE5Gd, "defvrtregion", hdfeos5_gddefvrtregion, 3);
    rb_define_method(cHE5Gd, "deftimeperiod", hdfeos5_gddeftimeperiod, 3);
    rb_define_method(cHE5Gd, "getpixels", hdfeos5_gdgetpixels, 3);
    rb_define_method(cHE5Gd, "getpixvalues", hdfeos5_gdgetpixvalues, 3);
    rb_define_method(cHE5Gd, "interpolate", hdfeos5_gdinterpolate, 3);
    rb_define_method(cHE5Gd, "writegrpattr", hdfeos5_gdwritegrpattr, 4);
    rb_define_method(cHE5Gd, "get_grpatt_", hdfeos5_gd_get_grpatt, 1);
    rb_define_method(cHE5Gd, "setextdata", hdfeos5_gdsetextdata, 3);
    rb_define_method(cHE5Gd, "getextdata", hdfeos5_gdgetextdata, 1);
    rb_define_method(cHE5Gd, "setalias", hdfeos5_gdsetalias, 1);
    rb_define_method(cHE5Gd, "dropalias", hdfeos5_gddropalias, 2);
    rb_define_method(cHE5Gd, "aliasinfo", hdfeos5_gdaliasinfo, 2);
    rb_define_method(cHE5Gd, "inqfldalias", hdfeos5_gdinqfldalias, 0);
    rb_define_method(cHE5Gd, "getaliaslist", hdfeos5_gdgetaliaslist, 1);

    /* Original of the HE5 Grid Class */;
    rb_define_method(cHE5Gd, "file", hdfeos5_gd_file, 0);
    rb_define_method(cHE5Gd, "name", hdfeos5_gd_inqname, 0);
    rb_define_method(cHE5Gd, "define_mode?", hdfeos5_grid_whether_in_define_mode, 0);
    rb_define_method(cHE5Gd, "get_att_", hdfeos5_gd_get_att, 1);
    rb_define_method(cHE5Gd, "setfield", hdfeos5_gdsetfield, 1);

    /* Difinitions of the HE5 Grid Field Class */;
    rb_define_method(cHE5GdField, "tileinfo", hdfeos5_gdtileinfo, 0);
    rb_define_method(cHE5GdField, "compinfo", hdfeos5_gdcompinfo, 0);
    rb_define_method(cHE5GdField, "fieldinfo", hdfeos5_gdfieldinfo, 0);
    rb_define_method(cHE5GdField, "writefield", hdfeos5_gdwritefield, 5);
    rb_define_method(cHE5GdField, "readfield", hdfeos5_gdreadfield, 4);
    rb_define_method(cHE5GdField, "get_att_", hdfeos5_gdfield_get_att, 1);
    rb_define_method(cHE5GdField, "inqlocattrs", hdfeos5_gdinqlocattrs, 0);
    rb_define_method(cHE5GdField, "writelocattr", hdfeos5_gdwritelocattr, 4);

    rb_define_method(cHE5GdField, "put_vars_char", hdfeos5_gdwritefield_char, 4);
    rb_define_method(cHE5GdField, "put_vars_int", hdfeos5_gdwritefield_int, 4);
    rb_define_method(cHE5GdField, "put_vars_long", hdfeos5_gdwritefield_long, 4);
    rb_define_method(cHE5GdField, "put_vars_float", hdfeos5_gdwritefield_float, 4);
    rb_define_method(cHE5GdField, "put_vars_double", hdfeos5_gdwritefield_double, 4);
    rb_define_method(cHE5GdField, "put_vars_short", hdfeos5_gdwritefield_short, 4);
    
    rb_define_method(cHE5GdField, "get_vars_char", hdfeos5_gdreadfield_char, 3);
    rb_define_method(cHE5GdField, "get_vars_int", hdfeos5_gdreadfield_int, 3);
    rb_define_method(cHE5GdField, "get_vars_long", hdfeos5_gdreadfield_long, 3);
    rb_define_method(cHE5GdField, "get_vars_float", hdfeos5_gdreadfield_float, 3);
    rb_define_method(cHE5GdField, "get_vars_double", hdfeos5_gdreadfield_double, 3);
    rb_define_method(cHE5GdField, "get_vars_short", hdfeos5_gdreadfield_short, 3);

    /* Original of the HE5 Grid Field Class */;
    rb_define_method(cHE5GdField, "grid", hdfeos5_gdfld_grid, 0);
    rb_define_method(cHE5GdField, "name", hdfeos5_gdfld_inqname, 0);
    rb_define_method(cHE5GdField, "setfield", hdfeos5_gdsetfield, 1);
    rb_define_method(cHE5GdField, "getfield", hdfeos5_gdgetfield, 0);
}
