/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by  The HDF Group and                                           *
 * The Board of Trustees of the University of Illinois.                      *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of H4H5TOOLS. The full H4H5TOOLS copyright notice,      *
 * including terms governing use, modification, and redistribution, is       *
 * contained in the COPYING file, which can be found at the root of the      *
 * source code distribution tree. The copyright notice can also be found     *
 * at https://www.hdfgroup.org/licenses.  If you do not have access to       *
 * either file, you may request a copy from help@hdfgroup.org.               *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/******************************************************************************

    Description: 

1. h4toh5 converter library API

See HDF4 to HDF5 mapping specification at
(https://support.hdfgroup.org/products/hdf5_tools/h4toh5/) for the default mapping 
from HDF4 object to HDF5 object.
 
The whole h4toh5 library APIs include 10 files, h4toh5util.h, h4toh5main.h, h4toh5util.c, h4toh5main.c, h4toh5sds.c, h4toh5image.c,h4toh5vdata.c,h4toh5vgroup.c,h4toh5pal.c and h4toh5anno.c.

2. this file 

This file includes four h4toh5 open and close APIs,
 H4toH5open(char* filename1,char* filename2); 
H4toH5close(hid_t h4toh5id); 
H4toH5glo_sds_attr(hid_t h4toh5id);
H4toH5_gloimageattr(hid_t h4toh5id);

Author:  Kent Yang(myang6@hdfgroup.org)
 

*****************************************************************************/


#include "h4toh5main.h"

/*-------------------------------------------------------------------------
 * Function:    H4toH5open_id
 *
 * Purpose:         The alternative starting up function of
                                h4toh5 library. HDF5 file id is passed as a parameter of
        this function. 
                                Users should use this function and h4toh5close to finish
        conversion
 *                          
 * Return:  -1 if failed, otherwise returning the index id of the table.
 *
 * In :              
                                filename: HDF4 filename
                                file5_id: HDF5 file id

                             
     Out:  
     Modification:           
 *-------------------------------------------------------------------------
 */ 

hid_t H4toH5open_id(char* filename,hid_t file5_id) {

    /* define variables for hdf4. */
    int32  istat; /* hdf4 library routine return value. */
    int32  file_id;/* file identfier of hdf file.*/
    int32  sd_id;/* sd interface identifer*/
    int32  gr_id;/* gr interface identifer*/
    int32  num_sds; /* number of SDS objects */
    int32  num_images; /* number of image objects */
    int32  num_glsdsattrs; /* number of global SD interface attributes */
    int32  num_glgrattrs; /* number of global GR interface attributes */
    short  use_dims = 0;
    /* char str_version[VER_LEN]; */ /* H4toH5 library version */
    int      ret_value = FAIL;  /* index id of the ID handler */
    h4toh5id_t *dt; /*  pointer to h4toh5 id struct for 
                    passing parameters of error handlings */


    /* write down the version number */
    /* For this release, we opt LIBH4TOH5_VERSION out. In the future release, we may use other way to record library version. */
    /* strncpy(str_version,LIBH4TOH5_VERSION,VER_LEN); */

    dt = malloc(sizeof(h4toh5id_t));
    if(dt==NULL) return FAIL;
    init_h4toh5id_t(dt);
    dt->h4toh5error = NULL;

    if (H4TOH5I_init_group(H4TOH5I_H4TOH5, H4TOH5I_HASHSIZE,
                 0, NULL)<0) {
        H4toH5error_set(dt,3,"cannot initialize hdf5 error handler",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if((ret_value=H4TOH5I_register(H4TOH5I_H4TOH5,dt))<0) {
        H4toH5error_set(dt,3,"unable to register h4toh5 id handler",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /* check whether this file is an hdf4 file. */
#ifndef WIN32

    if(test_file(filename,O_EXCL,292) != 0) {
        H4toH5error_set(dt,5,"the current hdf4file name is not set properly",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if (test_dir(filename) != 0 ) {
        H4toH5error_set(dt,5,"the current hdf4file name is a directory",
                 __FILE__,__LINE__);
        return FAIL;
    }
#endif

#if 0
    if(!Hishdf(filename)){
        H4toH5error_set(dt,5,"the current file is not an hdf file",
                 __FILE__,__LINE__);
        return FAIL;
    }
#endif

    /*open the current hdf4 file. */
    if(check_filetype(filename)==FAIL){
         H4toH5error_set(dt,5,"the current file is not an hdf or netcdf file",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if(check_filetype(filename)==0){
        file_id = Hopen(filename, DFACC_READ, 0);
        if(file_id == FAIL) {
            H4toH5error_set(dt,2,"no such hdf4 files",__FILE__,__LINE__);
            return FAIL;
        }

        /* open sd interface.*/
        sd_id = SDstart(filename,DFACC_READ);
        if(sd_id == FAIL) {
            H4toH5error_set(dt,2,"cannot start SD interface",
                    __FILE__,__LINE__);
            Hclose(file_id);
            return FAIL;
        }

        /* open gr interface.*/
        gr_id = GRstart(file_id);
        if(gr_id == FAIL) {
            H4toH5error_set(dt,2,"cannot obtain gr id",
                     __FILE__,__LINE__);
            SDend(sd_id);
            Hclose(file_id);
            return FAIL;
        }

        /* open V interface. */
        istat = Vstart(file_id);
        if(istat == FAIL) {
            H4toH5error_set(dt,2,"cannot start V interface",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }

        /* obtain SDS and image information */
        if(SDfileinfo(sd_id,&num_sds,&num_glsdsattrs) == FAIL) {
            H4toH5error_set(dt,2,"cannot obtain SDS information from the file",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
    
        if(GRfileinfo(gr_id,&num_images,&num_glgrattrs) == FAIL) {
            H4toH5error_set(dt,2,"cannot start GR information from the file",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
 
        /* initialize SDS and image tables. */
        if(num_sds > 0) {
            dt->sds_hashtab = malloc(sizeof(struct table)*SDS_HASHSIZE);
            if(init_tab(ret_value,SDS_HASHSIZE,dt->sds_hashtab)== FAIL){
                H4toH5error_set(dt,5,"cannot initialize sds hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }
        }

        if(num_images > 0) {
            dt->gr_hashtab = malloc(sizeof(struct table)*IMAGE_HASHSIZE);
            if(init_tab(ret_value,IMAGE_HASHSIZE,dt->gr_hashtab) == FAIL){
                H4toH5error_set(dt,5,"cannot initialize image hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }
        }
        /*Initialize the dimensional scale table. 
        Size of dimensional scale is fixed.*/
        if(num_sds > 0) use_dims = 1;
#ifdef  HAVE_LIBHDFEOS
        /* HDF-EOS2 use vdata to store 1-D array for swath */
        dt->has_swath = 0;
        if(use_dims == 0) {
            int num_swath = H4toH5eos_num_swath(filename);
            if(num_swath >0) {
                use_dims = 1;
                dt->has_swath = 1;
            }
        }
#endif
 
        /*Initialize the dimensional scale table. 
            Size of dimensional scale is fixed.*/
        if(use_dims ==1) {  
            dt->moddim_hashtab = malloc(sizeof(struct modname_table)*DIM_HASHSIZE);
            if(init_modnametab(ret_value,DIM_HASHSIZE,dt->moddim_hashtab) == FAIL) {
                H4toH5error_set(dt,5,"cannot initialize dimension hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }

            dt->fakedim_hashtab = malloc(sizeof(struct table));
            if(init_tab2(ret_value,dt->fakedim_hashtab) == FAIL){
                H4toH5error_set(dt,5,"cannot initialize pure dimension table",
                                     __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }

            dt->puredim_hashtab = malloc(sizeof(struct name_table)*DIMPURE_HASHSIZE);
            if(init_nametab(ret_value,DIMPURE_HASHSIZE,dt->puredim_hashtab)== FAIL) {
                 H4toH5error_set(dt,5,"cannot initialize pure dim. name hashing table",__FILE__,
                     __LINE__);
                 SDend(sd_id);
                 GRend(gr_id);
                 Hclose(file_id);
                 return FAIL;
            }
 
            dt->dimscale_hashtab = malloc(sizeof(struct name_table)*DIMSCALE_HASHSIZE);
            if(init_nametab(ret_value,DIMSCALE_HASHSIZE,dt->dimscale_hashtab)== FAIL) {
                 H4toH5error_set(dt,5,"cannot initialize dim. scale name hashing table",__FILE__,
                     __LINE__);
                 SDend(sd_id);
                 GRend(gr_id);
                 Hclose(file_id);
                 return FAIL;
            }
        }

    
        /*Initialize the palette table. 
            Size of dimensional scale is fixed.*/
        if(num_images > 0){
            dt->pal_hashtab = malloc(sizeof(struct table)*PAL_HASHSIZE);
            if(init_tab(ret_value,PAL_HASHSIZE,dt->pal_hashtab) == FAIL) {
                H4toH5error_set(dt,5,"cannot initialize palette hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }
        }

        /* Initialize the vgroup table */
        dt->vg_hashtab = malloc(sizeof(struct table)*VG_HASHSIZE);
        if(init_tab(ret_value,VG_HASHSIZE,dt->vg_hashtab) == FAIL) {
            H4toH5error_set(dt,5,"cannot initialize vgroup hashing table",
                         __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }

        /* Initialize the vdata table.*/
        dt->vd_hashtab = malloc(sizeof(struct table)*VD_HASHSIZE);
        if(init_tab(ret_value,VD_HASHSIZE,dt->vd_hashtab)== FAIL) {
            H4toH5error_set(dt,5,"cannot initialize vdata hashing table",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
    
        /* Initialize the object name table. The object name table is only used 
         to handle the name clashing of HDF4 converted objects when users use
         being converted HDF4 object names as their new HDF5 object names.
         The table size is fixed as OBJECT_HASHSIZE. */
        dt->name_hashtab = malloc(sizeof(struct name_table)*OBJECT_HASHSIZE);
        if(init_nametab(ret_value,OBJECT_HASHSIZE,dt->name_hashtab)== FAIL) {
            H4toH5error_set(dt,5,"cannot initialize name hashing table",__FILE__,
                                 __LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
     
        /*Initialize the group name table. This group name table is only used to
         handle the name clashing when users provide their HDF5 object names */
        dt->h5groupname_table= malloc(sizeof(struct name_table)*NAME_HASHSIZE);
        if(init_nametab(ret_value,NAME_HASHSIZE,dt->h5groupname_table)==FAIL){
            H4toH5error_set(dt,5,"cannot initialize h5 group name hashing table",__FILE__,
                             __LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
    
        /* HDF4 file id, sd interface id, gr interface id are provided,
             HDF5 file id is also provided. */
        dt->file5_id = file5_id;
        dt->file_id  = file_id;
        dt->sd_id        = sd_id;
        dt->gr_id        = gr_id;
#ifdef HAVE_LIBHDFEOS
        dt->hdf4filename = filename;
        dt->gd_fd = -1;
        dt->sw_fd = -1;
        dt->pt_fd = -1;
#endif
    }

    else if(check_filetype(filename) == 1){/* netcdf file */
        
        sd_id = SDstart(filename,DFACC_READ);
        if(sd_id == FAIL) {
            H4toH5error_set(dt,2,"cannot start SD interface",
                    __FILE__,__LINE__);
            return FAIL;
        }
        
        if(SDfileinfo(sd_id,&num_sds,&num_glsdsattrs) == FAIL) {
            H4toH5error_set(dt,2,"cannot obtain SDS information from the file",
                 __FILE__,__LINE__);
            SDend(sd_id);
            return FAIL;
        }

        if(num_sds > 0) {
            dt->sds_hashtab = malloc(sizeof(struct table)*SDS_HASHSIZE);
            if(init_tab(ret_value,SDS_HASHSIZE,dt->sds_hashtab)== FAIL){
                H4toH5error_set(dt,5,"cannot initialize sds hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                return FAIL;
            }
         }

         /*Initialize the dimensional scale table. 
            Size of dimensional scale is fixed.*/
        if(num_sds > 0) {  
            dt->moddim_hashtab = malloc(sizeof(struct modname_table)*DIM_HASHSIZE);
            if(init_modnametab(ret_value,DIM_HASHSIZE,dt->moddim_hashtab) == FAIL) {
                H4toH5error_set(dt,5,"cannot initialize dimension hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                return FAIL;
            }
        }

        /* Initialize the object name table. The object name table is only used 
         to handle the name clashing of HDF4 converted objects when users use
         being converted HDF4 object names as their new HDF5 object names.
         The table size is fixed as OBJECT_HASHSIZE. */
        dt->name_hashtab = malloc(sizeof(struct name_table)*OBJECT_HASHSIZE);
        if(init_nametab(ret_value,OBJECT_HASHSIZE,dt->name_hashtab)== FAIL) {
            H4toH5error_set(dt,5,"cannot initialize name hashing table",__FILE__,
                         __LINE__);
            SDend(sd_id);
            return FAIL;
        }

        dt->h5groupname_table= malloc(sizeof(struct name_table)*NAME_HASHSIZE);
        if(init_nametab(ret_value,NAME_HASHSIZE,dt->h5groupname_table)==FAIL){
            H4toH5error_set(dt,5,"cannot initialize h5 group name hashing table",__FILE__,
                 __LINE__);
            SDend(sd_id);
            return FAIL;
        }

        /* HDF4 file id, sd interface id, gr interface id are provided,
         HDF5 file id is also provided. */
        dt->file5_id = file5_id;
        dt->sd_id        = sd_id;
        dt->file_id = -1;
#ifdef HAVE_LIBHDFEOS
        dt->hdf4filename = filename;
        dt->gd_fd = -1;
        dt->sw_fd = -1;
        dt->pt_fd = -1;
#endif  
    }
    return ret_value;
}


/*-------------------------------------------------------------------------
 * Function:    H4toH5open
 *
 * Purpose:         starting up function of H4toH5 library functions.
                                Users should use this function and H4toH5close for every
        objects that are converted
 *                          
 * Return:  -1 if failed, otherwise returning the index id of the table.
 *
 * In :  
                                filename: HDF4 file name
        file5name: HDF5 file name
        h425_access: HDF5 file access flag 
                                
                             
     Out:  
     Modification:           
 *-------------------------------------------------------------------------
 */ 

hid_t H4toH5open(char* filename,char* file5name,int h425_access) {

    /* define variables for HDF4. */
    char*  h5_extension; /* the extension name of HDF5 file */
    int32  istat; /* hdf4 library routine return value. */
    int32  file_id;/* file identfier of hdf file.*/
    int32  sd_id;/* sd interface identifer*/
    int32  gr_id;/* gr interface identifer*/
    int32  num_sds; /* number of SDS objects */
    int32  num_images; /* number of image objects */
    int32  num_glsdsattrs; /* number of global SD interface attributes */
    int32  num_glgrattrs;  /* number of global GR interface attributes */
    /* char     str_version[VER_LEN]; */    /* H4toH5 library version */
    short  use_dims = 0;
    int      ret_value = FAIL; /* index id of the ID handler */
    hid_t  file5_id; /* HDF5 file id */
    h4toh5id_t *dt;  /*  pointer to h4toh5 id struct for 
                    passing parameters of error handlings */


    /* write down the version number */
    /* For this release, we opt LIBH4TOH5_VERSION out. In the future release, we may use other way to record library version. */
    /* strncpy(str_version,LIBH4TOH5_VERSION,VER_LEN); */

    dt = malloc(sizeof(h4toh5id_t));
    if(dt==NULL) return FAIL;
    init_h4toh5id_t(dt);
    dt->h4toh5error = NULL;

    if (H4TOH5I_init_group(H4TOH5I_H4TOH5, H4TOH5I_HASHSIZE,
                 0, NULL)<0) {
        H4toH5error_set(dt,3,"cannot initialize hdf5 error handler",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if((ret_value=H4TOH5I_register(H4TOH5I_H4TOH5,dt))<0) {
        H4toH5error_set(dt,3,"unable to register h4toh5 id handler",
                 __FILE__,__LINE__);
        return FAIL;
    }

    /* check whether this file is an hdf4 file. */
#ifndef WIN32

    if(test_file(filename,O_EXCL,292) != 0) {
        H4toH5error_set(dt,5,"the current hdf4file name is not set properly",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if (test_dir(filename) != 0 ) {
        H4toH5error_set(dt,5,"the current hdf4file name is a directory",
                 __FILE__,__LINE__);
        return FAIL;
    }
#endif

    /*0. check whether this file is an hdf file. */

#if 0
    if(!Hishdf(filename)){
        H4toH5error_set(dt,5,"the current file is not an hdf file",
                 __FILE__,__LINE__);
        return FAIL;
    }
#endif

    /*open the current hdf4 file. */
    if(check_filetype(filename)==FAIL){
         H4toH5error_set(dt,5,"the current file is not an hdf or netcdf file",
                 __FILE__,__LINE__);
        return FAIL;
    }

/* create or open current hdf5 file. */

    h5_extension = HDstrdup("h5");
    short file5name_null=0;
    if(file5name == NULL) {
        file5name= BuildFilename(filename,h5_extension);
        if(file5name == NULL) {
            H4toH5error_set(dt,1,"no enough memory for building hdf5 file name",
         __FILE__,__LINE__);
            return FAIL;
        }
        file5name_null = 1;
    }
    free(h5_extension);

    switch(h425_access) {
    
    case H425_CREATE:
        file5_id = H5Fcreate(file5name,H5F_ACC_EXCL,H5P_DEFAULT,H5P_DEFAULT);
        if(file5_id < 0) {
            H4toH5error_set(dt,3,"fail to create hdf5 file",
         __FILE__,__LINE__);
            if(1 == file5name_null)
                free(file5name);
            return FAIL;
        }
        break;
    case H425_OPEN:
        file5_id = H5Fopen(file5name,H5F_ACC_RDWR,H5P_DEFAULT);
        if(file5_id < 0) {
            H4toH5error_set(dt,3,"fail to open HDF5 file",
         __FILE__,__LINE__);
            if(1 == file5name_null)
                free(file5name);
            return FAIL;
        }
        break;
    case H425_CLOBBER:
        file5_id = H5Fcreate(file5name,H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);
        if(file5_id < 0) {
            H4toH5error_set(dt,3,"fail to create hdf5 file with clobber option",
         __FILE__,__LINE__);
             if(1 == file5name_null)
                free(file5name);
           return FAIL;
        }
        break;
    default:
         file5_id = H5Fcreate(file5name,H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);
         if(file5_id < 0) {
            H4toH5error_set(dt,3,"fail to create hdf5 file",
         __FILE__,__LINE__);
         if(1 == file5name_null)
            free(file5name);
           return FAIL;
        }
    }
    if(1 == file5name_null)
        free(file5name);
 
    /*1. open the current hdf4 file. */
    if(check_filetype(filename)==0){
        file_id = Hopen(filename, DFACC_READ, 0);
        if(file_id == FAIL) {
            H4toH5error_set(dt,2,"no such hdf4 files",__FILE__,__LINE__);
           return FAIL;
        }

 
        /* open SD interface.*/
        sd_id = SDstart(filename,DFACC_READ);
        if(sd_id == FAIL) {
            H4toH5error_set(dt,2,"cannot start SD interface",
                     __FILE__,__LINE__);
            Hclose(file_id);
            return FAIL;
        }

        /* open GR interface.*/
        gr_id = GRstart(file_id);
        if(gr_id == FAIL) {
            H4toH5error_set(dt,2,"cannot obtain gr id",
                         __FILE__,__LINE__);
            SDend(sd_id);
            Hclose(file_id);
            return FAIL;
        }

        /* open V interface. */
        istat = Vstart(file_id);
        if(istat == FAIL) {
            H4toH5error_set(dt,2,"cannot start V interface",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }

        /* obtain SD and image information */
        if(SDfileinfo(sd_id,&num_sds,&num_glsdsattrs) == FAIL) {
            H4toH5error_set(dt,2,"cannot obtain SDS information from the file",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
    
        if(GRfileinfo(gr_id,&num_images,&num_glgrattrs) == FAIL) {
            H4toH5error_set(dt,2,"cannot start GR information from the file",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }

        /* initialize SDS and image tables. */
        if(num_sds > 0) {
            dt->sds_hashtab = malloc(sizeof(struct table)*SDS_HASHSIZE);
            if(init_tab(ret_value,SDS_HASHSIZE,dt->sds_hashtab)== FAIL){
                H4toH5error_set(dt,5,"cannot initialize sds hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }
        }

        if(num_images > 0) {
            dt->gr_hashtab = malloc(sizeof(struct table)*IMAGE_HASHSIZE);
            if(init_tab(ret_value,IMAGE_HASHSIZE,dt->gr_hashtab) == FAIL){
                H4toH5error_set(dt,5,"cannot initialize image hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }
        }

        /*Initialize the dimensional scale table. 
        Size of dimensional scale is fixed.*/
        if(num_sds > 0) use_dims = 1;
#ifdef  HAVE_LIBHDFEOS
        /* HDF-EOS2 use vdata to store 1-D array for swath */
        dt->has_swath = 0;
        if(use_dims == 0) {
            int num_swath = H4toH5eos_num_swath(filename);
            if(num_swath >0) {
                use_dims = 1;
                dt->has_swath = 1;
            }

        }
#endif
        /*if(num_sds > 0)   */
        if(use_dims ==1) {  
            dt->moddim_hashtab = malloc(sizeof(struct modname_table)*DIM_HASHSIZE);
            if(init_modnametab(ret_value,DIM_HASHSIZE,dt->moddim_hashtab) == FAIL) {
                H4toH5error_set(dt,5,"cannot initialize dimension hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }

            dt->fakedim_hashtab = malloc(sizeof(struct table));
            if(init_tab2(ret_value,dt->fakedim_hashtab) == FAIL){
                H4toH5error_set(dt,5,"cannot initialize pure dimension table",
                                     __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }

            dt->puredim_hashtab = malloc(sizeof(struct name_table)*DIMPURE_HASHSIZE);
            if(init_nametab(ret_value,DIMPURE_HASHSIZE,dt->puredim_hashtab)== FAIL) {
                 H4toH5error_set(dt,5,"cannot initialize pure dim. name hashing table",__FILE__,
                     __LINE__);
                 SDend(sd_id);
                 GRend(gr_id);
                 Hclose(file_id);
                 return FAIL;
            }
 
            dt->dimscale_hashtab = malloc(sizeof(struct name_table)*DIMSCALE_HASHSIZE);
            if(init_nametab(ret_value,DIMSCALE_HASHSIZE,dt->dimscale_hashtab)== FAIL) {
                 H4toH5error_set(dt,5,"cannot initialize dim. scale name hashing table",__FILE__,
                     __LINE__);
                 SDend(sd_id);
                 GRend(gr_id);
                 Hclose(file_id);
                 return FAIL;
            }
     
        }

    
        /* initialize the palette table,
             Size of dimensional scale is fixed.*/
        if(num_images > 0){
            dt->pal_hashtab = malloc(sizeof(struct table)*PAL_HASHSIZE);
            if(init_tab(ret_value,PAL_HASHSIZE,dt->pal_hashtab) == FAIL) {
                H4toH5error_set(dt,5,"cannot initialize palette hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                GRend(gr_id);
                Hclose(file_id);
                return FAIL;
            }
        }

        /* initialize the vgroup table */
        dt->vg_hashtab = malloc(sizeof(struct table)*VG_HASHSIZE);
    
        if(init_tab(ret_value,VG_HASHSIZE,dt->vg_hashtab) == FAIL) {
            H4toH5error_set(dt,5,"cannot initialize vgroup hashing table",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }

        /* initialize the vdata table.*/
        dt->vd_hashtab = malloc(sizeof(struct table)*VD_HASHSIZE);
        if(init_tab(ret_value,VD_HASHSIZE,dt->vd_hashtab)== FAIL) {
            H4toH5error_set(dt,5,"cannot initialize vdata hashing table",
                     __FILE__,__LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
    
        /* Initialize the object name table. The object name table is only used 
             to handle the name clashing of HDF4 converted objects when users use
             being converted HDF4 object names as their new HDF5 object names.
             The table size is fixed as OBJECT_HASHSIZE. */
        dt->name_hashtab = malloc(sizeof(struct name_table)*OBJECT_HASHSIZE);
        if(init_nametab(ret_value,OBJECT_HASHSIZE,dt->name_hashtab)== FAIL) {
            H4toH5error_set(dt,5,"cannot initialize name hashing table",__FILE__,
                     __LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
     
    
        /*Initialize the group name table. This group name table is only used to
         handle the name clashing when users provide their HDF5 object names */
        dt->h5groupname_table= malloc(sizeof(struct name_table)*NAME_HASHSIZE);
        if(init_nametab(ret_value,NAME_HASHSIZE,dt->h5groupname_table)==FAIL){
            H4toH5error_set(dt,5,"cannot initialize h5 group name hashing table",__FILE__,
                     __LINE__);
            SDend(sd_id);
            GRend(gr_id);
            Hclose(file_id);
            return FAIL;
        }
        
        /* HDF4 file id, sd interface id, gr interface id are provided,
             HDF5 file id is also provided. */
        dt->file5_id = file5_id;
        dt->file_id = file_id;
        dt->sd_id = sd_id;
        dt->gr_id = gr_id;
#ifdef HAVE_LIBHDFEOS
        dt->hdf4filename = filename;
        dt->gd_fd = -1;
        dt->sw_fd = -1;
        dt->pt_fd = -1;
#endif
    }
    
    else if(check_filetype(filename) == 1) {/* netcdf file */
        sd_id = SDstart(filename,DFACC_READ);
        if(sd_id == FAIL) {
            H4toH5error_set(dt,2,"cannot start SD interface",
                    __FILE__,__LINE__);
            return FAIL;
        }
        
        if(SDfileinfo(sd_id,&num_sds,&num_glsdsattrs) == FAIL) {
            H4toH5error_set(dt,2,"cannot obtain SDS information from the file",
                 __FILE__,__LINE__);
            SDend(sd_id);
            return FAIL;
        }
        if(num_sds > 0) {
            dt->sds_hashtab = malloc(sizeof(struct table)*SDS_HASHSIZE);
            if(init_tab(ret_value,SDS_HASHSIZE,dt->sds_hashtab)== FAIL){
                H4toH5error_set(dt,5,"cannot initialize sds hashing table",
                 __FILE__,__LINE__);
                SDend(sd_id);
                return FAIL;
            }
        }

         /*Initialize the dimensional scale table. 
        Size of dimensional scale is fixed.*/
        if(num_sds > 0) {  
            dt->moddim_hashtab = malloc(sizeof(struct modname_table)*DIM_HASHSIZE);
            if(init_modnametab(ret_value,DIM_HASHSIZE,dt->moddim_hashtab) == FAIL) {
                H4toH5error_set(dt,5,"cannot initialize dimension hashing table",
             __FILE__,__LINE__);
                SDend(sd_id);
                return FAIL;
            }
        }

        /* Initialize the object name table. The object name table is only used 
             to handle the name clashing of HDF4 converted objects when users use
             being converted HDF4 object names as their new HDF5 object names.
             The table size is fixed as OBJECT_HASHSIZE. */
        dt->name_hashtab = malloc(sizeof(struct name_table)*OBJECT_HASHSIZE);
        if(init_nametab(ret_value,OBJECT_HASHSIZE,dt->name_hashtab)== FAIL) {
            H4toH5error_set(dt,5,"cannot initialize name hashing table",__FILE__,
                     __LINE__);
            SDend(sd_id);
            return FAIL;
        }

        dt->h5groupname_table= malloc(sizeof(struct name_table)*NAME_HASHSIZE);
        if(init_nametab(ret_value,NAME_HASHSIZE,dt->h5groupname_table)==FAIL){
            H4toH5error_set(dt,5,"cannot initialize h5 group name hashing table",__FILE__,
                     __LINE__);
            SDend(sd_id);
            return FAIL;
        }

        /* HDF4 file id, sd interface id, gr interface id are provided,
             HDF5 file id is also provided. */
        dt->file5_id = file5_id;
        dt->file_id = -1;
        dt->sd_id        = sd_id;
#ifdef HAVE_LIBHDFEOS
        dt->hdf4filename = filename;
        dt->gd_fd = -1;
        dt->sw_fd = -1;
        dt->pt_fd = -1;
#endif
    }    
    return ret_value;
}

/*-------------------------------------------------------------------------
 * Function:    H4toH5close
 *
 * Purpose:     Terminate access to the h4toh5 library
 *                          
 * Return:  FAIL if failed, SUCCEED if successful
 *
 * In :         index of h4toh5_id   
                             
     Out:  
     Modification:           
 *-------------------------------------------------------------------------
 */ 

int H4toH5close(hid_t h4toh5_index) {

    h4toh5id_t* temp_h4toh5; /*  pointer to h4toh5 id struct */

    temp_h4toh5 = H4TOH5I_object(h4toh5_index);
    if(temp_h4toh5 == NULL) 
        return FAIL;
    
    free_allhashmemory(temp_h4toh5);
    freeerror_list(temp_h4toh5->h4toh5error);

    if(temp_h4toh5->file_id == -1 && temp_h4toh5->sd_id != -1) {
        if(SDend(temp_h4toh5->sd_id)==FAIL)
            return FAIL;
    }
     
    else { 
        if(temp_h4toh5->gr_id != -1 && GRend(temp_h4toh5->gr_id)==FAIL)
            return FAIL;
        
        if(temp_h4toh5->file_id != -1 ) {

            if(Vend(temp_h4toh5->file_id) == FAIL)
                return FAIL;
            if(Hclose(temp_h4toh5->file_id) == FAIL) 
                return FAIL;
        }

        if(temp_h4toh5->sd_id != -1) {
            if(SDend(temp_h4toh5->sd_id)==FAIL)
                 return FAIL;
        }

        if(temp_h4toh5->file5_id != -1 && H5Fclose(temp_h4toh5->file5_id)==FAIL)
            return FAIL;
    }
#ifdef HAVE_LIBHDFEOS
    if (temp_h4toh5->gd_fd != -1) {
        if (GDclose(temp_h4toh5->gd_fd) == FAIL) return FAIL;
    }
    if (temp_h4toh5->sw_fd != -1) {
        if (SWclose(temp_h4toh5->sw_fd) == FAIL) return FAIL;
    }
    if (temp_h4toh5->pt_fd != -1) {
        if (PTclose(temp_h4toh5->pt_fd) == FAIL) return FAIL;
    }
    if (temp_h4toh5->grid_list != NULL)
        free(temp_h4toh5->grid_list);
    if (temp_h4toh5->swath_list != NULL)
        free(temp_h4toh5->swath_list);
    if (temp_h4toh5->point_list != NULL)
        free(temp_h4toh5->point_list);
#endif
    H4TOH5I_remove(h4toh5_index);
/* WILL check if this is necessary. */
    free(temp_h4toh5);
    return SUCCEED;
}


/*-------------------------------------------------------------------------
 * Function:    H4toH5glo_sds_attr
 *
 * Purpose:         Convert all global HDF4 SD interface attributes to attributes
                                of HDF5 root group
 *                          
 * Return:  FAIL if failed, SUCCEED if successful
 *
 * In :             h4toh5id: h4toh5 identifier      
 *                  attr_flag: Attribute flag
                             
   Out:  
   Modification:           
 *-------------------------------------------------------------------------
 */ 

int H4toH5glo_sds_attr(hid_t h4toh5id,int attr_flag) {

    int32               sd_id; /* SD interface id */
    int32               num_sds; /* number of SDS objects */
    int32               num_glsdsattrs; /* number of SD interface attributes */
    h4toh5id_t* dt; /*  pointer to h4toh5 id struct for 
                    passing parameters of error handlings */
    hid_t               h5_root; /* HDF5 root id */
    int                 check_glosds = 1;

    dt = H4TOH5I_object(h4toh5id);
    sd_id = dt->sd_id;

    /* obtain number of SD attributes. */
    if(SDfileinfo(sd_id,&num_sds,&num_glsdsattrs) == FAIL) {
        H4toH5error_set(dt,2,"cannot start SD interface",
                 __FILE__,__LINE__);
        return FAIL;
    }
    /* obtain HDF5 root id */
    h5_root = get_h5groupid("/",h4toh5id,attr_flag);
    if(h5_root <0) {
        H4toH5error_set(dt,3,"cannot get hdf5 root id",
                 __FILE__,__LINE__);
        return FAIL;
    }
    /* convert SD attributes. */
    if(sds_transattrs(h4toh5id,sd_id,h5_root,num_glsdsattrs,check_glosds,attr_flag) <0) {
        H4toH5error_set(dt,2,"cannot convert global sds attribute",
                 __FILE__,__LINE__);
        return FAIL;
    }
    /* close HDF5 group interface */
    if(H5Gclose(h5_root)<0) {
        H4toH5error_set(dt,3,"cannot close HDF5 group",
                 __FILE__,__LINE__);
        return FAIL;
    }

    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:    H4toH5glo_image_attr
 *
 * Purpose:         Convert all global HDF4 SD interface attributes to attributes
                                of HDF5 root group
    *                            
 * Return:  FAIL if failed, SUCCEED if successful
 *
 * In :                 h4toh5id: h4toh5 identifier 
                                attr_flag: Attribute flag
     Out:  
     Modification:           
 *-------------------------------------------------------------------------
 */ 

int H4toH5glo_image_attr(hid_t h4toh5id,int attr_flag) {

    int32 gr_id; /* GR id */
    int32 num_ri;/* number of raster images */
    int32 num_glgrattrs; /* number of GR interface attributes */
    h4toh5id_t* dt; /*  pointer to h4toh5 id struct for 
                    passing parameters of error handlings */
    hid_t       h5_root; /* HDF5 root id */
    int      check_glogr = 1; /* flag to check global GR attributes */

    dt = H4TOH5I_object(h4toh5id);
    gr_id = dt->gr_id;

    if(GRfileinfo(gr_id,&num_ri,&num_glgrattrs) == FAIL) {
        H4toH5error_set(dt,2,"cannot get GR file information",
                 __FILE__,__LINE__);
        return FAIL;
    }

    h5_root = get_h5groupid("/",h4toh5id,attr_flag);
    if(h5_root <0) {
        H4toH5error_set(dt,3,"cannot get hdf5 root id",
                 __FILE__,__LINE__);
        return FAIL;
    }

    if(gr_tranattrs(h4toh5id,gr_id,h5_root,num_glgrattrs,check_glogr,attr_flag) <0) {
        H4toH5error_set(dt,2,"cannot convert global gr attributes",
                 __FILE__,__LINE__);
        H5Gclose(h5_root);
        return FAIL;
    }
    
    /* close HDF5 group interface */
    if(H5Gclose(h5_root)<0) {
        H4toH5error_set(dt,3,"cannot close HDF5 group",
                 __FILE__,__LINE__);
        return FAIL;
    }

    return SUCCEED;
}

/*-------------------------------------------------------------------------
 * Function:        H4toH5check_objname_in_use
 *
 * Purpose:         check whether this object name is used 
 *                          
 * Return:          SUCCEED or FAIL
 *
 * In :             h4toh5id: H4toH5 identifier
                    objname: The absolute path of the HDF5 object name
                             flag
                             
     Out:
     Modification:               
 *-------------------------------------------------------------------------
 */
int H4toH5check_objname_in_use(hid_t h4toh5id,
                        char *h5par_path,
                        const char *objname) 
{


    h4toh5id_t *dt; /* pointer to h4toh5 id for error handlings */
    char* h5_aboname = NULL;
    int used;
    
    
    dt = H4TOH5I_object(h4toh5id);
    if(dt == NULL) {
         H4toH5error_set(dt,5,"the handler pointer is NULL",
                                     __FILE__,__LINE__);
             return -1;
    }
    if(objname == NULL) {
         H4toH5error_set(dt,5,"object name is NULL, please reinput object name",
                     __FILE__,__LINE__);
         return -1;
    }
    
    if(h5par_path == NULL) 
        h5_aboname = malloc(strlen(objname)+2);
    else 
        h5_aboname = malloc(strlen(h5par_path)+strlen(objname)+2);
    if(h5_aboname == NULL) {
        H4toH5error_set(dt,5,"cannot allocate memory for the absolute name",
                        __FILE__,__LINE__);
        return -1;
    }
    if(h5par_path == NULL) {
        strcpy(h5_aboname,"/");
        strcat(h5_aboname,objname);
    }
    else if(strcmp(h5par_path,"/")==0) {
        strcpy(h5_aboname,h5par_path);
        strcat(h5_aboname,objname);
    }
    else{
        strcpy(h5_aboname,h5par_path);
        strcat(h5_aboname,"/");
        strcat(h5_aboname,objname);
    }
    used = lookup_name(h4toh5id,h5_aboname,OBJECT_HASHSIZE,dt->name_hashtab);
    free(h5_aboname);
    
    return used;
}

/*-------------------------------------------------------------------------
 * Function:        H4toH5check_object
 *
 * Purpose:         check object information
 *                          
 * Return:          the absolute path of the object converted from HDF4
 *
 * In :             H4toh5 id
                    HDF4 object reference number
                    HDF4 object tag
                             
                             
   Out:             An integer pointer to indicate whether the object
                    is touched or not
   Modification:               
 *-------------------------------------------------------------------------
 */
char* H4toH5check_object(hid_t h4toh5id,
            uint16 objref,
            int32 obj_tag,
            int* flagptr) {

    h4toh5id_t *temph4toh5id; /* pointer to h4toh5 id for error handlings */
    int tempcheck_get;
    
    temph4toh5id = H4TOH5I_object(h4toh5id);
    
    switch(obj_tag) {
    
        case DFTAG_SD:
            *flagptr = lookup(h4toh5id,objref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,NULL);
            if(*flagptr == 1) return get_name(h4toh5id,objref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_NDG:
            *flagptr = lookup(h4toh5id,objref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,NULL);
            if(*flagptr == 1) return get_name(h4toh5id,objref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_SDG:
            *flagptr = lookup(h4toh5id,objref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,NULL);
            if(*flagptr == 1) return get_name(h4toh5id,objref,SDS_HASHSIZE,temph4toh5id->sds_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_RIG:
            *flagptr = lookup(h4toh5id,objref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,NULL);
            if(*flagptr == 1) return get_name(h4toh5id,objref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_RI:
             *flagptr = lookup(h4toh5id,objref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,NULL);
             if(*flagptr == 1) return get_name(h4toh5id,objref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_RI8:
             *flagptr = lookup(h4toh5id,objref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,NULL);
             if(*flagptr == 1) return get_name(h4toh5id,objref,IMAGE_HASHSIZE,temph4toh5id->gr_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_VG:
            *flagptr = lookup(h4toh5id,objref,VG_HASHSIZE,temph4toh5id->vg_hashtab,NULL);
            if(*flagptr == 1) return get_name(h4toh5id,objref,VG_HASHSIZE,temph4toh5id->vg_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_VH:
            *flagptr = lookup(h4toh5id,objref,VD_HASHSIZE,temph4toh5id->vd_hashtab,NULL);
            if(*flagptr == 1) return get_name(h4toh5id,objref,VD_HASHSIZE,temph4toh5id->vd_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_VS:
             *flagptr = lookup(h4toh5id,objref,VD_HASHSIZE,temph4toh5id->vd_hashtab,NULL);
             if(*flagptr == 1) return get_name(h4toh5id,objref,VD_HASHSIZE,temph4toh5id->vd_hashtab,&tempcheck_get);
            break;
    
        case DFTAG_LUT: 
             *flagptr = lookup(h4toh5id,objref,PAL_HASHSIZE,temph4toh5id->pal_hashtab,NULL);
             if(*flagptr == 1) return get_name(h4toh5id,objref,PAL_HASHSIZE,temph4toh5id->pal_hashtab,&tempcheck_get);
            break;
    
        default: 
            H4toH5error_set(temph4toh5id,5,"object tag cannot be transferred ",
                 __FILE__,__LINE__);
            *flagptr = -1;
            return NULL;
    }
    
     return NULL;
}

int check_filetype(char* filename) {
    /*int temp;
    temp = Hishdf(filename);
    */

    int sd_id = -1;
    if(Hishdf(filename) == 1) 
        return 0;
    else {
        sd_id = SDstart(filename,DFACC_READ);

        if(sd_id!= FAIL) {
            SDend(sd_id);
            return 1;
        }
        else 
            return FAIL;
        
    }
}

/**** leave the following function for future historical format storing. ***/
#if 0
/*-------------------------------------------------------------------------
 * Function:        set_formatconv(hid_t)
 *
 * Purpose:         set the format for history
 *                          
 * Return:          SUCCEED or FAIL
 *
 * In :                 ID for hdf5 root
                             
                             
     Out:
     Modification:               
 *-------------------------------------------------------------------------
 */ 
int set_formatconv(hid_t h5_root) {
    
    hid_t h5a_sid,h5a_id;
    hsize_t h5str_size;
    hid_t h5str_type;
    herr_t ret;
    time_t now;
    uint32 major_4v,minor_4v,rele_4;
    unsigned majnum,minnum,relnum;
    char libstr4[LIBVSTR_LEN];
    char libstr5[LIBVSTR_LEN];
    char attrname[30];
    char time_str[30];
    char attr_data[230];
    char temp_data[20];

    h4toh5_ZeroMemory(libstr4,LIBVSTR_LEN);
    h4toh5_ZeroMemory(libstr5,LIBVSTR_LEN);
    h4toh5_ZeroMemory(attrname,30);
    h4toh5_ZeroMemory(time_str,30);
    h4toh5_ZeroMemory(attr_data,230);
    h4toh5_ZeroMemory(temp_data,20);

    /* 1. attribute name. */
    strcpy(attrname,"format_conversion_history");

    /* 2. get hdf4 version, the lenght of LIBVSTR_LEN(80) */
    if(Hgetlibversion(&major_4v,&minor_4v,&rele_4,libstr4)==FAIL) {
        return FAIL;
    }

    /*3. get hdf5 version, */
    if(H5get_libversion(&majnum,&minnum,&relnum)<0) {
        return FAIL;
    }

    strcpy(libstr5,"NCSA HDF5 Version ");

    sprintf(temp_data,"%u",majnum);

    strncat(libstr5,temp_data,strlen(temp_data));
    strcat(libstr5,".");
    h4toh5_ZeroMemory(temp_data,20);
    sprintf(temp_data,"%u",minnum);
    strncat(libstr5,temp_data,strlen(temp_data));
    strcat(libstr5," Release ");
    h4toh5_ZeroMemory(temp_data,20);
    sprintf(temp_data,"%u",relnum);

    strncat(libstr5,temp_data,strlen(temp_data));
    strcat(libstr5,", May 1999");

    /*4. get time. */
    
    now = time(NULL);
    sprintf(time_str,"%s",ctime(&now));

    strcpy(attr_data,"The current HDF file was converted into an HDF5 file by using two libraries: ");
    strncat(attr_data,libstr4,strlen(libstr4));
    strcat(attr_data," and ");
    strncat(attr_data,libstr5,strlen(libstr5));
    strcat(attr_data,". The converting time is at  ");
    strncat(attr_data,time_str,strlen(time_str));
    h5str_size = strlen(attr_data);

    if ((h5str_type = mkstr(h5str_size,H5T_STR_NULLTERM))<0) {
     printf("failed to make string type \n"); 
        return FAIL;
    }

    h5a_sid = H5Screate(H5S_SCALAR);
    
    if(h5a_sid < 0) {
        printf("failed to create attribute space for HDF4_OBJECT. \n");
        return FAIL;
    }

    h5a_id = H5Acreate(h5_root,attrname,h5str_type,h5a_sid,H5P_DEFAULT);

    if(h5a_id <0) {
        fprintf(stderr,"failed to obtain attribute id for HDF4_OBJECT. \n");
        H5Sclose(h5a_sid);
        return FAIL;
    }

    ret = H5Awrite(h5a_id,h5str_type,(void *)attr_data);

    if(ret <0) {
        fprintf(stderr,"failed to obtain attribute.\n ");
        H5Aclose(h5a_id);
        H5Sclose(h5a_sid);
        return FAIL;
    }

    ret = H5Sclose(h5a_sid);
    ret = H5Aclose(h5a_id);
    return SUCCEED; 

}
    
#endif




/********The following routines are adapted from h5toh4 converter. *******/
/*****************************************************************************

                                             
Routine: test_file
 
                                            
Description: Test a file for read/write - ability.
 
                                         
Input: filename - Unix filename
Output: function return,    global variable - errno

*****************************************************************************/

int test_file(const char *filename,int oflag,mode_t mode)
{
    int fid;

    errno = 0;

    fid = open(filename, oflag, mode);
    if (fid < 0) {
        perror(filename);
    }
    close(fid);

    return errno;

}


/*****************************************************************************


                                            
Routine: test_dir
 
                                                
Description: Test the absolute path to determine if it is a directory
 
                                                
Input: path - pathname given
 
                                                
Output:  function return TRUE/FALSE

*****************************************************************************/

int test_dir(const char *path)
{

    struct stat buf;
    struct stat *buf_ptr;
    int idir;

    buf_ptr = &buf;

    idir = stat(path, buf_ptr);
    if (idir < 0) {
        if (errno == 2) {
            return 0;
        } else {
            perror(path);
        }
    }

    return S_ISDIR(buf_ptr->st_mode);
}

/*****************************************************************************

                                                
Routine: BuildFilename()
 
                                                
Description: Build a filename with new extension
 
                                                
Input: filename - present filename
                                                
ext     - extension to root of filename
 
                                                
Output: (filename:r).ext

*****************************************************************************/

char *BuildFilename(char *filename, char *ext)
{
    /* build outgoing filename */

    char *filename_out;
    char *lastper_ptr;
    char *lastdir_ptr;
    int root_len;

    lastper_ptr = strrchr(filename,'.');
    lastdir_ptr = strrchr(filename,'/');

    if ( lastper_ptr <= lastdir_ptr ) { /* no extension */
        root_len = strlen(filename);
    } else {    /* existing extension */
        root_len = (int)(lastper_ptr - filename); 
    }

    filename_out = (char *)HDmalloc(root_len + strlen(ext) + 2);
    filename_out = strncpy(filename_out, filename, (size_t)root_len);
    filename_out[root_len] = '\0';
    filename_out = strcat(filename_out,".");
    filename_out = strcat(filename_out,ext);

    return filename_out;
}

