/*-------------------------------------------------------------------------
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not
   be misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.
-------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#if !defined(_WIN32) || defined(__NUTC__)
#include <unistd.h>
#endif
#include "cgnslib.h"
#include "cgns_header.h"
#include "cgns_io.h"
#ifdef MEM_DEBUG
#include "cg_malloc.h"
#endif
#ifdef BUILD_HDF5
#include "adfh/ADFH.h"
#include "hdf5.h"
#endif

#define CGNS_NAN(x)  (!((x) < HUGE_VAL && (x) > -HUGE_VAL))

/***********************************************************************
 * global variable definitions
 ***********************************************************************/
int Idim;           /* current IndexDimension          */
int Cdim;           /* current CellDimension           */
int Pdim;           /* current PhysicalDimension           */
cgsize_t CurrentDim[9]; /* current vertex, cell & bnd zone size*/
CGNS_ENUMT( ZoneType_t ) CurrentZoneType;     /* current zone type               */
int NumberOfSteps;      /* Number of steps             */

/*----- the goto stack -----*/

int posit_depth = 0;
cgns_posit posit_stack[CG_MAX_GOTO_DEPTH+1];

/***********************************************************************\
 *          Internal functions                 *
\***********************************************************************/

void *cgi_malloc(size_t cnt, size_t size)
{
    void *buf = calloc(cnt, size);
    if (buf == NULL) {
        cgi_error("calloc failed for %d values of size %d", cnt, size);
        exit (1);
    }
    return buf;
}

void *cgi_realloc(void *oldbuf, size_t bytes)
{
    void *buf = realloc(oldbuf, bytes);
    if (buf == NULL) {
        cgi_error("realloc failed for %d bytes", bytes);
        exit (1);
    }
    return buf;
}

/***********************************************************************\
 *    Read CGNS file and store in internal data structures         *
\***********************************************************************/

int cgi_read()
{
    int b;
    double *id;

     /* get number of CGNSBase_t nodes and their ID */

    if (cgi_get_nodes(cg->rootid, "CGNSBase_t", &cg->nbases, &id)) return 1;
    if (cg->nbases==0) return 0;
    cg->base = CGNS_NEW(cgns_base,cg->nbases);
    for (b=0; b<cg->nbases; b++) cg->base[b].id = id[b];
    free(id);

     /* read and save CGNSBase_t data */
    for (b=0; b<cg->nbases; b++) if (cgi_read_base(&cg->base[b])) return 1;

    return 0;
}

int cgi_read_base(cgns_base *base)
{
    char_33 data_type;
    int ndim, *index;
    double *id;
    int n;
    void *vdata;
    cgsize_t dim_vals[12];

     /* Read CGNSBase_t Node */
    if (cgi_read_node(base->id, base->name, data_type, &ndim, dim_vals,
            &vdata, READ_DATA)) {
        cgi_error("Error reading base");
        return 1;
    }
    index = (int *)vdata;

     /* check data type */
    if (strcmp(data_type,"I4")!=0) {
        cgi_error("Unexpected data type for dimension data of base %s='%s'",
               base->name, data_type);
        return 1;
    }
    if ((cg->version==1050 && (ndim != 1 || dim_vals[0]!=1)) ||
        (cg->version >= 1100 && (ndim != 1 || dim_vals[0]!=2))) {
        cgi_error("Wrong definition of Base Dimensions.");
        return 1;
    }
    if (cg->version == 1050) {  /* old multiblock format */
        base->cell_dim = base->phys_dim = index[0];
    } else {
        base->cell_dim = index[0];
        base->phys_dim = index[1];
    }
    free(vdata);

    if (base->cell_dim<1 || base->cell_dim>3) {
        cgi_error("Invalid value for base cell dimension (=%d)",
               base->cell_dim);
        return 1;
    }
    if (base->phys_dim<1 || base->phys_dim>3) {
        cgi_error("Invalid value for base physical dimension(=%d)",
            base->phys_dim);
        return 1;
    }

     /* set Global variable */
    Cdim = base->cell_dim;
    Pdim = base->phys_dim;

    /* update version */
    if (cg->mode == CG_MODE_MODIFY && cg->version < 1100) {
        dim_vals[0] = 2;
        if (cgio_set_dimensions(cg->cgio, base->id, "I4", 1, dim_vals)) {
            cg_io_error("cgio_set_dimensions");
            return 1;
        }
        dim_vals[0] = base->cell_dim;
        dim_vals[1] = base->phys_dim;
        if (cgio_write_all_data(cg->cgio, base->id, dim_vals)) {
            cg_io_error("cgio_write_all_data");
            return 1;
        }
    }

     /* Family_t */
    if (cgi_get_nodes(base->id, "Family_t", &base->nfamilies, &id)) return 1;
    if (base->nfamilies>0) {
         /* read & save families */
        base->family = CGNS_NEW(cgns_family, base->nfamilies);
        for (n=0; n<base->nfamilies; n++) {
            base->family[n].id = id[n];
            base->family[n].link = cgi_read_link(id[n]);
            base->family[n].in_link = 0;
            if (cgi_read_family(&base->family[n])) return 1;
        }
        free(id);
    }

     /* ReferenceState_t */
    if (cgi_read_state(0, base->id, &base->state)) return 1;

     /* Gravity_t */
    if (cgi_read_gravity(0, base->id, &base->gravity)) return 1;

     /* Axisymmetry_t */
    if (cgi_read_axisym(0, base->id, &base->axisym)) return 1;

     /* RotatingCoordinates_t */
    if (cgi_read_rotating(0, base->id, &base->rotating)) return 1;

     /* ConvergenceHistory_t */
    if (cgi_read_converg(0, base->id, &base->converg)) return 1;

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(0, base->id, &base->ndescr, &base->descr,
        &base->data_class, &base->units)) return 1;

     /* FlowEquationSet_t */
    if (cgi_read_equations(0, base->id, &base->equations)) return 1;

     /* IntegralData_t */
    if (cgi_read_integral(0, base->id, &base->nintegrals,
        &base->integral)) return 1;

     /* SimulationType_t */
    if (cgi_read_simulation(base->id, &base->type, &base->type_id)) return 1;

     /* BaseIterativeData_t */
    if (cgi_read_biter(0, base->id, &base->biter)) return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(0, base->id, &base->nuser_data,
        &base->user_data)) return 1;

     /* Zone_t (depends on NumberOfSteps) */
    if (cgi_get_nodes(base->id, "Zone_t", &base->nzones, &id)) return 1;
    if (base->nzones>0) {
         /* Order zones alpha-numerically */
        if (cgi_sort_names(base->nzones, id)) {
            cgi_error("Error sorting zone names...");
            return 1;
        }
         /* read & save zones in sorted order */
        base->zone = CGNS_NEW(cgns_zone, base->nzones);
        for (n=0; n<base->nzones; n++) {
            base->zone[n].id = id[n];
            base->zone[n].link = cgi_read_link(id[n]);
            base->zone[n].in_link = 0;
            if (cgi_read_zone(&base->zone[n])) return 1;
        }
        free(id);
    }
    return 0;
}

int cgi_read_zone(cgns_zone *zone)
{
    int n, ndim;
    int in_link = zone->link ? 1 : zone->in_link;
    char_33 data_type;
    void *vdata;
    double *id;
    cgsize_t dim_vals[12];

     /* Zone_t */
    if (cgi_read_node(zone->id, zone->name, data_type, &ndim, dim_vals,
            &vdata, READ_DATA)) {
        cgi_error("Error reading node Zone_t");
        return 1;
    }

     /* verify data read */
    if (ndim!=2) {
        cgi_error("Wrong number of dimension for a Zone_t node");
        return 1;
    }
     /* ZoneType_t */
    if (cgi_read_zonetype(zone->id, zone->name, &zone->type)) return 1;

     /* Set IndexDimension of zone */
    if (zone->type==CGNS_ENUMV(Structured)) zone->index_dim=Cdim;
    else zone->index_dim=1;

     /* save Global Variable Idim */
    Idim = zone->index_dim;

    if (dim_vals[0]!=zone->index_dim || ((cg->version==1050 && dim_vals[1]!=2)
        || (cg->version>=1100 && dim_vals[1]!=3))) {
        cgi_error("Wrong number of dimension values for Zone_t %s",zone->name);
        return 1;
    }

     /* allocate memory to record zone size */
    zone->nijk=CGNS_NEW(cgsize_t, zone->index_dim*3);

    if (0 == strcmp(data_type, "I8")) {
        cglong_t *mesh_dim = (cglong_t *)vdata;
#if CG_SIZEOF_SIZE == 32
        if (cgi_check_dimensions(zone->index_dim, mesh_dim)) return 1;
#endif
        for (n=0; n<zone->index_dim; n++) {
            zone->nijk[n] = (cgsize_t)mesh_dim[n];
            zone->nijk[n+Idim] = (cgsize_t)mesh_dim[n+Idim];
            if (cg->version==1050) zone->nijk[n+2*Idim] = (cgsize_t)0;
            else zone->nijk[n+2*Idim]  = (cgsize_t)mesh_dim[n+2*Idim];
        }
    }
    else if (0 == strcmp(data_type, "I4")) {
        int *mesh_dim = (int *)vdata;
        for (n=0; n<zone->index_dim; n++) {
            zone->nijk[n] = (cgsize_t)mesh_dim[n];
            zone->nijk[n+Idim] = (cgsize_t)mesh_dim[n+Idim];
            if (cg->version==1050) zone->nijk[n+2*Idim] = (cgsize_t)0;
            else zone->nijk[n+2*Idim]  = (cgsize_t)mesh_dim[n+2*Idim];
        }
    }
    else {
        cgi_error("Unsupported data type for Zone_t node %s= %s",
               zone->name, data_type);
        return 1;
    }
    free(vdata);

     /* save Global Variables */
    for (n=0; n<Idim*3; n++) CurrentDim[n] = zone->nijk[n];
    CurrentZoneType = zone->type;

     /* verify data */
    if (zone->type==CGNS_ENUMV(Structured)) {
        for (n=0; n<zone->index_dim; n++) {
            if (zone->nijk[n] <=0 || zone->nijk[n]!=zone->nijk[n+Idim]+1) {
                cgi_error("Invalid structured zone dimensions");
                return 1;
            }
        }
    } else {
        if (zone->nijk[0]<0 || zone->nijk[1]<0 ||
            zone->nijk[2]>zone->nijk[0]) {
            cgi_error("Invalid unstructured zone dimensions");
            return 1;
        }
    }

    /* update version */
    if (cg->mode == CG_MODE_MODIFY && cg->version < 1100 && !in_link) {
        dim_vals[0] = zone->index_dim;
        dim_vals[1] = 3;
        if (cgio_set_dimensions(cg->cgio, zone->id, CG_SIZE_DATATYPE, 2, dim_vals)) {
            cg_io_error("cgio_set_dimensions");
            return 1;
        }
        if (cgio_write_all_data(cg->cgio, zone->id, zone->nijk)) {
            cg_io_error("cgio_write_all_data");
            return 1;
        }
    }

     /* GridCoordinates_t */
    if (cgi_read_zcoor(in_link, zone->id, &zone->nzcoor, &zone->zcoor))
        return 1;

     /* Elements_t: Only for Unstructured zones */
    if (cgi_read_section(in_link, zone->id, &zone->nsections, &zone->section))
        return 1;
    if (zone->type==CGNS_ENUMV( Structured ) && zone->nsections!=0) {
        cgi_error("Elements_t nodes is valid only for unstructured zones");
        return 1;
    }

     /* FamilyName_t */
    if (cgi_read_family_name(in_link, zone->id, zone->name, zone->family_name))
        return 1;

    /* CPEX 0034 */
    if (cgi_get_nodes(zone->id, "AdditionalFamilyName_t", &zone->nfamname, &id))
        return 1;
    if (zone->nfamname > 0) {
        char *fam;
        zone->famname = CGNS_NEW(cgns_famname, zone->nfamname);
        for (n = 0; n < zone->nfamname; n++) {
            zone->famname[n].id = id[n];
            if (cgi_read_string(id[n], zone->famname[n].name, &fam)) return 1;
            strncpy(zone->famname[n].family, fam, 32);
            free(fam);
        }
        free(id);
    }

     /* FlowSolution_t */
    if (cgi_read_sol(in_link, zone->id, &zone->nsols, &zone->sol))
        return 1;

     /* ZoneGridConnectivity_t */
    if (cgi_read_zconn(in_link, zone->id, &zone->nzconn, &zone->zconn)) return 1;

     /* ZoneBC_t */
    if (cgi_read_zboco(in_link, zone->id, &zone->zboco)) return 1;

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(in_link, zone->id, &zone->ndescr, &zone->descr,
        &zone->data_class, &zone->units)) return 1;

     /* DiscreteData_t */
    if (cgi_read_discrete(in_link, zone->id, &zone->ndiscrete,
        &zone->discrete)) return 1;

     /* IntegralData_t */
    if (cgi_read_integral(in_link, zone->id, &zone->nintegrals,
        &zone->integral)) return 1;

     /* ReferenceState_t */
    if (cgi_read_state(in_link, zone->id, &zone->state)) return 1;

     /* ConvergenceHistory_t */
    if (cgi_read_converg(in_link, zone->id, &zone->converg)) return 1;

     /* FlowEquationSet_t */
    if (cgi_read_equations(in_link, zone->id, &zone->equations)) return 1;

     /* Ordinal_t */
    if (cgi_read_ordinal(zone->id, &zone->ordinal)) return 1;

     /* RigidGridMotion_t */
    if (cgi_read_rmotion(in_link, zone->id, &zone->nrmotions,
        &zone->rmotion)) return 1;

     /* ArbitraryGridMotion_t */
    if (cgi_read_amotion(in_link, zone->id, &zone->namotions,
        &zone->amotion)) return 1;

     /* ZoneIterativeData_t can only exist if BaseIterativeData_t exist because
    it depends on it */
    if (NumberOfSteps) {
        if (cgi_read_ziter(in_link, zone->id, &zone->ziter)) return 1;
    } else zone->ziter = 0;

     /* UserDefinedData_t */
    if (cgi_read_user_data(in_link, zone->id, &zone->nuser_data,
        &zone->user_data)) return 1;

     /* RotatingCoordinates_t */
    if (cgi_read_rotating(in_link, zone->id, &zone->rotating)) return 1;

     /* ZoneSubRegion_t */
    if (cgi_read_subregion(in_link, zone->id, &zone->nsubreg,
        &zone->subreg)) return 1;

    return 0;
}

int cgi_read_family(cgns_family *family)
{
    int n, linked, in_link = family->link ? 1 : family->in_link;
    double *id;
    char *boconame;

     /* Family name */
    if (cgio_get_name(cg->cgio, family->id, family->name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

    /* CPEX 0033 */
    if (cgi_get_nodes(family->id, "FamilyName_t", &family->nfamname, &id))
        return 1;
    if (family->nfamname > 0) {
        char *fam;
        family->famname = CGNS_NEW(cgns_famname, family->nfamname);
        for (n = 0; n < family->nfamname; n++) {
            family->famname[n].id = id[n];
            if (cgi_read_string(id[n], family->famname[n].name, &fam)) return 1;
            strncpy(family->famname[n].family, fam, 32);
            free(fam);
        }
        free(id);
    }

     /* FamilyBC_t */
    if (cgi_get_nodes(family->id, "FamilyBC_t", &family->nfambc, &id))
        return 1;
    if (family->nfambc>0) {
        family->fambc = CGNS_NEW(cgns_fambc, family->nfambc);
        for (n=0; n<family->nfambc; n++) {
            family->fambc[n].id = id[n];
            family->fambc[n].link = cgi_read_link(id[n]);
            family->fambc[n].in_link = in_link;
            if (cgi_read_string(id[n], family->fambc[n].name, &boconame))
                return 1;
             /* get BCType */
            if (cgi_BCType(boconame, &family->fambc[n].type)) return 1;
            free(boconame);
            /* FamilyBCDataSet_t */
            linked = family->fambc[n].link ? 1 : in_link;
            if (cgi_read_family_dataset(linked, family->fambc[n].id,
                                        &family->fambc[n].ndataset,
                                        &family->fambc[n].dataset))
                return 1;
        }
        free(id);
    }

     /* GeometryReference_t */
    if (cgi_get_nodes(family->id, "GeometryReference_t", &family->ngeos, &id))
        return 1;
    if (family->ngeos>0) {
        family->geo = CGNS_NEW(cgns_geo, family->ngeos);
        for (n=0; n<family->ngeos; n++) {
            family->geo[n].id = id[n];
            family->geo[n].link = cgi_read_link(id[n]);
            family->geo[n].in_link = in_link;

             /* GeometryReference Name */
            if (cgio_get_name(cg->cgio, family->geo[n].id,
                    family->geo[n].name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }

            /* UserDefinedData_t */
            linked = family->geo[n].link ? 1 : in_link;
            if (cgi_read_user_data(linked, family->geo[n].id,
                &family->geo[n].nuser_data, &family->geo[n].user_data))
                return 1;
        }
        free(id);
    }

     /* GeometryReference_t Children */

    for (n=0; n<family->ngeos; n++) {
        int i, flag;
        char_33 dummy_name;
        cgns_geo *geo = &family->geo[n];

         /* Descriptor_t */
        if (cgi_get_nodes(geo->id, "Descriptor_t", &geo->ndescr, &id))
            return 1;
        if (geo->ndescr>0) {
            geo->descr = CGNS_NEW(cgns_descr, geo->ndescr);
            for (i=0; i<geo->ndescr; i++) {
                geo->descr[i].id = id[i];
                geo->descr[i].link = cgi_read_link(id[i]);
                geo->descr[i].in_link = in_link;
                if (cgi_read_string(id[i], geo->descr[i].name,
                    &geo->descr[i].text)) return 1;
            }
            free(id);
        }

     /* GeometryFile_t */
        if (cgi_get_nodes(geo->id, "GeometryFile_t", &flag, &id)) return 1;
        if (flag==1) {
            if (cgi_read_string(id[0], dummy_name, &geo->file)) return 1;
        } else {
            cgi_error("Incorrect definition of GeometryFile_t");
            return 1;
        }
        if (flag) free(id);

     /* GeometryFormat_t */
        if (cgi_get_nodes(geo->id, "GeometryFormat_t", &flag, &id)) return 1;
        if (flag==1) {
            char *geoformat;
            if (cgi_read_string(id[0], dummy_name, &geoformat)) return 1;
            if (strlen(geoformat)>32) {
                cgi_error("Geometry File Format is limited to 32 characters");
                return 1;
            } else strcpy(geo->format, geoformat);
            free(geoformat);
        } else {
            cgi_error("Incorrect definition of GeometryFormat_t");
            return 1;
        }
        if (flag) free(id);

     /* GeometryEntity_t */
        if (cgi_get_nodes(geo->id, "GeometryEntity_t", &geo->npart, &id))
            return 1;
        if (geo->npart>0) {
            geo->part = CGNS_NEW(cgns_part, geo->npart);
            for (i=0; i<geo->npart; i++) {
                geo->part[i].id = id[i];
                geo->part[i].link = cgi_read_link(id[i]);
                geo->part[i].in_link = in_link;
                if (cgio_get_name(cg->cgio, id[i], geo->part[i].name)) {
                    cg_io_error("cgio_get_name");
                    return 1;
                }
            }
            free(id);
        }
    }   /* loop through ngeos */

     /* Descriptor_t under Family_t */
    if (cgi_get_nodes(family->id, "Descriptor_t", &family->ndescr, &id))
        return 1;
    if (family->ndescr>0) {
        family->descr = CGNS_NEW(cgns_descr, family->ndescr);
        for (n=0; n<family->ndescr; n++) {
            family->descr[n].id = id[n];
            family->descr[n].link = cgi_read_link(id[n]);
            family->descr[n].in_link = in_link;
            if (cgi_read_string(id[n], family->descr[n].name,
                &family->descr[n].text)) return 1;
        }
        free(id);
    }

     /* Ordinal_t */
    if (cgi_read_ordinal(family->id, &family->ordinal)) return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(in_link, family->id, &family->nuser_data,
        &family->user_data)) return 1;

    /* RotatingCoordinates_t */
    if (cgi_read_rotating(in_link, family->id, &family->rotating)) return 1;

    return 0;
}

int cgi_read_family_dataset(int in_link, double parent_id, int *ndataset,
                            cgns_dataset **pdataset)
{
    int n, i, nnod, linked;
    double *id, *ids;
    char_33 name;
    char *string_data;
    int modified = 0;
    cgns_dataset *dataset;

     /* FamilyBCDataSet_t */
    if (cgi_get_nodes(parent_id, "FamilyBCDataSet_t", ndataset, &id))
        return 1;

     /* if not found, check for BCDataSet_t (pre 3.1.3) */
    if (*ndataset <= 0) {
        if (cgi_get_nodes(parent_id, "BCDataSet_t", ndataset, &id))
            return 1;
        modified = (cg->filetype != CG_FILE_ADF2);
    }
    if (*ndataset <= 0) {
        *pdataset = NULL;
        return 0;
    }
    dataset = CGNS_NEW(cgns_dataset, (*ndataset));
    *pdataset = dataset;

    for (n = 0; n < *ndataset; n++) {
        dataset[n].id = id[n];
        dataset[n].link = cgi_read_link(id[n]);
        dataset[n].in_link = in_link;
        linked = dataset[n].link ? 1 : in_link;

        if (cgi_read_string(dataset[n].id, dataset[n].name, &string_data) ||
            cgi_BCType(string_data, &dataset[n].type)) return 1;
        free(string_data);

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, dataset[n].id, &dataset[n].ndescr,
            &dataset[n].descr, &dataset[n].data_class,
            &dataset[n].units)) return 1;

     /* ReferenceState_t */
        if (cgi_read_state(linked, dataset[n].id, &dataset[n].state))
            return 1;

     /* BCData_t */
        dataset[n].dirichlet = dataset[n].neumann = NULL;
        if (cgi_get_nodes(dataset[n].id, "BCData_t", &nnod, &ids)) return 1;
        if (nnod > 0) {
            for (i = 0; i < nnod; i++) {
                /* Name */
                if (cgio_get_name(cg->cgio, ids[i], name)) {
                    cg_io_error("cgio_get_name");
                    return 1;
                }
                if (strcmp(name, "DirichletData")==0) {
                    if (dataset[n].dirichlet!=0) {
                        cgi_error("Dirichet Data defined more than once...");
                        return 1;
                    }
                    dataset[n].dirichlet=CGNS_NEW(cgns_bcdata, 1);
                    dataset[n].dirichlet->id = ids[i];
                    dataset[n].dirichlet->link = cgi_read_link(ids[i]);
                    dataset[n].dirichlet->in_link = linked;
                    strcpy(dataset[n].dirichlet->name,"DirichletData");
                    if (cgi_read_bcdata(dataset[n].dirichlet)) return 1;
                } else if (strcmp(name, "NeumannData")==0) {
                    if (dataset[n].neumann!=0) {
                        cgi_error("Neumann Data defined more than once...");
                        return 1;
                    }
                    dataset[n].neumann=CGNS_NEW(cgns_bcdata, 1);
                    dataset[n].neumann->id = ids[i];
                    dataset[n].neumann->link = cgi_read_link(ids[i]);
                    dataset[n].neumann->in_link = linked;
                    strcpy(dataset[n].neumann->name,"NeumannData");
                    if (cgi_read_bcdata(dataset[n].neumann)) return 1;
                }
            }
            free(ids);
        }

        /* UserDefinedData_t */
        if (cgi_read_user_data(linked, dataset[n].id,
            &dataset[n].nuser_data, &dataset[n].user_data)) return 1;

        /* fix label if needed */
        if (modified && !linked && cg->mode == CG_MODE_MODIFY) {
            if (cgio_set_label(cg->cgio, id[n], "FamilyBCDataSet_t")) {
                cg_io_error("cgio_set_label");
                return 1;
            }
        }
    }
    free(id);

    return 0;
}

int cgi_read_family_name(int in_link, double parent_id, char_33 parent_name,
                         char_33 family_name)
{
    int fam_flag;
    double *id;
    char_33 NodeName;
    char *FamilyName=0;     /* allocated in cgi_read_node */

    family_name[0]='\0';
    if (cgi_get_nodes(parent_id, "FamilyName_t", &fam_flag, &id)) return 1;
    if (fam_flag==1) {

        if (cg->version>1200) {

         /* FamilyName in data field of the ADF node */
            if (cgi_read_string(id[0], NodeName, &FamilyName)) return 1;
            if (strlen(FamilyName) > 32) FamilyName[32]='\0';
            strcpy(family_name, FamilyName);
            if (FamilyName) free(FamilyName);

        } else {
         /* FamilyName is the ADF node name */
            if (cgio_get_name(cg->cgio, id[0], family_name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            /* update version */
            if (cg->mode == CG_MODE_MODIFY && !in_link) {
                double dummy_id;
                cgsize_t len = (cgsize_t)strlen(family_name);
                if (cgi_delete_node(parent_id, id[0])) return 1;
                if (cgi_new_node(parent_id, "FamilyName", "FamilyName_t",
                    &dummy_id, "C1", 1, &len, (void *)family_name))
                    return 1;
            }
        }
        free(id);

    } else if (fam_flag<0 || fam_flag>1) {
        cgi_error("Family name defined incorrectly under '%s',",parent_name);
        return 1;
    }
    return 0;
}

int cgi_read_zcoor(int in_link, double parent_id, int *nzcoor, cgns_zcoor **zcoor)
{
    double *idg, *id;
    int g, z, n, linked;
    cgsize_t DataSize[3];

    if (cgi_get_nodes(parent_id, "GridCoordinates_t", nzcoor, &idg)) return 1;
    if ((*nzcoor)<=0) return 0;

    zcoor[0] = CGNS_NEW(cgns_zcoor, (*nzcoor));

    for (g=0; g<(*nzcoor); g++) {
        zcoor[0][g].id = idg[g];
        zcoor[0][g].link = cgi_read_link(idg[g]);
        zcoor[0][g].in_link = in_link;
        linked = zcoor[0][g].link ? 1 : in_link;

         /* Name */
        if (cgio_get_name(cg->cgio, zcoor[0][g].id, zcoor[0][g].name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }

         /* Rind Planes */
        if (cgi_read_rind(zcoor[0][g].id, &zcoor[0][g].rind_planes)) return 1;

         /* Assume that the coordinates are always at the node */
        if (cgi_datasize(Idim, CurrentDim, CGNS_ENUMV(Vertex), zcoor[0][g].rind_planes,
            DataSize)) return 1;

         /* DataArray_t */
        if (cgi_get_nodes(zcoor[0][g].id, "DataArray_t", &zcoor[0][g].ncoords,
            &id)) return 1;
        if (zcoor[0][g].ncoords > 0) {
            zcoor[0][g].coord = CGNS_NEW(cgns_array, zcoor[0][g].ncoords);
            for (z=0; z<zcoor[0][g].ncoords; z++) {
                zcoor[0][g].coord[z].id = id[z];
                zcoor[0][g].coord[z].link = cgi_read_link(id[z]);
                zcoor[0][g].coord[z].in_link = linked;
                if (cgi_read_array(&zcoor[0][g].coord[z],"GridCoordinates_t",
                    zcoor[0][g].id)) return 1;

                 /* check data */
                if (zcoor[0][g].coord[z].data_dim != Idim) {
                    cgi_error("Wrong number of dimension in DataArray %s",zcoor[0][g].coord[z].name);
                    return 1;
                }
                for (n=0; n<Idim; n++) {
                    if (zcoor[0][g].coord[z].dim_vals[n] != DataSize[n]) {
                        cgi_error("Invalid coordinates array dimension");
                        return 1;
                    }
                }
                if (strcmp(zcoor[0][g].coord[z].data_type,"R4") &&
                    strcmp(zcoor[0][g].coord[z].data_type,"R8")) {
                    cgi_error("Datatype %d not supported for coordinates");
                    return 1;
                }
            }
            free(id);
        }

         /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, zcoor[0][g].id, &zcoor[0][g].ndescr,
            &zcoor[0][g].descr, &zcoor[0][g].data_class, &zcoor[0][g].units))
            return 1;

         /* UserDefinedData_t */
        if (cgi_read_user_data(linked, zcoor[0][g].id, &zcoor[0][g].nuser_data,
            &zcoor[0][g].user_data)) return 1;

    }
    free(idg);

    return 0;
}

int cgi_read_section(int in_link, double parent_id, int *nsections,
                     cgns_section **section)
{
    double *id, *idi;
    int n, i, linked;
    int ndim, nchild, npe, changed;
    int *edata;
    CGNS_ENUMT(ElementType_t) el_type;
    char_33 data_type, temp_name;
    void *vdata;
    cgsize_t pdata_cnt, nelements, dim_vals[12];

    if (cgi_get_nodes(parent_id, "Elements_t", nsections, &id)) return 1;
    if (*nsections<=0) {
        section[0] = 0;
        return 0;
    }

    section[0] = CGNS_NEW(cgns_section, (*nsections));
    for (n=0; n<(*nsections); n++) {
        section[0][n].id = id[n];
        section[0][n].link = cgi_read_link(id[n]);
        section[0][n].in_link = in_link;
        linked = section[0][n].link ? 1 : in_link;

     /* Elements_t */
        if (cgi_read_node(section[0][n].id, section[0][n].name, data_type,
                &ndim, dim_vals, &vdata, READ_DATA)) {
            cgi_error("Error reading Elements_t node");
            return 1;
        }

     /* verify data read */
        if (strcmp(data_type,"I4")!=0) {
            cgi_error("Unsupported data type for Elements_t node %s= %s",
                   section[0][n].name, data_type);
            return 1;
        }
        if (ndim!=1) {
            cgi_error("Wrong number of dimension for Elements_t node '%s'.",
                section[0][n].name);
            return 1;
        }
        if (dim_vals[0]!=2) {
            cgi_error("Wrong dimension value for Elements_t node '%s'.",
                 section[0][n].name);
            return 1;
        }
        edata = (int *)vdata;
        el_type = (CGNS_ENUMT(ElementType_t))edata[0];
        /* additional element types added in 3 */
        changed = 0;
        if (cg->version < 3100) {
            if (cg->version < 3000) {
                if (el_type > CGNS_ENUMV(MIXED)) {
                    cgi_error("Element Type %s not supported in:'%s'",
                        cg_ElementTypeName(el_type), section[0][n].name);
                    return 1;
                }
            }
            /* reordered in 3.1 */
            else if (el_type > CGNS_ENUMV(PYRA_5) &&
                     el_type < CGNS_ENUMV(NGON_n)) {
                if (el_type == CGNS_ENUMV(PYRA_14))
                    el_type = CGNS_ENUMV(PYRA_13);
                else
                    el_type--;
                changed++;
            }
        }
        section[0][n].el_type = el_type;
        section[0][n].el_bound = edata[1];
        free(vdata);

        if (INVALID_ENUM(el_type,NofValidElementTypes)) {
            cgi_error("Invalid Element Type for Elements_t :'%s'",
                section[0][n].name);
            return 1;
        }

     /* Descriptor_t */
        if (cgi_get_nodes(section[0][n].id, "Descriptor_t",
            &section[0][n].ndescr, &idi)) return 1;
        if (section[0][n].ndescr>0) {
            section[0][n].descr = CGNS_NEW(cgns_descr, section[0][n].ndescr);
            for (i=0; i<section[0][n].ndescr; i++) {
                section[0][n].descr[i].id = idi[i];
                section[0][n].descr[i].link = cgi_read_link(idi[i]);
                section[0][n].descr[i].in_link = linked;
                if (cgi_read_string(idi[i], section[0][n].descr[i].name,
                    &section[0][n].descr[i].text)) return 1;
            }
            free(idi);
        }

     /* IndexRange_t */
        if (cgi_get_nodes(section[0][n].id, "IndexRange_t", &nchild, &idi))
            return 1;
        if (nchild==1) {
            if (cgi_read_node(idi[0], temp_name, data_type, &ndim, dim_vals,
                    &vdata, READ_DATA)) {
                cgi_error("Error reading element range");
                return 1;
            }
        } else {
            cgi_error("Error exit: ElementRange incorrectly defined");
            return 1;
        }
        if (nchild) free(idi);

     /* verify that the name matches the type intended */
        if (strcmp(temp_name,"ElementRange")) {
            cgi_error("Invalid point set type: '%s'",temp_name);
            return 1;
        }
     /* verify dimension vector */
        if (ndim!=1 || dim_vals[0]!=2) {
            cgi_error("Invalid dimensions in definition of ElementRange");
            return 1;
        }

     /* nelements */
        if (0 == strcmp(data_type, "I8")) {
            cglong_t *data = (cglong_t *)vdata;
#if CG_SIZEOF_SIZE == 32
            if (cgio_check_dimensions(ndim, data)) {
                cg_io_error("cgio_check_dimensions");
                return 1;
            }
#endif
            section[0][n].range[0] = (cgsize_t)data[0];
            section[0][n].range[1] = (cgsize_t)data[1];
        }
        else if (0 == strcmp(data_type, "I4")) {
            int *data = (int *)vdata;
            section[0][n].range[0] = (cgsize_t)data[0];
            section[0][n].range[1] = (cgsize_t)data[1];
        }
        else {
            cgi_error("Data type %s not supported for ElementRange", data_type);
            return 1;
        }
        nelements = section[0][n].range[1] - section[0][n].range[0] + 1;
        free(vdata);

     /* rind elements */
        if (cgi_read_rind(section[0][n].id, &section[0][n].rind_planes))
            return 1;

     /* initialize */
        section[0][n].connect = 0;
        section[0][n].parelem = 0;
        section[0][n].parface = 0;

     /* DataArray_t:  ElementConnectivity & ParentData DataArray_t */
        if (cgi_get_nodes(section[0][n].id, "DataArray_t", &nchild, &idi))
            return 1;
        for (i=0; i<nchild; i++) {
            if (cgio_get_name(cg->cgio, idi[i], temp_name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }

         /* ElementConnectivity */
            if (strcmp(temp_name,"ElementConnectivity")==0) {
                if (section[0][n].connect) {
                    cgi_error("Error:  ElementConnectivity defined more than once");
                    return 1;
                }
                section[0][n].connect = CGNS_NEW(cgns_array, 1);
                section[0][n].connect->id = idi[i];
                section[0][n].connect->link = cgi_read_link(idi[i]);
                section[0][n].connect->in_link = linked;
                if (cgi_read_array(section[0][n].connect, "Elements_t",
                    section[0][n].id)) return 1;

             /* check data */
                if (strcmp(section[0][n].connect->data_type,"I4") &&
                    strcmp(section[0][n].connect->data_type,"I8")) {
                    cgi_error("Datatype %s not supported for element connectivity",
                        section[0][n].connect->data_type);
                    return 1;
                }
                if (cg_npe(section[0][n].el_type, &npe)) return 1;

                if (cg->version <= 1100) {
                    if (section[0][n].connect->dim_vals[0] != npe ||
                        section[0][n].connect->dim_vals[1] != nelements ||
                        section[0][n].connect->data_dim != 2 ) {
                        cgi_error("Error exit:  Element connectivity incorrectly defined");
                        return 1;
                    }
                 /* Rewrite with new data array parameters starting with version 1200 */
                    section[0][n].connect->data_dim = 1;
                    section[0][n].connect->dim_vals[0] = npe*nelements;
                    section[0][n].connect->dim_vals[1] = 0;
                    if (cg->mode == CG_MODE_MODIFY && !linked) {
                        /* read the data into memory */
                        if (cgi_read_node(section[0][n].connect->id,
                                section[0][n].connect->name,
                                section[0][n].connect->data_type,
                                &ndim, dim_vals, &vdata, READ_DATA)) return 1;
                        if (cgio_set_dimensions(cg->cgio,
                                section[0][n].connect->id, "I4",
                                1, section[0][n].connect->dim_vals)) {
                            cg_io_error("cgio_set_dimensions");
                            return 1;
                        }
                        if (cgio_write_all_data(cg->cgio,
                                section[0][n].connect->id, vdata)) {
                            cg_io_error("cgio_write_all_data");
                            return 1;
                        }
                        CGNS_FREE(vdata);
                    }

                } else if (cg->version < 3100) {
                    cgsize_t size, *elem_data = 0;
                    int modified = 0;
                    if (section[0][n].el_type == CGNS_ENUMV(MIXED)) {
                        int ne;
                        size = section[0][n].connect->dim_vals[0];
                        elem_data = CGNS_NEW(cgsize_t, size);
                        if (cgi_read_int_data(section[0][n].connect->id,
                                section[0][n].connect->data_type,
                                size, elem_data)) return 1;
                        for (size = 0, ne = 0; ne < nelements; ne++) {
                            el_type = (CGNS_ENUMT(ElementType_t))elem_data[size];
                            if (cg->version < 3000) {
                                if (el_type > CGNS_ENUMV(MIXED)) {
                                    modified++;
                                    el_type++;
                                    elem_data[size] = el_type;
                                }
                            }
                            else {
                                if (el_type > CGNS_ENUMV(PYRA_5) &&
                                    el_type < CGNS_ENUMV(NGON_n)) {
                                    if (el_type == CGNS_ENUMV(PYRA_14))
                                        el_type = CGNS_ENUMV(PYRA_13);
                                    else
                                        el_type--;
                                    modified++;
                                    elem_data[size] = el_type;
                                }
                            }
                            if (el_type > CGNS_ENUMV(NGON_n))
                                npe = el_type - CGNS_ENUMV(NGON_n);
                            else
                                cg_npe (el_type, &npe);
                            if (npe <= 0) {
                                cgi_error("Error exit: invalid element type in MIXED elements");
                                return 1;
                            }
                            size += (npe + 1);
                        }
                        if (!modified) {
                            CGNS_FREE(elem_data);
                            elem_data = 0;
                        }
                    }
                    size = cgi_element_data_size(section[0][n].el_type,
                                                 nelements, elem_data);
                    if (size < 0) return 1;
                    /* size may be zero, since elements not read */
                    if ((size && section[0][n].connect->dim_vals[0] != size) ||
                        section[0][n].connect->data_dim != 1) {
                        cgi_error("Error exit:  Element connectivity incorrectly defined");
                        return 1;
                    }
                    /* rewrite if needed */
                    if ((changed || modified) &&
                        cg->mode == CG_MODE_MODIFY && !linked) {
                        if (changed) {
                            dim_vals[0] = (cgsize_t)section[0][n].el_type;
                            dim_vals[1] = (cgsize_t)section[0][n].el_bound;
                            if (cgio_write_all_data(cg->cgio,
                                    section[0][n].id, dim_vals)) {
                                cg_io_error("cgio_write_all_data");
                                return 1;
                            }
                            changed = 0;
                        }
                        if (modified) {
                            if (strcmp(section[0][n].connect->data_type, CG_SIZE_DATATYPE)) {
                                if (cgio_set_dimensions(cg->cgio,
                                        section[0][n].connect->id, CG_SIZE_DATATYPE,
                                        1, section[0][n].connect->dim_vals)) {
                                    cg_io_error("cgio_set_dimensions");
                                    return 1;
                                }
                                strcpy(section[0][n].connect->data_type, CG_SIZE_DATATYPE);
                            }
                            if (cgio_write_all_data(cg->cgio,
                                    section[0][n].connect->id, elem_data)) {
                                cg_io_error("cgio_write_all_data");
                                return 1;
                            }
                            CGNS_FREE(elem_data);
                            elem_data = 0;
                        }
                    }
                    if (elem_data) {
                        strcpy(section[0][n].connect->data_type, CG_SIZE_DATATYPE);
                        section[0][n].connect->data = (void *)elem_data;
                    }
                }

            } else if (strcmp(temp_name,"ParentData")==0) {
                if (section[0][n].parelem) {
                    cgi_error("Error:  Element ParentData defined more than once");
                    return 1;
                }
                section[0][n].parelem = CGNS_NEW(cgns_array, 1);
                section[0][n].parelem->id = idi[i];
                section[0][n].parelem->link = cgi_read_link(idi[i]);
                section[0][n].parelem->in_link = linked;
                if (cgi_read_array(section[0][n].parelem, "Elements_t",
                    section[0][n].id)) return 1;

                /* check data */
                if (strcmp(section[0][n].parelem->data_type,"I4") &&
                    strcmp(section[0][n].parelem->data_type,"I8")) {
                    cgi_error("Datatype %s not supported for element 'ParentData'",
                        section[0][n].parelem->data_type);
                    return 1;
                }
                if(section[0][n].parelem->range[0] > 0 &&
                    section[0][n].parelem->range[1] > 0)
                    pdata_cnt = section[0][n].parelem->range[1] -
                            section[0][n].parelem->range[0] + 1;
                else
                    pdata_cnt = nelements;

                if (section[0][n].parelem->dim_vals[0] != pdata_cnt ||
                    section[0][n].parelem->dim_vals[1] != 4 ||
                    section[0][n].parelem->data_dim != 2 ) {
                    cgi_error("Error exit:  Element 'ParentData' incorrectly defined");
                    return 1;
                }

            } else if (strcmp(temp_name,"ParentElements")==0) {
                if (section[0][n].parelem) {
                    cgi_error("Error:  Element ParentElements defined more than once");
                    return 1;
                }
                section[0][n].parelem = CGNS_NEW(cgns_array, 1);
                section[0][n].parelem->id = idi[i];
                section[0][n].parelem->link = cgi_read_link(idi[i]);
                section[0][n].parelem->in_link = linked;
                if (cgi_read_array(section[0][n].parelem, "Elements_t",
                    section[0][n].id)) return 1;

                /* check data */
                if (strcmp(section[0][n].parelem->data_type,"I4") &&
                    strcmp(section[0][n].parelem->data_type,"I8")) {
                    cgi_error("Datatype %s not supported for element 'ParentElements'",
                        section[0][n].parelem->data_type);
                    return 1;
                }
                if(section[0][n].parelem->range[0] > 0 &&
                    section[0][n].parelem->range[1] > 0)
                    pdata_cnt = section[0][n].parelem->range[1] -
                            section[0][n].parelem->range[0] + 1;
                else
                    pdata_cnt = nelements;

                if (section[0][n].parelem->dim_vals[0] != pdata_cnt ||
                    section[0][n].parelem->dim_vals[1] != 2 ||
                    section[0][n].parelem->data_dim != 2 ) {
                    cgi_error("Error exit:  Element 'ParentElements' incorrectly defined");
                    return 1;
                }
            } else if (strcmp(temp_name,"ParentElementsPosition")==0) {
                if (section[0][n].parface) {
                    cgi_error("Error:  Element ParentElementsPosition defined more than once");
                    return 1;
                }
                section[0][n].parface = CGNS_NEW(cgns_array, 1);
                section[0][n].parface->id = idi[i];
                section[0][n].parface->link = cgi_read_link(idi[i]);
                section[0][n].parface->in_link = linked;
                if (cgi_read_array(section[0][n].parface, "Elements_t",
                    section[0][n].id)) return 1;

                /* check data */
                if (strcmp(section[0][n].parface->data_type,"I4") &&
                    strcmp(section[0][n].parface->data_type,"I8")) {
                    cgi_error("Datatype %s not supported for element 'ParentElementsPosition'",
                        section[0][n].parelem->data_type);
                    return 1;
                }
                if(section[0][n].parface->range[0] > 0 &&
                    section[0][n].parface->range[1] > 0)
                    pdata_cnt = section[0][n].parface->range[1] -
                            section[0][n].parface->range[0] + 1;
                else
                    pdata_cnt = nelements;

                if (section[0][n].parface->dim_vals[0] != pdata_cnt ||
                    section[0][n].parface->dim_vals[1] != 2 ||
                    section[0][n].parface->data_dim != 2 ) {
                    cgi_error("Error exit:  Element 'ParentElementsPosition' incorrectly defined");
                    return 1;
                }
            }
        }   /* loop through DataArray_t */
/* check
        cgi_array_print("connect",section[0][n].connect);
        if (section[0][n].parent) cgi_array_print("parent",section[0][n].parent);
*/
        if (nchild) free(idi);
        if (section[0][n].connect == 0) {
            cgi_error("Error exit: ElementConnectivity undefined in Element_t node '%s'.",
                section[0][n].name);
            return 1;
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, section[0][n].id,
            &section[0][n].nuser_data, &section[0][n].user_data)) return 1;

	if (section[0][n].parelem != NULL &&
	    0 == strcmp(section[0][n].parelem->name, "ParentData") &&
            cg->mode == CG_MODE_MODIFY && !linked &&
            cg->filetype != CG_FILE_ADF2) {
	    void *pardata;
	    pdata_cnt = section[0][n].parelem->dim_vals[0];
	    strcpy(data_type, section[0][n].parelem->data_type);
	    if (0 == strcmp(data_type, "I8")) {
	        pardata = malloc((size_t)(pdata_cnt * 4 * sizeof(cglong_t)));
		vdata = (void *)(((cglong_t *)pardata) + (pdata_cnt * 2));
	    } else {
	        pardata = malloc((size_t)(pdata_cnt * 4 * sizeof(int)));
		vdata = (void *)(((int *)pardata) + (pdata_cnt * 2));
	    }
	    if (pardata == NULL) {
		cgi_error("malloc failed for ParentData conversion array");
		return 1;
	    }
	    if (cgio_read_all_data(cg->cgio, section[0][n].parelem->id, pardata)) {
                cg_io_error("cgio_read_all_data");
		return 1;
	    }
	    if (cgi_delete_node(section[0][n].id, section[0][n].parelem->id))
		return 1;

	    memset(section[0][n].parelem, 0, sizeof(cgns_array));
            strcpy(section[0][n].parelem->data_type, data_type);
            strcpy(section[0][n].parelem->name, "ParentElements");
            section[0][n].parelem->data_dim =2;
            section[0][n].parelem->dim_vals[0]=pdata_cnt;
            section[0][n].parelem->dim_vals[1]=2;
            if (cgi_write_array(section[0][n].id, section[0][n].parelem)) return 1;
            if (cgio_write_all_data(cg->cgio, section[0][n].parelem->id, pardata)) {
                cg_io_error("cgio_write_all_data");
		return 1;
	    }

            section[0][n].parface = CGNS_NEW(cgns_array, 1);
            strcpy(section[0][n].parface->data_type, data_type);
            strcpy(section[0][n].parface->name, "ParentElementsPosition");
            section[0][n].parface->data_dim =2;
            section[0][n].parface->dim_vals[0]=pdata_cnt;
            section[0][n].parface->dim_vals[1]=2;
            if (cgi_write_array(section[0][n].id, section[0][n].parface)) return 1;
            if (cgio_write_all_data(cg->cgio, section[0][n].parface->id, vdata)) {
                cg_io_error("cgio_write_all_data");
		return 1;
	    }
	}

    }   /* loop through element sections */
    free(id);

    return 0;
}

int cgi_read_sol(int in_link, double parent_id, int *nsols, cgns_sol **sol)
{
    double *id, *idf;
    int s, z, n, linked;
    cgsize_t DataSize[3], DataCount = 0;

    if (cgi_get_nodes(parent_id, "FlowSolution_t", nsols, &id))
        return 1;
    if (*nsols<=0) {
        sol[0] = 0;
        return 0;
    }

    sol[0] = CGNS_NEW(cgns_sol, (*nsols));
    for (s=0; s<(*nsols); s++) {
        sol[0][s].id = id[s];
        sol[0][s].link = cgi_read_link(id[s]);
        sol[0][s].in_link = in_link;
        linked = sol[0][s].link ? 1 : in_link;

     /* FlowSolution_t Name */
        if (cgio_get_name(cg->cgio, sol[0][s].id, sol[0][s].name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }

     /* GridLocation */
        if (cgi_read_location(sol[0][s].id, sol[0][s].name,
            &sol[0][s].location)) return 1;

     /* Rind Planes */
        if (cgi_read_rind(sol[0][s].id, &sol[0][s].rind_planes)) return 1;

     /* Determine data size */
        if (cgi_datasize(Idim, CurrentDim, sol[0][s].location,
                sol[0][s].rind_planes, DataSize)) return 1;

     /* check for PointList/PointRange */
        if (cgi_read_one_ptset(linked, sol[0][s].id,
                &sol[0][s].ptset)) return 1;
        if (sol[0][s].ptset != NULL) {
            if (sol[0][s].ptset->type == CGNS_ENUMV(ElementList) ||
                sol[0][s].ptset->type == CGNS_ENUMV(ElementRange)) {
                cgi_error("ElementList/Range not supported under FlowSolution");
                return 1;
            }
            DataCount = sol[0][s].ptset->size_of_patch;
        }

     /* DataArray_t */
        if (cgi_get_nodes(sol[0][s].id, "DataArray_t", &sol[0][s].nfields,
            &idf)) return 1;
        if (sol[0][s].nfields > 0) {
            sol[0][s].field = CGNS_NEW(cgns_array, sol[0][s].nfields);
            for (z=0; z<sol[0][s].nfields; z++) {
                sol[0][s].field[z].id = idf[z];
                sol[0][s].field[z].link = cgi_read_link(idf[z]);
                sol[0][s].field[z].in_link = linked;

                if (cgi_read_array(&sol[0][s].field[z],"FlowSolution_t",
                    sol[0][s].id)) return 1;

             /* check data */
                if (sol[0][s].ptset == NULL) {
                    if (sol[0][s].field[z].data_dim != Idim) {
                        cgi_error("Wrong number of dimension in DataArray %s",
                            sol[0][s].field[z].name);
                        return 1;
                    }
                    for (n=0; n<Idim; n++) {
                        if (sol[0][s].field[z].dim_vals[n]!=DataSize[n]) {
                            cgi_error("Invalid field array dimension");
                            return 1;
                        }
                    }
                } else {
                    if (sol[0][s].field[z].data_dim != 1 ||
                        sol[0][s].field[z].dim_vals[0] != DataCount) {
                        cgi_error("Invalid field array dimension for ptset solution");
                        return 1;
                    }
                }
                if (strcmp(sol[0][s].field[z].data_type,"I4") &&
                    strcmp(sol[0][s].field[z].data_type,"I8") &&
                    strcmp(sol[0][s].field[z].data_type,"R4") &&
                    strcmp(sol[0][s].field[z].data_type,"R8")) {
                    cgi_error("Datatype %d not supported for flow solutions");
                    return 1;
                }
            }
            free(idf);
        }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, sol[0][s].id, &sol[0][s].ndescr,
            &sol[0][s].descr, &sol[0][s].data_class, &sol[0][s].units))
            return 1;

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, sol[0][s].id, &sol[0][s].nuser_data,
            &sol[0][s].user_data)) return 1;
    }

    free(id);

    return 0;
}

int cgi_read_zconn(int in_link, double parent_id, int *nzconn, cgns_zconn **zconn)
{
    int i, n, linked;
    double *ids, *id;
    cgns_zconn *zc;

    if (cgi_get_nodes(parent_id, "ZoneGridConnectivity_t", nzconn, &ids))
        return 1;
    if (*nzconn<=0) {
        *zconn = 0;
        return 0;
    }
    zc = CGNS_NEW(cgns_zconn, *nzconn);
    *zconn = zc;

    for (i = 0; i < *nzconn; i++) {
        zc[i].id = ids[i];
        zc[i].link = cgi_read_link(ids[i]);
        zc[i].in_link = in_link;
        linked = zc[i].link ? 1 : in_link;

        /* Name */
        if (cgio_get_name(cg->cgio, zc[i].id, zc[i].name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }

        /* OversetHoles_t */
        if (cgi_get_nodes(zc[i].id, "OversetHoles_t", &zc[i].nholes, &id))
            return 1;
        if (zc[i].nholes > 0) {
            zc[i].hole = CGNS_NEW(cgns_hole,zc[i].nholes);
            for (n=0; n<zc[i].nholes; n++) {
                zc[i].hole[n].id = id[n];
                zc[i].hole[n].link = cgi_read_link(id[n]);
                zc[i].hole[n].in_link = linked;
                if (cgi_read_hole(&zc[i].hole[n])) return 1;
            }
            free(id);
        }

        /* GridConnectivity_t */
        if (cgi_get_nodes(zc[i].id, "GridConnectivity_t",
            &zc[i].nconns, &id)) return 1;
        if (zc[i].nconns > 0) {
            zc[i].conn = CGNS_NEW(cgns_conn,zc[i].nconns);
            for (n=0; n<zc[i].nconns; n++) {
                zc[i].conn[n].id = id[n];
                zc[i].conn[n].link = cgi_read_link(id[n]);
                zc[i].conn[n].in_link = linked;
                if (cgi_read_conn(&zc[i].conn[n])) return 1;
            }
            free(id);
        }

        /* GridConnectivity1to1_t */
        if (cgi_get_nodes(zc[i].id, "GridConnectivity1to1_t",
            &zc[i].n1to1, &id)) return 1;
        if (zc[i].n1to1 >0) {
            zc[i].one21 = CGNS_NEW(cgns_1to1, zc[i].n1to1);
            for (n=0; n<zc[i].n1to1; n++) {
                zc[i].one21[n].id = id[n];
                zc[i].one21[n].link = cgi_read_link(id[n]);
                zc[i].one21[n].in_link = linked;
                if (cgi_read_1to1(&zc[i].one21[n])) return 1;
            }
            free(id);
        }

        /* Descriptor_t */
        if (cgi_get_nodes(zc[i].id, "Descriptor_t",
            &zc[i].ndescr, &id)) return 1;
        if (zc[i].ndescr>0) {
            zc[i].descr = CGNS_NEW(cgns_descr, zc[i].ndescr);
            for (n=0; n<zc[i].ndescr; n++) {
                zc[i].descr[n].id = id[n];
                zc[i].descr[n].link = cgi_read_link(id[n]);
                zc[i].descr[n].in_link = linked;
                if (cgi_read_string(id[n], zc[i].descr[n].name,
                    &zc[i].descr[n].text)) return 1;
            }
            free(id);
        }

        /* UserDefinedData_t */
        if (cgi_read_user_data(linked, zc[i].id, &zc[i].nuser_data,
            &zc[i].user_data)) return 1;
    }

    free(ids);
    return 0;
}

int cgi_read_1to1(cgns_1to1 *one21)
{
    int i, n, ndim;
    int nIA_t, nIR_t;
    int linked = one21->link ? 1 : one21->in_link;
    double *IA_id, *IR_id, *id;
    char_33 name, data_type;
    char *string_data;
    void *vdata;
    cgsize_t dim_vals[12];

     /* get donor name */
    if (cgi_read_string(one21->id, one21->name, &string_data)) return 1;
    strcpy(one21->donor, string_data);
    free(string_data);

     /* get ADF-ID of point sets for donor and receiver */
    one21->ptset.id=0;
    one21->ptset.link=0;
    one21->dptset.id=0;
    one21->dptset.link=0;
    if (cgi_get_nodes(one21->id, "IndexRange_t", &nIR_t, &IR_id)) return 1;
    for (i=0; i<nIR_t; i++) {
        if (cgio_get_name(cg->cgio, IR_id[i], name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
        if (strcmp(name, "PointRange")==0) {
            if (one21->ptset.id==0) {
                one21->ptset.id=IR_id[i];
                one21->ptset.link=cgi_read_link(IR_id[i]);
                one21->ptset.in_link=linked;
                one21->ptset.type=CGNS_ENUMV(PointRange);
            } else {
                cgi_error("Multiple PointRange definition for %s",one21->name);
                return 1;
            }
        } else if (strcmp(name, "PointRangeDonor")==0) {
            if (one21->dptset.id==0) {
                one21->dptset.id=IR_id[i];
                one21->dptset.link=cgi_read_link(IR_id[i]);
                one21->dptset.in_link=linked;
                one21->dptset.type=CGNS_ENUMV(PointRangeDonor);
            } else {
                cgi_error("Multiple PointRangeDonor definition for %s",one21->name);
                return 1;
            }
        }
    }
    if (nIR_t>0) free(IR_id);

    if (cg->filetype == CGIO_FILE_ADF || cg->filetype == CGIO_FILE_ADF2) {
      if (one21->ptset.id==0 || one21->dptset.id==0) {
        cgi_error("PointRange or PointRangeDonor undefined for %s",one21->name);
        return 1;
      }
    }
#ifdef BUILD_HDF5
    else if (cg->filetype == CGIO_FILE_HDF5 || cg->filetype == CGIO_FILE_PHDF5) {
    /*
     * Convert the double id to a hid_t id and compare that to 0 instead of
     * comparing doubles, this avoids issues with comparing doubles when
     * compiler optimization is enabled.
     */
      hid_t hid_ptset, hid_dptset;
      to_HDF_ID(one21->ptset.id,hid_ptset);
      to_HDF_ID(one21->dptset.id,hid_dptset);

      if (hid_ptset==0 || hid_dptset==0) {
        cgi_error("PointRange or PointRangeDonor undefined for %s",one21->name);
        return 1;
      }
    }
#endif
    else {
        return 1;
    }

     /* Read Point set Receiver */
    if (cgi_read_ptset(one21->id, &one21->ptset)) return 1;

     /* Read Point set Donor */
    if (cgi_read_ptset(one21->id, &one21->dptset)) return 1;

     /* Get "int[IndexDimension]" children */
    if (cgi_get_nodes(one21->id, "\"int[IndexDimension]\"", &nIA_t, &IA_id))
        return 1;

    if (nIA_t==0) {
        one21->transform = CGNS_NEW(int, Idim);
     /* set default transformation matrix to 1,2,3 */
        for (i=0; i<Idim; i++) one21->transform[i]=i+1;

    } else if (nIA_t<0 || nIA_t>1) {
        cgi_error("Invalid definition of transformation matrix for %s",one21->name);
        return 1;

    } else if (nIA_t==1) {
        if (cgi_read_node(IA_id[0], name, data_type, &ndim, dim_vals,
                &vdata, READ_DATA)) {
            cgi_error("Error reading 1to1-connectivity transformation matrix");
            return 1;
        }
        one21->transform = (int *)vdata;
    /* verify plausibility of data */
        if (strcmp("Transform", name)) {
            cgi_error("The ADF name should be 'Transform' and not '%s'",name);
            return 1;
        }
        if (strcmp(data_type, "I4")!=0) {
            cgi_error("Data type '%s' not supported for Transform",data_type);
            return 1;
        }
        if (ndim != 1 || dim_vals[0] != Idim) {
            cgi_error("Error in dimension for node type Transform");
            return 1;
        }
        for (i=0; i<Idim; i++) {
            if (one21->transform[i] >Idim || one21->transform[i] <(-1*Idim)) {
                cgi_error("Invalid transformation matrix");
                return 1;
            }
        }
        free(IA_id);
    }
     /* Ordinal_t */
    if (cgi_read_ordinal(one21->id, &one21->ordinal)) return 1;

     /* Descriptor_t */
    if (cgi_get_nodes(one21->id, "Descriptor_t", &one21->ndescr, &id))
        return 1;
    if (one21->ndescr>0) {
        one21->descr = CGNS_NEW(cgns_descr, one21->ndescr);
        for (n=0; n<one21->ndescr; n++) {
            one21->descr[n].id = id[n];
            one21->descr[n].link = cgi_read_link(id[n]);
            one21->descr[n].in_link = linked;
            if (cgi_read_string(id[n], one21->descr[n].name,
                &one21->descr[n].text)) return 1;
        }
        free(id);
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, one21->id, &one21->nuser_data,
        &one21->user_data)) return 1;

    /* GridConnectivityProperty_t */
    if (cgi_read_cprop(linked, one21->id, &one21->cprop)) return 1;

    return 0;
}

int cgi_read_conn(cgns_conn *conn)
{
    int i, nchild;
    int linked = conn->link ? 1 : conn->in_link;
    char_33 name, parent_label;
    double *id, parent_id;
    char *string_data;      /* allocated in cgi_read_node */

     /* get donor name */
    if (cgi_read_string(conn->id, conn->name, &string_data)) return 1;
    if (cgi_check_strlen(string_data)) return 1;
    strcpy(conn->donor, string_data);
    free(string_data);

     /* GridLocation */
    if (cgi_read_location(conn->id, conn->name, &conn->location)) return 1;
    if (conn->location != CGNS_ENUMV(Vertex) &&
        conn->location != CGNS_ENUMV(CellCenter) &&
        conn->location != CGNS_ENUMV(FaceCenter) &&
        conn->location != CGNS_ENUMV(IFaceCenter) &&
        conn->location != CGNS_ENUMV(JFaceCenter) &&
        conn->location != CGNS_ENUMV(KFaceCenter)) {
        cgi_error("Unsupported GridLocation %s for Connectivity %s",
            cg_GridLocationName(conn->location), conn->name);
        return 1;
    }

     /* Receiver IndexArray_t ? */
    conn->ptset.id=0;
    conn->ptset.link=0;
    if (cgi_get_nodes(conn->id, "IndexArray_t", &nchild, &id)) return 1;
    for (i=0; i<nchild; i++) {
        if (cgio_get_name(cg->cgio, id[i], name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
        if (strcmp(name, "PointList")==0) {
            if (conn->ptset.id==0) {
                conn->ptset.id=id[i];
                conn->ptset.link=cgi_read_link(id[i]);
                conn->ptset.in_link=linked;
                conn->ptset.type=CGNS_ENUMV( PointList );
                if (cgi_read_ptset(conn->id, &conn->ptset)) return 1;
            } else {
                cgi_error("Multiple PointList definition for %s",conn->name);
                return 1;
            }
        }
    }
    if (nchild>0) free(id);

     /* Receiver IndexRange_t ? */
    if (cgi_get_nodes(conn->id, "IndexRange_t", &nchild, &id)) return 1;
    for (i=0; i<nchild; i++) {
        if (cgio_get_name(cg->cgio, id[i], name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
        if (strcmp(name, "PointRange")==0) {
            if (conn->ptset.id==0) {
                conn->ptset.id=id[i];
                conn->ptset.link=cgi_read_link(id[i]);
                conn->ptset.in_link=linked;
                conn->ptset.type=CGNS_ENUMV( PointRange );
                if (cgi_read_ptset(conn->id, &conn->ptset)) return 1;
            } else {
                cgi_error("Multiple PointSet definition for %s",conn->name);
                return 1;
            }
        }
    }
    if (nchild>0) free(id);

     /* check */
    if (cg->filetype == CGIO_FILE_ADF || cg->filetype == CGIO_FILE_ADF2) {
      if (conn->ptset.id==0) {
        cgi_error("Niether PointRange nor PointList defined for GridConnectivity_t '%s'",
		  conn->name);
        return 1;
      }
    }
#ifdef BUILD_HDF5
    else if (cg->filetype == CGIO_FILE_HDF5 || cg->filetype == CGIO_FILE_PHDF5) {
      hid_t hid;
      to_HDF_ID(conn->ptset.id, hid);
      if (hid==0) {
        cgi_error("Niether PointRange nor PointList defined for GridConnectivity_t '%s'",
		  conn->name);
        return 1;
      }
    }
#endif
    else {
      return 1;
    }

     /* Find the parent node for Donor IndexArray_t */
    parent_id = 0;
    parent_label[0]='\0';
    if (cg->version <1100 || cg->version>1200) {
     /* Version 1.05 and 1.27+ put IndexArray_t directly under GridConnectivity_t */
        parent_id = conn->id;
        strcpy(parent_label,"GridConnectivity_t");

    } else {
     /* version 1.1 to 1.20 used intermediate structures StructuredDonor_t & UnstructuredDonor_t */
        if (cgi_get_nodes(conn->id, "StructuredDonor_t", &nchild, &id))
            return 1;
        if (nchild>1) {
            cgi_error("StructuredDonor_t defined more than once for GridConnectivity_t '%s'",
                conn->name);
            return 1;
        } else if (nchild==1) {
            parent_id = id[0];
            strcpy(parent_label,"StructuredDonor_t");
            free(id);
        }
        if (cgi_get_nodes(conn->id, "UnstructuredDonor_t", &nchild, &id))
            return 1;
        if (nchild>1) {
            cgi_error("UnstructuredDonor_t defined more than once for GridConnectivity_t '%s'",
                conn->name);
            return 1;
        } else if (nchild==1) {
            if (parent_id) {
                cgi_error("Multiple donors found under GridConnectivity_t '%s'",conn->name);
                return 1;
            }
            parent_id = id[0];
            strcpy(parent_label,"UnstructuredDonor_t");
            free(id);
        }
        if (!parent_id) {
            cgi_error("Error:  Donor data undefined for GridConnectivity_t '%s'", conn->name);
            return 1;
        }
    }

     /* Read Donor IndexArray_t */
    conn->dptset.id=0;
    conn->dptset.link=0;
    if (cgi_get_nodes(parent_id, "IndexArray_t", &nchild, &id)) return 1;

    for (i=0; i<nchild; i++) {
        if (cgio_get_name(cg->cgio, id[i], name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
        if (strcmp(name, "PointListDonor") && strcmp(name, "CellListDonor"))
            continue;
        if (conn->dptset.id==0) {
            conn->dptset.id=id[i];
            conn->dptset.link=cgi_read_link(id[i]);
            conn->dptset.in_link=linked;
            if (strcmp(name, "PointListDonor")==0)
              conn->dptset.type=CGNS_ENUMV( PointListDonor );
            else {
                if (strcmp(parent_label,"StructuredDonor_t")==0) {
                    cgi_error("StructuredDonor_t doesn't support CellListDonor");
                    return 1;
                }
                conn->dptset.type=CGNS_ENUMV( CellListDonor );
            }
            if (cgi_read_ptset(parent_id, &conn->dptset)) return 1;
        } else {
            cgi_error("Multiple PointListDonor/CellListDonor definition for %s",conn->name);
            return 1;
        }
    }
    if (nchild>0) free(id);
/*
    if (conn->dptset.id==0) {
        cgi_error("Error:  Donor patch undefined for GridConnectivity_t '%s'", conn->name);
        return 1;
    }
*/

     /* Read InterpolantsDonor if it exist */
    conn->interpolants=0;
    conn->narrays = 0;
    if (strcmp(parent_label,"StructuredDonor_t")) {
        if (cgi_get_nodes(parent_id, "DataArray_t", &nchild, &id)) return 1;
        conn->narrays = nchild;
        for (i=0; i<nchild; i++) {
            if (cgio_get_name(cg->cgio, id[i], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name, "InterpolantsDonor")) continue;
            if (conn->interpolants==0) {
                conn->interpolants = CGNS_NEW(cgns_array, 1);
                conn->interpolants->id = id[0];
                conn->interpolants->link = cgi_read_link(id[0]);
                conn->interpolants->in_link = linked;
                if (cgi_read_array(conn->interpolants, parent_label, parent_id))
                    return 1;
            } else {
                cgi_error("InterpolantsDonor defined more than once for GridConnectivity_t '%s'",
                       conn->name);
                return 1;
            }
        }
        if (nchild) free(id);
    }

     /* Get GridConnectivityType_t (conn->type) */
    if (cgi_get_nodes(conn->id, "GridConnectivityType_t", &nchild, &id))
        return 1;

    if (nchild==0) {
      conn->type = CGNS_ENUMV( Overset );
    } else if (nchild<0 || nchild>1) {
        cgi_error("Invalid definition of GridConnectivityType_t for %s",conn->name);
        return 1;
    } else if (nchild==1) {
     /* Read the grid connectivity type value in the GridConnectivityType_t node */
        if (cgi_read_string(id[0], name, &string_data)) return 1;
        if (cgi_GridConnectivityType(string_data, &conn->type)) return 1;
        free(string_data);
    }
    if (nchild) free(id);

    /* update the version */
    if (cg->mode == CG_MODE_MODIFY && !linked &&
        cg->version >= 1100 && cg->version <= 1200) {
        if (cgio_move_node(cg->cgio, parent_id,
                conn->dptset.id, conn->id)) {
            cg_io_error("cgio_move_node");
            return 1;
        }
        if (conn->interpolants) {
            if (cgio_move_node(cg->cgio, parent_id,
                    conn->interpolants->id, conn->id)) {
                cg_io_error("cgio_move_node");
                return 1;
            }
        }
        if (cgi_delete_node(conn->id, parent_id)) return 1;
    }

     /* Ordinal_t */
    conn->ordinal=0;
    if (cgi_read_ordinal(conn->id, &conn->ordinal)) return 1;

     /* Descriptor_t */
    if (cgi_get_nodes(conn->id, "Descriptor_t", &conn->ndescr, &id)) return 1;
    if (conn->ndescr>0) {
        conn->descr = CGNS_NEW(cgns_descr, conn->ndescr);
        for (i=0; i<conn->ndescr; i++) {
            conn->descr[i].id = id[i];
            conn->descr[i].link = cgi_read_link(id[i]);
            conn->descr[i].in_link = linked;
            if (cgi_read_string(id[i], conn->descr[i].name,
                &conn->descr[i].text)) return 1;
        }
        free(id);
    }

     /* GridConnectivityProperty_t */
    if (cgi_read_cprop(linked, conn->id, &conn->cprop)) return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, conn->id, &conn->nuser_data,
        &conn->user_data)) return 1;

    return 0;
}

int cgi_read_cprop(int in_link, double parent_id, cgns_cprop **cprop)
{
    int nchild, n, linked;
    double *id;
    char *type_name;    /* allocated in cgi_read_node */
    char_33 name;

     /* get number of GridConnectivityProperty_t nodes and their ID */
    if (cgi_get_nodes(parent_id, "GridConnectivityProperty_t", &nchild, &id)) return 1;
    if (nchild<=0) {
        cprop[0]=0;
        return 0;
    } else if (nchild>1) {
        cgi_error("Error: Multiple GridConnectivityProperty_t found...");
        free(id);
        return 1;
    }
    cprop[0] = CGNS_NEW(cgns_cprop, 1);
    cprop[0]->id = id[0];
    cprop[0]->link = cgi_read_link(id[0]);
    cprop[0]->in_link = in_link;
    linked = cprop[0]->link ? 1 : in_link;
    free(id);

     /* Descriptor_t */
    if (cgi_get_nodes(cprop[0]->id, "Descriptor_t", &nchild, &id)) return 1;
    cprop[0]->ndescr = 0;
    if (nchild>0) {
        cprop[0]->ndescr = nchild;
        cprop[0]->descr = CGNS_NEW(cgns_descr, nchild);
        for (n=0; n<nchild; n++) {
            cprop[0]->descr[n].id = id[n];
            cprop[0]->descr[n].link = cgi_read_link(id[n]);
            cprop[0]->descr[n].in_link = linked;
            if (cgi_read_string(id[n], cprop[0]->descr[n].name,
                &cprop[0]->descr[n].text)) return 1;
        }
        free(id);
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, cprop[0]->id, &cprop[0]->nuser_data,
        &cprop[0]->user_data)) return 1;

     /* AverageInterface_t */
    if (cgi_get_nodes(cprop[0]->id, "AverageInterface_t", &nchild, &id))
        return 1;
    if (nchild<=0) {
        cprop[0]->caverage = 0;
    } else if (nchild>1) {
        cgi_error("Error: Multiple AverageInterface_t found...");
        free(id);
        return 1;
    } else {
        cprop[0]->caverage = CGNS_NEW(cgns_caverage, 1);
        cprop[0]->caverage->id = id[0];
        cprop[0]->caverage->link = cgi_read_link(id[0]);
        cprop[0]->caverage->in_link = linked;
        in_link = cprop[0]->caverage->link ? 1 : linked;
        free(id);

     /* Descriptor_t */
        if (cgi_get_nodes(cprop[0]->caverage->id, "Descriptor_t", &nchild, &id))
            return 1;
        cprop[0]->caverage->ndescr = 0;
        if (nchild>0) {
            cprop[0]->caverage->ndescr = nchild;
            cprop[0]->caverage->descr = CGNS_NEW(cgns_descr, nchild);
            for (n=0; n<nchild; n++) {
                cprop[0]->caverage->descr[n].id = id[n];
                cprop[0]->caverage->descr[n].link = cgi_read_link(id[n]);
                cprop[0]->caverage->descr[n].in_link = in_link;
                if (cgi_read_string(id[n], cprop[0]->caverage->descr[n].name,
                    &cprop[0]->caverage->descr[n].text)) return 1;
            }
            free(id);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(in_link, cprop[0]->caverage->id,
            &cprop[0]->caverage->nuser_data, &cprop[0]->caverage->user_data))
            return 1;

     /* AverageInterfaceType_t */
        if (cgi_get_nodes(cprop[0]->caverage->id, "AverageInterfaceType_t",
            &nchild, &id)) return 1;
        if (nchild==0) {
            cgi_error("Error: AverageInterfaceType_t missing under AverageInterface_t");
            return 1;
        } else if (nchild >1) {
            cgi_error("File incorrect: multiple definition of AverageInterfaceType");
            free(id);
            return 1;
        } else {
            if (cgi_read_string(id[0], name, &type_name)) return 1;
            free(id);
            if (cgi_AverageInterfaceType(type_name, &cprop[0]->caverage->type))
                return 1;
            free(type_name);
        }
    }

     /* Periodic_t */
    if (cgi_get_nodes(cprop[0]->id, "Periodic_t", &nchild, &id)) return 1;
    if (nchild<=0) {
        cprop[0]->cperio = 0;
    } else if (nchild>1) {
        cgi_error("Error: Multiple Periodic_t found...");
        free(id);
        return 1;
    } else {
        cprop[0]->cperio = CGNS_NEW(cgns_cperio, 1);
        cprop[0]->cperio->id = id[0];
        cprop[0]->cperio->link = cgi_read_link(id[0]);
        cprop[0]->cperio->in_link = linked;
        in_link = cprop[0]->cperio->link ? 1 : linked;
        free(id);

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(in_link, cprop[0]->cperio->id,
            &cprop[0]->cperio->ndescr, &cprop[0]->cperio->descr,
            &cprop[0]->cperio->data_class, &cprop[0]->cperio->units))
            return 1;

     /* UserDefinedData_t */
        if (cgi_read_user_data(in_link, cprop[0]->cperio->id,
            &cprop[0]->cperio->nuser_data, &cprop[0]->cperio->user_data))
            return 1;

     /* DataArray_t: RotationCenter, RotationAngle, Translation: <real, 1, PhysicalDimension> */
        if (cgi_get_nodes(cprop[0]->cperio->id, "DataArray_t", &nchild, &id))
            return 1;
        if (nchild==0) {
            cgi_error("Error: Three DataArray_t nodes missing under Periodic_t");
            return 1;
        } else if (nchild!=3) {
            cgi_error("Error: 3 DataArray_t required under Periodic_t");
            free(id);
            return 1;
        }
        cprop[0]->cperio->narrays = nchild;
        cprop[0]->cperio->array = CGNS_NEW(cgns_array, cprop[0]->cperio->narrays);

        for (n=0; n<(cprop[0]->cperio->narrays); n++) {
            cgns_array *array;
            cprop[0]->cperio->array[n].id = id[n];
            cprop[0]->cperio->array[n].link = cgi_read_link(id[n]);
            cprop[0]->cperio->array[n].in_link = in_link;

            if (cgi_read_array(&cprop[0]->cperio->array[n], "Periodic_t",
                cprop[0]->cperio->id)) return 1;

            array = &cprop[0]->cperio->array[n];

             /* check data */
            if (strcmp("RotationCenter",array->name) &&
                strcmp("RotationAngle",array->name) &&
                strcmp("Translation",array->name)) {
                cgi_error("Error: Wrong DataArray_t found under Periodic_t: '%s'",array->name);
                free(id);
                return 1;
            } else if (strcmp(array->data_type,"R4") || array->data_dim!=1
                || array->dim_vals[0]!=Pdim) {
                cgi_error("Error: Array '%s' incorrectly sized",array->name);
                free(id);
                return 1;
            }
        } /* loop through arrays */
        free(id);
    }
    return 0;
}

int cgi_read_hole(cgns_hole *hole)
{
    int linked = hole->link ? 1 : hole->in_link;
    int nIA_t, nIR_t;
    double *IA_id, *IR_id, *id;
    int set, n;

     /* name of OversetHoles_t Node */
    if (cgio_get_name(cg->cgio, hole->id, hole->name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

     /* GridLocation */
    if (cgi_read_location(hole->id, hole->name, &hole->location)) return 1;
    if (hole->location != CGNS_ENUMV( Vertex ) &&
        hole->location != CGNS_ENUMV( CellCenter )) {
        cgi_error("Unsupported GridLocation %s for Overset Hole %s",
            cg_GridLocationName(hole->location), hole->name);
        return 1;
    }

     /* get number of IndexArray_t and IndexRange_t nodes and their ID */
    if (cgi_get_nodes(hole->id, "IndexArray_t", &nIA_t, &IA_id)) return 1;
    if (cgi_get_nodes(hole->id, "IndexRange_t", &nIR_t, &IR_id)) return 1;

     /* Hole defined with several PointRange */
    if (nIA_t==0 && nIR_t>0) {
        hole->nptsets = nIR_t;
        hole->ptset = CGNS_NEW(cgns_ptset, nIR_t);
        for (set=0; set<nIR_t; set++) {
            hole->ptset[set].id = IR_id[set];
            hole->ptset[set].link = cgi_read_link(IR_id[set]);
            hole->ptset[set].in_link = linked;
            hole->ptset[set].type = CGNS_ENUMV( PointRange );
            if (cgi_read_ptset(hole->id, &hole->ptset[set])) return 1;
        }
        free(IR_id);

     /* Hole defined with one single PointList */
    } else if (nIA_t==1 && nIR_t==0) {
        hole->nptsets = 1;
        hole->ptset = CGNS_NEW(cgns_ptset, 1);
        hole->ptset[0].id = IA_id[0];
        hole->ptset[0].link = cgi_read_link(IA_id[0]);
        hole->ptset[0].in_link = linked;
        hole->ptset[0].type = CGNS_ENUMV( PointList );
        if (cgi_read_ptset(hole->id, &hole->ptset[0])) return 1;
        free(IA_id);

     /* Empty hole (requested by Cetin) */
    } else if (nIA_t==0 && nIR_t==0) {
        hole->nptsets = 1;
        hole->ptset = CGNS_NEW(cgns_ptset, 1);
        hole->ptset[0].npts = 0;
        hole->ptset[0].type = CGNS_ENUMV( PointList ); /* initialize */
        strcpy(hole->ptset[0].data_type, "I4");
        hole->ptset[0].id = 0;
        hole->ptset[0].link = 0;
        hole->ptset[0].in_link = linked;
        strcpy(hole->ptset[0].name,"Empty");
    } else {
        cgi_error("Overset hole '%s' defined incorrectly with %d IndexArray_t and %d IndexRange_t.",
               hole->name, nIA_t, nIR_t);
        return 1;
    }

     /* Descriptor_t */
    if (cgi_get_nodes(hole->id, "Descriptor_t", &hole->ndescr, &id)) return 1;
    if (hole->ndescr>0) {
        hole->descr = CGNS_NEW(cgns_descr, hole->ndescr);
        for (n=0; n<hole->ndescr; n++) {
            hole->descr[n].id = id[n];
            hole->descr[n].link = cgi_read_link(id[n]);
            hole->descr[n].in_link = linked;
            if (cgi_read_string(id[n], hole->descr[n].name,
                &hole->descr[n].text)) return 1;
        }
        free(id);
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, hole->id, &hole->nuser_data,
        &hole->user_data)) return 1;

    return 0;
}

int cgi_read_zboco(int in_link, double parent_id, cgns_zboco **zboco)
{
    int nnod, n, linked;
    double *id;

    if (cgi_get_nodes(parent_id, "ZoneBC_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        zboco[0] = 0;
        return 0;
    }
    zboco[0] = CGNS_NEW(cgns_zboco, 1);
    zboco[0]->id = id[0];
    zboco[0]->link = cgi_read_link(id[0]);
    zboco[0]->in_link = in_link;
    linked = zboco[0]->link ? 1 : in_link;
    free(id);

     /* Name */
    if (cgio_get_name(cg->cgio, zboco[0]->id, zboco[0]->name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

     /* get number of BC_t */
    if (cgi_get_nodes(zboco[0]->id, "BC_t", &zboco[0]->nbocos, &id)) return 1;
    if (zboco[0]->nbocos > 0) {
        zboco[0]->boco = CGNS_NEW(cgns_boco,zboco[0]->nbocos);
        for (n=0; n<zboco[0]->nbocos; n++) {
            zboco[0]->boco[n].id = id[n];
            zboco[0]->boco[n].link = cgi_read_link(id[n]);
            zboco[0]->boco[n].in_link = linked;
            if (cgi_read_boco(&zboco[0]->boco[n])) return 1;
        }               /* loop through BC_t nodes      */
        free(id);
    }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, zboco[0]->id, &zboco[0]->ndescr, &zboco[0]->descr,
        &zboco[0]->data_class, &zboco[0]->units)) return 1;

     /* ReferenceState_t */
    if (cgi_read_state(linked, zboco[0]->id, &zboco[0]->state)) return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, zboco[0]->id, &zboco[0]->nuser_data,
        &zboco[0]->user_data)) return 1;

    return 0;
}

int cgi_read_boco(cgns_boco *boco)
{
    int ierr=0, modified = 0;
    int linked = boco->link ? 1 : boco->in_link;
    int nIA_t, n, i;
    double *IA_id, *id;
    char *boconame;
    char_33 name, data_type;
    cgns_ptset *ptset;
    int ndim;
    cgsize_t dim_vals[12];
    void *vdata;

     /* get BC_t */
    if (cgi_read_string(boco->id, boco->name, &boconame) ||
        cgi_BCType(boconame, &boco->type)) return 1;
    free(boconame);

    /* GridLocation_t */
    if (cg->version > 1200) {
        if (cgi_read_location(boco->id, boco->name, &boco->location)) return 1;
    } else {
     /* Until version 1.2, GridLocation was under BCDataSet_t */
        if (boco->ndataset) {   /* Wild assumption that all BCDataSet have same
                       GridLocation_t value */
            if (cgi_read_location(boco->dataset[0].id, boco->dataset[0].name,
                &boco->location)) return 1;
        } else {
            boco->location= CGNS_ENUMV(Vertex);
        }
    }

     /* read point set */
    if (cgi_read_one_ptset(linked, boco->id, &boco->ptset)) return 1;
    if (boco->ptset == 0) {
        cgi_error("Boundary condition patch '%s' not defined",boco->name);
        return 1;
    }

#ifdef CG_FIX_ELEMENTLIST_RANGE
    /* fix ElementList/Range - no longer allowed (CPEX 0031) */
    if (boco->ptset->type == CGNS_ENUMV(ElementList) ||
        boco->ptset->type == CGNS_ENUMV(ElementRange)) {
        modified++;
        if (boco->ptset->type == CGNS_ENUMV(ElementList)) {
            boco->ptset->type = CGNS_ENUMV(PointList);
            strcpy(boco->ptset->name, "PointList");
        } else {
            boco->ptset->type = CGNS_ENUMV(PointRange);
            strcpy(boco->ptset->name, "PointRange");
        }
        if (Cdim == 1) boco->location = CGNS_ENUMV(Vertex);
        else if (Cdim == 2) boco->location = CGNS_ENUMV(EdgeCenter);
        else boco->location = CGNS_ENUMV(FaceCenter);
    }
#endif

    /* fix GridLocation */
#ifdef CG_FIX_BC_CELL_CENTER
    if (boco->location == CGNS_ENUMV(CellCenter)) {
        if (Cdim == 1) boco->location = CGNS_ENUMV(Vertex);
        else if (Cdim == 2) boco->location = CGNS_ENUMV(EdgeCenter);
        else boco->location = CGNS_ENUMV(FaceCenter);
        cgi_warning("GridLocation CellCenter for BC_t is deprecated - "
            "changed to %s", GridLocationName[boco->location]);
        modified++;
    }
#endif

     /* FamilyName_t */
    if (cgi_read_family_name(linked, boco->id, boco->name, boco->family_name))
        return 1;

    /* CPEX 0034 */
    if (cgi_get_nodes(boco->id, "AdditionalFamilyName_t", &boco->nfamname, &id))
        return 1;
    if (boco->nfamname > 0) {
        char *fam;
        boco->famname = CGNS_NEW(cgns_famname, boco->nfamname);
        for (n = 0; n < boco->nfamname; n++) {
            boco->famname[n].id = id[n];
            if (cgi_read_string(id[n], boco->famname[n].name, &fam)) return 1;
            strncpy(boco->famname[n].family, fam, 32);
            free(fam);
        }
        free(id);
    }

     /* InwardNormalList */
    boco->normal = 0;
    if (cgi_get_nodes(boco->id, "IndexArray_t", &nIA_t, &IA_id))
        return 1;
    for (n=0; n<nIA_t; n++) {
        if (cgio_get_name(cg->cgio, IA_id[n], name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
        if (strcmp(name, "InwardNormalList")) continue;

        boco->normal = CGNS_NEW(cgns_array, 1);
        boco->normal->id = IA_id[n];
        boco->normal->link = cgi_read_link(IA_id[n]);
        boco->normal->in_link = linked;
        if (cgi_read_node(IA_id[n], boco->normal->name, boco->normal->data_type,
            &boco->normal->data_dim, boco->normal->dim_vals, &boco->normal->data,
            READ_DATA)) {
            cgi_error("Error reading boco->normal");
            return 1;
        }

     /* set to NULL useless elements of data structure */
        boco->normal->ndescr = 0;
        boco->normal->units = 0;
        boco->normal->exponents = 0;
        boco->normal->convert = 0;

     /* data verify */
        if (boco->normal->data_dim!=2 || boco->normal->dim_vals[0]!=Pdim ||
            boco->normal->dim_vals[1]!=boco->ptset->size_of_patch ||
            (strcmp(boco->normal->data_type,"R4") &&
             strcmp(boco->normal->data_type,"R8"))) {
            /*printf("boco->normal->dim_vals[1]=%d, boco->ptset->size_of_patch=%d\n",
                boco->normal->dim_vals[1],boco->ptset->size_of_patch);*/
            cgi_error("InwardNormalList incorrectly defined for BC_t '%s'",boco->name);
            return 1;
        }
        break;
    }
    if (nIA_t) free(IA_id);

     /* InwardNormalIndex */
    boco->Nindex = 0;
    if (cgi_get_nodes(boco->id, "\"int[IndexDimension]\"", &nIA_t, &IA_id))
        return 1;
    for (n=0; n<nIA_t; n++) {

        if (cgio_get_name(cg->cgio, IA_id[n], name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
        if (strcmp(name, "InwardNormalIndex")) continue;

        boco->index_id=IA_id[n];

        if (cgi_read_node(IA_id[n], name, data_type, &ndim, dim_vals,
                &vdata, READ_DATA)) return 1;
        if (strcmp(data_type,"I4")!=0 || dim_vals[0]!=Idim) {
            cgi_error("InwardNormalIndex incorrectly defined for BC_t '%s'",boco->name);
            return 1;
        }
        boco->Nindex = (int *)vdata;
        break;
    }
    if (nIA_t) free(IA_id);

     /* BCDataSet_t */
    if (cgi_read_dataset(linked, boco->id, &boco->ndataset, &boco->dataset))
        return 1;

     /* Verify that BCData for Dirichlet/Neumann contains the right number of data */
    for (n=0; n<boco->ndataset; n++) {
        ptset = boco->dataset[n].ptset ? boco->dataset[n].ptset : boco->ptset;
        if (boco->dataset[n].dirichlet) {
            for (i=0; i<boco->dataset[n].dirichlet->narrays; i++) {
                cgns_array array = boco->dataset[n].dirichlet->array[i];
                if (array.data_dim!=1 || (array.dim_vals[0] != 1 &&
                    array.dim_vals[0] != ptset->size_of_patch)) {
                    cgi_error("Wrong array size for Dirichlet data");
                    return 1;
                }
            }
        }
        if (boco->dataset[n].neumann) {
            for (i=0; i<boco->dataset[n].neumann->narrays; i++) {
                cgns_array array = boco->dataset[n].neumann->array[i];
                if (array.data_dim!=1 || (array.dim_vals[0] != 1 &&
                    array.dim_vals[0] != ptset->size_of_patch)) {
                    cgi_error("Wrong array size for Neumann data");
                    return 1;
                }
            }
        }
    }

    if ((cg->version <= 1270 || modified) &&
        cg->mode == CG_MODE_MODIFY && !linked) {
        double dummy_id;
        /* fix point set name */
        if (cgio_get_name(cg->cgio, boco->ptset->id, name) ||
            strcmp(name, boco->ptset->name)) {
            if (cgio_set_name(cg->cgio, boco->id, boco->ptset->id,
                    boco->ptset->name)) {
                cg_io_error("cgio_set_name");
                return 1;
            }
        }
        /* fix grid location */
        ierr = cgio_get_node_id(cg->cgio, boco->id, "GridLocation",
                                &dummy_id);
        if (!ierr) cgi_delete_node(boco->id, dummy_id);
        if (boco->location != CGNS_ENUMV(Vertex)) {
            const char *locname = GridLocationName[boco->location];
            cgsize_t len = (cgsize_t)strlen(locname);
            if (cgi_new_node(boco->id, "GridLocation", "GridLocation_t",
                    &dummy_id, "C1", 1, &len, locname))
                return 1;
        }
    }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, boco->id, &boco->ndescr, &boco->descr,
        &boco->data_class, &boco->units)) return 1;

     /* ReferenceState_t */
    if (cgi_read_state(linked, boco->id, &boco->state)) return 1;

     /* Ordinal_t */
    if (cgi_read_ordinal(boco->id, &boco->ordinal)) return 1;

     /* BCProperty_t */
    if (cgi_read_bprop(linked, boco->id, &boco->bprop)) return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, boco->id, &boco->nuser_data,
        &boco->user_data)) return 1;

    return 0;
}

int cgi_read_bprop(int in_link, double parent_id, cgns_bprop **bprop)
{
    int nchild, n, linked;
    double *id;
    char *type_name;    /* allocated in cgi_read_node */
    char_33 name;

     /* get number of BCProperty_t nodes and their ID */
    if (cgi_get_nodes(parent_id, "BCProperty_t", &nchild, &id)) return 1;
    if (nchild<=0) {
        bprop[0]=0;
        return 0;
    } else if (nchild>1) {
        cgi_error("Error: Multiple BCProperty_t found...");
        free(id);
        return 1;
    }
    bprop[0] = CGNS_NEW(cgns_bprop, 1);
    bprop[0]->id = id[0];
    bprop[0]->link = cgi_read_link(id[0]);
    bprop[0]->in_link = in_link;
    linked = bprop[0]->link ? 1 : in_link;
    free(id);

     /* Descriptor_t */
    if (cgi_get_nodes(bprop[0]->id, "Descriptor_t", &nchild, &id)) return 1;
    bprop[0]->ndescr = 0;
    if (nchild>0) {
        bprop[0]->ndescr = nchild;
        bprop[0]->descr = CGNS_NEW(cgns_descr, nchild);
        for (n=0; n<nchild; n++) {
            bprop[0]->descr[n].id = id[n];
            bprop[0]->descr[n].link = cgi_read_link(id[n]);
            bprop[0]->descr[n].in_link = linked;
            if (cgi_read_string(id[n], bprop[0]->descr[n].name,
                &bprop[0]->descr[n].text)) return 1;
        }
        free(id);
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, bprop[0]->id, &bprop[0]->nuser_data,
        &bprop[0]->user_data)) return 1;

     /* WallFunction_t */
    if (cgi_get_nodes(bprop[0]->id, "WallFunction_t", &nchild, &id)) return 1;
    if (nchild<=0) {
        bprop[0]->bcwall = 0;
    } else if (nchild>1) {
        cgi_error("Error: Multiple WallFunction_t found...");
        free(id);
        return 1;
    } else {
        bprop[0]->bcwall = CGNS_NEW(cgns_bcwall, 1);
        bprop[0]->bcwall->id = id[0];
        bprop[0]->bcwall->link = cgi_read_link(id[0]);
        bprop[0]->bcwall->in_link = linked;
        in_link = bprop[0]->bcwall->link ? 1 : linked;
        free(id);

     /* Descriptor_t */
        if (cgi_get_nodes(bprop[0]->bcwall->id, "Descriptor_t", &nchild, &id))
            return 1;
        bprop[0]->bcwall->ndescr = 0;
        if (nchild>0) {
            bprop[0]->bcwall->ndescr = nchild;
            bprop[0]->bcwall->descr = CGNS_NEW(cgns_descr, nchild);
            for (n=0; n<nchild; n++) {
                bprop[0]->bcwall->descr[n].id = id[n];
                bprop[0]->bcwall->descr[n].link = cgi_read_link(id[n]);
                bprop[0]->bcwall->descr[n].in_link = in_link;
                if (cgi_read_string(id[n], bprop[0]->bcwall->descr[n].name,
                    &bprop[0]->bcwall->descr[n].text)) return 1;
            }
            free(id);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(in_link, bprop[0]->bcwall->id,
            &bprop[0]->bcwall->nuser_data, &bprop[0]->bcwall->user_data))
            return 1;

     /* WallFunctionType_t */
        if (cgi_get_nodes(bprop[0]->bcwall->id, "WallFunctionType_t",
            &nchild, &id)) return 1;
        if (nchild==0) {
            cgi_error("Error: WallFunctionType_t missing under WallFunction_t");
            return 1;
        } else if (nchild >1) {
            cgi_error("File incorrect: multiple definition of WallFunctionType");
            free(id);
            return 1;
        } else {
            if (cgi_read_string(id[0], name, &type_name)) return 1;
            free(id);
            if (cgi_WallFunctionType(type_name, &bprop[0]->bcwall->type)) return 1;
            free(type_name);
        }
    }

     /* Area_t */
    if (cgi_get_nodes(bprop[0]->id, "Area_t", &nchild, &id)) return 1;
    if (nchild<=0) {
        bprop[0]->bcarea = 0;
    } else if (nchild>1) {
        cgi_error("Error: Multiple Area_t found...");
        free(id);
        return 1;
    } else {
        bprop[0]->bcarea = CGNS_NEW(cgns_bcarea, 1);
        bprop[0]->bcarea->id = id[0];
        bprop[0]->bcarea->link = cgi_read_link(id[0]);
        bprop[0]->bcarea->in_link = linked;
        in_link = bprop[0]->bcarea->link ? 1 : linked;
        free(id);

     /* Descriptor_t */
        if (cgi_get_nodes(bprop[0]->bcarea->id, "Descriptor_t", &nchild, &id))
            return 1;
        bprop[0]->bcarea->ndescr = 0;
        if (nchild>0) {
            bprop[0]->bcarea->ndescr = nchild;
            bprop[0]->bcarea->descr = CGNS_NEW(cgns_descr, nchild);
            for (n=0; n<nchild; n++) {
                bprop[0]->bcarea->descr[n].id = id[n];
                bprop[0]->bcarea->descr[n].link = cgi_read_link(id[n]);
                bprop[0]->bcarea->descr[n].in_link = in_link;
                if (cgi_read_string(id[n], bprop[0]->bcarea->descr[n].name,
                    &bprop[0]->bcarea->descr[n].text)) return 1;
            }
            free(id);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(in_link, bprop[0]->bcarea->id,
            &bprop[0]->bcarea->nuser_data, &bprop[0]->bcarea->user_data))
            return 1;

     /* AreaType_t */
        if (cgi_get_nodes(bprop[0]->bcarea->id, "AreaType_t", &nchild, &id))
            return 1;
        if (nchild==0) {
            cgi_error("Error: AreaType_t missing under Area_t");
            return 1;
        } else if (nchild >1) {
            cgi_error("File incorrect: multiple definition of AreaType");
            free(id);
            return 1;
        } else {
            if (cgi_read_string(id[0], name, &type_name)) return 1;
            free(id);
            if (cgi_AreaType(type_name, &bprop[0]->bcarea->type)) return 1;
            free(type_name);
        }

     /* DataArray_t: SurfaceArea <real,1,1>, RegionName <char, 1, 32> */
        if (cgi_get_nodes(bprop[0]->bcarea->id, "DataArray_t", &nchild, &id))
            return 1;
        if (nchild==0) {
            cgi_error("Error: SurfaceArea and RegionName missing under Area_t");
            return 1;
        } else if (nchild!=2) {
            cgi_error("Error: 2 DataArray_t (SurfaceArea & RegionName) required under Area_t");
            free(id);
            return 1;
        }
        bprop[0]->bcarea->narrays = nchild;
        bprop[0]->bcarea->array = CGNS_NEW(cgns_array, bprop[0]->bcarea->narrays);

        for (n=0; n<(bprop[0]->bcarea->narrays); n++) {
            cgns_array *array;
            bprop[0]->bcarea->array[n].id = id[n];
            bprop[0]->bcarea->array[n].link = cgi_read_link(id[n]);
            bprop[0]->bcarea->array[n].in_link = in_link;

            if (cgi_read_array(&bprop[0]->bcarea->array[n], "Area_t",
                bprop[0]->bcarea->id)) return 1;

             /* check data */
            array = &bprop[0]->bcarea->array[n];
            if ((strcmp("SurfaceArea",array->name)==0 && (strcmp(array->data_type,"R4")
                || array->data_dim!=1 || array->dim_vals[0]!=1)) ||
                (strcmp("RegionName",array->name)==0 && (strcmp(array->data_type,"C1")
                || array->data_dim!=1 || array->dim_vals[0]!=32)) ){
                cgi_error("Error: Array '%s' incorrectly sized",array->name);
                free(id);
                return 1;
            } else if (strcmp("SurfaceArea",array->name) && strcmp("RegionName",array->name)) {
                cgi_error("Error: Wrong DataArray_t found under Area_t: '%s'",array->name);
                free(id);
                return 1;
            }
        } /* loop through arrays */
        free(id);
    }
    return 0;
}

int cgi_read_dataset(int in_link, double parent_id, int *ndataset,
                     cgns_dataset **dataset)
{
    int n, i, nnod, linked;
    double *id, *ids;
    char_33 name;
    char *string_data;
    double *IA_id, *IR_id;
    int nIA_t, nIR_t, nn;

     /* BCDataSet_t */
    if (cgi_get_nodes(parent_id, "BCDataSet_t", ndataset, &id)) return 1;
    if (*ndataset<=0) {
        dataset[0]=0;
        return 0;
    }
    dataset[0]=CGNS_NEW(cgns_dataset, (*ndataset));
    for (n=0; n<*ndataset; n++) {
        dataset[0][n].id = id[n];
        dataset[0][n].link = cgi_read_link(id[n]);
        dataset[0][n].in_link = in_link;
        linked = dataset[0][n].link ? 1 : in_link;
        if (cgi_read_string(dataset[0][n].id, dataset[0][n].name, &string_data) ||
            cgi_BCType(string_data, &dataset[0][n].type)) return 1;
        free(string_data);

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, dataset[0][n].id, &dataset[0][n].ndescr,
            &dataset[0][n].descr, &dataset[0][n].data_class,
            &dataset[0][n].units)) return 1;

     /* ReferenceState_t */
        if (cgi_read_state(linked, dataset[0][n].id, &dataset[0][n].state))
            return 1;

     /* BCData_t */
        dataset[0][n].dirichlet=dataset[0][n].neumann=0;
        if (cgi_get_nodes(dataset[0][n].id, "BCData_t", &nnod, &ids)) return 1;
        if (nnod>0) {

            for (i=0; i<nnod; i++) {
             /* Name */
                if (cgio_get_name(cg->cgio, ids[i], name)) {
                    cg_io_error("cgio_get_name");
                    return 1;
                }
                if (strcmp(name,"DirichletData")==0) {
                    if (dataset[0][n].dirichlet!=0) {
                        cgi_error("Dirichet Data defined more than once...");
                        return 1;
                    }
                    dataset[0][n].dirichlet=CGNS_NEW(cgns_bcdata, 1);
                    dataset[0][n].dirichlet->id = ids[i];
                    dataset[0][n].dirichlet->link = cgi_read_link(ids[i]);
                    dataset[0][n].dirichlet->in_link = linked;
                    strcpy(dataset[0][n].dirichlet->name,"DirichletData");
                    if (cgi_read_bcdata(dataset[0][n].dirichlet)) return 1;
                } else if (strcmp(name,"NeumannData")==0) {
                    if (dataset[0][n].neumann!=0) {
                        cgi_error("Neumann Data defined more than once...");
                        return 1;
                    }
                    dataset[0][n].neumann=CGNS_NEW(cgns_bcdata, 1);
                    dataset[0][n].neumann->id = ids[i];
                    dataset[0][n].neumann->link = cgi_read_link(ids[i]);
                    dataset[0][n].neumann->in_link = linked;
                    strcpy(dataset[0][n].neumann->name,"NeumannData");
                    if (cgi_read_bcdata(dataset[0][n].neumann)) return 1;
                }
            }
            free(ids);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, dataset[0][n].id,
            &dataset[0][n].nuser_data, &dataset[0][n].user_data)) return 1;

     /* GridLocation_t */
        if (cgi_read_location(dataset[0][n].id, dataset[0][n].name,
            &dataset[0][n].location)) return 1;

     /* PointSet */
        /* get number of IndexArray_t and IndexRange_t nodes and their
         * ID
         */
        if (cgi_get_nodes(dataset[0][n].id, "IndexArray_t", &nIA_t,
                          &IA_id)) return 1;
        if (cgi_get_nodes(dataset[0][n].id, "IndexRange_t", &nIR_t,
                          &IR_id)) return 1;

        /* initialized */
        dataset[0][n].ptset = 0;

        for (nn=0; nn<nIR_t; nn++)
        {
            if (cgio_get_name(cg->cgio, IR_id[nn], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }

            if (strcmp(name,"PointRange") && strcmp(name,"ElementRange"))
            {
                cgi_error("Invalid name for IndexRange_t");
                return 1;
            }
            if (dataset[0][n].ptset!=0) {
                cgi_error("Multiple definition of boundary patch found");
                return 1;
            }
            dataset[0][n].ptset = CGNS_NEW(cgns_ptset, 1);
            if (strcmp(name,"ElementRange")==0)
              dataset[0][n].ptset->type = CGNS_ENUMV(ElementRange);
            else
              dataset[0][n].ptset->type = CGNS_ENUMV(PointRange);
            dataset[0][n].ptset->id=IR_id[nn];
            dataset[0][n].ptset->link=cgi_read_link(IR_id[nn]);
            dataset[0][n].ptset->in_link=linked;
            if (cgi_read_ptset(dataset[0][n].id, dataset[0][n].ptset))
                return 1;
        }
        if (nIR_t) free(IR_id);

        for (nn=0; nn<nIA_t; nn++)
        {
            if (cgio_get_name(cg->cgio, IA_id[nn], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name, "PointList") && strcmp(name,"ElementList"))
                continue;

            if (dataset[0][n].ptset!=0) {
                cgi_error("Multiple definition of boundary patch found");
                return 1;
            }
            dataset[0][n].ptset = CGNS_NEW(cgns_ptset, 1);
            if (strcmp(name,"ElementList")==0)
              dataset[0][n].ptset->type = CGNS_ENUMV( ElementList );
            else
              dataset[0][n].ptset->type = CGNS_ENUMV( PointList );
            dataset[0][n].ptset->id = IA_id[nn];
            dataset[0][n].ptset->link = cgi_read_link(IA_id[nn]);
            dataset[0][n].ptset->in_link = linked;
            if (cgi_read_ptset(dataset[0][n].id, dataset[0][n].ptset))
                return 1;
        }

        if (nIA_t) free(IA_id);

    }
    free(id);

    return 0;
}

int cgi_read_bcdata(cgns_bcdata *bcdata)
{
    int n, linked = bcdata->link ? 1 : bcdata->in_link;
    double *id;

     /* DataArray_t */
    if (cgi_get_nodes(bcdata->id, "DataArray_t", &bcdata->narrays, &id))
        return 1;
    if (bcdata->narrays>0) {
        bcdata->array = CGNS_NEW(cgns_array, bcdata->narrays);

        for (n=0; n<bcdata->narrays; n++) {
            bcdata->array[n].id = id[n];
            bcdata->array[n].link = cgi_read_link(id[n]);
            bcdata->array[n].in_link = linked;
            cgi_read_array(&bcdata->array[n],"BCData_t",bcdata->id);
        }
        free(id);
    }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, bcdata->id, &bcdata->ndescr, &bcdata->descr,
        &bcdata->data_class, &bcdata->units)) return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, bcdata->id, &bcdata->nuser_data,
        &bcdata->user_data)) return 1;

    return 0;
}

int cgi_read_one_ptset(int linked, double parent_id, cgns_ptset **pptset)
{
    int i, nI_t;
    double *I_id;
    char_33 name;
    cgns_ptset *ptset = NULL;

    if (cgi_get_nodes(parent_id, "IndexArray_t", &nI_t, &I_id))
        return 1;
    for (i = 0; i < nI_t; i++) {
        if (cgio_get_name(cg->cgio, I_id[i], name)) {
            cg_io_error("cgio_get_name for PointList");
            return 1;
        }
        if (strcmp(name, "PointList") && strcmp(name, "ElementList"))
            continue;
        if (ptset != NULL) {
            cgi_error("Multiple definitions of PointList/PointRange");
            return 1;
        }
        ptset = CGNS_NEW(cgns_ptset, 1);
        if (0 == strcmp(name, "ElementList"))
            ptset->type = CGNS_ENUMV(ElementList);
        else
            ptset->type = CGNS_ENUMV(PointList);
        ptset->id=I_id[i];
        ptset->link=cgi_read_link(I_id[i]);
        ptset->in_link=linked;
        if (cgi_read_ptset(I_id[i], ptset)) return 1;
    }
    if (nI_t) free(I_id);

    if (cgi_get_nodes(parent_id, "IndexRange_t", &nI_t, &I_id))
        return 1;
    for (i = 0; i < nI_t; i++) {
        if (cgio_get_name(cg->cgio, I_id[i], name)) {
            cg_io_error("cgio_get_name for PointRange");
            return 1;
        }
        if (strcmp(name, "PointRange") && strcmp(name, "ElementRange"))
            continue;
        if (ptset != NULL) {
            cgi_error("Multiple definitions of PointList/PointRange");
            return 1;
        }
        ptset = CGNS_NEW(cgns_ptset, 1);
        if (0 == strcmp(name, "ElementRange"))
            ptset->type = CGNS_ENUMV(ElementRange);
        else
            ptset->type = CGNS_ENUMV(PointRange);
        ptset->id=I_id[i];
        ptset->link=cgi_read_link(I_id[i]);
        ptset->in_link=linked;
        if (cgi_read_ptset(I_id[i], ptset)) return 1;
    }
    if (nI_t) free(I_id);

    *pptset = ptset;
    return 0;
}

int cgi_read_ptset(double parent_id, cgns_ptset *ptset)
{
    int ndim;
    cgsize_t dim_vals[12];
    void **dummy=0;

     /* Get name of point set just to verify consistency */
    if (cgi_read_node(ptset->id, ptset->name, ptset->data_type, &ndim, dim_vals,
        dummy, SKIP_DATA)) {
        cgi_error("Error reading ptset");
        return 1;
    }

     /* change read data for ElementList/Range stuff */
    if (cg->version <= 1200 && ndim == 1 &&
        (ptset->type == CGNS_ENUMV(ElementRange) ||
         ptset->type == CGNS_ENUMV(ElementList))) {
        ndim = 2;
        dim_vals[1]=dim_vals[0];
        dim_vals[0]=Idim;
        if (cg->mode == CG_MODE_MODIFY && ptset->link == 0 &&
            ptset->in_link == 0) {
            if (cgio_set_dimensions(cg->cgio, ptset->id, CG_SIZE_DATATYPE,
                    2, dim_vals)) {
                cg_io_error("cgio_set_dimensions");
                return 1;
            }
        }
    }

     /* verify that the name matches the type intended */
    if (INVALID_ENUM(ptset->type,NofValidPointSetTypes)) {
        cgi_error("Invalid point set type: '%s'",ptset->name);
        return 1;
    }

     /* verify data type */
    if (strcmp(ptset->data_type,"I4") && strcmp(ptset->data_type,"I8")) {
        cgi_error("Data type %s not supported for point set type %d",
            ptset->data_type, ptset->type);
        return 1;
    }

     /* verify dimension vector */
    if (!(ndim==2 && dim_vals[0]>0 && dim_vals[1]>0)) {
        cgi_error("Invalid definition of point set:  ptset->type='%s', ndim=%d, dim_vals[0]=%d",
            PointSetTypeName[ptset->type], ndim, dim_vals[0]);
        return 1;
    }

     /* npts */
    ptset->npts = dim_vals[1];

     /* size_of_patch */
    if (ptset->type == CGNS_ENUMV(PointList) ||
        ptset->type == CGNS_ENUMV(ElementList) ||
        ptset->type == CGNS_ENUMV(PointListDonor)) {
        ptset->size_of_patch = ptset->npts;
    }
    else {
     /* read points to calculate size_of_patch */
        int i;
        cgsize_t size=1;
        for (i=0; i<ndim; i++) size*=dim_vals[i];
        if (size<=0) {
            cgi_error("Error reading node %s",ptset->name);
            return 1;
        }
        if (0 == strcmp(ptset->data_type,"I8")) {
            cglong_t total = 1;
            cglong_t *pnts = CGNS_NEW(cglong_t, size);
            if (cgio_read_all_data(cg->cgio, ptset->id, pnts)) {
                cg_io_error("cgio_read_all_data");
                return 1;
            }
#if CG_SIZEOF_SIZE == 32
            if (cgio_check_dimensions(2*Idim, pnts)) {
                cg_io_error("cgio_check_dimensions");
                return 1;
            }
#endif
            for (i=0; i<Idim; i++) total *= (pnts[i+Idim]-pnts[i]+1);
            free(pnts);
#if CG_SIZEOF_SIZE == 32
            if (total > CG_MAX_INT32) {
                cgi_error("patch size too large for a 32-bit integer");
                return 1;
            }
#endif
            ptset->size_of_patch = (cgsize_t)total;
        }
        else if (0 == strcmp(ptset->data_type,"I4")) {
            int *pnts = CGNS_NEW(int, size);
            if (cgio_read_all_data(cg->cgio, ptset->id, pnts)) {
                cg_io_error("cgio_read_all_data");
                return 1;
            }
            ptset->size_of_patch = 1;
            for (i=0; i<Idim; i++) ptset->size_of_patch *= (pnts[i+Idim]-pnts[i]+1);
            free(pnts);
        }
        else {
            cgi_error("Invalid datatype for a range pointset");
            return 1;
        }
    }
    return 0;
}

int cgi_read_equations(int in_link, double parent_id,
                       cgns_equations **equations)
{
    double *id;
    int n, nnod, ndim, linked;
    char *string_data;
    char_33 name, data_type;
    cgsize_t dim_vals[12];
    void *vdata;

    if (cgi_get_nodes(parent_id, "FlowEquationSet_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        equations[0]=0;
        return 0;
    }
    equations[0] = CGNS_NEW(cgns_equations, 1);
    equations[0]->id = id[0];
    equations[0]->link = cgi_read_link(id[0]);
    equations[0]->in_link = in_link;
    linked = equations[0]->link ? 1 : in_link;
    free(id);
    strcpy(equations[0]->name, "FlowEquationSet");

     /* GoverningEquations_t */
    equations[0]->governing = 0;
    if (cgi_get_nodes(equations[0]->id, "GoverningEquations_t", &nnod, &id))
        return 1;
    if (nnod>0) {
        equations[0]->governing = CGNS_NEW(cgns_governing,1);
        equations[0]->governing->id = id[0];
        equations[0]->governing->link = cgi_read_link(id[0]);
        equations[0]->governing->in_link = linked;
        if (cgi_read_string(id[0], equations[0]->governing->name, &string_data) ||
            cgi_GoverningEquationsType(string_data, &equations[0]->governing->type))
            return 1;
        free(string_data);
        free(id);

     /* initialize dependants */
        equations[0]->governing->diffusion_model=0;

     /* DiffusionModel */
        if (cgi_get_nodes(equations[0]->governing->id,
            "\"int[1+...+IndexDimension]\"", &nnod, &id)) return 1;
        if (nnod>0) {
            if (cgi_read_node(id[0], name, data_type, &ndim,
                    dim_vals, &vdata, READ_DATA)) {
                cgi_error("Error reading diffusion model");
                return 1;
            }
            if (ndim!=1 || dim_vals[0]<=0 ||
                strcmp(data_type,"I4")) {
                cgi_error("Diffusion Model '%s' defined incorrectly",name);
                return 1;
            }
            equations[0]->governing->dim_vals = (int)dim_vals[0],
            equations[0]->governing->diffusion_model = (int *)vdata;
            free(id);
        }

     /* Descriptor_t */
        if (cgi_get_nodes(equations[0]->governing->id, "Descriptor_t",
            &equations[0]->governing->ndescr, &id)) return 1;
        if (equations[0]->governing->ndescr>0) {
            equations[0]->governing->descr = CGNS_NEW(cgns_descr, equations[0]->governing->ndescr);
            for (n=0; n<equations[0]->governing->ndescr; n++) {
                equations[0]->governing->descr[n].id = id[n];
                equations[0]->governing->descr[n].link = cgi_read_link(id[n]);
                equations[0]->governing->descr[n].in_link = linked;
                if (cgi_read_string(id[n], equations[0]->governing->descr[n].name,
                    &equations[0]->governing->descr[n].text)) return 1;
            }
            free(id);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, equations[0]->governing->id,
            &equations[0]->governing->nuser_data,
            &equations[0]->governing->user_data)) return 1;
    }

     /* GasModel_t */
    if (cgi_read_model(linked, equations[0]->id, "GasModel_t",
        &equations[0]->gas)) return 1;

     /* ViscosityModel_t */
    if (cgi_read_model(linked, equations[0]->id, "ViscosityModel_t",
        &equations[0]->visc)) return 1;

     /* ThermalConductivityModel_t */
    if (cgi_read_model(linked, equations[0]->id, "ThermalConductivityModel_t",
        &equations[0]->conduct)) return 1;

     /* TurbulenceClosure_t */
    if (cgi_read_model(linked, equations[0]->id, "TurbulenceClosure_t",
        &equations[0]->closure)) return 1;

     /* TurbulenceModel_t */
    if (cgi_read_model(linked, equations[0]->id, "TurbulenceModel_t",
        &equations[0]->turbulence)) return 1;

     /* initialize dependants */
    if (equations[0]->turbulence) {
        equations[0]->turbulence->diffusion_model=0;

     /* DiffusionModel */
        if (cgi_get_nodes(equations[0]->turbulence->id,
            "\"int[1+...+IndexDimension]\"", &nnod, &id)) return 1;
        if (nnod>0) {
            if (cgi_read_node(id[0], name, data_type, &ndim,
                    dim_vals, &vdata, READ_DATA)) {
                cgi_error("Error reading Turbulence Diffusion Model");
                return 1;
            }
            if (ndim!=1 || dim_vals[0]<=0 ||
                strcmp(data_type,"I4")) {
                cgi_error("Diffusion Model '%s' defined incorrectly",name);
                return 1;
            }
            equations[0]->turbulence->dim_vals = (int)dim_vals[0],
            equations[0]->turbulence->diffusion_model = (int *)vdata;
            free(id);
        }
    }

     /* ThermalRelaxationModel_t */
    if (cgi_read_model(linked, equations[0]->id, "ThermalRelaxationModel_t",
        &equations[0]->relaxation)) return 1;

     /* ChemicalKineticsModel_t */
    if (cgi_read_model(linked, equations[0]->id, "ChemicalKineticsModel_t",
        &equations[0]->chemkin)) return 1;

     /* EquationDimension */
    equations[0]->equation_dim = 0;
    if (cgi_get_nodes(equations[0]->id, "\"int\"", &nnod, &id)) return 1;
    if (nnod>0) {
        if (cgi_read_node(id[0], name, data_type, &ndim, dim_vals,
                &vdata, READ_DATA)) {
            cgi_error("Error reading base");
            return 1;
        }
     /* verify data */
        if (strcmp(name,"EquationDimension") || strcmp(data_type, "I4") ||
            ndim!=1 || dim_vals[0]!=1) {
            cgi_error("Error reading equation dimension for Flow Equation Set");
            return 1;
        }
        equations[0]->equation_dim = *((int *)vdata);
        free(vdata);
        free(id);
    }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, equations[0]->id, &equations[0]->ndescr,
        &equations[0]->descr, &equations[0]->data_class, &equations[0]->units))
        return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, equations[0]->id, &equations[0]->nuser_data,
        &equations[0]->user_data)) return 1;

    /* EMElectricFieldModel_t */
    if (cgi_read_model(linked, equations[0]->id, "EMElectricFieldModel_t",
        &equations[0]->elecfield)) return 1;

    /* EMMagneticFieldModel_t */
    if (cgi_read_model(linked, equations[0]->id, "EMMagneticFieldModel_t",
        &equations[0]->magnfield)) return 1;

    /* EMConductivityModel_t */
    if (cgi_read_model(linked, equations[0]->id, "EMConductivityModel_t",
        &equations[0]->emconduct)) return 1;

    return 0;
}

int cgi_read_model(int in_link, double parent_id, char *label,
                   cgns_model **model)
{
    int n, nnod, linked;
    double *id;
    char *string_data;

    if (cgi_get_nodes(parent_id, label, &nnod, &id)) return 1;

    if (nnod<=0) {
        model[0]=0;
        return 0;
    }
    model[0] = CGNS_NEW(cgns_model,1);
    model[0]->id = id[0];
    model[0]->link = cgi_read_link(id[0]);
    model[0]->in_link = in_link;
    linked = model[0]->link ? 1 : in_link;
    free(id);

     /* Model Type */
    if (cgi_read_string(model[0]->id, model[0]->name, &string_data)) return 1;
    if (cgi_ModelType(string_data, &model[0]->type)) return 1;
    free(string_data);

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, model[0]->id, &model[0]->ndescr,
        &model[0]->descr, &model[0]->data_class, &model[0]->units)) return 1;

     /* DataArray_t */
    if (cgi_get_nodes(model[0]->id, "DataArray_t", &model[0]->narrays, &id))
        return 1;

    if (model[0]->narrays>0) {
        model[0]->array = CGNS_NEW(cgns_array, model[0]->narrays);
        for (n=0; n<model[0]->narrays; n++) {
            model[0]->array[n].id = id[n];
            model[0]->array[n].link = cgi_read_link(id[n]);
            model[0]->array[n].in_link = linked;
            if (cgi_read_array(&model[0]->array[n],"Model_t",
                model[0]->id)) return 1;

             /* verify data */
            if (model[0]->array[n].data_dim!=1 ||
                model[0]->array[n].dim_vals[0]!=1) {
                cgi_error("Wrong data dimension in %s definition",model[0]->name);
                return 1;
            }
        }
        free(id);
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, model[0]->id, &model[0]->nuser_data,
        &model[0]->user_data)) return 1;

    return 0;
}

int cgi_read_state(int in_link, double parent_id, cgns_state **state)
{
    char_33 name;
    int n, nnod, defined=0, linked;
    double *id;
    char *string_data;

    if (cgi_get_nodes(parent_id, "ReferenceState_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        state[0]=0;
        return 0;
    }
    state[0] = CGNS_NEW(cgns_state, 1);
    state[0]->id=id[0];
    state[0]->link=cgi_read_link(id[0]);
    state[0]->in_link=in_link;
    linked = state[0]->link ? 1 : in_link;
    free(id);

     /* Name */
    if (cgio_get_name(cg->cgio, state[0]->id, state[0]->name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

     /* initialize dependents */
    state[0]->data_class = CGNS_ENUMV( DataClassNull );
    state[0]->StateDescription = 0;
    state[0]->ndescr=0;

     /* Descriptor_t and ReferenceStateDescription */
    if (cgi_get_nodes(state[0]->id, "Descriptor_t", &nnod, &id)) return 1;

    if (nnod>0) {

        for (n=0; n<nnod; n++) {
            if (cgio_get_name(cg->cgio, id[n], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name,"ReferenceStateDescription")) {
                if (state[0]->ndescr==0) state[0]->descr = CGNS_NEW(cgns_descr, 1);
                else state[0]->descr = CGNS_RENEW(cgns_descr, state[0]->ndescr+1, state[0]->descr);

                state[0]->descr[state[0]->ndescr].id = id[n];
                state[0]->descr[state[0]->ndescr].link = cgi_read_link(id[n]);
                state[0]->descr[state[0]->ndescr].in_link = linked;
                if (cgi_read_string(id[n], state[0]->descr[state[0]->ndescr].name,
                    &state[0]->descr[state[0]->ndescr].text)) return 1;
                state[0]->ndescr++;
            } else {
                if (defined) {
                    cgi_error("Reference State node may only hold one ReferenceStateDescription");
                    return 1;
                }
                state[0]->StateDescription= CGNS_NEW(cgns_descr, 1);
                state[0]->StateDescription->id = id[n];
                state[0]->StateDescription->link = cgi_read_link(id[n]);
                state[0]->StateDescription->in_link = linked;
                if (cgi_read_string(id[n], state[0]->StateDescription->name,
                    &state[0]->StateDescription->text)) return 1;
                defined ++;
            }
        }
        free(id);
    }

     /* DataClass_t */
    if (cgi_get_nodes(state[0]->id, "DataClass_t", &nnod, &id)) return 1;
    if (nnod>0) {
        if (cgi_read_string(id[0], name, &string_data)) return 1;
        cgi_DataClass(string_data, &state[0]->data_class);
        free(string_data);
        free(id);
    }

     /* DimensionalUnits_t */
    if (cgi_read_units(linked, state[0]->id, &state[0]->units)) return 1;


     /* DataArray_t */
    if (cgi_get_nodes(state[0]->id, "DataArray_t", &state[0]->narrays, &id))
        return 1;
    if (state[0]->narrays>0) {
        state[0]->array = CGNS_NEW(cgns_array, state[0]->narrays);
        for (n=0; n<state[0]->narrays; n++) {
            state[0]->array[n].id = id[n];
            state[0]->array[n].link = cgi_read_link(id[n]);
            state[0]->array[n].in_link = linked;
            if (cgi_read_array(&state[0]->array[n],"ReferenceState_t",
                state[0]->id)) return 1;

             /* verify data */
            if (state[0]->array[n].data_dim!=1 ||
                state[0]->array[n].dim_vals[0]!=1) {
                cgi_error("Wrong data dimension in Reference State definition");
                return 1;
            }
        }
        free(id);
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, state[0]->id, &state[0]->nuser_data,
        &state[0]->user_data)) return 1;

    return 0;
}

int cgi_read_gravity(int in_link, double parent_id, cgns_gravity **gravity)
{
    int i, nnod, linked;
    double *id;
    char_33 temp_name;

    if (cgi_get_nodes(parent_id, "Gravity_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        gravity[0]=0;
        return 0;
    }
    gravity[0] = CGNS_NEW(cgns_gravity, 1);
    gravity[0]->id=id[0];
    gravity[0]->link=cgi_read_link(id[0]);
    gravity[0]->in_link=in_link;
    linked = gravity[0]->link ? 1 : in_link;
    free(id);

     /* Name */
    if (cgio_get_name(cg->cgio, gravity[0]->id, gravity[0]->name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

     /* initialize dependents */
    gravity[0]->vector=0;
    gravity[0]->narrays = 0;

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, gravity[0]->id, &gravity[0]->ndescr,
        &gravity[0]->descr, &gravity[0]->data_class, &gravity[0]->units))
        return 1;

     /* DataArray_t:  GravityVector */
    if (cgi_get_nodes(gravity[0]->id, "DataArray_t", &nnod, &id)) return 1;
    for (i=0; i<nnod; i++) {
        if (cgio_get_name(cg->cgio, id[i], temp_name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }

     /* GravityVector */
        if (strcmp(temp_name,"GravityVector")==0) {
            gravity[0]->vector = CGNS_NEW(cgns_array, 1);
            gravity[0]->vector->id = id[i];
            gravity[0]->vector->link = cgi_read_link(id[i]);
            gravity[0]->vector->in_link = linked;
            if (cgi_read_array(gravity[0]->vector, "Gravity_t",
                gravity[0]->id)) return 1;
            gravity[0]->narrays = 1;

             /* check data */
            if (strcmp(gravity[0]->vector->data_type,"R4")) {
                cgi_error("Datatype %s not supported for gravity vector",gravity[0]->vector->data_type);
                return 1;
            }
            if (gravity[0]->vector->data_dim != 1 || gravity[0]->vector->dim_vals[0] != Pdim) {
                cgi_error("Error exit:  Gravity vector incorrectly dimensioned");
                return 1;
            }
        }
    }   /* loop through DataArray_t */
    if (nnod) free(id);

     /* check data */
    if (gravity[0]->vector == 0) {
        cgi_error("Error exit: Gravity vector undefined in Gravity_t node");
        return 1;
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, gravity[0]->id, &gravity[0]->nuser_data,
        &gravity[0]->user_data)) return 1;

    return 0;
}

int cgi_read_axisym(int in_link, double parent_id, cgns_axisym **axisym)
{
    int i, nnod, linked, ref_point_flag=0, axis_flag=0;
    double *id;
    char_33 temp_name;

    if (cgi_get_nodes(parent_id, "Axisymmetry_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        axisym[0]=0;
        return 0;
    }
    if (Pdim !=2) {
        cgi_error("Error: Axisymmetry_t can only be defined for 2D data model");
        return 1;
    }
    axisym[0] = CGNS_NEW(cgns_axisym, 1);
    axisym[0]->id=id[0];
    axisym[0]->link=cgi_read_link(id[0]);
    axisym[0]->in_link=in_link;
    linked = axisym[0]->link ? 1 : in_link;
    free(id);

     /* Name */
    if (cgio_get_name(cg->cgio, axisym[0]->id, axisym[0]->name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

     /* initialize dependents */
    axisym[0]->narrays=0;

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, axisym[0]->id, &axisym[0]->ndescr,
        &axisym[0]->descr, &axisym[0]->data_class, &axisym[0]->units))
        return 1;

     /* DataArray_t:
     Required: AxisymmetryReferencePoint, AxisymmetryAxisVector
     Optional: AxisymmetryAngle, CoordinateNames
      */
    if (cgi_get_nodes(axisym[0]->id, "DataArray_t", &nnod, &id)) return 1;
    if (nnod > 0) axisym[0]->array = CGNS_NEW(cgns_array, nnod);

    for (i=0; i<nnod; i++) {
        if (cgio_get_name(cg->cgio, id[i], temp_name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
     /* AxisymmetryReferencePoint & AxisymmetryAxisVector */
        if (strcmp(temp_name,"AxisymmetryReferencePoint")==0 ||
            strcmp(temp_name,"AxisymmetryAxisVector")==0) {

            if (strcmp(temp_name,"AxisymmetryReferencePoint")==0) ref_point_flag = 1;
            else if (strcmp(temp_name,"AxisymmetryAxisVector")==0) axis_flag = 1;

            axisym[0]->array[axisym[0]->narrays].id = id[i];
            axisym[0]->array[axisym[0]->narrays].link = cgi_read_link(id[i]);
            axisym[0]->array[axisym[0]->narrays].in_link = linked;
            if (cgi_read_array(&axisym[0]->array[axisym[0]->narrays],
                "Axisymmetry_t", axisym[0]->id)) return 1;

             /* check data */
            if (strcmp(axisym[0]->array[axisym[0]->narrays].data_type,"R4")) {
                cgi_error("Error: Datatype %s not supported for %s",
                axisym[0]->array[axisym[0]->narrays].data_type, temp_name);
                return 1;
            }
            if (axisym[0]->array[axisym[0]->narrays].data_dim != 1 ||
                axisym[0]->array[axisym[0]->narrays].dim_vals[0] != Pdim) {
                cgi_error("Error: %s incorrectly dimensioned",temp_name);
                return 1;
            }
            axisym[0]->narrays ++;
        }
     /* AxisymmetryAngle */
        else if (strcmp(temp_name,"AxisymmetryAngle")==0) {
            axisym[0]->array[axisym[0]->narrays].id = id[i];
            axisym[0]->array[axisym[0]->narrays].link = cgi_read_link(id[i]);
            axisym[0]->array[axisym[0]->narrays].in_link = linked;
            if (cgi_read_array(&axisym[0]->array[axisym[0]->narrays],
                "Axisymmetry_t", axisym[0]->id)) return 1;

             /* check data */
            if (strcmp(axisym[0]->array[axisym[0]->narrays].data_type,"R4")) {
                cgi_error("Error: Datatype %s not supported for %s",
                axisym[0]->array[axisym[0]->narrays].data_type, temp_name);
                return 1;
            }
            if (axisym[0]->array[axisym[0]->narrays].data_dim != 1 ||
                axisym[0]->array[axisym[0]->narrays].dim_vals[0] != 1) {
                cgi_error("Error: %s incorrectly dimensioned",temp_name);
                return 1;
            }
            axisym[0]->narrays ++;
        }
     /* CoordinateNames */
        else if (strcmp(temp_name,"CoordinateNames")==0) {
            axisym[0]->array[axisym[0]->narrays].id = id[i];
            axisym[0]->array[axisym[0]->narrays].link = cgi_read_link(id[i]);
            axisym[0]->array[axisym[0]->narrays].in_link = linked;
            if (cgi_read_array(&axisym[0]->array[axisym[0]->narrays],
                "Axisymmetry_t", axisym[0]->id)) return 1;

             /* check data */
            if (strcmp(axisym[0]->array[axisym[0]->narrays].data_type,"C1")) {
                cgi_error("Error: Datatype %s not supported for %s",
                axisym[0]->array[axisym[0]->narrays].data_type, temp_name);
                return 1;
            }
            if (axisym[0]->array[axisym[0]->narrays].data_dim != 2 ||
                axisym[0]->array[axisym[0]->narrays].dim_vals[0] != 32 ||
                axisym[0]->array[axisym[0]->narrays].dim_vals[1] != 2) {
                cgi_error("Error: %s incorrectly dimensioned",temp_name);
                return 1;
            }
            axisym[0]->narrays ++;
        }
    }   /* loop through DataArray_t */
    if (nnod) free(id);

     /* check data */
    if (!ref_point_flag || !axis_flag) {
        cgi_error("Error: AxisymmetryReferencePoint & AxisymmetryAxisVector are required");
        return 1;
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, axisym[0]->id, &axisym[0]->nuser_data,
        &axisym[0]->user_data)) return 1;

    return 0;
}

int cgi_read_rotating(int in_link, double parent_id, cgns_rotating **rotating)
{
    int i, nnod, linked, rot_rate_flag=0, rot_center_flag=0;
    double *id;
    char_33 temp_name;

    if (cgi_get_nodes(parent_id, "RotatingCoordinates_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        rotating[0]=0;
        return 0;
    }
    rotating[0] = CGNS_NEW(cgns_rotating, 1);
    rotating[0]->id=id[0];
    rotating[0]->link=cgi_read_link(id[0]);
    rotating[0]->in_link=in_link;
    linked = rotating[0]->link ? 1 : in_link;
    free(id);

     /* Name */
    if (cgio_get_name(cg->cgio, rotating[0]->id, rotating[0]->name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

     /* initialize dependents */
    rotating[0]->narrays=0;

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, rotating[0]->id, &rotating[0]->ndescr,
        &rotating[0]->descr, &rotating[0]->data_class, &rotating[0]->units))
        return 1;

     /* DataArray_t:
     Required: RotationCenter, RotationRateVector
     Optional: none
      */
    if (cgi_get_nodes(rotating[0]->id, "DataArray_t", &nnod, &id)) return 1;
    if (nnod > 0) rotating[0]->array = CGNS_NEW(cgns_array, nnod);

    for (i=0; i<nnod; i++) {
        if (cgio_get_name(cg->cgio, id[i], temp_name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }
     /* RotationCenter, RotationRateVector */
        if (strcmp(temp_name,"RotationCenter")==0 ||
            strcmp(temp_name,"RotationRateVector")==0) {

            if (strcmp(temp_name,"RotationCenter")==0) rot_center_flag = 1;
            else if (strcmp(temp_name,"RotationRateVector")==0) rot_rate_flag = 1;

            rotating[0]->array[rotating[0]->narrays].id = id[i];
            rotating[0]->array[rotating[0]->narrays].link = cgi_read_link(id[i]);
            rotating[0]->array[rotating[0]->narrays].in_link = linked;
            if (cgi_read_array(&rotating[0]->array[rotating[0]->narrays],
                "RotatingCoordinates_t", rotating[0]->id)) return 1;

             /* check data */
            if (strcmp(rotating[0]->array[rotating[0]->narrays].data_type,"R4")) {
                cgi_error("Error: Datatype %s not supported for %s",
                rotating[0]->array[rotating[0]->narrays].data_type, temp_name);
                return 1;
            }
            if (rotating[0]->array[rotating[0]->narrays].data_dim != 1 ||
                rotating[0]->array[rotating[0]->narrays].dim_vals[0] != Pdim) {
                cgi_error("Error: %s incorrectly dimensioned",temp_name);
                return 1;
            }
            rotating[0]->narrays ++;
        }
    }   /* loop through DataArray_t */
    if (nnod) free(id);

     /* check data */
    if (!rot_rate_flag || !rot_center_flag) {
        cgi_error("Error: RotationCenter & RotationRateVector are required");
        return 1;
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, rotating[0]->id, &rotating[0]->nuser_data,
        &rotating[0]->user_data)) return 1;

    return 0;
}

int cgi_read_converg(int in_link, double parent_id, cgns_converg **converg)
{
    char_33 data_type, name;
    int ndim, n, nnod;
    double *id;
    char *string_data;
    void *iterations;
    int nnorm=0, linked;
    cgsize_t dim_vals[12];

    if (cgi_get_nodes(parent_id, "ConvergenceHistory_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        converg[0]=0;
        return 0;
    }
    converg[0] = CGNS_NEW(cgns_converg, 1);
    converg[0]->id = id[0];
    converg[0]->link = cgi_read_link(id[0]);
    converg[0]->in_link = in_link;
    linked = converg[0]->link ? 1 : in_link;
    free(id);

    if (cgi_read_node(converg[0]->id, converg[0]->name, data_type, &ndim,
            dim_vals, &iterations, READ_DATA)) {
        cgi_error("Error reading Convergence History node");
        return 1;
    }
     /* verify data:  Temporarily commented and replaced by 4 lines below
    if (strcmp(data_type,"I4") || ndim!=1 || dim_vals[0]!=1) {
        cgi_error("ConvergenceHistory_t node '%s' incorrect",converg[0]->name);
        return 1;
    }
    converg[0]->iterations = *((int *)iterations);
    free(iterations);
      */
     /* The check was removed because Bob was storing other type of data
    at the level.  This is a temporary changed */
    if (strcmp(data_type,"I4")==0 && dim_vals[0]>=1) {
        converg[0]->iterations = *((int *)iterations);
        free(iterations);
    } else converg[0]->iterations=0;

     /* initialize dependents */
    converg[0]->data_class = CGNS_ENUMV( DataClassNull );
    converg[0]->NormDefinitions = 0;
    converg[0]->ndescr=0;

     /* Descriptor_t and NormDefinitions */
    if (cgi_get_nodes(converg[0]->id, "Descriptor_t", &nnod, &id)) return 1;

    if (nnod>0) {
        for (n=0; n<nnod; n++) {
            if (cgio_get_name(cg->cgio, id[n], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name,"NormDefinitions")) {
                if (converg[0]->ndescr==0) converg[0]->descr = CGNS_NEW(cgns_descr, 1);
                else converg[0]->descr=CGNS_RENEW(cgns_descr,converg[0]->ndescr+1,converg[0]->descr);
                converg[0]->descr[converg[0]->ndescr].id = id[n];
                converg[0]->descr[converg[0]->ndescr].link = cgi_read_link(id[n]);
                converg[0]->descr[converg[0]->ndescr].in_link = linked;
                if (cgi_read_string(id[n], converg[0]->descr[converg[0]->ndescr].name,
                    &converg[0]->descr[converg[0]->ndescr].text)) return 1;
                converg[0]->ndescr++;
            } else {
                if (nnorm) {
                    cgi_error("Convergence History may only hold one NormDefinitions Node");
                    return 1;
                }
                converg[0]->NormDefinitions = CGNS_NEW(cgns_descr, 1);
                converg[0]->NormDefinitions->id = id[n];
                converg[0]->NormDefinitions->link = cgi_read_link(id[n]);
                converg[0]->NormDefinitions->in_link = linked;
                if (cgi_read_string(id[n], converg[0]->NormDefinitions->name,
                    &converg[0]->NormDefinitions->text)) return 1;
                nnorm ++;
            }
        }
        free(id);
    }

     /* DataClass_t */
    if (cgi_get_nodes(converg[0]->id, "DataClass_t", &nnod, &id)) return 1;
    if (nnod>0) {
        if (cgi_read_string(id[0], name, &string_data)) return 1;
        cgi_DataClass(string_data, &converg[0]->data_class);
        free(string_data);
        free(id);
    }

     /* DimensionalUnits_t */
    if (cgi_read_units(linked, converg[0]->id, &converg[0]->units)) return 1;

     /* DataArray_t */
    if (cgi_get_nodes(converg[0]->id, "DataArray_t", &converg[0]->narrays, &id))
        return 1;
    if (converg[0]->narrays>0) {
        converg[0]->array = CGNS_NEW(cgns_array, converg[0]->narrays);
        for (n=0; n<converg[0]->narrays; n++) {
            converg[0]->array[n].id = id[n];
            converg[0]->array[n].link = cgi_read_link(id[n]);
            converg[0]->array[n].in_link = linked;
            if (cgi_read_array(&converg[0]->array[n],"ConvergenceHistory_t",
                converg[0]->id)) return 1;

             /* verify data :  Temporiraly commented for Bob Bush
            if (converg[0]->array[n].data_dim!=1) {
                cgi_error("Wrong nr of dimension in Conversion History definition");
                return 1;
            }
              */
        }
        free(id);
    }

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, converg[0]->id, &converg[0]->nuser_data,
        &converg[0]->user_data)) return 1;

    return 0;
}

int cgi_read_discrete(int in_link, double parent_id, int *ndiscrete,
                      cgns_discrete **discrete)
{
    double *id, *idi;
    int n, i, j, linked;
    cgsize_t DataSize[3], DataCount = 0;

    if (cgi_get_nodes(parent_id, "DiscreteData_t", ndiscrete, &id)) return 1;
    if (*ndiscrete<=0) {
        discrete[0] = 0;
        return 0;
    }

    discrete[0] = CGNS_NEW(cgns_discrete, (*ndiscrete));
    for (n=0; n<(*ndiscrete); n++) {
        discrete[0][n].id = id[n];
        discrete[0][n].link = cgi_read_link(id[n]);
        discrete[0][n].in_link = in_link;
        linked = discrete[0][n].link ? 1 : in_link;

     /* name of node */
        if (cgio_get_name(cg->cgio, id[n], discrete[0][n].name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, id[n], &discrete[0][n].ndescr,
            &discrete[0][n].descr, &discrete[0][n].data_class,
            &discrete[0][n].units)) return 1;

     /* GridLocation_t */
        if (cgi_read_location(discrete[0][n].id, discrete[0][n].name,
            &discrete[0][n].location)) return 1;

     /* Rind Planes */
        if (cgi_read_rind(discrete[0][n].id, &discrete[0][n].rind_planes))
            return 1;

     /* Determine data size */
        if (cgi_datasize(Idim, CurrentDim, discrete[0][n].location,
            discrete[0][n].rind_planes, DataSize)) return 1;

     /* check for PointList/PointRange */
        if (cgi_read_one_ptset(linked, discrete[0][n].id,
                &discrete[0][n].ptset)) return 1;
        if (discrete[0][n].ptset != NULL) {
            if (discrete[0][n].ptset->type == CGNS_ENUMV(ElementList) ||
                discrete[0][n].ptset->type == CGNS_ENUMV(ElementRange)) {
                cgi_error("ElementList/Range not supported under DiscreteData");
                return 1;
            }
            DataCount = discrete[0][n].ptset->size_of_patch;
        }

     /* DataArray_t */
        if (cgi_get_nodes(discrete[0][n].id, "DataArray_t",
            &discrete[0][n].narrays, &idi)) return 1;
        if (discrete[0][n].narrays>0) {
            discrete[0][n].array = CGNS_NEW(cgns_array, discrete[0][n].narrays);
            for (i=0; i<discrete[0][n].narrays; i++) {
                discrete[0][n].array[i].id = idi[i];
                discrete[0][n].array[i].link = cgi_read_link(idi[i]);
                discrete[0][n].array[i].in_link = linked;
                if (cgi_read_array(&discrete[0][n].array[i],
                    "DiscreteData_t", discrete[0][n].id)) return 1;

             /* verify data */
                if (discrete[0][n].ptset == NULL) {
                    if (discrete[0][n].array[i].data_dim!=Idim) {
                        cgi_error("Wrong data dimension in Discrete Data definition");
                        return 1;
                    }
                    for (j=0; j<Idim; j++) {
                        if (discrete[0][n].array[i].dim_vals[j]!= DataSize[j]) {
                            cgi_error("Invalid array dimension for Discrete Data '%s'",
                                discrete[0][n].name);
                            return 1;
                        }
                    }
                } else {
                    if (discrete[0][n].array[i].data_dim != 1 ||
                        discrete[0][n].array[i].dim_vals[0] != DataCount) {
                        cgi_error("Invalid array dimension for ptset solution");
                        return 1;
                    }
                }
                if (strcmp(discrete[0][n].array[i].data_type,"I4") &&
                    strcmp(discrete[0][n].array[i].data_type,"I8") &&
                    strcmp(discrete[0][n].array[i].data_type,"R4") &&
                    strcmp(discrete[0][n].array[i].data_type,"R8")) {
                    cgi_error("Datatype %d not supported for Discrete Data");
                    return 1;
                }
            }
            free(idi);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, discrete[0][n].id,
            &discrete[0][n].nuser_data, &discrete[0][n].user_data)) return 1;
    }
    free(id);

    return 0;
}

int cgi_read_integral(int in_link, double parent_id, int *nintegrals,
                      cgns_integral **integral)
{
    double *id, *idi;
    int n, i, linked;

    if (cgi_get_nodes(parent_id, "IntegralData_t", nintegrals, &id)) return 1;
    if (*nintegrals<=0) {
        integral[0] = 0;
        return 0;
    }

    integral[0] = CGNS_NEW(cgns_integral, (*nintegrals));
    for (n=0; n<(*nintegrals); n++) {
        integral[0][n].id = id[n];
        integral[0][n].link = cgi_read_link(id[n]);
        integral[0][n].in_link = in_link;
        linked = integral[0][n].link ? 1 : in_link;

     /* IntegralData_t Name */
        if (cgio_get_name(cg->cgio, integral[0][n].id, integral[0][n].name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, id[n], &integral[0][n].ndescr,
            &integral[0][n].descr, &integral[0][n].data_class,
            &integral[0][n].units)) return 1;

     /* DataArray_t */
        if (cgi_get_nodes(id[n], "DataArray_t", &integral[0][n].narrays, &idi))
            return 1;
        if (integral[0][n].narrays>0) {
            integral[0][n].array = CGNS_NEW(cgns_array, integral[0][n].narrays);
            for (i=0; i<integral[0][n].narrays; i++) {
                integral[0][n].array[i].id = idi[i];
                integral[0][n].array[i].link = cgi_read_link(idi[i]);
                integral[0][n].array[i].in_link = linked;
                if (cgi_read_array(&integral[0][n].array[i],
                    "IntegralData_t", integral[0][n].id)) return 1;

             /* verify data :  Temporarily commented
                if (integral[0][n].array[i].data_dim!=1 ||
                    integral[0][n].array[i].dim_vals[0]!=1) {
                    cgi_error("Wrong data dimension in Integral Data definition");
                    return 1;
                }
             */

            }
            free(idi);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, integral[0][n].id,
            &integral[0][n].nuser_data, &integral[0][n].user_data)) return 1;
    }
    free(id);

    return 0;
}

int cgi_read_rmotion(int in_link, double parent_id, int *nrmotions,
                     cgns_rmotion **rmotion)
{
    cgns_array *array;
    char *string_data;
    double *id, *idi;
    int n, i, linked;

    if (cgi_get_nodes(parent_id, "RigidGridMotion_t", nrmotions, &id))
        return 1;
    if (*nrmotions <= 0) {
        rmotion[0] = 0;
        return 0;
    }

    rmotion[0] = CGNS_NEW(cgns_rmotion, (*nrmotions));
    for (n=0; n<(*nrmotions); n++) {
        rmotion[0][n].id = id[n];
        rmotion[0][n].link = cgi_read_link(id[n]);
        rmotion[0][n].in_link = in_link;
        linked = rmotion[0][n].link ? 1 : in_link;

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, id[n], &rmotion[0][n].ndescr,
            &rmotion[0][n].descr, &rmotion[0][n].data_class,
            &rmotion[0][n].units)) return 1;

     /* RigidGridMotion_t Name and RigidGridMotionType_t */
        if (cgi_read_string(id[n], rmotion[0][n].name, &string_data) ||
            cgi_RigidGridMotionType(string_data, &rmotion[0][n].type))
            return 1;
        free(string_data);

     /* DataArrays */
        if (cgi_get_nodes(id[n], "DataArray_t", &rmotion[0][n].narrays, &idi))
            return 1;
        if (rmotion[0][n].narrays<=0) {
            cgi_error("RigidGridMotion_t '%s' defined incorrectly",rmotion[0][n].name);
            return 1;
        }
        rmotion[0][n].array = CGNS_NEW(cgns_array, rmotion[0][n].narrays);
        for (i=0; i<rmotion[0][n].narrays; i++) {
            rmotion[0][n].array[i].id = idi[i];
            rmotion[0][n].array[i].link = cgi_read_link(idi[i]);
            rmotion[0][n].array[i].in_link = linked;
            if (cgi_read_array(&rmotion[0][n].array[i],
                "RigidGridMotion_t", rmotion[0][n].id)) return 1;

             /* verify that data type is R4 or R8 and that data dimensions are correct */
            array = &rmotion[0][n].array[i];    /* 'array' used only to shorten the text */
            if (strcmp("OriginLocation",array->name)==0 ||
                strcmp("RigidRotationAngle",array->name)==0 ||
                strcmp("RigidVelocity" ,array->name)==0 ||
                strcmp("RigidRotationRate" ,array->name)==0) {
                if (strcmp(array->data_type,"R4") && strcmp(array->data_type,"R8")) {
                    cgi_error("Wrong data type for %s",array->name);
                    return 1;
                }
                if ((strcmp("OriginLocation",array->name)==0 && array->data_dim!=2) ||
                    (strcmp("OriginLocation",array->name) && array->data_dim!=1) ||
                    array->dim_vals[0]!=Pdim ||
                    (strcmp("OriginLocation",array->name)==0 && array->dim_vals[1]!=2)) {
                    cgi_error("Wrong data dimension in '%s' definition",array->name);
                    return 1;
                }
            }
        }           /* loop through DataArray_t */
        for (i=0; i<rmotion[0][n].narrays; i++) {
            if (strcmp("OriginLocation",rmotion[0][n].array[i].name)==0) break;
            if (i==(rmotion[0][n].narrays-1)) {
                cgi_error("OriginLocation undefined under RigidGridMotion_t '%s'",
                       rmotion[0][n].name);
                return 1;
            }
        }
        free(idi);

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, rmotion[0][n].id,
            &rmotion[0][n].nuser_data, &rmotion[0][n].user_data)) return 1;

    }           /* loop through RigidGridMotion_t */
    free(id);
    return 0;
}

int cgi_read_amotion(int in_link, double parent_id, int *namotions,
                     cgns_amotion **amotion)
{
    double *id, *idi;
    char *string_data;
    cgsize_t DataSize[3];
    int n, i, j, linked;

    if (cgi_get_nodes(parent_id, "ArbitraryGridMotion_t", namotions, &id)) return 1;
    if (*namotions <= 0) {
        amotion[0] = 0;
        return 0;
    }

    amotion[0] = CGNS_NEW(cgns_amotion, (*namotions));
    for (n=0; n<(*namotions); n++) {
        amotion[0][n].id = id[n];
        amotion[0][n].link = cgi_read_link(id[n]);
        amotion[0][n].in_link = in_link;
        linked = amotion[0][n].link ? 1 : in_link;

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, id[n], &amotion[0][n].ndescr,
            &amotion[0][n].descr, &amotion[0][n].data_class,
            &amotion[0][n].units)) return 1;

     /* ArbitraryGridMotion_t Name and ArbitraryGridMotionType_t */
        if (cgi_read_string(id[n], amotion[0][n].name, &string_data) ||
            cgi_ArbitraryGridMotionType(string_data, &amotion[0][n].type))
            return 1;
        free(string_data);

     /* GridLocation */
        if (cgi_read_location(id[n], amotion[0][n].name,
            &amotion[0][n].location)) return 1;

     /* Rind Planes */
        if (cgi_read_rind(id[n], &amotion[0][n].rind_planes)) return 1;

     /* Determine data size */
        if (cgi_datasize(Idim, CurrentDim, amotion[0][n].location,
            amotion[0][n].rind_planes, DataSize)) return 1;

     /* DataArray_t */
        if (cgi_get_nodes(id[n], "DataArray_t", &amotion[0][n].narrays, &idi))
            return 1;

        if (amotion[0][n].narrays>0) {
            amotion[0][n].array = CGNS_NEW(cgns_array, amotion[0][n].narrays);
            for (i=0; i<amotion[0][n].narrays; i++) {
                amotion[0][n].array[i].id = idi[i];
                amotion[0][n].array[i].link = cgi_read_link(idi[i]);
                amotion[0][n].array[i].in_link = linked;
                if (cgi_read_array(&amotion[0][n].array[i],
                    "ArbitraryGridMotion_t", amotion[0][n].id)) return 1;

             /* verify data */
                if (amotion[0][n].array[i].data_dim!=Idim) {
                    cgi_error("Wrong data dimension for ArbitraryGridMotion array '%s'",
                           amotion[0][n].array[i].name);
                    return 1;
                }

             /* Check that the data size is consistent with the zone dimension, the grid
                location and rind data (not done for EdgeCenter and FaceCenter ... yet) */
                if (amotion[0][n].location == CGNS_ENUMV( Vertex ) ||
                    amotion[0][n].location == CGNS_ENUMV( CellCenter ) ||
                    amotion[0][n].location == CGNS_ENUMV( IFaceCenter ) ||
                    amotion[0][n].location == CGNS_ENUMV( JFaceCenter ) ||
                    amotion[0][n].location == CGNS_ENUMV( KFaceCenter )) {
                    for (j=0; j<Idim; j++) {
                        if (amotion[0][n].array[i].dim_vals[j]!= DataSize[j]) {
                            cgi_error("Invalid array dimension for ArbitraryGridMotion array '%s'",
                                   amotion[0][n].array[i].name);
                            return 1;
                        }
                    }
                }
                if (strcmp(amotion[0][n].array[i].data_type,"R4") &&
                    strcmp(amotion[0][n].array[i].data_type,"R8") ) {
                    cgi_error("Datatype %d not supported for ArbitraryGridMotion array");
                    return 1;
                }
            }
            free(idi);
        }

     /* UserDefinedData_t */
        if (cgi_read_user_data(linked, amotion[0][n].id,
            &amotion[0][n].nuser_data, &amotion[0][n].user_data)) return 1;
    }
    free(id);
    return 0;
}

/* end */

int cgi_read_array(cgns_array *array, char *parent_label, double parent_id)
{
    int data_flag=1;
    int linked = array->link ? 1 : array->in_link;
    char_33 data_type, temp_name;
    int nchild, ndim;
    double *idi;
    cgsize_t dim_vals[12];

     /* These data arrays are not loaded in memory, just their addresses */
    if (strcmp(parent_label,"GridCoordinates_t")==0 ||
        strcmp(parent_label,"FlowSolution_t")==0 ||
        strcmp(parent_label,"Elements_t")==0 ||
        strcmp(parent_label,"ZoneSubRegion_t")==0 ||
        strcmp(parent_label,"DiscreteData_t")==0 ||
	strcmp(parent_label,"UserDefinedData_t")==0) {
        data_flag=SKIP_DATA;
        array->data=0;
    }
    if (cgi_read_node(array->id, array->name, array->data_type,
        &array->data_dim, array->dim_vals, &array->data, data_flag)) {
        cgi_error("Error reading array under %s",parent_label);
        return 1;
    }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, array->id, &array->ndescr, &array->descr,
        &array->data_class, &array->units)) return 1;

     /* DataConversion_t */
    if (cgi_read_conversion(linked, array->id, &array->convert)) return 1;

     /* DimensionalExponents_t */
    if (cgi_read_exponents(linked, array->id, &array->exponents)) return 1;

    /* IndexRange_t */
    if (cgi_get_nodes(array->id, "IndexRange_t", &nchild, &idi))
        return 1;
    if (nchild==1) {
        void *vdata;
        if (cgi_read_node(idi[0], temp_name, data_type, &ndim, dim_vals,
                          &vdata, READ_DATA)) {
            cgi_error("Error reading array range");
            return 1;
        }

        if (nchild) free(idi);

     /* verify that the name matches the type intended */
        if (strcmp(temp_name,"ArrayDataRange")) {
            cgi_error("Invalid point set type: '%s'",temp_name);
            return 1;
        }
        /* Accept only I4 and I8 */
        if (strcmp(data_type,"I4") && strcmp(data_type,"I8")) {
            cgi_error("Data type %s not supported for ArrayDataRange", data_type);
            return 1;
        }
        /* verify dimension vector */
        if (ndim!=1 || dim_vals[0]!=2) {
            cgi_error("Invalid dimensions in definition of ArrayDataRange");
            return 1;
        }

        /* nelements */
        if (0 == strcmp(data_type,"I8")) {
            cglong_t *data = (cglong_t *)vdata;
#if CG_SIZEOF_SIZE == 32
            if (cgio_check_dimensions(2, data)) {
                cg_io_error("cgio_check_dimensions");
                return 1;
            }
#endif
            array->range[0] = (cgsize_t)data[0];
            array->range[1] = (cgsize_t)data[1];
        }
        else {
            int *data = (int *)vdata;
            array->range[0] = (cgsize_t)data[0];
            array->range[1] = (cgsize_t)data[1];
        }
        free(vdata);
    }

    return 0;
}

int cgi_read_conversion(int in_link, double parent_id, cgns_conversion **convert)
{
    int nnod, ndim;
    double *id;
    cgsize_t dim_vals[12];

    if (cgi_get_nodes(parent_id, "DataConversion_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        convert[0]=0;
        return 0;
    }
    convert[0] = CGNS_NEW(cgns_conversion, 1);
    convert[0]->id = id[0];
    convert[0]->link = cgi_read_link(id[0]);
    convert[0]->in_link = in_link;
    free(id);

    if (cgi_read_node(convert[0]->id, convert[0]->name, convert[0]->data_type,
        &ndim, dim_vals,  &convert[0]->data, READ_DATA)) {
        cgi_error("Error reading '%s'",convert[0]->name);
        return 1;
    }
    if (strcmp(convert[0]->data_type,"R4") && strcmp(convert[0]->data_type,"R8")) {
        cgi_error("Wrong Data Type in '%s'",convert[0]->name);
        return 1;
    }
    if (ndim!=1 || dim_vals[0]!=2) {
        cgi_error("Wrong dimensions in '%s'",convert[0]->name);
        return 1;
    }
    return 0;
}

int cgi_read_exponents(int in_link, double parent_id, cgns_exponent **exponents)
{
    int nnod, ndim;
    double *id;
    cgsize_t dim_vals[12];

    if (cgi_get_nodes(parent_id, "DimensionalExponents_t", &nnod, &id)) return 1;
    if (nnod <= 0) {
        exponents[0]=0;
        return 0;
    }
    exponents[0] = CGNS_NEW(cgns_exponent, 1);
    exponents[0]->id = id[0];
    exponents[0]->link = cgi_read_link(id[0]);
    exponents[0]->in_link = in_link;
    free(id);

    if (cgi_read_node(exponents[0]->id, exponents[0]->name,
        exponents[0]->data_type, &ndim, dim_vals, &exponents[0]->data, READ_DATA)) {
        cgi_error("Error reading '%s'",exponents[0]->name);
        return 1;
    }
    if (strcmp(exponents[0]->data_type,"R4") &&
        strcmp(exponents[0]->data_type,"R8")) {
        cgi_error("Wrong Data Type in '%s'",exponents[0]->name);
        return 1;
    }
    if (ndim != 1 || dim_vals[0] != 5) {
        cgi_error("Wrong dimensions in '%s'",exponents[0]->name);
        return 1;
    }
    exponents[0]->nexps = 5;

    if (cgi_get_nodes(exponents[0]->id, "AdditionalExponents_t", &nnod, &id))
        return 1;
    if (nnod > 0) {
        int ierr;
        char_33 data_type, name;
        void *data;
        ierr = cgi_read_node(id[0], name, data_type, &ndim, dim_vals,
                             &data, READ_DATA);
        free(id);
        if (ierr) {
            cgi_error("Error reading AdditionalExponents for 's'",
                exponents[0]->name);
            return 1;
        }
        if (strcmp(data_type, exponents[0]->data_type)) {
            free(data);
            cgi_error("mismatch in data type for AdditionalExponents for '%s'",
                exponents[0]->name);
            return 1;
        }
        if (ndim != 1 || dim_vals[0] != 3) {
            free(data);
            cgi_error("Wrong dimensions in AdditionalExponents for '%s'",
                exponents[0]->name);
            return 1;
        }
        exponents[0]->data = (void *) realloc (exponents[0]->data,
            8 * size_of(exponents[0]->data_type));
        if (exponents[0]->data == NULL) {
            free(data);
            cgi_error("realloc failed for DimensionalExponents");
            return 1;
        }
        if (0 == strcmp(exponents[0]->data_type,"R4")) {
            float *exps = (float *)exponents[0]->data;
            for (ndim = 0; ndim < 3; ndim++)
                exps[5+ndim] = *((float *)data + ndim);
        } else {
            double *exps = (double *)exponents[0]->data;
            for (ndim = 0; ndim < 3; ndim++)
                exps[5+ndim] = *((double *)data + ndim);
        }

        exponents[0]->nexps = 8;
        free(data);
    }
    return 0;
}

int cgi_read_units(int in_link, double parent_id, cgns_units **units)
{
    char_33 unit_name;
    char *string_data;
    double *id;
    int nnod;

    if (cgi_get_nodes(parent_id, "DimensionalUnits_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        units[0]=0;
        return 0;
    }
    units[0] = CGNS_NEW(cgns_units, 1);
    units[0]->id = id[0];
    units[0]->link = cgi_read_link(id[0]);
    units[0]->in_link = in_link;
    free(id);

    if (cgi_read_string(units[0]->id, units[0]->name, &string_data)) return 1;
    if (strlen(string_data) != 32*5) {
        free(string_data);
        cgi_error("Dimensional Units defined incorrectly.");
        return 1;
    }
    units[0]->nunits = 5;

    /* change from Celcius to Celsius */
    if (0 == strncmp(&string_data[96], "Celcius", 7)) {
        string_data[99] = 's';
        if (cg->mode == CG_MODE_MODIFY && !in_link) {
            if (cgio_write_all_data(cg->cgio, units[0]->id, string_data)) {
                cg_io_error("cgio_write_all_data");
                return 1;
            }
        }
    }

    strncpy (unit_name, string_data, 32);
    unit_name[32] = 0;
    cgi_MassUnits(unit_name, &units[0]->mass);

    strncpy (unit_name, &string_data[32], 32);
    unit_name[32] = 0;
    cgi_LengthUnits(unit_name, &units[0]->length);

    strncpy (unit_name, &string_data[64], 32);
    unit_name[32] = 0;
    cgi_TimeUnits(unit_name, &units[0]->time);

    strncpy (unit_name, &string_data[96], 32);
    unit_name[32] = 0;
    cgi_TemperatureUnits(unit_name, &units[0]->temperature);

    strncpy (unit_name, &string_data[128], 32);
    unit_name[32] = 0;
    cgi_AngleUnits(unit_name, &units[0]->angle);

    free(string_data);

    units[0]->current = CGNS_ENUMV( ElectricCurrentUnitsNull );
    units[0]->amount = CGNS_ENUMV( SubstanceAmountUnitsNull );
    units[0]->intensity = CGNS_ENUMV( LuminousIntensityUnitsNull );

    if (cgi_get_nodes(units[0]->id, "AdditionalUnits_t", &nnod, &id))
        return 1;
    if (nnod > 0) {
        int ierr = cgi_read_string(id[0], unit_name, &string_data);
        free(id);
        if (ierr) return 1;
        if (strlen(string_data) != 32*3) {
            free(string_data);
            cgi_error("AdditionalUnits for '%s' defined incorrectly.",
                units[0]->name);
            return 1;
        }
        units[0]->nunits = 8;

        strncpy (unit_name, string_data, 32);
        unit_name[32] = 0;
        cgi_ElectricCurrentUnits(unit_name, &units[0]->current);

        strncpy (unit_name, &string_data[32], 32);
        unit_name[32] = 0;
        cgi_SubstanceAmountUnits(unit_name, &units[0]->amount);

        strncpy (unit_name, &string_data[64], 32);
        unit_name[32] = 0;
        cgi_LuminousIntensityUnits(unit_name, &units[0]->intensity);

        free(string_data);
    }

    return 0;
}

int cgi_read_string(double id, char_33 name, char **string_data)
{
    int n, ndim;
    char_33 data_type;
    cgsize_t length[2], len=1;

    if (cgi_read_node(id, name, data_type, &ndim, length, (void **)string_data, READ_DATA)) {
        cgi_error("Error reading string");
        return 1;
    }
     /* verify dimensions */
    if (strcmp(data_type,"C1")!=0) {
        cgi_error("Invalid datatype for character data: %s",data_type);
        return 1;
    }
     /* add the string terminator */
    for (n=0; n<ndim; n++) len *= length[n];
    string_data[0][len]='\0';

    return 0;
}

int cgi_read_DDD(int in_link, double parent_id, int *ndescr,
                 cgns_descr **descr, CGNS_ENUMV( DataClass_t ) *data_class,
                 cgns_units **units)
{
    double *id;
    int n, nnod;
    char_33 name;
    char *string_data;


     /* Descriptor_t */
    descr[0] = 0;
    if (cgi_get_nodes(parent_id, "Descriptor_t", ndescr, &id)) return 1;
    if (*ndescr>0) {
        descr[0] = CGNS_NEW(cgns_descr, (*ndescr));
        for (n=0; n<(*ndescr); n++) {
            descr[0][n].id = id[n];
            descr[0][n].link = cgi_read_link(id[n]);
            descr[0][n].in_link = in_link;
            if (cgi_read_string(id[n], descr[0][n].name,
                &descr[0][n].text)) return 1;
        }
        free(id);
    }

     /* DataClass_t */
    *data_class = CGNS_ENUMV( DataClassNull );
    if (cgi_get_nodes(parent_id, "DataClass_t", &nnod, &id)) return 1;
    if (nnod>0) {
        if (cgi_read_string(id[0], name, &string_data)) return 1;
        cgi_DataClass(string_data, data_class);
        free(string_data);
        free(id);
    }

     /* DimensionalUnits_t */
    if (cgi_read_units(in_link, parent_id, units)) return 1;
    return 0;
}

int cgi_read_ordinal(double parent_id, int *ordinal)
{
    int nnod;
    double *id;
    char_33 name, data_type;
    int ndim;
    void *ordinal_data;
    cgsize_t dim_vals[12];

    if (cgi_get_nodes(parent_id, "Ordinal_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        (*ordinal)=0;
        return 0;
    }
    if (cgi_read_node(id[0], name, data_type, &ndim, dim_vals,
        &ordinal_data, READ_DATA)) {
        cgi_error("Error reading Ordinal node");
        return 1;
    }
    if (ndim!=1 || dim_vals[0]!=1 || strcmp(data_type,"I4")) {
        cgi_error("Ordinal '%s' defined incorrectly",name);
        return 1;
    }
    free(id);
    (*ordinal)=*(int *)ordinal_data;
    free(ordinal_data);
    return 0;
}

int cgi_read_rind(double parent_id, int **rind_planes)
{
    int n, nnod;
    double *id;
    char_33 name, data_type;
    int ndim;
    cgsize_t dim_vals[12];

    if (cgi_get_nodes(parent_id, "Rind_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        rind_planes[0] = (int *) malloc (2*Idim*sizeof(int));
        if (!rind_planes[0]) {
            cgi_error("Error allocating rind_planes.");
            return 1;
        }
        for (n=0; n<2*Idim; n++) rind_planes[0][n]=0;
        return 0;
    }

    if (cgi_read_node(id[0], name, data_type, &ndim, dim_vals,
        (void **)rind_planes, READ_DATA)) {
        cgi_error("Error reading Rind Planes");
        return 1;
    }
    if (ndim!=1 || dim_vals[0]!=2*Idim || strcmp(data_type,"I4")) {
        cgi_error("Rind Planes '%s' defined incorrectly",name);
        return 1;
    }
    free(id);
    return 0;
}

int cgi_read_location(double parent_id, char_33 parent_name,
                      CGNS_ENUMT(GridLocation_t) *location)
{
    int nGL_t;
    double *id;
    char *location_name;    /* allocated in cgi_read_node */
    char_33 name;

     /* get number of GridLocation_t nodes and their ID */
    if (cgi_get_nodes(parent_id, "GridLocation_t", &nGL_t, &id)) return 1;

    if (nGL_t==0) {
      *location = CGNS_ENUMV( Vertex );
    } else if (nGL_t<0 || nGL_t >1) {
        cgi_error("Invalid definition of GridLocation for %s",parent_name);
        return 1;
    } else if (nGL_t==1) {

     /* Read the grid location value in the GridLocation_t node */
        if (cgi_read_string(id[0], name, &location_name)) return 1;
        free(id);

        if (cgi_GridLocation(location_name, location)) return 1;
        free(location_name);

    }
    return 0;
}

int cgi_read_zonetype(double parent_id, char_33 parent_name,
                      CGNS_ENUMT(ZoneType_t) *type)
{
    int nchild;
    double *id;
    char *zonetype_name;    /* allocated in cgi_read_node */
    char_33 name;

     /* get number of ZoneType_t nodes and their ID */
    if (cgi_get_nodes(parent_id, "ZoneType_t", &nchild, &id)) return 1;
    if (nchild==0) {
      /* set default */
      *type = CGNS_ENUMV( Structured );
        return 0;
    }

    if (nchild >1) {
        cgi_error("Invalid definition of ZoneType for %s",parent_name);
        return 1;
    }

    if (cgi_read_string(id[0], name, &zonetype_name)) return 1;
    free(id);

    if (cgi_ZoneType(zonetype_name, type)) return 1;
    free(zonetype_name);
    return 0;
}

int cgi_read_simulation(double parent_id, CGNS_ENUMT(SimulationType_t) *type,
                        double *type_id)
{
    int nchild;
    double *id;
    char *type_name;    /* allocated in cgi_read_node */
    char_33 name;

     /* initialize */
    *type = CGNS_ENUMV( SimulationTypeNull );
    *type_id = 0;

     /* get number of SimulationType_t nodes and their ID */
    if (cgi_get_nodes(parent_id, "SimulationType_t", &nchild, &id)) return 1;
    if (nchild==0) return 0;
    if (nchild >1) {
        cgi_error("File incorrect: multiple definition of SimulationType");
        return 1;
    }
    *type_id = id[0];
    if (cgi_read_string(id[0], name, &type_name)) return 1;
    free(id);

    if (cgi_SimulationType(type_name, type)) return 1;
    free(type_name);
    return 0;
}

int cgi_read_biter(int in_link, double parent_id, cgns_biter **biter)
{
    double *id;
    char_33 datatype;
    cgns_array *array;
    int ndim, *data, nnod;
    int i, linked;
    int nzones_max = 0, nfamilies_max = 0;
    void *vdata;
    cgsize_t dim_vals[12];

     /* get number of BaseIterativeData_t node */
    if (cgi_get_nodes(parent_id, "BaseIterativeData_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        biter[0]=0;
        return 0;
    } else if (nnod>1) {
        cgi_error("Error: Multiple BaseIterativeData_t found...");
        return 1;
    }

    biter[0] = CGNS_NEW(cgns_biter, 1);

    biter[0]->id = id[0];
    biter[0]->link = cgi_read_link(id[0]);
    biter[0]->in_link = in_link;
    linked = biter[0]->link ? 1 : in_link;
    free(id);

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, biter[0]->id, &biter[0]->ndescr, &biter[0]->descr,
        &biter[0]->data_class, &biter[0]->units)) return 1;

     /* Name and NumberOfSteps */
    NumberOfSteps = biter[0]->nsteps = 0;
    if (cgi_read_node(biter[0]->id, biter[0]->name, datatype, &ndim,
            dim_vals, &vdata, READ_DATA)) {
        cgi_error("Error reading BaseIterativeData_t");
        return 1;
    }
    if (ndim!=1 || dim_vals[0]!=1 || strcmp(datatype,"I4")) {
        cgi_error("Error in data dimension or type for NumberOfSteps");
        return 1;
    }
    data = (int *)vdata;
    if (data[0]<0) {
        cgi_error("Error in data:  NumberOfSteps<0!");
        return 1;
    }
    NumberOfSteps = biter[0]->nsteps = data[0];
    if (biter[0]->nsteps == 0) return 0;
    free(vdata);

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, biter[0]->id, &biter[0]->nuser_data,
        &biter[0]->user_data)) return 1;

     /* DataArray_t */
    if (cgi_get_nodes(biter[0]->id, "DataArray_t", &biter[0]->narrays, &id))
        return 1;
    if (biter[0]->narrays == 0) return 0; /* If no arrays we're done. */
    biter[0]->array = CGNS_NEW(cgns_array, biter[0]->narrays);

    for (i=0; i<(biter[0]->narrays); i++) {
        biter[0]->array[i].id = id[i];
        biter[0]->array[i].link = cgi_read_link(id[i]);
        biter[0]->array[i].in_link = linked;
        if (cgi_read_array(&biter[0]->array[i], "BaseIterativeData_t",
            biter[0]->id)) return 1;
        array = &biter[0]->array[i];

     /* check data */
        if (strcmp("TimeValues",array->name)==0 ||
            strcmp("IterationValues",array->name)==0 ||
            strcmp("NumberOfZones",array->name)==0 ||
            strcmp("NumberOfFamilies",array->name)==0) {
            if (array->data_dim!=1 || array->dim_vals[0]!=biter[0]->nsteps) {
                cgi_error("Error: Array '%s' incorrectly sized",array->name);
                return 1;
            }
            if ((strcmp("TimeValues",array->name)==0 && strcmp(array->data_type,"R4") &&
                 strcmp(array->data_type,"R8")) ||
                (strcmp("IterationValues",array->name)==0 && strcmp(array->data_type,"I4"))) {
                cgi_error("Incorrect data type for %s under %s",array->name,biter[0]->name);
                return 1;
            }
        }
    }       /* loop through arrays */

    free(id);

     /* check data: verify that at least one of {TimeValues or IterationValues} is defined */
    for (i=0; i<(biter[0]->narrays); i++) {
        array = &biter[0]->array[i];
        if (strcmp("TimeValues",array->name)==0 || strcmp("IterationValues",array->name)==0) break;
        if (i == ((biter[0]->narrays)-1)) {
            cgi_error("Error:  TimeValues or IterationValues must be defined for '%s'",biter[0]->name);
            return 1;
        }
    }

     /* check data: Compute nzones_max and nfamilies_max */
    for (i=0; i<(biter[0]->narrays); i++) {
        int step;
        array = &biter[0]->array[i];
        if (strcmp("NumberOfZones",array->name)==0) {
            for (step=0; step<biter[0]->nsteps; step++) {
                int nzones = *((int *)(array->data)+step);
                nzones_max = MAX(nzones_max, nzones);
            }
        } else if (strcmp("NumberOfFamilies",array->name)==0) {
            for (step=0; step<biter[0]->nsteps; step++) {
                int nfamilies = *((int *)(array->data)+step);
                nfamilies_max = MAX(nfamilies_max, nfamilies);
            }
        }
    }

     /* check data:  ZonePointers can't be defined without NumberOfZones and
             FamilyPointers can't be defined without NumberOfFamilies */
    for (i=0; i<(biter[0]->narrays); i++) {
        array = &biter[0]->array[i];
        if (strcmp("ZonePointers",array->name)==0) {
            if (nzones_max==0) {
                cgi_error("NumberofZones (DataArray_t) missing under %s",biter[0]->name);
                return 1;
            } else {        /* check dimensions and data type */
                if (array->data_dim!=3 || array->dim_vals[0]!=32 || array->dim_vals[1]!=nzones_max ||
                    array->dim_vals[2]!=biter[0]->nsteps || strcmp(array->data_type,"C1")) {
                    cgi_error("Incorrect definition of ZonePointers under %s",biter[0]->name);
                    return 1;
                }
            }
        } else if (strcmp("FamilyPointers",array->name)==0) {
            if (nfamilies_max==0) {
                cgi_error("NumberOfFamilies (DataArray_t) missing under %s",biter[0]->name);
                return 1;
            } else {           /* check dimensions and data type */
                if (array->data_dim!=3 || array->dim_vals[0]!=32 || array->dim_vals[1]!=nfamilies_max ||
                    array->dim_vals[2]!=biter[0]->nsteps || strcmp(array->data_type,"C1")) {
                    cgi_error("Incorrect definition of FamilyPointers under %s",biter[0]->name);
                    return 1;
                }
            }
        }
    }
    return 0;
}

int cgi_read_ziter(int in_link, double parent_id, cgns_ziter **ziter)
{
    double *id;
    cgns_array *array;
    char_33 datatype;
    int ndim, nnod;
    void *data;
    int i, linked;
    cgsize_t dim_vals[12];

     /* get number of ZoneIterativeData_t node */
    if (cgi_get_nodes(parent_id, "ZoneIterativeData_t", &nnod, &id)) return 1;
    if (nnod<=0) {
        ziter[0]=0;
        return 0;
    } else if (nnod>1) {
        cgi_error("Error: Multiple ZoneIterativeData_t found...");
        return 1;
    }
    ziter[0] = CGNS_NEW(cgns_ziter, 1);
    ziter[0]->id = id[0];
    ziter[0]->link = cgi_read_link(id[0]);
    ziter[0]->in_link = in_link;
    linked = ziter[0]->link ? 1 : in_link;
    free(id);

     /* Name */
    if (cgi_read_node(ziter[0]->id, ziter[0]->name, datatype, &ndim,
        dim_vals, &data, READ_DATA)) {
        cgi_error("Error reading ZoneIterativeData_t");
        return 1;
    }
    if (strcmp(datatype,"MT")) {
        cgi_error("Error in ZoneIterativeData_t node");
        return 1;
    }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
    if (cgi_read_DDD(linked, ziter[0]->id, &ziter[0]->ndescr, &ziter[0]->descr,
        &ziter[0]->data_class, &ziter[0]->units)) return 1;

     /* UserDefinedData_t */
    if (cgi_read_user_data(linked, ziter[0]->id, &ziter[0]->nuser_data,
        &ziter[0]->user_data)) return 1;

     /* DataArray_t */
    if (cgi_get_nodes(ziter[0]->id, "DataArray_t", &ziter[0]->narrays, &id))
        return 1;
    if (ziter[0]->narrays==0) return 0; /* If no arrays we're done. */
    ziter[0]->array = CGNS_NEW(cgns_array,ziter[0]->narrays);

    for (i=0; i<(ziter[0]->narrays); i++) {
        ziter[0]->array[i].id = id[i];
        ziter[0]->array[i].link = cgi_read_link(id[i]);
        ziter[0]->array[i].in_link = linked;
        if (cgi_read_array(&ziter[0]->array[i], "ZoneIterativeData_t",
            ziter[0]->id)) return 1;
        array = &ziter[0]->array[i];

     /* check data */
        if (strcmp("RigidGridMotionPointers",array->name)==0 ||
            strcmp("ArbitraryGridMotionPointers",array->name)==0 ||
            strcmp("GridCoordinatesPointers",array->name)==0 ||
            strcmp("FlowSolutionPointers",array->name)==0) {
            if (array->data_dim!=2 || array->dim_vals[0]!=32 ||
                array->dim_vals[1]!=NumberOfSteps) {
                cgi_error("Error: Array '%s/%s' incorrectly sized", ziter[0]->name, array->name);
                return 1;
            }
            if (strcmp(array->data_type,"C1")) {
                cgi_error("Incorrect data type for %s under %s",array->name,ziter[0]->name);
                return 1;
            }
        }
    }       /* loop through arrays */
    free(id);

    return 0;
}

int cgi_read_user_data(int in_link, double parent_id, int *nuser_data,
                       cgns_user_data **user_data)
{
    double *id, *idi;
    int n, i, linked;
    double *IA_id, *IR_id;
    int nIA_t, nIR_t, nn;
    char_33 name;

    if (cgi_get_nodes(parent_id, "UserDefinedData_t", nuser_data, &id))
        return 1;
    if (*nuser_data<=0) {
        user_data[0] = 0;
        return 0;
    }

    user_data[0] = CGNS_NEW(cgns_user_data, (*nuser_data));
    for (n=0; n<(*nuser_data); n++) {
        user_data[0][n].id = id[n];
        user_data[0][n].link = cgi_read_link(id[n]);
        user_data[0][n].in_link = in_link;
        linked = user_data[0][n].link ? 1 : in_link;

     /* UserDefinedData_t Name */
        if (cgio_get_name(cg->cgio, user_data[0][n].id, user_data[0][n].name)) {
            cg_io_error("cgio_get_name");
            return 1;
        }

     /* Descriptor_t, DataClass_t, DimensionalUnits_t */
        if (cgi_read_DDD(linked, id[n], &user_data[0][n].ndescr,
            &user_data[0][n].descr, &user_data[0][n].data_class,
            &user_data[0][n].units)) return 1;

     /* DataArray_t */
        if (cgi_get_nodes(id[n], "DataArray_t", &user_data[0][n].narrays,
            &idi)) return 1;
        if (user_data[0][n].narrays>0) {
            user_data[0][n].array = CGNS_NEW(cgns_array, user_data[0][n].narrays);
            for (i=0; i<user_data[0][n].narrays; i++) {
                user_data[0][n].array[i].id = idi[i];
                user_data[0][n].array[i].link = cgi_read_link(idi[i]);
                user_data[0][n].array[i].in_link = linked;
                if (cgi_read_array(&user_data[0][n].array[i],
                    "UserDefinedData_t", user_data[0][n].id)) return 1;
            }
            free(idi);
        }

     /* GridLocation_t */
        if (cgi_read_location(user_data[0][n].id, user_data[0][n].name,
            &user_data[0][n].location)) return 1;

     /* FamilyName_t */
        if (cgi_read_family_name(linked, user_data[0][n].id,
                                 user_data[0][n].name,
                                 user_data[0][n].family_name))
            return 1;

     /* CPEX 0034 - AdditionalFamilyNames */
        if (cgi_get_nodes(user_data[0][n].id, "AdditionalFamilyName_t",
            &user_data[0][n].nfamname, &idi)) return 1;
        if (user_data[0][n].nfamname > 0) {
            char *fam;
            user_data[0][n].famname = CGNS_NEW(cgns_famname,
                                               user_data[0][n].nfamname);
            for (i = 0; i < user_data[0][n].nfamname; i++) {
                user_data[0][n].famname[i].id = idi[i];
                if (cgi_read_string(idi[i], user_data[0][n].famname[i].name,
                        &fam)) return 1;
                strncpy(user_data[0][n].famname[i].family, fam, 32);
                free(fam);
            }
            free(idi);
        }

     /* Ordinal_t */
        if (cgi_read_ordinal(user_data[0][n].id, &user_data[0][n].ordinal))
            return 1;

     /* PointSet */
        /* get number of IndexArray_t and IndexRange_t nodes and their
         * ID
         */
        if (cgi_get_nodes(user_data[0][n].id, "IndexArray_t", &nIA_t,
                          &IA_id)) return 1;
        if (cgi_get_nodes(user_data[0][n].id, "IndexRange_t", &nIR_t,
                          &IR_id)) return 1;

        /* initialized */
        user_data[0][n].ptset = 0;

        for (nn=0; nn<nIR_t; nn++)
        {
            if (cgio_get_name(cg->cgio, IR_id[nn], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name,"PointRange") && strcmp(name,"ElementRange")) {
                cgi_error("Invalid name for IndexRange_t");
                return 1;
            }
            if (user_data[0][n].ptset!=0) {
                cgi_error("Multiple definition of boundary patch found");
                return 1;
            }
            user_data[0][n].ptset = CGNS_NEW(cgns_ptset, 1);
            if (strcmp(name,"ElementRange")==0)
              user_data[0][n].ptset->type = CGNS_ENUMV( ElementRange );
            else
              user_data[0][n].ptset->type = CGNS_ENUMV( PointRange );
            user_data[0][n].ptset->id=IR_id[nn];
            user_data[0][n].ptset->link=cgi_read_link(IR_id[nn]);
            user_data[0][n].ptset->in_link=linked;
            if (cgi_read_ptset(user_data[0][n].id, user_data[0][n].ptset))
                return 1;
        }
        if (nIR_t) free(IR_id);

        for (nn=0; nn<nIA_t; nn++)
        {
            if (cgio_get_name(cg->cgio, IA_id[nn], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name, "PointList") && strcmp(name,"ElementList"))
                continue;

            if (user_data[0][n].ptset!=0) {
                cgi_error("Multiple definition of boundary patch found");
                return 1;
            }
            user_data[0][n].ptset = CGNS_NEW(cgns_ptset, 1);
            if (strcmp(name,"ElementList")==0)
              user_data[0][n].ptset->type = CGNS_ENUMV( ElementList );
            else
              user_data[0][n].ptset->type = CGNS_ENUMV( PointList );
            user_data[0][n].ptset->id = IA_id[nn];
            user_data[0][n].ptset->link = cgi_read_link(IA_id[nn]);
            user_data[0][n].ptset->in_link = linked;
            if (cgi_read_ptset(user_data[0][n].id, user_data[0][n].ptset))
                return 1;
        }

        if (nIA_t) free(IA_id);

        /* UserDefinedData_t */
        if (cgi_read_user_data(linked, user_data[0][n].id,
            &user_data[0][n].nuser_data, &user_data[0][n].user_data)) return 1;
    }
    free(id);

    return 0;
}

int cgi_read_subregion(int in_link, double parent_id, int *nsubreg,
                       cgns_subreg **subreg)
{
    double *id, *idi;
    int n, i, linked;
    double *IA_id, *IR_id;
    int nIA_t, nIR_t, nn;
    char_33 data_type, name;
    cgns_subreg *reg;
    int ndim, ndescr;
    char *text;
    void *data;
    cgsize_t dim_vals[12];

    if (cgi_get_nodes(parent_id, "ZoneSubRegion_t", nsubreg, &id))
        return 1;
    if (*nsubreg <= 0) {
        *subreg = 0;
        return 0;
    }

    reg = CGNS_NEW(cgns_subreg, (*nsubreg));
    *subreg = reg;

    for (n = 0; n < (*nsubreg); n++) {
        reg[n].id = id[n];
        reg[n].link = cgi_read_link(id[n]);
        reg[n].in_link = in_link;
        linked = reg[n].link ? 1 : in_link;

        if (cgi_read_node(reg[n].id, reg[n].name, data_type, &ndim,
                dim_vals, &data, READ_DATA)) {
            cgi_error("Error reading ZoneSubRegion node");
            return 1;
        }
        if (ndim != 1 || dim_vals[0] != 1 || strcmp(data_type, "I4")) {
            cgi_error("Bad dimension value for ZoneSubRegion node");
            return 1;
        }
        reg[n].reg_dim = *((int *)data);
        free(data);

        /* Descriptor_t */
        if (cgi_get_nodes(id[n], "Descriptor_t", &nn, &idi)) return 1;
        ndescr = 0;
        if (nn > 0) {
            for (i = 0; i < nn; i++) {
                if (cgi_read_string(idi[i], name, &text)) return 1;
                if (0 == strcmp(name, "BCRegionName")) {
                    reg[n].bcname = CGNS_NEW(cgns_descr, 1);
                    reg[n].bcname->id = idi[i];
                    reg[n].bcname->link = cgi_read_link(idi[i]);
                    reg[n].bcname->in_link = in_link;
                    strcpy(reg[n].bcname->name, name);
                    reg[n].bcname->text = text;
                }
                else if (0 == strcmp(name, "GridConnectivityRegionName")) {
                    reg[n].gcname = CGNS_NEW(cgns_descr, 1);
                    reg[n].gcname->id = idi[i];
                    reg[n].gcname->link = cgi_read_link(idi[i]);
                    reg[n].gcname->in_link = in_link;
                    strcpy(reg[n].gcname->name, name);
                    reg[n].gcname->text = text;
                }
                else {
                    free(text);
                    ndescr++;
                }
            }
        }
        if (ndescr > 0) {
            int j = 0;
            reg[n].ndescr = ndescr;
            reg[n].descr = CGNS_NEW(cgns_descr, ndescr);
            for (i = 0; i < nn; i++) {
                if (cgi_read_string(idi[i], name, &text)) return 1;
                if (strcmp(name, "BCRegionName") &&
                    strcmp(name, "GridConnectivityRegionName")) {
                    reg[n].descr[j].id = idi[i];
                    reg[n].descr[j].link = cgi_read_link(idi[i]);
                    reg[n].descr[j].in_link = in_link;
                    strcpy(reg[n].descr[j].name, name);
                    reg[n].descr[j].text = text;
                    j++;
                }
                else {
                    free(text);
                }
            }
        }
        if (nn) free(idi);

        /* DataClass_t */
        if (cgi_get_nodes(id[n], "DataClass_t", &nn, &idi)) return 1;
        if (nn > 0) {
            if (cgi_read_string(idi[0], name, &text)) return 1;
            cgi_DataClass(text, &reg[n].data_class);
            free(text);
            free(idi);
        }

        /* DimensionalUnits_t */
        if (cgi_read_units(in_link, id[n], &reg[n].units)) return 1;

        /* DataArray_t */
        if (cgi_get_nodes(id[n], "DataArray_t", &reg[n].narrays,
              &idi)) return 1;
        if (reg[n].narrays > 0) {
            reg[n].array = CGNS_NEW(cgns_array, reg[n].narrays);
            for (i = 0; i < reg[n].narrays; i++) {
                reg[n].array[i].id = idi[i];
                reg[n].array[i].link = cgi_read_link(idi[i]);
                reg[n].array[i].in_link = linked;
                if (cgi_read_array(&reg[n].array[i],
                        "ZoneSubRegion_t", reg[n].id)) return 1;
            }
            free(idi);
        }

        /* GridLocation_t */
        if (cgi_read_location(reg[n].id, reg[n].name,
            &reg[n].location)) return 1;

        /* FamilyName_t */
        if (cgi_read_family_name(linked, reg[n].id,
                reg[n].name, reg[n].family_name))
            return 1;

        /* CPEX 0034 */
        if (cgi_get_nodes(reg[n].id, "AdditionalFamilyName_t", &reg[n].nfamname, &idi))
            return 1;
        if (reg[n].nfamname > 0) {
            char *fam;
            reg[n].famname = CGNS_NEW(cgns_famname, reg[n].nfamname);
            for (i = 0; i < reg[n].nfamname; i++) {
                reg[n].famname[i].id = idi[i];
                if (cgi_read_string(idi[i], reg[n].famname[i].name, &fam)) return 1;
                strncpy(reg[n].famname[i].family, fam, 32);
                free(fam);
            }
            free(idi);
        }

        /* PointSet */
        /* get number of IndexArray_t and IndexRange_t nodes and their ID */
        if (cgi_get_nodes(reg[n].id, "IndexArray_t", &nIA_t,
                          &IA_id)) return 1;
        if (cgi_get_nodes(reg[n].id, "IndexRange_t", &nIR_t,
                          &IR_id)) return 1;

        /* initialized */
        reg[n].ptset = 0;

        for (nn = 0; nn < nIR_t; nn++) {
            if (cgio_get_name(cg->cgio, IR_id[nn], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name,"PointRange")) {
                cgi_error("Invalid name for IndexRange_t");
                return 1;
            }
            if (reg[n].ptset != NULL) {
                cgi_error("Multiple definition of boundary patch found");
                return 1;
            }
            reg[n].ptset = CGNS_NEW(cgns_ptset, 1);
            reg[n].ptset->type = CGNS_ENUMV(PointRange);
            reg[n].ptset->id=IR_id[nn];
            reg[n].ptset->link=cgi_read_link(IR_id[nn]);
            reg[n].ptset->in_link=linked;
            if (cgi_read_ptset(reg[n].id, reg[n].ptset))
                return 1;
        }
        if (nIR_t) free(IR_id);

        for (nn = 0; nn < nIA_t; nn++) {
            if (cgio_get_name(cg->cgio, IA_id[nn], name)) {
                cg_io_error("cgio_get_name");
                return 1;
            }
            if (strcmp(name, "PointList"))
                continue;

            if (reg[n].ptset != NULL) {
                cgi_error("Multiple definition of boundary patch found");
                return 1;
            }
            reg[n].ptset = CGNS_NEW(cgns_ptset, 1);
            reg[n].ptset->type = CGNS_ENUMV(PointList);
            reg[n].ptset->id = IA_id[nn];
            reg[n].ptset->link = cgi_read_link(IA_id[nn]);
            reg[n].ptset->in_link = linked;
            if (cgi_read_ptset(reg[n].id, reg[n].ptset))
                return 1;
        }

        if (nIA_t) free(IA_id);

         /* Rind Planes */
        if (cgi_read_rind(reg[n].id, &reg[n].rind_planes)) return 1;

        /* UserDefinedData_t */
        if (cgi_read_user_data(linked, reg[n].id,
            &reg[n].nuser_data, &reg[n].user_data)) return 1;
    }
    free(id);

    return 0;
}

int cgi_read_node(double node_id, char_33 name, char_33 data_type,
                  int *ndim, cgsize_t *dim_vals, void **data, int data_flag)
{
    int n;
    cgsize_t size=1;

     /* name of node */
    if (cgio_get_name(cg->cgio, node_id, name)) {
        cg_io_error("cgio_get_name");
        return 1;
    }

     /* read node data type */
    if (cgio_get_data_type(cg->cgio, node_id, data_type)) {
        cg_io_error("cgio_get_data_type");
        return 1;
    }

    if (strcmp(data_type,"MT")==0) {
        *ndim = 0;
        return 0;
    }

    if (cgio_get_dimensions(cg->cgio, node_id, ndim, dim_vals)) {
        cg_io_error("cgio_get_dimensions");
        return 1;
    }

     /* Skipping data */
    if (!data_flag) return 0;

     /* allocate data */
    for (n=0; n<(*ndim); n++) size*=dim_vals[n];
    if (size<=0) {
        cgi_error("Error reading node %s",name);
        return 1;
    }
    if (strcmp(data_type,"I4")==0) data[0]=CGNS_NEW(int, size);
    else if (strcmp(data_type,"I8")==0) data[0]=CGNS_NEW(cglong_t, size);
    else if (strcmp(data_type,"R4")==0) data[0]=CGNS_NEW(float, size);
    else if (strcmp(data_type,"R8")==0) data[0]=CGNS_NEW(double, size);
    else if (strcmp(data_type,"C1")==0) data[0]=CGNS_NEW(char, size+1);

     /* read data */
    if (cgio_read_all_data(cg->cgio, node_id, data[0])) {
        cg_io_error("cgio_read_all_data");
        return 1;
    }
    return 0;
}

cgns_link *cgi_read_link (double node_id)
{
    int len;
    cgns_link *link;

    if (cgio_is_link(cg->cgio, node_id, &len)) {
        cg_io_error ("cgio_is_link");
        return 0;
    }
    if (len > 0) {
        int file_len, name_len;
        if (cgio_link_size (cg->cgio, node_id, &file_len, &name_len)) {
            cg_io_error ("cgio_link_size");
            return 0;
        }
        len = name_len + file_len + 2;
        link = (cgns_link *) cgi_malloc (1, len + sizeof(cgns_link));
        link->filename = (char *)(link + 1);
        link->name_in_file = link->filename + file_len + 1;
        if (cgio_get_link(cg->cgio, node_id, link->filename,
                link->name_in_file)) {
            free (link);
            cg_io_error ("cgio_get_link");
            return 0;
        }
        link->filename[file_len] = 0;
        link->name_in_file[name_len] = 0;
        return link;
    }
    return 0;
}

int cgi_datasize(int Idim, cgsize_t *CurrentDim,
                 CGNS_ENUMV(GridLocation_t) location,
                 int *rind_planes, cgsize_t *DataSize)
{
    int j;

    if (location==CGNS_ENUMV( Vertex )) {
        for (j=0; j<Idim; j++)
            DataSize[j] = CurrentDim[j] + rind_planes[2*j] + rind_planes[2*j+1];

    } else if (location==CGNS_ENUMV(CellCenter) ||
              (location==CGNS_ENUMV(FaceCenter) && Cdim==2) ||
              (location==CGNS_ENUMV(EdgeCenter) && Cdim==1)) {
        for (j=0; j<Idim; j++)
            DataSize[j] = CurrentDim[j+Idim] + rind_planes[2*j] + rind_planes[2*j+1];

    } else if (location == CGNS_ENUMV( IFaceCenter ) ||
               location == CGNS_ENUMV( JFaceCenter ) ||
               location == CGNS_ENUMV( KFaceCenter )) {
        for (j=0; j<Idim; j++) {
            DataSize[j] = CurrentDim[j] + rind_planes[2*j] + rind_planes[2*j+1];
            if ((location == CGNS_ENUMV( IFaceCenter ) && j!=0) ||
                (location == CGNS_ENUMV( JFaceCenter ) && j!=1) ||
                (location == CGNS_ENUMV( KFaceCenter ) && j!=2)) DataSize[j]--;
        }
    } else {
        cgi_error("Location not yet supported");
        return 1;
    }
    return 0;
}

int cgi_check_dimensions(int ndim, cglong_t *dims)
{
    int n;
    cglong_t sum = 1;

    if (cgio_check_dimensions(ndim, dims)) {
        cg_io_error("cgio_check_dimensions");
        return 1;
    }
    for (n = 0; n < ndim; n++) {
        sum *= dims[n];
    }
    if (sum > CG_MAX_INT32) {
        cgi_error("array size exceeds that for a 32-bit integer");
        return 1;
    }
    return 0;
}

int cgi_check_location(int dim, CGNS_ENUMT(ZoneType_t) type,
	CGNS_ENUMT(GridLocation_t) loc)
{
    if (loc == CGNS_ENUMV(Vertex) || loc == CGNS_ENUMV(CellCenter))
        return 0;
    if (loc == CGNS_ENUMV(EdgeCenter)) {
        if (dim >= 2) return 0;
    } else if (loc == CGNS_ENUMV(FaceCenter)) {
        if (dim >= 3) return 0;
    } else if (loc == CGNS_ENUMV(IFaceCenter) ||
               loc == CGNS_ENUMV(JFaceCenter) ||
               loc == CGNS_ENUMV(KFaceCenter)) {
        if (type != CGNS_ENUMV(Structured)) {
            cgi_error("GridLocation [IJK]FaceCenter only valid for Structured Grid");
            return 1;
        }
        if (dim >= 3) return 0;
    }
    cgi_error("GridLocation %s not valid for CellDimension %d",
        cg_GridLocationName(loc), dim);
    return 1;
}

int cgi_read_int_data(double id, char_33 data_type, cgsize_t cnt, cgsize_t *data)
{
    cgsize_t n;

#if CG_SIZEOF_SIZE == 64
    if (0 == strcmp(data_type, "I4")) {
        int *pnts = (int *)malloc((size_t)(cnt*sizeof(int)));
        if (NULL == pnts) {
            cgi_error("Error allocating I4->I8 data array...");
            return 1;
        }
        if (cgio_read_all_data(cg->cgio, id, (void *)pnts)) {
            cg_io_error("cgio_read_all_data");
            free(pnts);
            return 1;
        }
        for (n = 0; n < cnt; n++)
            data[n] = (cgsize_t)pnts[n];
        free(pnts);
    }
#else
    if (0 == strcmp(data_type, "I8")) {
        cglong_t *pnts = (cglong_t *)malloc((size_t)(cnt*sizeof(cglong_t)));
        if (NULL == pnts) {
            cgi_error("Error allocating I8->I4 data array...");
            return 1;
        }
        if (cgio_read_all_data(cg->cgio, id, (void *)pnts)) {
            cg_io_error("cgio_read_all_data");
            free(pnts);
            return 1;
        }
        for (n = 0; n < cnt; n++)
            data[n] = (cgsize_t)pnts[n];
        free(pnts);
    }
#endif
    else {
        if (cgio_read_all_data(cg->cgio, id, (void *)data)) {
            cg_io_error("cgio_read_all_data");
            return 1;
        }
    }
    return 0;
}

int cgi_convert_data(cgsize_t cnt,
                     CGNS_ENUMT(DataType_t) from_type, const void *from_data,
                     CGNS_ENUMT(DataType_t) to_type, void *to_data)
{
    int ierr = 0;
    cgsize_t n;

    if (from_type == CGNS_ENUMV(Character)) {
        const char *src = (const char *)from_data;
        /* C1 -> C1 */
        if (to_type == CGNS_ENUMV(Character)) {
            char *dest = (char *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (char)src[n];
        }
        /* C1 -> I4 */
        else if (to_type == CGNS_ENUMV(Integer)) {
            int *dest = (int *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (int)src[n];
        }
        /* C1 -> I8 */
        else if (to_type == CGNS_ENUMV(LongInteger)) {
            cglong_t *dest = (cglong_t *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (cglong_t)src[n];
        }
        /* C1 -> R4 */
        else if (to_type == CGNS_ENUMV(RealSingle)) {
            float *dest = (float *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (float)src[n];
        }
        /* C1 -> R8 */
        else if (to_type == CGNS_ENUMV(RealDouble)) {
            double *dest = (double *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (double)src[n];
        }
        else {
            ierr = 1;
        }
    }

    else if (from_type == CGNS_ENUMV(Integer)) {
        const int *src = (const int *)from_data;
        /* I4 -> C1 */
        if (to_type == CGNS_ENUMV(Character)) {
            char *dest = (char *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (char)src[n];
        }
        /* I4 -> I4 */
        else if (to_type == CGNS_ENUMV(Integer)) {
            int *dest = (int *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (int)src[n];
        }
        /* I4 -> I8 */
        else if (to_type == CGNS_ENUMV(LongInteger)) {
            cglong_t *dest = (cglong_t *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (cglong_t)src[n];
        }
        /* I4 -> R4 */
        else if (to_type == CGNS_ENUMV(RealSingle)) {
            float *dest = (float *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (float)src[n];
        }
        /* I4 -> R8 */
        else if (to_type == CGNS_ENUMV(RealDouble)) {
            double *dest = (double *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (double)src[n];
        }
        else {
            ierr = 1;
        }
    }

    else if (from_type == CGNS_ENUMV(LongInteger)) {
        const cglong_t *src = (const cglong_t *)from_data;
        /* I8 -> C1 */
        if (to_type == CGNS_ENUMV(Character)) {
            char *dest = (char *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (char)src[n];
        }
        /* I8 -> I4 */
        else if (to_type == CGNS_ENUMV(Integer)) {
            int *dest = (int *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (int)src[n];
        }
        /* I8 -> I8 */
        else if (to_type == CGNS_ENUMV(LongInteger)) {
            cglong_t *dest = (cglong_t *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (cglong_t)src[n];
        }
        /* I8 -> R4 */
        else if (to_type == CGNS_ENUMV(RealSingle)) {
            float *dest = (float *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (float)src[n];
        }
        /* I8 -> R8 */
        else if (to_type == CGNS_ENUMV(RealDouble)) {
            double *dest = (double *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (double)src[n];
        }
        else {
            ierr = 1;
        }
    }

    else if (from_type == CGNS_ENUMV(RealSingle)) {
        const float *src = (const float *)from_data;
        /* R4 -> C1 */
        if (to_type == CGNS_ENUMV(Character)) {
            char *dest = (char *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (char)src[n];
        }
        /* R4 -> I4 */
        else if (to_type == CGNS_ENUMV(Integer)) {
            int *dest = (int *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (int)src[n];
        }
        /* R4 -> I8 */
        else if (to_type == CGNS_ENUMV(LongInteger)) {
            cglong_t *dest = (cglong_t *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (cglong_t)src[n];
        }
        /* R4 -> R4 */
        else if (to_type == CGNS_ENUMV(RealSingle)) {
            float *dest = (float *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (float)src[n];
        }
        /* R4 -> R8 */
        else if (to_type == CGNS_ENUMV(RealDouble)) {
            double *dest = (double *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (double)src[n];
        }
        else {
            ierr = 1;
        }
    }

    else if (from_type == CGNS_ENUMV(RealDouble)) {
        const double *src = (const double *)from_data;
        /* R8 -> C1 */
        if (to_type == CGNS_ENUMV(Character)) {
            char *dest = (char *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (char)src[n];
        }
        /* R8 -> I4 */
        else if (to_type == CGNS_ENUMV(Integer)) {
            int *dest = (int *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (int)src[n];
        }
        /* R8 -> I8 */
        else if (to_type == CGNS_ENUMV(LongInteger)) {
            cglong_t *dest = (cglong_t *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (cglong_t)src[n];
        }
        /* R8 -> R4 */
        else if (to_type == CGNS_ENUMV(RealSingle)) {
            float *dest = (float *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (float)src[n];
        }
        /* R8 -> R8 */
        else if (to_type == CGNS_ENUMV(RealDouble)) {
            double *dest = (double *)to_data;
            for (n = 0; n < cnt; n++)
                dest[n] = (double)src[n];
        }
        else {
            ierr = 1;
        }
    }

    else {
        ierr = 1;
    }

    if (ierr)
        cgi_error("invalid data type conversion %d->%d",
            from_type, to_type);
    return ierr;
}

/***********************************************************************\
 *       Write a CGNS file from in-memory data             *
\***********************************************************************/

int cgi_write(int file_number)
{
    cgns_base *base;
    int n, b;
    cgsize_t dim_vals;
    double dummy_id;
    float FileVersion;

    cg = cgi_get_file(file_number);
    if (cg == 0) return 1;

     /* write version number */
    dim_vals = 1;
     /* Changed due to round off error on CRAY:
    FileVersion = (float)CGNSLibVersion/1000; */
/* The FileVersion will always be the latest
    if (cg->version == 1050) FileVersion = (float) 1.05;
    else if (cg->version == 1100) FileVersion = (float) 1.10;
    else if (cg->version == 1200) FileVersion = (float) 1.2;
    else if (cg->version == 1270) FileVersion = (float) 1.27;
    else if (cg->version == 2000) FileVersion = (float) 2.00;
    else if (cg->version == 2100) FileVersion = (float) 2.10;
    else {
        cgi_error("FileVersion can't be set in cgi_write!");
        return 1;
    }
*/
    FileVersion = (float) CGNS_DOTVERS;
    if (cgi_new_node(cg->rootid, "CGNSLibraryVersion",
        "CGNSLibraryVersion_t", &dummy_id, "R4", 1, &dim_vals,
        (void *)&FileVersion)) return 1;

     /* write all CGNSBase_t nodes in ADF file */
    for (b=0; b<cg->nbases; b++) {
        int *data;
        data = CGNS_NEW(int, 2);
        base = &(cg->base[b]);

        data[0]=base->cell_dim;
        data[1]=base->phys_dim;

     /* Create the CGNSBase_t nodes */
        dim_vals=2;
        if (cgi_new_node(cg->rootid, base->name, "CGNSBase_t", &base->id,
            "I4", 1, &dim_vals, (void *)data)) return 1;
        free(data);

     /* set Global variable */
        Cdim = base->cell_dim;
        Pdim = base->phys_dim;

     /* Descriptor_t */
        for (n=0; n<base->ndescr; n++)
            if (cgi_write_descr(base->id, &base->descr[n])) return 1;

     /* ReferenceState_t */
        if (base->state && cgi_write_state(base->id, base->state)) return 1;

     /* Gravity_t */
        if (base->gravity && cgi_write_gravity(base->id, base->gravity)) return 1;

     /* Axisymmetry_t */
        if (base->axisym && cgi_write_axisym(base->id, base->axisym)) return 1;

     /* RotatingCoordinates_t */
        if (base->rotating && cgi_write_rotating(base->id, base->rotating)) return 1;

     /* Zone_t */
        for (n=0; n<base->nzones; n++) {
            if (cgi_write_zone(base->id, &base->zone[n])) return 1;
        }

     /* Family_t */
        for (n=0; n<base->nfamilies; n++)
            if (cgi_write_family(base->id, &base->family[n])) return 1;

     /* DataClass_t */
        if (base->data_class && cgi_write_dataclass(base->id, base->data_class))
            return 1;

     /* DimensionalUnits_t */
        if (base->units && cgi_write_units(base->id, base->units))
            return 1;

     /* ConvergenceHistory_t */
        if (base->converg && cgi_write_converg(base->id, base->converg))
            return 1;

     /* FlowEquationSet_t */
        if (base->equations && cgi_write_equations(base->id, base->equations))
            return 1;

     /* IntegralData_t */
        for (n=0; n<base->nintegrals; n++)
            if (cgi_write_integral(base->id, &base->integral[n])) return 1;

     /* SimulationType_t */
        if (base->type) {
            dim_vals = (cgsize_t)strlen(SimulationTypeName[base->type]);
            if (cgi_new_node(base->id, "SimulationType", "SimulationType_t", &base->type_id,
                "C1", 1, &dim_vals, (void *)SimulationTypeName[base->type])) return 1;
        }

     /* BaseIterativeData_t */
        if (base->biter && cgi_write_biter(base->id, base->biter)) return 1;

     /* UserDefinedData_t */
        for (n=0; n<base->nuser_data; n++)
            if (cgi_write_user_data(base->id, &base->user_data[n])) return 1;

    }
    return 0;
}

int cgi_write_zone(double parent_id, cgns_zone *zone)
{
    int n;
    cgsize_t dim_vals[2];
    double dummy_id;

    Idim = zone->index_dim;
    if (zone->link) {
        return cgi_write_link(parent_id, zone->name, zone->link, &zone->id);
    }

     /* Create the Zone_t nodes */
    dim_vals[0]= Idim;
    dim_vals[1]= 3;
    if (cgi_new_node(parent_id, zone->name, "Zone_t", &zone->id,
        CG_SIZE_DATATYPE, 2, dim_vals, (void *)zone->nijk)) return 1;

     /* write ZoneType */
    dim_vals[0] = (cgsize_t)strlen(ZoneTypeName[zone->type]);
    if (cgi_new_node(zone->id, "ZoneType", "ZoneType_t", &dummy_id,
        "C1", 1, dim_vals, (void *)ZoneTypeName[zone->type])) return 1;

     /* set Global variable
    for (n=0; n<Idim*3; n++) CurrentDim[n]=zone->nijk[n];
      */

     /* GridCoordinates_t */
    for (n=0; n<zone->nzcoor; n++)
        if (cgi_write_zcoor(zone->id, &zone->zcoor[n])) return 1;

     /* FamilyName_t */
    if (zone->family_name[0]!='\0') {
        dim_vals[0] = (cgsize_t)strlen(zone->family_name);
        if (cgi_new_node(zone->id, "FamilyName", "FamilyName_t", &dummy_id, "C1",
            1, dim_vals, (void *)zone->family_name)) return 1;
    }

    /* CPEX 0034 */
    for (n = 0; n < zone->nfamname; n++) {
        dim_vals[0] = (cgsize_t)strlen(zone->famname[n].family);
        if (cgi_new_node(zone->id, zone->famname[n].name, "AdditionalFamilyName_t",
            &dummy_id, "C1", 1, dim_vals, (void *)zone->famname[n].family)) return 1;
    }

     /* Elements_t */
    for (n=0; n<zone->nsections; n++)
        if (cgi_write_section(zone->id, &zone->section[n])) return 1;

     /* FlowSolution_t */
    for (n=0; n<zone->nsols; n++)
        if (cgi_write_sol(zone->id, &zone->sol[n])) return 1;

     /* ZoneGridConnectivity_t */
    for (n=0; n<zone->nzconn; n++)
        if (cgi_write_zconn(zone->id, &zone->zconn[n])) return 1;

     /* ZoneBC_t */
    if (zone->zboco && cgi_write_zboco(zone->id, zone->zboco)) return 1;

     /* DescreteData_t */
    for (n=0; n<zone->ndiscrete; n++)
        if (cgi_write_discrete(zone->id, &zone->discrete[n])) return 1;

     /* Descriptor_t */
    for (n=0; n<zone->ndescr; n++)
        if (cgi_write_descr(zone->id, &zone->descr[n])) return 1;

     /* ReferenceState_t */
    if (zone->state && cgi_write_state(zone->id, zone->state)) return 1;

     /* DataClass_t */
    if (zone->data_class && cgi_write_dataclass(zone->id, zone->data_class))
        return 1;

     /* DimensionalUnits_t */
    if (zone->units && cgi_write_units(zone->id, zone->units))
        return 1;

     /* ConvergenceHistory_t */
    if (zone->converg && cgi_write_converg(zone->id, zone->converg))
        return 1;

     /* FlowEquationSet_t */
    if (zone->equations && cgi_write_equations(zone->id, zone->equations))
        return 1;

     /* IntegralData_t */
    for (n=0; n<zone->nintegrals; n++)
        if (cgi_write_integral(zone->id, &zone->integral[n])) return 1;

     /* Ordinal_t */
    if (zone->ordinal && cgi_write_ordinal(zone->id, zone->ordinal)) return 1;

     /* RigidGridMotion_t */
    for (n=0; n<zone->nrmotions; n++)
        if (cgi_write_rmotion(zone->id, &zone->rmotion[n])) return 1;

     /* ArbitraryGridMotion_t */
    for (n=0; n<zone->namotions; n++)
        if (cgi_write_amotion(zone->id, &zone->amotion[n])) return 1;

     /* ZoneIterativeData_t */
    if (zone->ziter && cgi_write_ziter(zone->id, zone->ziter)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<zone->nuser_data; n++)
        if (cgi_write_user_data(zone->id, &zone->user_data[n])) return 1;

     /* RotatingCoordinates_t */
    if (zone->rotating && cgi_write_rotating(zone->id, zone->rotating)) return 1;

    return 0;
}

int cgi_write_family(double parent_id, cgns_family *family)
{
    int n;
    cgsize_t dim_vals;

    if (family->link) {
        return cgi_write_link(parent_id, family->name,
            family->link, &family->id);
    }

     /* Family_t */
    if (cgi_new_node(parent_id, family->name, "Family_t",
        &family->id, "MT", 0, 0, 0)) return 1;

    /* CPEX 0033 */
    for (n = 0; n < family->nfamname; n++) {
        dim_vals = (cgsize_t)strlen(family->famname[n].family);
        if (cgi_new_node(family->id, family->famname[n].name, "FamilyName_t",
            &family->famname[n].id, "C1", 1, &dim_vals,
            (void *)family->famname[n].family)) return 1;
    }

     /* Descriptor_t */
    for (n=0; n<family->ndescr; n++)
        if (cgi_write_descr(family->id, &family->descr[n])) return 1;

     /* FamilyBC_t */
    for (n=0; n<family->nfambc; n++) {
        cgns_fambc *fambc = &family->fambc[n];
        if (fambc->link) {
            if (cgi_write_link(family->id, fambc->name,
                fambc->link, &fambc->id)) return 1;
        }
        else {
            dim_vals = (cgsize_t)strlen(BCTypeName[fambc->type]);
            if (cgi_new_node(family->id, fambc->name, "FamilyBC_t",
                &fambc->id, "C1", 1, &dim_vals, BCTypeName[fambc->type]))
                return 1;
             /* FamilyBCDataSet_t */
            for (n=0; n < fambc->ndataset; n++)
                if (cgi_write_dataset(fambc->id, "FamilyBCDataSet_t",
                    &fambc->dataset[n])) return 1;
        }
    }

     /* GeometryReference_t */
    for (n=0; n<family->ngeos; n++) {
        int i;
        double dummy_id;
        cgns_geo *geo = &family->geo[n];

        if (geo->link) {
            if (cgi_write_link(family->id, geo->name, geo->link, &geo->id))
                return 1;
        }
        else {
            if (cgi_new_node(family->id, geo->name, "GeometryReference_t",
                &geo->id, "MT", 0, 0, 0)) return 1;
         /* Descriptor */
            for (i=0; i<geo->ndescr; i++)
                if (cgi_write_descr(geo->id, &geo->descr[i])) return 1;

         /* GeometryFile */
            dim_vals = (cgsize_t)strlen(geo->file);
            if (cgi_new_node(geo->id, "GeometryFile", "GeometryFile_t",
                &dummy_id, "C1", 1, &dim_vals, geo->file)) return 1;

         /* GeometryFormat */
            dim_vals = (cgsize_t)strlen(geo->format);
            if (cgi_new_node(geo->id, "GeometryFormat", "GeometryFormat_t",
                &dummy_id, "C1", 1, &dim_vals, geo->format)) return 1;

         /* GeometryEntities */
            for (i=0; i<geo->npart; i++) {
                if (cgi_new_node(geo->id, geo->part[i].name, "GeometryEntity_t",
                    &dummy_id, "MT", 0, 0, 0)) return 1;
            }

         /* UserDefinedData_t */
            for (i=0; i<geo->nuser_data; i++) {
                if (cgi_write_user_data(geo->id, &geo->user_data[i])) return 1;
            }
        }
    }

     /* Ordinal_t */
    if (family->ordinal &&
        cgi_write_ordinal(family->id, family->ordinal)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<family->nuser_data; n++)
        if (cgi_write_user_data(family->id, &family->user_data[n])) return 1;

     /* RotatingCoordinates_t */
    if (family->rotating && cgi_write_rotating(family->id, family->rotating))
        return 1;

    return 0;
}

int cgi_write_section(double parent_id, cgns_section *section)
{
    int n, data[2];
    cgsize_t dim_vals;
    double dummy_id;

    if (section->link) {
        return cgi_write_link(parent_id, section->name,
            section->link, &section->id);
    }

     /* Elements_t */
    dim_vals = 2;
    data[0]=section->el_type;
    data[1]=section->el_bound;
    if (cgi_new_node(parent_id, section->name, "Elements_t",
        &section->id, "I4", 1, &dim_vals, data)) return 1;

     /* ElementRange */
    if (cgi_new_node(section->id, "ElementRange", "IndexRange_t", &dummy_id,
        CG_SIZE_DATATYPE, 1, &dim_vals, section->range)) return 1;

     /* ElementConnectivity */
    if (section->connect &&
        cgi_write_array(section->id, section->connect)) return 1;

     /* ParentData */
    if (section->parelem &&
        cgi_write_array(section->id, section->parelem)) return 1;
    if (section->parface &&
        cgi_write_array(section->id, section->parface)) return 1;

     /* Descriptor_t */
    for (n=0; n<section->ndescr; n++)
        if (cgi_write_descr(section->id, &section->descr[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<section->nuser_data; n++)
        if (cgi_write_user_data(section->id, &section->user_data[n])) return 1;

    return 0;
}

int cgi_write_zcoor(double parent_id, cgns_zcoor *zcoor)
{
    int n;

    if (zcoor->link) {
        return cgi_write_link(parent_id, zcoor->name,
            zcoor->link, &zcoor->id);
    }

     /* GridCoordinates_t */
    if (cgi_new_node(parent_id, zcoor->name, "GridCoordinates_t",
        &zcoor->id, "MT", 0, 0, 0)) return 1;

     /* Rind_t */
    if (cgi_write_rind(zcoor->id, zcoor->rind_planes, Idim)) return 1;

     /* Descriptor_t */
    for (n=0; n<zcoor->ndescr; n++)
        if (cgi_write_descr(zcoor->id, &zcoor->descr[n])) return 1;

     /* DataClass_t */
    if (zcoor->data_class &&
        cgi_write_dataclass(zcoor->id, zcoor->data_class)) return 1;

     /* DimensionalUnits_t */
    if (zcoor->units && cgi_write_units(zcoor->id, zcoor->units)) return 1;

     /* DataArray_t */
    for (n=0; n<zcoor->ncoords; n++)
        if (cgi_write_array(zcoor->id, &zcoor->coord[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<zcoor->nuser_data; n++)
        if (cgi_write_user_data(zcoor->id, &zcoor->user_data[n])) return 1;

    return 0;
}

int cgi_write_sol(double parent_id, cgns_sol *sol)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;

    if (sol->link) {
        return cgi_write_link(parent_id, sol->name, sol->link, &sol->id);
    }

     /* FlowSolution_t */
    if (cgi_new_node(parent_id, sol->name, "FlowSolution_t",
        &sol->id, "MT", 0, 0, 0)) return 1;

     /* GridLocation_t */
    if (sol->location!=CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[sol->location]);
        if (cgi_new_node(sol->id, "GridLocation", "GridLocation_t",
            &dummy_id, "C1", 1, &dim_vals,
            (void *)GridLocationName[sol->location])) return 1;
    }

     /* Rind_t */
    if (cgi_write_rind(sol->id, sol->rind_planes, Idim)) return 1;

     /* Descriptor_t */
    for (n=0; n<sol->ndescr; n++)
        if (cgi_write_descr(sol->id, &sol->descr[n])) return 1;

     /* DataClass_t */
    if (sol->data_class &&
        cgi_write_dataclass(sol->id, sol->data_class)) return 1;

     /* DimensionalUnits_t */
    if (sol->units && cgi_write_units(sol->id, sol->units)) return 1;

     /* DataArray_t */
    for (n=0; n<sol->nfields; n++)
        if (cgi_write_array(sol->id, &sol->field[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<sol->nuser_data; n++)
        if (cgi_write_user_data(sol->id, &sol->user_data[n])) return 1;

    return 0;
}

int cgi_write_zconn(double parent_id, cgns_zconn *zconn)
{
    int n;

    if (zconn->link) {
        return cgi_write_link(parent_id, zconn->name,
            zconn->link, &zconn->id);
    }

     /* ZoneGridConnectivity_t */
    if (cgi_new_node(parent_id, zconn->name, "ZoneGridConnectivity_t",
        &zconn->id, "MT", 0, 0, 0)) return 1;

     /* GridConnectivity1to1_t */
    for (n=0; n<zconn->n1to1; n++)
        if (cgi_write_1to1(zconn->id, &zconn->one21[n])) return 1;

     /* GridConnectivity_t */
    for (n=0; n<zconn->nconns; n++)
        if (cgi_write_conns(zconn->id, &zconn->conn[n])) return 1;

     /* OversetHoles_t */
    for (n=0; n<zconn->nholes; n++)
        if (cgi_write_holes(zconn->id, &zconn->hole[n])) return 1;

     /* Descriptor_t */
    for (n=0; n<zconn->ndescr; n++)
        if (cgi_write_descr(zconn->id, &zconn->descr[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<zconn->nuser_data; n++)
        if (cgi_write_user_data(zconn->id, &zconn->user_data[n])) return 1;

    return 0;
}

int cgi_write_1to1(double parent_id, cgns_1to1 *one21)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;
    cgns_ptset *ptset;

    if (one21->link) {
        return cgi_write_link(parent_id, one21->name,
            one21->link, &one21->id);
    }

    dim_vals = (cgsize_t)strlen(one21->donor);
    if (cgi_new_node(parent_id, one21->name, "GridConnectivity1to1_t",
        &one21->id, "C1", 1, &dim_vals, one21->donor)) return 1;

     /* Transform */
    dim_vals = Idim;
    if (cgi_new_node(one21->id, "Transform", "\"int[IndexDimension]\"", &dummy_id,
        "I4", 1, &dim_vals, (void *)one21->transform)) return 1;

     /* PointRange & PointRangeDonor: Move nodes to their final positions */
    ptset = &(one21->ptset);
    if (cgi_move_node(cg->rootid, ptset->id, one21->id,
        PointSetTypeName[ptset->type])) return 1;

    ptset = &(one21->dptset);
    if (cgi_move_node(cg->rootid, ptset->id, one21->id,
        PointSetTypeName[ptset->type])) return 1;

     /* Descriptor_t */
    for (n=0; n<one21->ndescr; n++)
        if (cgi_write_descr(one21->id, &one21->descr[n])) return 1;

     /* Ordinal_t */
    if (one21->ordinal &&
        cgi_write_ordinal(one21->id, one21->ordinal)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<one21->nuser_data; n++)
        if (cgi_write_user_data(one21->id, &one21->user_data[n])) return 1;

    /* GridConnectivityProperty_t */
    if (one21->cprop &&
        cgi_write_cprop(one21->id, one21->cprop)) return 1;

    return 0;
}

int cgi_write_conns(double parent_id, cgns_conn *conn)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;
    cgns_ptset *ptset;

    if (conn->link) {
        return cgi_write_link(parent_id, conn->name,
            conn->link, &conn->id);
    }

    dim_vals = (cgsize_t)strlen(conn->donor);
    if (cgi_new_node(parent_id, conn->name, "GridConnectivity_t",
        &conn->id, "C1", 1, &dim_vals, conn->donor)) return 1;

     /* GridConnectivityType_t */
    dim_vals = (cgsize_t)strlen(GridConnectivityTypeName[conn->type]);
    if (cgi_new_node(conn->id, "GridConnectivityType",
        "GridConnectivityType_t", &dummy_id, "C1", 1, &dim_vals,
        (void *)GridConnectivityTypeName[conn->type])) return 1;

     /* write GridLocation */
    if (conn->location!=CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[conn->location]);
        if (cgi_new_node(conn->id, "GridLocation", "GridLocation_t",
            &dummy_id, "C1", 1, &dim_vals,
            (void *)GridLocationName[conn->location])) return 1;
    }

     /* PointRange or PointList: Move node to its final position */
    ptset = &(conn->ptset);
    if (cgi_move_node(cg->rootid, ptset->id, conn->id,
        PointSetTypeName[ptset->type])) return 1;

     /* Cell or Point ListDonor: Move node to its final position */
    ptset = &(conn->dptset);
    if (ptset->id) {
        if (cgi_move_node(cg->rootid, ptset->id, conn->id,
            PointSetTypeName[ptset->type])) return 1;
    }

     /* InterpolantsDonor */
    if (conn->interpolants) {
        if (cgi_write_array(conn->id, conn->interpolants)) return 1;
    }

     /* Descriptor_t */
    for (n=0; n<conn->ndescr; n++)
        if (cgi_write_descr(conn->id, &conn->descr[n])) return 1;

     /* Ordinal_t */
    if (conn->ordinal &&
        cgi_write_ordinal(conn->id, conn->ordinal)) return 1;

     /* GridConnectivityProperty_t */
    if (conn->cprop &&
        cgi_write_cprop(conn->id, conn->cprop)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<conn->nuser_data; n++)
        if (cgi_write_user_data(conn->id, &conn->user_data[n])) return 1;

    return 0;
}

int cgi_write_cprop(double parent_id, cgns_cprop *cprop)
{
    cgsize_t dim_vals;
    int n;
    double dummy_id;

    if (cprop->link) {
        return cgi_write_link(parent_id, "GridConnectivityProperty",
            cprop->link, &cprop->id);
    }

     /* GridConnectivityProperty_t */
    if (cgi_new_node(parent_id, "GridConnectivityProperty",
        "GridConnectivityProperty_t", &cprop->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<cprop->ndescr; n++)
        if (cgi_write_descr(cprop->id, &cprop->descr[n])) return 1;

     /* AverageInterface_t */
    if (cprop->caverage) {
        cgns_caverage *caverage = cprop->caverage;
        if (caverage->link) {
            if (cgi_write_link(cprop->id, "AverageInterface",
                caverage->link, &caverage->id)) return 1;
        }
        else {
            if (cgi_new_node(cprop->id, "AverageInterface", "AverageInterface_t",
                &caverage->id, "MT", 0, 0, 0)) return 1;

         /* AverageInterface_t/Descriptor_t */
            for (n=0; n<caverage->ndescr; n++)
                if (cgi_write_descr(caverage->id, &caverage->descr[n])) return 1;

         /* AverageInterface_t/AverageInterfaceType_t */
            dim_vals = (cgsize_t)strlen(AverageInterfaceTypeName[caverage->type]);
            if (cgi_new_node(caverage->id, "AverageInterfaceType",
                "AverageInterfaceType_t", &dummy_id, "C1", 1, &dim_vals,
                (void *)AverageInterfaceTypeName[caverage->type])) return 1;

         /* AverageInterface_t/UserDefinedData_t */
            for (n=0; n<caverage->nuser_data; n++)
                if (cgi_write_user_data(caverage->id, &caverage->user_data[n]))
                    return 1;
        }
    }

     /* Periodic_t */
    if (cprop->cperio) {
        cgns_cperio *cperio = cprop->cperio;
        if (cperio->link) {
            if (cgi_write_link(cprop->id, "Periodic",
                cperio->link, &cperio->id)) return 1;
        }
        else {
            if (cgi_new_node(cprop->id, "Periodic", "Periodic_t", &cperio->id,
                "MT", 0, 0, 0)) return 1;

         /* Periodic_t/Descriptor_t */
            for (n=0; n<cperio->ndescr; n++)
                if (cgi_write_descr(cperio->id, &cperio->descr[n])) return 1;

         /* Periodic_t/DataArray_t */
            for (n=0; n<cperio->narrays; n++)
                if (cgi_write_array(cperio->id, &cperio->array[n])) return 1;

         /* Periodic_t/DataClass_t */
            if (cperio->data_class &&
                cgi_write_dataclass(cperio->id, cperio->data_class)) return 1;

         /* Periodic_t/DimensionalUnits_t */
            if (cperio->units &&
                cgi_write_units(cperio->id, cperio->units)) return 1;

         /* Periodic_t/UserDefinedData_t */
            for (n=0; n<cperio->nuser_data; n++)
                if (cgi_write_user_data(cperio->id, &cperio->user_data[n])) return 1;
        }
    }

     /* UserDefinedData_t */
    for (n=0; n<cprop->nuser_data; n++)
        if (cgi_write_user_data(cprop->id, &cprop->user_data[n])) return 1;

    return 0;
}

int cgi_write_holes(double parent_id, cgns_hole *hole)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;
    char PointSetName[33];
    cgns_ptset *ptset;

    if (hole->link) {
        return cgi_write_link(parent_id, hole->name,
            hole->link, &hole->id);
    }

     /* OversetHoles_t */
    if (cgi_new_node(parent_id, hole->name, "OversetHoles_t",
        &hole->id, "MT", 0, 0, 0)) return 1;

     /* GridLocation_t */
    if (hole->location!=CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[hole->location]);
        if (cgi_new_node(hole->id, "GridLocation", "GridLocation_t",
            &dummy_id, "C1", 1, &dim_vals,
            (void *)GridLocationName[hole->location])) return 1;
    }

     /* PointRange(s) and PointList */
    for (n=0; n<hole->nptsets; n++) {
        ptset = &(hole->ptset[n]);

        if (ptset->type == CGNS_ENUMV( PointRange )) sprintf(PointSetName,"PointRange%d",n+1);
        else sprintf(PointSetName,"PointSetTypeName[ptset->type]");

     /* Move node to its final position */
        if (cgi_move_node(cg->rootid, ptset->id, hole->id,
            PointSetName)) return 1;
    }
     /* Descriptor_t */
    for (n=0; n<hole->ndescr; n++)
        if (cgi_write_descr(hole->id, &hole->descr[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<hole->nuser_data; n++)
        if (cgi_write_user_data(hole->id, &hole->user_data[n])) return 1;

    return 0;
}

int cgi_write_zboco(double parent_id, cgns_zboco *zboco)
{
    int n;

    if (zboco->link) {
        return cgi_write_link(parent_id, "ZoneBC",
            zboco->link, &zboco->id);
    }

     /* ZoneBC_t */
    if (cgi_new_node(parent_id, "ZoneBC", "ZoneBC_t", &zboco->id,
        "MT", 0, 0, 0)) return 1;

     /* BC_t */
    for (n=0; n<zboco->nbocos; n++)
        if (cgi_write_boco(zboco->id, &zboco->boco[n])) return 1;

     /* Descriptor_t */
    for (n=0; n<zboco->ndescr; n++)
        if (cgi_write_descr(zboco->id, &zboco->descr[n])) return 1;

     /* ReferenceState_t */
    if (zboco->state && cgi_write_state(zboco->id, zboco->state))
        return 1;

     /* DataClass_t */
    if (zboco->data_class &&
        cgi_write_dataclass(zboco->id, zboco->data_class)) return 1;

     /* DimensionalUnits_t */
    if (zboco->units && cgi_write_units(zboco->id, zboco->units))
        return 1;

     /* UserDefinedData_t */
    for (n=0; n<zboco->nuser_data; n++)
        if (cgi_write_user_data(zboco->id, &zboco->user_data[n])) return 1;

    return 0;
}

int cgi_write_boco(double parent_id, cgns_boco *boco)
{
    cgsize_t dim_vals;
    int n;
    double dummy_id;

    if (boco->link) {
        return cgi_write_link(parent_id, boco->name,
            boco->link, &boco->id);
    }

     /* BC_t */
    dim_vals = (cgsize_t)strlen(BCTypeName[boco->type]);
    if (cgi_new_node(parent_id, boco->name, "BC_t", &boco->id, "C1",
        1, &dim_vals, BCTypeName[boco->type])) return 1;

     /* PointRange, PointList:  Move node to its final position */
    if (boco->ptset) {
     /* Move node to its final position */
        if (cgi_move_node(cg->rootid, boco->ptset->id, boco->id,
            PointSetTypeName[boco->ptset->type])) return 1;
    }

     /* GridLocation_t */
    if (boco->location != CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[boco->location]);
        if (cgi_new_node(boco->id, "GridLocation", "GridLocation_t", &dummy_id,
            "C1", 1, &dim_vals, (void *)GridLocationName[boco->location])) return 1;
    }

     /* FamilyName_t */
    if (boco->family_name[0]!='\0') {
        dim_vals = (cgsize_t)strlen(boco->family_name);
        if (cgi_new_node(boco->id, "FamilyName", "FamilyName_t", &dummy_id, "C1",
            1, &dim_vals, (void *)boco->family_name)) return 1;
    }

    /* CPEX 0034 */
    for (n = 0; n < boco->nfamname; n++) {
        dim_vals = (cgsize_t)strlen(boco->famname[n].family);
        if (cgi_new_node(boco->id, boco->famname[n].name, "AdditionalFamilyName_t",
            &dummy_id, "C1", 1, &dim_vals, (void *)boco->famname[n].family)) return 1;
    }

     /* BCDataSet_t */
    for (n=0; n<boco->ndataset; n++)
        if (cgi_write_dataset(boco->id, "BCDataSet_t", &boco->dataset[n])) return 1;

     /* InwardNormalIndex */
    if (boco->Nindex) {
        dim_vals = Idim;
        if (cgi_new_node(boco->id, "InwardNormalIndex",
            "\"int[IndexDimension]\"", &boco->index_id, "I4", 1,
            &dim_vals, (void *)boco->Nindex)) return 1;
    }

     /* InwardNormalList */
    if (boco->normal) {
        if (boco->normal->link) {
            if (cgi_write_link(boco->id, boco->normal->name,
                boco->normal->link, &boco->normal->id)) return 1;
        }
        else {
            if (cgi_new_node(boco->id, boco->normal->name, "IndexArray_t", &boco->normal->id,
                boco->normal->data_type, boco->normal->data_dim, boco->normal->dim_vals,
                boco->normal->data)) return 1;
        }
    }

     /* Descriptor_t */
    for (n=0; n<boco->ndescr; n++)
        if (cgi_write_descr(boco->id, &boco->descr[n])) return 1;

     /* ReferenceState_t */
    if (boco->state &&
        cgi_write_state(boco->id, boco->state)) return 1;

     /* DataClass_t */
    if (boco->data_class &&
        cgi_write_dataclass(boco->id, boco->data_class)) return 1;

     /* DimensionalUnits_t */
    if (boco->units && cgi_write_units(boco->id, boco->units))
        return 1;

     /* Ordinal_t */
    if (boco->ordinal &&
        cgi_write_ordinal(boco->id, boco->ordinal)) return 1;

     /* BCProperty_t */
    if (boco->bprop &&
        cgi_write_bprop(boco->id, boco->bprop)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<boco->nuser_data; n++)
        if (cgi_write_user_data(boco->id, &boco->user_data[n])) return 1;

    return 0;
}

int cgi_write_bprop(double parent_id, cgns_bprop *bprop)
{
    cgsize_t dim_vals;
    int n;
    double dummy_id;

    if (bprop->link) {
        return cgi_write_link(parent_id, "BCProperty",
            bprop->link, &bprop->id);
    }

     /* BCProperty_t */
    if (cgi_new_node(parent_id, "BCProperty", "BCProperty_t", &bprop->id,
        "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<bprop->ndescr; n++)
        if (cgi_write_descr(bprop->id, &bprop->descr[n])) return 1;

     /* WallFunction_t */
    if (bprop->bcwall) {
        cgns_bcwall *bcwall = bprop->bcwall;
        if (bcwall->link) {
            if (cgi_write_link(bprop->id, "WallFunction",
                bcwall->link, &bcwall->id)) return 1;
        }
        else {
            if (cgi_new_node(bprop->id, "WallFunction", "WallFunction_t",
                &bcwall->id, "MT", 0, 0, 0)) return 1;

         /* WallFunction_t/Descriptor_t */
            for (n=0; n<bcwall->ndescr; n++)
                if (cgi_write_descr(bcwall->id, &bcwall->descr[n])) return 1;

         /* WallFunction_t/WallFunctionType_t */
            dim_vals = (cgsize_t)strlen(WallFunctionTypeName[bcwall->type]);
            if (cgi_new_node(bcwall->id, "WallFunctionType", "WallFunctionType_t",
                &dummy_id, "C1", 1, &dim_vals, (void *)WallFunctionTypeName[bcwall->type])) return 1;
         /* WallFunction_t/UserDefinedData_t */
            for (n=0; n<bcwall->nuser_data; n++)
                if (cgi_write_user_data(bcwall->id, &bcwall->user_data[n])) return 1;
        }
    }

     /* Area_t */
    if (bprop->bcarea) {
        cgns_bcarea *bcarea = bprop->bcarea;
        if (bcarea->link) {
            if (cgi_write_link(bprop->id, "Area",
                bcarea->link, &bcarea->id)) return 1;
        }
        else {
            if (cgi_new_node(bprop->id, "Area", "Area_t", &bcarea->id,
                "MT", 0, 0, 0)) return 1;

         /* Area_t/Descriptor_t */
            for (n=0; n<bcarea->ndescr; n++)
                if (cgi_write_descr(bcarea->id, &bcarea->descr[n])) return 1;

         /* Area_t/AreaType_t */
            dim_vals = (cgsize_t)strlen(AreaTypeName[bcarea->type]);
            if (cgi_new_node(bcarea->id, "AreaType", "AreaType_t", &dummy_id,
                "C1", 1, &dim_vals, (void *)AreaTypeName[bcarea->type])) return 1;

         /* Area_t/DataArray_t */
            for (n=0; n<bcarea->narrays; n++)
                if (cgi_write_array(bcarea->id, &bcarea->array[n])) return 1;

         /* Area_t/UserDefinedData_t */
            for (n=0; n<bcarea->nuser_data; n++)
                if (cgi_write_user_data(bcarea->id, &bcarea->user_data[n])) return 1;
        }
    }

     /* UserDefinedData_t */
    for (n=0; n<bprop->nuser_data; n++)
        if (cgi_write_user_data(bprop->id, &bprop->user_data[n])) return 1;

    return 0;
}

int cgi_write_dataset(double parent_id, const char *label, cgns_dataset *dataset)
{
    cgsize_t dim_vals;
    int n;
    double dummy_id;

    if (dataset->link) {
        return cgi_write_link(parent_id, dataset->name,
            dataset->link, &dataset->id);
    }

     /* BCDataSet_t */
    dim_vals= (cgsize_t)strlen(BCTypeName[dataset->type]);
    if (cgi_new_node(parent_id, dataset->name, label, &dataset->id,
        "C1", 1, &dim_vals, (void *)BCTypeName[dataset->type])) return 1;

     /* DirichletData */
    if (dataset->dirichlet) {
        if (dataset->dirichlet->link) {
            if (cgi_write_link(dataset->id, "DirichletData",
                dataset->dirichlet->link, &dataset->dirichlet->id))
                return 1;
        }
        else {
            if (cgi_new_node(dataset->id, "DirichletData", "BCData_t",
                &dataset->dirichlet->id, "MT", 0, 0, 0)) return 1;
            if (cgi_write_bcdata(dataset->dirichlet->id, dataset->dirichlet))
                return 1;
        }
    }

     /* NeumannData */
    if (dataset->neumann) {
        if (dataset->neumann->link) {
            if (cgi_write_link(dataset->id, "NeumannData",
                dataset->neumann->link, &dataset->neumann->id))
                return 1;
        }
        else {
            if (cgi_new_node(dataset->id, "NeumannData", "BCData_t",
                &dataset->neumann->id, "MT", 0, 0, 0)) return 1;
            if (cgi_write_bcdata(dataset->neumann->id, dataset->neumann))
                return 1;
        }
    }

     /* Descriptor_t */
    for (n=0; n<dataset->ndescr; n++)
        if (cgi_write_descr(dataset->id, &dataset->descr[n])) return 1;

     /* ReferenceState_t */
    if (dataset->state &&
        cgi_write_state(dataset->id, dataset->state)) return 1;

     /* DataClass_t */
    if (dataset->data_class &&
        cgi_write_dataclass(dataset->id, dataset->data_class)) return 1;

     /* DimensionalUnits_t */
    if (dataset->units &&
        cgi_write_units(dataset->id, dataset->units)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<dataset->nuser_data; n++)
        if (cgi_write_user_data(dataset->id, &dataset->user_data[n])) return 1;

    /* GridLocation_t */
    if (dataset->location != CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[dataset->location]);
        if (cgi_new_node(dataset->id, "GridLocation", "GridLocation_t",
                         &dummy_id, "C1", 1, &dim_vals,
                         (void *)GridLocationName[dataset->location]))
            return 1;
    }

    /* PointRange, PointList:  Move node to its final position */
    if (dataset->ptset) {
     /* Move node to its final position */
        if (cgi_move_node(cg->rootid, dataset->ptset->id, dataset->id,
            PointSetTypeName[dataset->ptset->type])) return 1;
    }

    return 0;
}

int cgi_write_bcdata(double bcdata_id, cgns_bcdata *bcdata)
{
    int n;

     /* DataArray_t */
    for (n=0; n<bcdata->narrays; n++)
        if (cgi_write_array(bcdata_id, &bcdata->array[n])) return 1;

     /* Descriptor_t */
    for (n=0; n<bcdata->ndescr; n++)
        if (cgi_write_descr(bcdata_id, &bcdata->descr[n])) return 1;

     /* DataClass_t */
    if (bcdata->data_class &&
        cgi_write_dataclass(bcdata->id, bcdata->data_class)) return 1;

     /* DimensionalUnits_t */
    if (bcdata->units &&
        cgi_write_units(bcdata->id, bcdata->units)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<bcdata->nuser_data; n++)
        if (cgi_write_user_data(bcdata->id, &bcdata->user_data[n])) return 1;

    return 0;
}

int cgi_write_ptset(double parent_id, char_33 name, cgns_ptset *ptset,
                    int Idim, void *ptset_ptr)
{
    cgsize_t dim_vals[12];
    int ndim;
    char_33 label;

    if (ptset->link) {
        return cgi_write_link(parent_id, name, ptset->link, &ptset->id);
    }

     /* Set label */
    if (ptset->type == CGNS_ENUMV(PointRange) ||
        ptset->type == CGNS_ENUMV(ElementRange) ||
        ptset->type == CGNS_ENUMV(PointRangeDonor))
         strcpy(label,"IndexRange_t");
    else strcpy(label,"IndexArray_t");

     /* Dimension vector */
    dim_vals[0]=Idim;
    dim_vals[1]=ptset->npts;
    ndim = 2;

     /* Create the node */
    if (cgi_new_node(parent_id, name, label, &ptset->id,
        ptset->data_type, ndim, dim_vals, ptset_ptr)) return 1;

    return 0;
}

int cgi_write_equations(double parent_id, cgns_equations *equations)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;
    cgns_governing *governing;

    if (equations->link) {
        return cgi_write_link(parent_id, "FlowEquationSet",
            equations->link, &equations->id);
    }

     /* FlowEquationSet_t */
    if (cgi_new_node(parent_id, "FlowEquationSet", "FlowEquationSet_t",
        &equations->id, "MT", 0, 0, 0)) return 1;

     /* EquationDimension */
    if (equations->equation_dim) {
        dim_vals=1;
        if (cgi_new_node(equations->id, "EquationDimension", "\"int\"",
            &dummy_id, "I4", 1, &dim_vals, (void *)&equations->equation_dim))
            return 1;
    }

     /* GoverningEquations_t */
    if (equations->governing) {
        governing = equations->governing;
        if (governing->link) {
            if (cgi_write_link(equations->id, "GoverningEquations",
                governing->link, &governing->id)) return 1;
        }
        else {
            dim_vals = (cgsize_t)strlen(GoverningEquationsTypeName[governing->type]);
            if (cgi_new_node(equations->id, "GoverningEquations",
                "GoverningEquations_t", &governing->id, "C1", 1, &dim_vals,
                GoverningEquationsTypeName[governing->type])) return 1;

         /* Descriptor_t */
            for (n=0; n<governing->ndescr; n++)
                if (cgi_write_descr(governing->id, &governing->descr[n])) return 1;

         /* DiffusionModel */
            if (governing->diffusion_model) {
                dim_vals=governing->dim_vals;
                if (cgi_new_node(governing->id, "DiffusionModel",
                    "\"int[1+...+IndexDimension]\"", &dummy_id, "I4", 1,
                    &dim_vals, (void *)governing->diffusion_model)) return 1;
            }

         /* UserDefinedData_t */
            for (n=0; n<governing->nuser_data; n++)
                if (cgi_write_user_data(governing->id, &governing->user_data[n])) return 1;
        }
    }

     /* GasModel_t */
    if (equations->gas &&
        cgi_write_model(equations->id, equations->gas)) return 1;

     /* ViscosityModel_t */
    if (equations->visc &&
        cgi_write_model(equations->id, equations->visc)) return 1;

     /* ThermalConductivityModel_t */
    if (equations->conduct &&
        cgi_write_model(equations->id, equations->conduct)) return 1;

     /* TurbulenceClosure_t */
    if (equations->closure &&
        cgi_write_model(equations->id, equations->closure)) return 1;

     /* TurbulenceModel_t */
    if (equations->turbulence) {
        if (cgi_write_model(equations->id, equations->turbulence)) return 1;

     /* DiffusionModel */
        if (equations->turbulence->diffusion_model) {
            dim_vals=equations->turbulence->dim_vals;
            if (cgi_new_node(equations->turbulence->id, "DiffusionModel",
                "\"int[1+...+IndexDimension]\"", &dummy_id, "I4", 1, &dim_vals,
                (void *) equations->turbulence->diffusion_model)) return 1;
        }
    }

      /* ThermalRelaxationModel_t */
    if (equations->relaxation &&
        cgi_write_model(equations->id, equations->relaxation)) return 1;

      /* ChemicalKineticsModel_t */
    if (equations->chemkin &&
        cgi_write_model(equations->id, equations->chemkin)) return 1;

     /* Descriptor_t */
    for (n=0; n<equations->ndescr; n++)
        if (cgi_write_descr(equations->id, &equations->descr[n])) return 1;

     /* DataClass_t */
    if (equations->data_class &&
        cgi_write_dataclass(equations->id, equations->data_class)) return 1;

     /* DimensionalUnits_t */
    if (equations->units &&
        cgi_write_units(equations->id, equations->units)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<equations->nuser_data; n++)
        if (cgi_write_user_data(equations->id, &equations->user_data[n])) return 1;

      /* EMElectricFieldModel_t */
    if (equations->elecfield &&
        cgi_write_model(equations->id, equations->elecfield)) return 1;

      /* EMMagneticFieldModel_t */
    if (equations->magnfield &&
        cgi_write_model(equations->id, equations->magnfield)) return 1;

      /* EMConductivityModel_t */
    if (equations->emconduct &&
        cgi_write_model(equations->id, equations->emconduct)) return 1;

    return 0;
}

int cgi_write_model(double parent_id, cgns_model *model)
{
    int n;
    cgsize_t dim_vals;
    char_33 label;

    if (model->link) {
        return cgi_write_link(parent_id, model->name,
            model->link, &model->id);
    }

     /* xModel_t */
    sprintf(label,"%s_t",model->name);
    dim_vals = (cgsize_t)strlen(ModelTypeName[model->type]);

    if (cgi_new_node(parent_id, model->name, label, &model->id,
        "C1", 1, &dim_vals, ModelTypeName[model->type])) return 1;

     /* Descriptor_t */
    for (n=0; n<model->ndescr; n++)
        if (cgi_write_descr(model->id, &model->descr[n])) return 1;

     /* DataClass_t */
    if (model->data_class &&
        cgi_write_dataclass(model->id, model->data_class)) return 1;

     /* DimensionalUnits_t */
    if (model->units &&
        cgi_write_units(model->id, model->units)) return 1;

     /* DataArray */
    for (n=0; n<model->narrays; n++)
        if (cgi_write_array(model->id, &model->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<model->nuser_data; n++)
        if (cgi_write_user_data(model->id, &model->user_data[n])) return 1;

    return 0;
}

int cgi_write_state(double parent_id, cgns_state *state)
{
    int n;

    if (state->link) {
        return cgi_write_link(parent_id, "ReferenceState",
            state->link, &state->id);
    }

     /* ReferenceState_t */
    if (cgi_new_node(parent_id, "ReferenceState", "ReferenceState_t",
        &state->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<state->ndescr; n++)
        if (cgi_write_descr(state->id, &state->descr[n])) return 1;

     /* ReferenceStateDescription */
    if (state->StateDescription &&
        cgi_write_descr(state->id, state->StateDescription)) return 1;

     /* DataClass_t */
    if (state->data_class &&
        cgi_write_dataclass(state->id, state->data_class)) return 1;

     /* DimensionalUnits_t */
    if (state->units &&
        cgi_write_units(state->id, state->units)) return 1;

     /* DataArray */
    for (n=0; n<state->narrays; n++)
        if (cgi_write_array(state->id, &state->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<state->nuser_data; n++)
        if (cgi_write_user_data(state->id, &state->user_data[n])) return 1;

    return 0;
}

int cgi_write_gravity(double parent_id, cgns_gravity *gravity)
{
    int n;

    if (gravity->link) {
        return cgi_write_link(parent_id, "Gravity",
            gravity->link, &gravity->id);
    }

     /* Gravity_t */
    if (cgi_new_node(parent_id, "Gravity", "Gravity_t",
        &gravity->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<gravity->ndescr; n++)
        if (cgi_write_descr(gravity->id, &gravity->descr[n])) return 1;

     /* DataClass_t */
    if (gravity->data_class &&
        cgi_write_dataclass(gravity->id, gravity->data_class)) return 1;

     /* DimensionalUnits_t */
    if (gravity->units &&
        cgi_write_units(gravity->id, gravity->units)) return 1;

     /* DataArray */
    if (gravity->vector && cgi_write_array(gravity->id, gravity->vector)) return 1;

     /* UserDefinedData_t */
    for (n=0; n<gravity->nuser_data; n++)
        if (cgi_write_user_data(gravity->id, &gravity->user_data[n])) return 1;

    return 0;
}

int cgi_write_axisym(double parent_id, cgns_axisym *axisym)
{
    int n;

    if (axisym->link) {
        return cgi_write_link(parent_id, "Axisymmetry",
            axisym->link, &axisym->id);
    }

     /* Axisymmetry_t */
    if (cgi_new_node(parent_id, "Axisymmetry", "Axisymmetry_t",
        &axisym->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<axisym->ndescr; n++)
        if (cgi_write_descr(axisym->id, &axisym->descr[n])) return 1;

     /* DataClass_t */
    if (axisym->data_class &&
        cgi_write_dataclass(axisym->id, axisym->data_class)) return 1;

     /* DimensionalUnits_t */
    if (axisym->units &&
        cgi_write_units(axisym->id, axisym->units)) return 1;

     /* DataArray */
    for (n=0; n<axisym->narrays; n++)
        if (cgi_write_array(axisym->id, &axisym->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<axisym->nuser_data; n++)
        if (cgi_write_user_data(axisym->id, &axisym->user_data[n])) return 1;

    return 0;
}

int cgi_write_rotating(double parent_id, cgns_rotating *rotating)
{
    int n;

    if (rotating->link) {
        return cgi_write_link(parent_id, "RotatingCoordinates",
            rotating->link, &rotating->id);
    }

     /* RotatingCoordinates_t */
    if (cgi_new_node(parent_id, "RotatingCoordinates", "RotatingCoordinates_t",
        &rotating->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<rotating->ndescr; n++)
        if (cgi_write_descr(rotating->id, &rotating->descr[n])) return 1;

     /* DataClass_t */
    if (rotating->data_class &&
        cgi_write_dataclass(rotating->id, rotating->data_class)) return 1;

     /* DimensionalUnits_t */
    if (rotating->units &&
        cgi_write_units(rotating->id, rotating->units)) return 1;

     /* DataArray */
    for (n=0; n<rotating->narrays; n++)
        if (cgi_write_array(rotating->id, &rotating->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<rotating->nuser_data; n++)
        if (cgi_write_user_data(rotating->id, &rotating->user_data[n])) return 1;

    return 0;
}

int cgi_write_converg(double parent_id, cgns_converg *converg)
{
    int n;
    cgsize_t dim_vals;

    if (converg->link) {
        return cgi_write_link(parent_id, converg->name,
            converg->link, &converg->id);
    }

     /* ConvergenceHistory_t */
    dim_vals = 1;
    if (cgi_new_node(parent_id, converg->name, "ConvergenceHistory_t",
        &converg->id, "I4", 1, &dim_vals, (void *)&converg->iterations)) return 1;

     /* Descriptor_t */
    for (n=0; n<converg->ndescr; n++)
        if (cgi_write_descr(converg->id, &converg->descr[n])) return 1;

     /* NormDefinitions */
    if (converg->NormDefinitions &&
        cgi_write_descr(converg->id, converg->NormDefinitions)) return 1;

     /* DataClass_t */
    if (converg->data_class &&
        cgi_write_dataclass(converg->id, converg->data_class)) return 1;

     /* DimensionalUnits_t */
    if (converg->units &&
        cgi_write_units(converg->id, converg->units)) return 1;

     /* DataArray */
    for (n=0; n<converg->narrays; n++)
        if (cgi_write_array(converg->id, &converg->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<converg->nuser_data; n++)
        if (cgi_write_user_data(converg->id, &converg->user_data[n])) return 1;

    return 0;
}

int cgi_write_discrete(double parent_id, cgns_discrete *discrete)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;

    if (discrete->link) {
        return cgi_write_link(parent_id, discrete->name,
            discrete->link, &discrete->id);
    }

     /* DiscreteData_t */
    if (cgi_new_node(parent_id, discrete->name, "DiscreteData_t",
        &discrete->id, "MT", 0, 0, 0)) return 1;

     /* GridLocation_t */
    if (discrete->location != CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[discrete->location]);
        if (cgi_new_node(discrete->id, "GridLocation", "GridLocation_t", &dummy_id,
            "C1", 1, &dim_vals, (void *)GridLocationName[discrete->location])) return 1;
    }

     /* Rind_t */
    if (cgi_write_rind(discrete->id, discrete->rind_planes, Idim)) return 1;

     /* Descriptor_t */
    for (n=0; n<discrete->ndescr; n++)
        if (cgi_write_descr(discrete->id, &discrete->descr[n])) return 1;

     /* DataClass_t */
    if (discrete->data_class &&
        cgi_write_dataclass(discrete->id, discrete->data_class)) return 1;

     /* DimensionalUnits_t */
    if (discrete->units &&
        cgi_write_units(discrete->id, discrete->units)) return 1;

     /* DataArray_t */
    for (n=0; n<discrete->narrays; n++)
        if (cgi_write_array(discrete->id, &discrete->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<discrete->nuser_data; n++)
        if (cgi_write_user_data(discrete->id, &discrete->user_data[n])) return 1;

    return 0;
}

int cgi_write_integral(double parent_id, cgns_integral *integral)
{
    int n;

    if (integral->link) {
        return cgi_write_link(parent_id, integral->name,
            integral->link, &integral->id);
    }

     /* IntegralData_t */
    if (cgi_new_node(parent_id, integral->name, "IntegralData_t",
        &integral->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<integral->ndescr; n++)
        if (cgi_write_descr(integral->id, &integral->descr[n])) return 1;

     /* DataClass_t */
    if (integral->data_class &&
        cgi_write_dataclass(integral->id, integral->data_class)) return 1;

     /* DimensionalUnits_t */
    if (integral->units &&
        cgi_write_units(integral->id, integral->units)) return 1;

     /* DataArray_t */
    for (n=0; n<integral->narrays; n++)
        if (cgi_write_array(integral->id, &integral->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<integral->nuser_data; n++)
        if (cgi_write_user_data(integral->id, &integral->user_data[n])) return 1;

    return 0;
}

int cgi_write_rmotion(double parent_id, cgns_rmotion *rmotion)
{
    int n;
    cgsize_t dim_vals;

    if (rmotion->link) {
        return cgi_write_link(parent_id, rmotion->name,
            rmotion->link, &rmotion->id);
    }

     /* RigidGridMotion_t Name and RigidGridMotionType_t */
    dim_vals=(cgsize_t)strlen(RigidGridMotionTypeName[rmotion->type]);
    if (cgi_new_node(parent_id, rmotion->name, "RigidGridMotion_t", &rmotion->id,
        "C1", 1, &dim_vals, (void *)RigidGridMotionTypeName[rmotion->type])) return 1;

     /* Descriptor_t */

    for (n=0; n<rmotion->ndescr; n++)
        if (cgi_write_descr(rmotion->id, &rmotion->descr[n])) return 1;

     /* DataClass_t */
    if (rmotion->data_class &&
        cgi_write_dataclass(rmotion->id, rmotion->data_class)) return 1;

     /* DimensionalUnits_t */
    if (rmotion->units &&
        cgi_write_units(rmotion->id, rmotion->units)) return 1;

     /* DataArray_t */
    for (n=0; n<rmotion->narrays; n++)
        if (cgi_write_array(rmotion->id, &rmotion->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<rmotion->nuser_data; n++)
        if (cgi_write_user_data(rmotion->id, &rmotion->user_data[n])) return 1;

    return 0;
}

int cgi_write_amotion(double parent_id, cgns_amotion *amotion)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;

    if (amotion->link) {
        return cgi_write_link(parent_id, amotion->name,
            amotion->link, &amotion->id);
    }

     /* ArbitraryGridMotion_t Name and ArbitraryGridMotionType_t */
    dim_vals=(cgsize_t)strlen(ArbitraryGridMotionTypeName[amotion->type]);
    if (cgi_new_node(parent_id, amotion->name, "ArbitraryGridMotion_t", &amotion->id,
        "C1", 1, &dim_vals, (void *)ArbitraryGridMotionTypeName[amotion->type])) return 1;

     /* Descriptor_t */
    for (n=0; n<amotion->ndescr; n++)
        if (cgi_write_descr(amotion->id, &amotion->descr[n])) return 1;

     /* GridLocation_t */
    if (amotion->location != CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[amotion->location]);
        if (cgi_new_node(amotion->id, "GridLocation", "GridLocation_t", &dummy_id,
            "C1", 1, &dim_vals, (void *)GridLocationName[amotion->location])) return 1;
    }

     /* Rind_t */
    if (cgi_write_rind(amotion->id, amotion->rind_planes, Idim)) return 1;

     /* DataClass_t */
    if (amotion->data_class &&
        cgi_write_dataclass(amotion->id, amotion->data_class)) return 1;

     /* DimensionalUnits_t */
    if (amotion->units &&
        cgi_write_units(amotion->id, amotion->units)) return 1;

     /* DataArray_t */
    for (n=0; n<amotion->narrays; n++)
        if (cgi_write_array(amotion->id, &amotion->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<amotion->nuser_data; n++)
        if (cgi_write_user_data(amotion->id, &amotion->user_data[n])) return 1;

    return 0;
}

int cgi_write_biter(double parent_id, cgns_biter *biter)
{
    int n;
    cgsize_t dim_vals;

    if (biter->link) {
        return cgi_write_link(parent_id, biter->name,
            biter->link, &biter->id);
    }

     /* BaseIterativeData_t name and NumberOfSteps */
    dim_vals=1;
    if (cgi_new_node(parent_id, biter->name, "BaseIterativeData_t",
        &biter->id, "I4", 1,  &dim_vals, (void *)&biter->nsteps)) return 1;

     /* Descriptor_t */
    for (n=0; n<biter->ndescr; n++)
        if (cgi_write_descr(biter->id, &biter->descr[n])) return 1;

     /* DataClass_t */
    if (biter->data_class &&
        cgi_write_dataclass(biter->id, biter->data_class)) return 1;

     /* DimensionalUnits_t */
    if (biter->units &&
        cgi_write_units(biter->id, biter->units)) return 1;

     /* DataArray_t */
    for (n=0; n<biter->narrays; n++)
        if (cgi_write_array(biter->id, &biter->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<biter->nuser_data; n++)
        if (cgi_write_user_data(biter->id, &biter->user_data[n])) return 1;

    return 0;
}

int cgi_write_ziter(double parent_id, cgns_ziter *ziter)
{
    int n;

    if (ziter->link) {
        return cgi_write_link(parent_id, ziter->name,
            ziter->link, &ziter->id);
    }

     /* ZoneIterativeData_t name */
    if (cgi_new_node(parent_id, ziter->name, "ZoneIterativeData_t",
        &ziter->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<ziter->ndescr; n++)
        if (cgi_write_descr(ziter->id, &ziter->descr[n])) return 1;

     /* DataClass_t */
    if (ziter->data_class &&
        cgi_write_dataclass(ziter->id, ziter->data_class)) return 1;

     /* DimensionalUnits_t */
    if (ziter->units &&
        cgi_write_units(ziter->id, ziter->units)) return 1;

     /* DataArray_t */
    for (n=0; n<ziter->narrays; n++)
        if (cgi_write_array(ziter->id, &ziter->array[n])) return 1;

     /* UserDefinedData_t */
    for (n=0; n<ziter->nuser_data; n++)
        if (cgi_write_user_data(ziter->id, &ziter->user_data[n])) return 1;

    return 0;
}

int cgi_write_array(double parent_id, cgns_array *array)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;

    if (array->link) {
        return cgi_write_link(parent_id, array->name,
            array->link, &array->id);
    }

    if (cgi_new_node(parent_id, array->name, "DataArray_t", &array->id,
        array->data_type, array->data_dim, array->dim_vals, array->data))
        return 1;

     /* DimensionalExponents_t */
    if (array->exponents &&
        cgi_write_exponents(array->id, array->exponents)) return 1;

     /* DataConversion_t */
    if (array->convert) {
        dim_vals=2;
        if (cgi_new_node(array->id, "DataConversion", "DataConversion_t",
            &array->convert->id, array->convert->data_type, 1, &dim_vals,
            array->convert->data)) return 1;
    }

     /* DataClass_t */
    if (array->data_class &&
        cgi_write_dataclass(array->id, array->data_class)) return 1;

     /* Descriptor_t */
    for (n=0; n<array->ndescr; n++)
        if (cgi_write_descr(array->id, &array->descr[n])) return 1;

     /* DimensionalUnits_t */
    if (array->units &&
        cgi_write_units(array->id, array->units)) return 1;

    /* ElementRange */
    dim_vals = 2;
    if(array->range[0] != 0 && array->range[1] != 0)
        if (cgi_new_node(array->id, "ArrayDataRange", "IndexRange_t",
                         &dummy_id, "I4", 1, &dim_vals, array->range))
            return 1;

    return 0;
}

int cgi_write_rind(double parent_id, int *rind_planes, int index_dim)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;

     /* write Rind only if different from the default (6*0) */
    if (rind_planes==0) return 0;
    for (n=0; n<2*index_dim; n++) {
        if (rind_planes[n]!=0) {
            dim_vals=2*index_dim;
            if (cgi_new_node(parent_id, "Rind", "Rind_t", &dummy_id,
                "I4", 1, &dim_vals, (void *)rind_planes)) return 1;
            return 0;
        }
    }
    return 0;
}

int cgi_write_units(double parent_id, cgns_units *units)
{
    char *string_data;
    cgsize_t dim_vals[2];

    if (units->link) {
        return cgi_write_link(parent_id, "DimensionalUnits",
            units->link, &units->id);
    }

    string_data = (char *) malloc ((32*5+1)*sizeof(char));
    if (string_data == NULL) {
        cgi_error("Error allocating memory in cgi_write_units.");
        return 1;
    }
    sprintf(string_data,"%-32s%-32s%-32s%-32s%-32s",MassUnitsName[units->mass],
        LengthUnitsName[units->length], TimeUnitsName[units->time],
        TemperatureUnitsName[units->temperature], AngleUnitsName[units->angle]);

    dim_vals[0]=32;
    dim_vals[1]=5;

    if (cgi_new_node(parent_id, "DimensionalUnits", "DimensionalUnits_t",
        &units->id, "C1", 2, dim_vals, (void *)string_data)) return 1;

    if (units->nunits == 8) {
        double dummy_id;
        sprintf(string_data, "%-32s%-32s%-32s",
            ElectricCurrentUnitsName[units->current],
            SubstanceAmountUnitsName[units->amount],
            LuminousIntensityUnitsName[units->intensity]);
        dim_vals[1]=3;
        if (cgi_new_node(units->id, "AdditionalUnits", "AdditionalUnits_t",
            &dummy_id, "C1", 2, dim_vals, (void *)string_data)) return 1;
    }

    free(string_data);

    return 0;
}

int cgi_write_exponents(double parent_id, cgns_exponent *exponent)
{
    cgsize_t dim_vals = 5;

    if (cgi_new_node(parent_id, "DimensionalExponents",
        "DimensionalExponents_t", &exponent->id,
        exponent->data_type, 1, &dim_vals, exponent->data)) return 1;
    if (exponent->nexps == 8) {
        double dummy_id;
        void *data;
        if (0 == strcmp(exponent->data_type,"R4"))
            data = (void *)((float *)exponent->data + 5);
        else
            data = (void *)((double *)exponent->data + 5);
        dim_vals = 3;
        if (cgi_new_node(exponent->id, "AdditionalExponents",
            "AdditionalExponents_t", &dummy_id,
            exponent->data_type, 1, &dim_vals, data)) return 1;
    }
    return 0;
}

int cgi_write_dataclass(double parent_id, CGNS_ENUMV(DataClass_t) data_class)
{
    cgsize_t dim_vals;
    double dummy_id;

    dim_vals=(cgsize_t)strlen(DataClassName[data_class]);
    if (cgi_new_node(parent_id, "DataClass", "DataClass_t", &dummy_id,
        "C1", 1, &dim_vals, (void *)DataClassName[data_class])) return 1;

    return 0;
}

int cgi_write_descr(double parent_id, cgns_descr *descr)
{
    cgsize_t dim_vals;

    if (descr->link) {
        return cgi_write_link(parent_id, descr->name,
            descr->link, &descr->id);
    }

    dim_vals=(cgsize_t)strlen(descr->text);
    if (cgi_new_node(parent_id, descr->name, "Descriptor_t",
        &descr->id, "C1", 1, &dim_vals, (void *)descr->text)) return 1;

    return 0;
}

int cgi_write_ordinal(double parent_id, int ordinal)
{
    cgsize_t dim_vals;
    double dummy_id;

    dim_vals=1;
    if (cgi_new_node(parent_id, "Ordinal", "Ordinal_t", &dummy_id,
        "I4", 1, &dim_vals, (void *)&ordinal)) return 1;

    return 0;
}

int cgi_write_user_data(double parent_id, cgns_user_data *user_data)
{
    int n;
    cgsize_t dim_vals;
    double dummy_id;

    if (user_data->link) {
        return cgi_write_link(parent_id, user_data->name,
            user_data->link, &user_data->id);
    }

     /* UserDefinedData_t */
    if (cgi_new_node(parent_id, user_data->name, "UserDefinedData_t",
        &user_data->id, "MT", 0, 0, 0)) return 1;

     /* Descriptor_t */
    for (n=0; n<user_data->ndescr; n++)
        if (cgi_write_descr(user_data->id, &user_data->descr[n])) return 1;

     /* DataClass_t */
    if (user_data->data_class &&
        cgi_write_dataclass(user_data->id, user_data->data_class)) return 1;

     /* DimensionalUnits_t */
    if (user_data->units &&
        cgi_write_units(user_data->id, user_data->units)) return 1;

     /* DataArray_t */
    for (n=0; n<user_data->narrays; n++)
        if (cgi_write_array(user_data->id, &user_data->array[n])) return 1;

    /* GridLocation_t */
    if (user_data->location != CGNS_ENUMV( Vertex )) {
        dim_vals = (cgsize_t)strlen(GridLocationName[user_data->location]);
        if (cgi_new_node(user_data->id, "GridLocation", "GridLocation_t",
                         &dummy_id, "C1", 1, &dim_vals,
                         (void *)GridLocationName[user_data->location]))
            return 1;
    }

    /* FamilyName_t */
    if (user_data->family_name[0]!='\0') {
        dim_vals = (cgsize_t)strlen(user_data->family_name);
        if (cgi_new_node(user_data->id, "FamilyName", "FamilyName_t",
                         &dummy_id, "C1", 1, &dim_vals,
                         (void *)user_data->family_name))
            return 1;
    }

    /* CPEX 0034 */
    for (n = 0; n < user_data->nfamname; n++) {
        dim_vals = (cgsize_t)strlen(user_data->famname[n].family);
        if (cgi_new_node(user_data->id, user_data->famname[n].name,
            "AdditionalFamilyName_t", &dummy_id, "C1", 1, &dim_vals,
            (void *)user_data->famname[n].family)) return 1;
    }

    /* Ordinal_t */
    if (user_data->ordinal &&
        cgi_write_ordinal(user_data->id, user_data->ordinal)) return 1;

    /* PointRange, PointList:  Move node to its final position */
    if (user_data->ptset) {
     /* Move node to its final position */
        if (cgi_move_node(cg->rootid, user_data->ptset->id, user_data->id,
            PointSetTypeName[user_data->ptset->type])) return 1;
    }

    /* UserDefinedData_t */
    for (n=0; n < user_data->nuser_data; n++)
        if (cgi_write_user_data(user_data->id, &user_data->user_data[n]))
            return 1;

    return 0;
}

int cgi_write_link(double parent_id, char *name, cgns_link *link, double *id)
{
    if (cgio_create_link(cg->cgio, parent_id, name,
            link->filename, link->name_in_file, id)) {
        cg_io_error("cgio_create_link");
        return 1;
    }
    (cg->added)++;
    return 0;
}


/* cgi_new_node creates an ADF node under parent_id and returns node_id */
int cgi_new_node(double parent_id, char const *name, char const *label,
                 double *node_id, char const *data_type,
                 int ndim, cgsize_t const *dim_vals, void const *data)
{
     /* verify input */
    if (cgi_check_strlen(name) || cgi_check_strlen(label) ||
        cgi_check_strlen(data_type)) return 1;

    if (cgio_create_node(cg->cgio, parent_id, name, node_id)) {
        cg_io_error("cgio_create_node");
        return 1;
    }
    (cg->added)++;
    if (cgio_set_label(cg->cgio, *node_id, label)) {
        cg_io_error("cgio_set_label");
        return 1;
    }
     /* return if empty */
    if (strcmp(data_type, "MT")==0) return 0;

    if (cgio_set_dimensions(cg->cgio, *node_id, data_type, ndim, dim_vals)) {
         cg_io_error("cgio_set_dimensions");
         return 1;
    }

    if (data == NULL) return 0;

#if 0
     /* verify that data doesn't contain NaN */
    if (strcmp(data_type,"I4")==0 || strcmp(data_type,"I8")==0 ||
        strcmp(data_type,"R4")==0 || strcmp(data_type,"R8")==0) {
        cgsize_t i, ndata=1, nbad=0;

        for (i=0; i<ndim; i++) ndata *= dim_vals[i];

        if (strcmp(data_type,"I4")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((int *)data+i))) nbad++;
	} else if (strcmp(data_type,"I8")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((cglong_t *)data+i))) nbad++;
        } else if (strcmp(data_type,"R4")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((float *)data+i))) nbad++;
        } else if (strcmp(data_type,"R8")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((double *)data+i))) nbad++;
        }
        if (nbad) {
            cgi_error("**** NaN encountered **** ");
            return 1;
        }
    }
#endif

     /* Write the data to disk */
    if (cgio_write_all_data(cg->cgio, *node_id, data)) {
        cg_io_error("cgio_write_all_data");
        return 1;
    }
    return 0;
}

/* cgi_new_node_partial creates an ADF node under parent_id and returns
 * node_id
 * It will write data for a subset of dim_vals based on rmin and rmax
 * using ADF_Write_Data(..).
*/
int cgi_new_node_partial(double parent_id, char const *name, char const *label,
                         double *node_id, char const *data_type, int ndim,
                         cgsize_t const *dim_vals, cgsize_t const *rmin,
                         cgsize_t const *rmax, void const *data)
{
    cgsize_t i, m_start[12], m_end[12], m_dim[12], stride[12];

     /* verify input */
    if (cgi_check_strlen(name) || cgi_check_strlen(label) ||
        cgi_check_strlen(data_type)) return 1;

    if (cgio_create_node(cg->cgio, parent_id, name, node_id)) {
        cg_io_error("cgio_create_node");
        return 1;
    }
    (cg->added)++;
    if (cgio_set_label(cg->cgio, *node_id, label)) {
        cg_io_error("cgio_set_label");
        return 1;
    }
     /* return if empty */
    if (strcmp(data_type, "MT")==0) return 0;

    for (i = 0; i < ndim; ++i)
    {
        m_start[i] = 1;
        m_end[i] = rmax[i] - rmin[i] + 1;
        m_dim[i] = m_end[i];
        stride[i] = 1;
    }

    if (cgio_set_dimensions(cg->cgio, *node_id, data_type, ndim, dim_vals)) {
         cg_io_error("cgio_set_dimensions");
         return 1;
    }

    if (data == NULL) return 0;

#if 0
     /* verify that data doesn't contain NaN */
    if (strcmp(data_type,"I4")==0 || strcmp(data_type,"I8")==0 ||
        strcmp(data_type,"R4")==0 || strcmp(data_type,"R8")==0) {
        cgsize_t ndata = 1, nbad=0;

        for (i=0; i<ndim; i++)
            ndata *= rmax[i] - rmin[i] + 1;

        if (strcmp(data_type,"I4")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((int *)data+i))) nbad++;
	} else if (strcmp(data_type,"I9")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((cglong_t *)data+i))) nbad++;
        } else if (strcmp(data_type,"R4")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((float *)data+i))) nbad++;
        } else if (strcmp(data_type,"R8")==0) {
            for (i=0; i<ndata; i++) if (CGNS_NAN(*((double *)data+i))) nbad++;
        }
        if (nbad) {
            cgi_error("**** NaN encountered **** ");
            return 1;
        }
    }
#endif

     /* Write the data to disk */
    if (cgio_write_data(cg->cgio, *node_id, rmin, rmax, stride,
            ndim, m_dim, m_start, m_end, stride, data)) {
        cg_io_error("cgio_write_data");
        return 1;
    }

    return 0;
}

int cgi_move_node(double current_parent_id, double node_id,
          double new_parent_id, cchar_33 node_name)
{

    if (cgio_move_node(cg->cgio, current_parent_id, node_id,
            new_parent_id)) {
        cg_io_error("cgio_move_node");
        return 1;
    }
    if (cgio_set_name(cg->cgio, new_parent_id, node_id, node_name)) {
        cg_io_error("cgio_set_name");
        return 1;
    }
    return 0;
}

int cgi_delete_node (double parent_id, double node_id)
{
    (cg->deleted)++;
    if (cgio_delete_node(cg->cgio, parent_id, node_id)) {
        cg_io_error ("cgio_delete_node");
        return 1;
    }
    return 0;
}

/***********************************************************************\
 *            Alphanumerical sorting routine               *
\***********************************************************************/

int cgi_sort_names(int nnam, double *ids)
{
    int i,j,k;
    int leni, lenj;
    char_33 temp;
    double temp_id;
    char_33 *names;

    names = CGNS_NEW(char_33, nnam);
    for (i=0; i<nnam; i++) {
        if (cgio_get_name(cg->cgio, ids[i], names[i])) {
            cg_io_error("cgio_get_name");
            return 1;
        }
    }

    for (i=0; i<nnam; i++) {
        leni=(int)strlen(names[i]);

        for (j=i+1; j<nnam; j++) {
            lenj=(int)strlen(names[j]);

            for (k=0; k<leni && k<lenj; k++) {

                if ((int)names[j][k] < (int)names[i][k]) {
                    strcpy(temp, names[i]);
                    strcpy(names[i], names[j]);
                    strcpy(names[j], temp);
                    leni=(int)strlen(names[i]);
                    temp_id = ids[i];
                    ids[i]=ids[j];
                    ids[j]=temp_id;

                    break;
                } else if ((int)names[j][k]>(int)names[i][k]) {
                    break;
                }
                if (k==(int)(strlen(names[j])-1)) {
                    strcpy(temp, names[i]);
                    strcpy(names[i], names[j]);
                    strcpy(names[j], temp);
                    leni=(int)strlen(names[i]);
                    temp_id = ids[i];
                    ids[i]=ids[j];
                    ids[j]=temp_id;
                }
            }
        }
    }

    free(names);

    return 0;
}

/***********************************************************************\
 * ADF parser:  returns the children id with "label" under "parent_id" *
\***********************************************************************/

int cgi_get_nodes(double parent_id, char *label, int *nnodes, double **id)
{
    int nid, n, nchildren, len;
    char nodelabel[CGIO_MAX_NAME_LENGTH+1];
    double *idlist;

    *nnodes = 0;
    if (cgio_number_children(cg->cgio, parent_id, &nchildren)) {
        cg_io_error ("cgio_number_children");
        return 1;
    }
    if (nchildren < 1) return 0;
    idlist = CGNS_NEW (double, nchildren);
    if (cgio_children_ids(cg->cgio, parent_id, 1, nchildren,
            &len, idlist)) {
        cg_io_error ("cgio_children_ids");
        return 1;
    }
    if (len != nchildren) {
        CGNS_FREE (idlist);
        cgi_error ("mismatch in number of children and child IDs read");
        return 1;
    }
    nid = 0;
    for (nid = 0, n = 0; n < nchildren; n++) {
        if (cgio_get_label(cg->cgio, idlist[n], nodelabel)) {
            cg_io_error ("cgio_get_label");
            return 1;
        }
        if (0 == strcmp (nodelabel, label)) {
            if (nid < n) idlist[nid] = idlist[n];
            nid++;
        }
        else
            cgio_release_id (cg->cgio, idlist[n]);
    }
    if (nid > 0) {
        *id = idlist;
        *nnodes = nid;
    }
    else
        CGNS_FREE (idlist);
    return 0;
}

/***********************************************************************\
 *        Data Types functions                     *
\***********************************************************************/

char *type_of(char_33 data_type)
{
    if (strcmp(data_type, "I4")==0) return "int";
    else if (strcmp(data_type, "R4")==0) return "float";
    else if (strcmp(data_type, "R8")==0) return "double";
    else if (strcmp(data_type, "C1")==0) return "char";

    else {
        cgi_error("data_type '%s' not supported by function 'type_of'",data_type);
        return 0;
    }
}

int size_of(char_33 data_type)
{
    if (strcmp(data_type, "I4") == 0) return sizeof(int);
    if (strcmp(data_type, "I8") == 0) return sizeof(cglong_t);
    if (strcmp(data_type, "R4") == 0) return sizeof(float);
    if (strcmp(data_type, "R8") == 0) return sizeof(double);
    if (strcmp(data_type, "C1") == 0) return sizeof(char);

    cgi_error("data_type '%s' not supported by function 'size_of'",data_type);
    return 0;
}

const char *cgi_adf_datatype(CGNS_ENUMV(DataType_t) type)
{

    if (type == CGNS_ENUMV(Integer)) return "I4";
    if (type == CGNS_ENUMV(LongInteger)) return "I8";
    if (type == CGNS_ENUMV(RealSingle)) return "R4";
    if (type == CGNS_ENUMV(RealDouble)) return "R8";
    if (type == CGNS_ENUMV(Character))  return "C1";
    return "NULL";
}

CGNS_ENUMT(DataType_t) cgi_datatype(cchar_33 adf_type)
{
    if (strcmp(adf_type, "I4") == 0) return CGNS_ENUMV(Integer);
    if (strcmp(adf_type, "I8") == 0) return CGNS_ENUMV(LongInteger);
    if (strcmp(adf_type, "R4") == 0) return CGNS_ENUMV(RealSingle);
    if (strcmp(adf_type, "R8") == 0) return CGNS_ENUMV(RealDouble);
    if (strcmp(adf_type, "C1") == 0) return CGNS_ENUMV(Character);
    return CGNS_ENUMV(DataTypeNull);
}

/***********************************************************************\
 *        Check input functions                    *
\***********************************************************************/

int cgi_zone_no(cgns_base *base, char *zonename, int *zone_no)
{
    int i;

    for (i=0; i<base->nzones; i++) {
        if (strcmp(base->zone[i].name,zonename)==0) {
            *zone_no = i+1;
            return 0;
        }
    }
    cgi_error("Zone %s not found",zonename);
    return 1;
}

int cgi_check_strlen(char const *string)
{
    if (strlen(string) > 32) {
        cgi_error("Name exceeds 32 characters limit: %s",string);
        return 1;
    }
    return 0;
}

int cgi_check_strlen_x2(char const *string)
{
    int n1,n2,p;

    if (strlen(string) > 65) {
        cgi_error("Name exceeds 65 characters limit: %s",string);
        return 1;
    }
    p=0;
    n1=0;
    n2=0;
    while (string[p])
    {
      if (string[p]=='/')
      {
	if (n2!=0){
	  cgi_error("Zone or Family with base scope should have only one / : %s",string);
	  return 1;
	}
	if (n1==0){
	  cgi_error("Base part of the name is empty in %s",string);
	  return 1;
	}
	if (p==strlen(string)-1){
	  cgi_error("Zone or Family part of the name is empty in %s",string);
	  return 1;
	}
	n2++;
      }
      if (!n2) n1++;
      else     n2++;
      if (n1>32){
        cgi_error("Base part of the name exceed 32 chars limit: %s",string);
        return 1;
      }
      if (n2>34){
        cgi_error("Zone or Family part of the name exceed 32 chars limit: %s",string);
        return 1;
      }
      p++;
    }
    return 0;
}

int cgi_check_mode(char const *filename, int file_mode, int mode_wanted)
{
    if (mode_wanted==CG_MODE_READ && file_mode==CG_MODE_WRITE) {
        cgi_error("File %s not open for reading", filename);
        return 1;
    }
    if (mode_wanted==CG_MODE_WRITE && file_mode==CG_MODE_READ) {
        cgi_error("File %s not open for writing", filename);
        return 1;
    }
    return 0;
}

/***********************************************************************\
 *        Miscellaneous                        *
\***********************************************************************/

int cgi_add_czone(char_33 zonename, cgsize6_t range, cgsize6_t donor_range,
                  int index_dim, int *ndouble, char_33 **Dzonename,
                  cgsize6_t **Drange, cgsize6_t **Ddonor_range)
{
    int differ=1, k, j;

     /* check if this interface was already found */
    for (k=0; k<(*ndouble); k++) {
        differ=0;
        if (strcmp(Dzonename[0][k],zonename)) {
            differ=1;
            continue;
        }
        for (j=0; j<index_dim; j++) {
            if (Drange[0][k][j]==Drange[0][k][j+index_dim]) continue;
            if (Drange[0][k][j]!=MIN(donor_range[j],donor_range[j+index_dim]) ||
                Drange[0][k][j+index_dim]!=MAX(donor_range[j],donor_range[j+index_dim])) {
                differ=1;
                break;
            }
        }
        if (differ) continue;
        for (j=0; j<index_dim; j++) {
            if (Ddonor_range[0][k][j]==Ddonor_range[0][k][j+index_dim]) continue;
            if (Ddonor_range[0][k][j]!=MIN(range[j],range[j+index_dim]) ||
                Ddonor_range[0][k][j+index_dim]!=MAX(range[j],range[j+index_dim])) {
                differ=1;
                break;
            }
        }
        if (differ==0) break;
    }
     /* Return 0:  interface already recorded.  */
    if (k!=(*ndouble)) return 0;

     /* save new interface */
     /* allocate memory */
    if ((*ndouble)==0) {
        Dzonename[0]    = CGNS_NEW(char_33,     (*ndouble)+1);
        Drange[0]       = CGNS_NEW(cgsize6_t,   (*ndouble)+1);
        Ddonor_range[0] = CGNS_NEW(cgsize6_t,   (*ndouble)+1);
    } else {
        Dzonename[0]    = CGNS_RENEW(char_33,   (*ndouble)+1, Dzonename[0]);
        Drange[0]       = CGNS_RENEW(cgsize6_t, (*ndouble)+1, Drange[0]);
        Ddonor_range[0] = CGNS_RENEW(cgsize6_t, (*ndouble)+1, Ddonor_range[0]);
    }
     /* store interface info temporarily */
    strcpy(Dzonename[0][(*ndouble)],zonename);
    for (j=0; j<index_dim; j++) {
        Drange[0][(*ndouble)][j] = MIN(range[j],range[j+index_dim]);
        Drange[0][(*ndouble)][j+index_dim]= MAX(range[j],range[j+index_dim]);
        Ddonor_range[0][(*ndouble)][j]= MIN(donor_range[j],donor_range[j+index_dim]);
        Ddonor_range[0][(*ndouble)][j+index_dim]= MAX(donor_range[j],donor_range[j+index_dim]);
    }
    (*ndouble)++;
    return 1;
}

/* this function takes the element type, count and connectivity list
   and returns the total size required for the connectivity */

cgsize_t cgi_element_data_size(CGNS_ENUMT(ElementType_t) type,
                               cgsize_t nelems, const cgsize_t *connect)
{
    int npe;
    cgsize_t ne, size = 0;

    if (type == CGNS_ENUMV(MIXED)) {
        if (connect == 0) return 0;
        for (ne = 0; ne < nelems; ne++) {
            type = (CGNS_ENUMT(ElementType_t))connect[size++];
            if (cg->version < 3200 && type >= CGNS_ENUMV(NGON_n))
                npe = (int)(type - CGNS_ENUMV(NGON_n));
            else
                cg_npe(type, &npe);
            if (npe <= 0) {
                cgi_error("unhandled element type in MIXED list - %d\n", type);
                return -1;
            }
            size += npe;
        }
    }
    else if (type == CGNS_ENUMV(NGON_n) || type == CGNS_ENUMV(NFACE_n)) {
        if (connect == 0) return 0;
        for (ne = 0; ne < nelems; ne++) {
            npe = (int)connect[size++];
            size += npe;
        }
    }
    else {
        if (cg_npe(type, &npe) || npe <= 0) {
            cgi_error("unhandled element type - %d\n", type);
            return -1;
        }
        size = nelems * npe;
    }
    return size;
}

/***********************************************************************\
 *       Get the memory address of a data structure        *
\***********************************************************************/

cgns_file *cgi_get_file(int file_number)
{
    int filenum = file_number - file_number_offset;
    if (filenum <= 0 || filenum > n_cgns_files) {
        cgi_error("CGNS file %d is not open",file_number);
        return 0;
    }
    cg = &(cgns_files[filenum-1]);
    if (cg->mode == CG_MODE_CLOSED) {
        cgi_error("CGNS %d is closed",file_number);
        return 0;
    }
    return cg;
}

cgns_base *cgi_get_base(cgns_file *cg, int B)
{
    if (B>cg->nbases || B<=0) {
        cgi_error("Base number %d invalid",B);
        return 0;
    }
    return &(cg->base[B-1]);
}

cgns_zone *cgi_get_zone(cgns_file *cg, int B, int Z)
{
    cgns_base *base;

    base = cgi_get_base(cg, B);
    if (base==0) return 0;

    if (Z>base->nzones || Z<=0) {
        cgi_error("Zone number %d invalid",Z);
        return 0;
    }
    return &(base->zone[Z-1]);
}

cgns_family *cgi_get_family(cgns_file *cg, int B, int F)
{
    cgns_base *base;

    base = cgi_get_base(cg, B);
    if (base==0) return 0;

    if (F>base->nfamilies || F<=0) {
        cgi_error("Family number %d invalid",F);
        return 0;
    }
    return &base->family[F-1];
}

cgns_biter *cgi_get_biter(cgns_file *cg, int B)
{
    cgns_base *base;

    base = cgi_get_base(cg, B);
    if (base==0) return 0;

    if (base->biter == 0) {
        cgi_error("BaseIterativeData_t node doesn't exist under CGNSBase %d",B);
        return 0;
    } else return base->biter;
}

cgns_gravity *cgi_get_gravity(cgns_file *cg, int B)
{
    cgns_base *base;

    base = cgi_get_base(cg, B);
    if (base==0) return 0;

    if (base->gravity==0) {
        cgi_error("Gravity_t node doesn't exist under CGNSBase %d",B);
        return 0;
    } else return base->gravity;
}

cgns_axisym *cgi_get_axisym(cgns_file *cg, int B)
{
    cgns_base *base;

    base = cgi_get_base(cg, B);
    if (base==0) return 0;

    if (base->axisym==0) {
        cgi_error("Axisymmetry_t node doesn't exist under CGNSBase %d",B);
        return 0;
    } else return base->axisym;
}

cgns_rotating *cgi_get_rotating(cgns_file *cg, int B, int Z)
{
    cgns_base *base;
    cgns_zone *zone;

     /* RotatingCoordinates_t under a base */
    if (Z==0) {
        base = cgi_get_base(cg, B);
        if (base==0) return 0;

        if (base->rotating==0) {
            cgi_error("RotatingCoordinates_t node doesn't exist under CGNSBase %d",B);
            return 0;
        } else return base->rotating;
    } else {
        zone = cgi_get_zone(cg, B, Z);
        if (zone==0) return 0;

        if (zone->rotating==0) {
            cgi_error("RotatingCoordinates_t node doesn't exist under zone %d",Z);
            return 0;
        } else return zone->rotating;
    }
}

cgns_ziter *cgi_get_ziter(cgns_file *cg, int B, int Z)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (zone->ziter == 0) {
        cgi_error("ZoneIterativeData_t node doesn't exist under zone %d",Z);
        return 0;
    } else return zone->ziter;
}

cgns_zcoor *cgi_get_zcoorGC(cgns_file *cg, int B, int Z)
{
    cgns_zone *zone;
    int i, index_dim;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    index_dim = zone->index_dim;

    if (zone->nzcoor == 0 && (cg->mode == CG_MODE_WRITE || cg->mode == CG_MODE_MODIFY)) {
        zone->zcoor = CGNS_NEW(cgns_zcoor, 1);
        strcpy(zone->zcoor->name, "GridCoordinates");
        zone->zcoor->id = 0;
        zone->zcoor->link = 0;
        zone->zcoor->ndescr = 0;
        zone->zcoor->rind_planes = CGNS_NEW(int, 2*index_dim);
        for (i=0; i<2*index_dim; i++) zone->zcoor->rind_planes[i]=0;
        zone->zcoor->ncoords = 0;
        zone->zcoor->data_class = CGNS_ENUMV( DataClassNull );
        zone->zcoor->units = 0;
        zone->zcoor->nuser_data= 0;

        if (cg->mode == CG_MODE_MODIFY) {
         /* Create node GridCoordinates_t node in file */
            if (cgi_new_node(zone->id, "GridCoordinates", "GridCoordinates_t",
                 &zone->zcoor->id, "MT", 0, 0, 0)) return 0;
        }
        zone->nzcoor=1;
        return zone->zcoor;
    } else {
        for (i=0; i<zone->nzcoor; i++) {
            if (strcmp(zone->zcoor[i].name,"GridCoordinates")==0) {
                return &zone->zcoor[i];
            }
        }
    }
    cgi_error("Node 'GridCoordinates' not found for zone '%s'",zone->name);
    return 0;
}

cgns_zcoor *cgi_get_zcoor(cgns_file *cg, int B, int Z, int C)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (C>zone->nzcoor || C<=0) {
        cgi_error("GridCoordinates node number %d invalid",C);
        return 0;
    }
    return &(zone->zcoor[C-1]);
}

cgns_sol *cgi_get_sol(cgns_file *cg, int B, int Z, int S)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (S>zone->nsols || S<=0) {
        cgi_error("FlowSolution node number %d invalid",S);
        return 0;
    }
    return &(zone->sol[S-1]);
}

cgns_section *cgi_get_section(cgns_file *cg, int B, int Z, int S)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (S>zone->nsections || S<=0) {
        cgi_error("Elements_t node number %d invalid",S);
        return 0;
    }
    return &zone->section[S-1];
}

cgns_array *cgi_get_field(cgns_file *cg, int B, int Z, int S, int F)
{
    cgns_sol *sol;

    sol = cgi_get_sol(cg, B, Z, S);
    if (sol==0) return 0;

    if (F>sol->nfields || F<=0) {
        cgi_error("Solution array number  %d invalid",F);
        return 0;
    }
    return &(sol->field[F-1]);
}

cgns_zconn *cgi_get_zconnZC(cgns_file *cg, int B, int Z, int C)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (C > 0 && C <= zone->nzconn) {
        zone->active_zconn = C;
        return &zone->zconn[C-1];
    }
    cgi_error("ZoneGridConnectivity_t node number %d invalid",C);
    return 0;
}

cgns_zconn *cgi_get_zconn(cgns_file *cg, int B, int Z)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    /* return active zconn if set */
    if (zone->nzconn > 0 && zone->active_zconn > 0 &&
        zone->active_zconn <= zone->nzconn) {
        return &zone->zconn[zone->active_zconn-1];
    }

/* Allocate automatically only in MODE_WRITE.  In MODE_MODIFY, can't do it
   because a cg_goto would create the node even if not wanted */
    if (zone->zconn == 0) {
        if (cg->mode == CG_MODE_WRITE) {
            zone->zconn = CGNS_NEW(cgns_zconn, 1);
            strcpy(zone->zconn->name, "ZoneGridConnectivity");
            zone->zconn->id=0;
            zone->zconn->link=0;
            zone->zconn->ndescr=0;
            zone->zconn->n1to1=0;
            zone->zconn->nconns=0;
            zone->zconn->nholes=0;
            zone->zconn->nuser_data=0;

        } else {
            cgi_error("No grid connectivity information for zone %d", Z);
            return 0;
        }
    }
    zone->active_zconn = 1;
    return zone->zconn;
}

cgns_cprop *cgi_get_cprop(cgns_file *cg, int B, int Z, int I)
{
    cgns_conn *conn;

    conn = cgi_get_conn(cg, B, Z, I);
    if (conn==0) return 0;

    if (conn->cprop == 0)
        cgi_error("GridConnectivityProperty_t node doesn't exist under GridConnectivity_t %d",I);

    return conn->cprop;
}

cgns_hole *cgi_get_hole(cgns_file *cg, int B, int Z, int I)
{
    cgns_zconn *zconn;

    zconn = cgi_get_zconn(cg, B, Z);
    if (zconn==0) return 0;

    if (I>zconn->nholes || I<=0) {
        cgi_error("OversetHoles node number %d invalid",I);
        return 0;
    }
    return &(zconn->hole[I-1]);
}

cgns_conn *cgi_get_conn(cgns_file *cg, int B, int Z, int I)
{
    cgns_zconn *zconn;

    zconn = cgi_get_zconn(cg, B, Z);
    if (zconn==0) return 0;

    if (I>zconn->nconns || I<=0) {
        cgi_error("GridConnectivity_t node number %d invalid",I);
        return 0;
    }
    return &(zconn->conn[I-1]);
}

cgns_1to1 *cgi_get_1to1(cgns_file *cg, int B, int Z, int I)
{
    cgns_zconn *zconn;

    zconn = cgi_get_zconn(cg, B, Z);
    if (zconn==0) return 0;

    if (I>zconn->n1to1 || I<=0) {
        cgi_error("GridConnectivity1to1_t node number %d invalid",I);
        return 0;
    }
    return &(zconn->one21[I-1]);
}

cgns_zboco *cgi_get_zboco(cgns_file *cg, int B, int Z)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

/* Allocate automatically only in MODE_WRITE.  In MODE_MODIFY, can't do it
   because a cg_goto would create the node even if not wanted */
    if (zone->zboco == 0) {
        if (cg->mode == CG_MODE_WRITE) {
            zone->zboco = CGNS_NEW(cgns_zboco, 1);
            strcpy(zone->zboco->name,"ZoneBC");
            zone->zboco->id=0;
            zone->zboco->link=0;
            zone->zboco->ndescr=0;
            zone->zboco->nbocos=0;
            zone->zboco->state=0;
            zone->zboco->data_class=CGNS_ENUMV( DataClassNull );
            zone->zboco->units=0;
            zone->zboco->nuser_data=0;

        } else {
            cgi_error("No boundary condition data in zone %d",Z);
            return 0;
        }
    }
    return zone->zboco;
}

cgns_bprop *cgi_get_bprop(cgns_file *cg, int B, int Z, int BC)
{
    cgns_boco *boco;

    boco = cgi_get_boco(cg, B, Z, BC);
    if (boco==0) return 0;

    if (boco->bprop == 0)
        cgi_error("BCProperty_t node doesn't exist under BC_t %d",BC);
    return boco->bprop;
}

cgns_boco *cgi_get_boco(cgns_file *cg, int B, int Z, int BC)
{
    cgns_zboco *zboco;

    zboco = cgi_get_zboco(cg, B, Z);
    if (zboco==0) return 0;

    if (BC>zboco->nbocos || BC<=0) {
        cgi_error("BC_t node number %d invalid",BC);
        return 0;
    }
    return &(zboco->boco[BC-1]);
}

cgns_dataset *cgi_get_dataset(cgns_file *cg, int B, int Z, int BC, int DSet)
{
    cgns_boco *boco = cgi_get_boco(cg, B, Z, BC);
    if (boco==0) return 0;

    if (DSet>boco->ndataset || DSet<=0) {
        cgi_error("BCDataSet_t node number %d invalid",DSet);
        return 0;
    }
    return &boco->dataset[DSet-1];
}

cgns_bcdata *cgi_get_bcdata(cgns_file *cg, int B, int Z, int BC, int Dset,
                            CGNS_ENUMV( BCDataType_t ) type)
{
    cgns_dataset *dataset = cgi_get_dataset(cg, B, Z, BC, Dset);
    if (dataset==0) return 0;

    if (type==CGNS_ENUMV( Dirichlet )) {
        if (dataset->dirichlet==0) {
            cgi_error("BCData_t type Dirichlet doesn't exist for Zone %d, BC=%d, BCDataSet=%d",
                Z, BC, Dset);
            return 0;
        } else return dataset->dirichlet;
    } else if (type==CGNS_ENUMV( Neumann )) {
        if (dataset->neumann==0) {
            cgi_error("BCData_t type Neumann doesn't exist for Zone %d, BC=%d, BCDataSet=%d",
                Z, BC, Dset);
            return 0;
        } else return dataset->neumann;
    } else {
        cgi_error("BCData must be of type Dirichlet or Neumann");
        return 0;
    }
}

cgns_converg *cgi_get_converg(cgns_file *cg, int B, int Z)
{
    if (Z==0) {
        cgns_base *base=cgi_get_base(cg, B);
        if (base==0) return 0;

        if (base->converg== 0) {
            cgi_error("ConvergenceHistory_t node doesn't exist under CGNSBase %d",B);
            return 0;
        } else return base->converg;
    } else {
        cgns_zone *zone=cgi_get_zone(cg, B, Z);
        if (zone==0) return 0;

        if (zone->converg== 0) {
            cgi_error("ConvergenceHistory_t node doesn't exist under CGNSBase %d, Zone %d",B,Z);
            return 0;
        } else return zone->converg;
    }
}

cgns_equations *cgi_get_equations(cgns_file *cg, int B, int Z)
{
    if (Z==0) {
        cgns_base *base=cgi_get_base(cg, B);
        if (base==0) return 0;

/* todo: error checking if node doesn't exist in all these cgi_get_functions */
/*   also make sure that they are all initialized correctly */
        if (base->equations == 0) {
            cgi_error("FlowEquationSet_t Node doesn't exist under CGNSBase %d",B);
            return 0;
        } else return base->equations;
    } else {
        cgns_zone *zone=cgi_get_zone(cg, B, Z);
        if (zone==0) return 0;

        if (zone->equations == 0) {
            cgi_error("FlowEquationSet_t Node doesn't exist under CGNSBase %d, Zone %d",B,Z);
            return 0;
        } else return zone->equations;
    }
}

cgns_governing *cgi_get_governing(cgns_file *cg, int B, int Z)
{
    cgns_equations *eq=cgi_get_equations(cg, B, Z);
    if (eq==0) return 0;

    if (eq->governing==0) {
        if (Z==0) cgi_error("GoverningEquations_t undefined for CGNSBase %d",B);
        else cgi_error("GoverningEquations_t undefined for CGNSBase %d, Zone %d", B, Z);
        return 0;
    } else return eq->governing;
}

cgns_model *cgi_get_model(cgns_file *cg, int B, int Z, char *model)
{
    cgns_equations *eq=cgi_get_equations(cg, B, Z);
    if (eq==0) return 0;

    if (strcmp(model, "GasModel_t")==0 && eq->gas)
        return eq->gas;
    else if (strcmp(model, "ViscosityModel_t")==0 && eq->visc)
        return eq->visc;
    else if (strcmp(model, "ThermalConductivityModel_t")==0 && eq->conduct)
        return eq->conduct;
    else if (strcmp(model, "TurbulenceModel_t")==0 && eq->turbulence)
        return eq->turbulence;
    else if (strcmp(model, "TurbulenceClosure_t")==0 && eq->closure)
        return eq->closure;
    else if (strcmp(model, "ThermalRelaxationModel_t")==0 && eq->relaxation)
        return eq->relaxation;
    else if (strcmp(model, "ChemicalKineticsModel_t")==0 && eq->chemkin)
        return eq->chemkin;
    else if (strcmp(model, "EMElectricFieldModel_t")==0 && eq->elecfield)
        return eq->elecfield;
    else if (strcmp(model, "EMMagneticFieldModel_t")==0 && eq->magnfield)
        return eq->magnfield;
    else if (strcmp(model, "EMConductivityModel_t")==0 && eq->emconduct)
        return eq->emconduct;
    else {
        if (Z==0) cgi_error("%s undefined for CGNSBase %d",model, B);
        else cgi_error("%s undefined for CGNSBase %d, Zone %d",model, B, Z);
        return 0;
    }
}

cgns_integral *cgi_get_integral(cgns_file *cg, int B, int Z, int N)
{
    if (Z==0) {
        cgns_base *base=cgi_get_base(cg, B);
        if (base==0) return 0;

        if (N>base->nintegrals || N<=0) {
            cgi_error("IntegralData_t node number %d invalid under CGNSBase %d",N, B);
            return 0;
        } else return &base->integral[N-1];
    } else {
        cgns_zone *zone=cgi_get_zone(cg, B, Z);
        if (zone==0) return 0;

        if (N>zone->nintegrals || N<=0) {
            cgi_error("IntegralData_t node number %d invalid under CGNSBase %d, Zone %d",N,B,Z);
            return 0;
        } else return &zone->integral[N-1];
    }
}

cgns_discrete *cgi_get_discrete(cgns_file *cg, int B, int Z, int D)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (D>zone->ndiscrete || D<=0) {
        cgi_error("DiscreteData node number %d invalid",D);
        return 0;
    }
    return &zone->discrete[D-1];
}

cgns_rmotion *cgi_get_rmotion(cgns_file *cg, int B, int Z, int R)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (R>zone->nrmotions || R<=0) {
        cgi_error("RigidGridMotion node number %d invalid",R);
        return 0;
    }
    return &zone->rmotion[R-1];
}

cgns_amotion *cgi_get_amotion(cgns_file *cg, int B, int Z, int R)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (R>zone->namotions || R<=0) {
        cgi_error("ArbitraryGridMotion node number %d invalid",R);
        return 0;
    }
    return &zone->amotion[R-1];
}

cgns_state *cgi_get_state(cgns_file *cg, int B, int Z, int ZBC, int BC, int Dset)
{
     /* defined under CGNSBase_t */
    if (Z==0 && ZBC==0 && BC==0 && Dset==0) {
        cgns_base *base = cgi_get_base(cg, B);
        if (base==0) return 0;
        if (base->state==0) {
            cgi_error("ReferenceState_t undefined under CGNSBase %d",B);
            return 0;
        } else return base->state;
     /* defined under Zone_t */
    } else if (ZBC==0 && BC==0 && Dset==0) {
        cgns_zone *zone = cgi_get_zone(cg, B, Z);
        if (zone==0) return 0;
        if (zone->state==0) {
            cgi_error("ReferenceState_t undefined under CGNSBase %d, Zone %d",B,Z);
            return 0;
        } else return zone->state;
     /* defined under ZoneBC_t */
    } else if (BC==0 && Dset==0) {
        cgns_zboco *zboco = cgi_get_zboco(cg, B, Z);
        if (zboco==0) return 0;
        if (zboco->state==0) {
            cgi_error("ReferenceState_t undefined under CGNSBase %d, Zone %d, ZoneBC_t",B,Z);
            return 0;
        } else return zboco->state;
     /* defined under BC_t */
    } else if (Dset==0) {
        cgns_boco *boco = cgi_get_boco(cg, B, Z, BC);
        if (boco==0) return 0;
        if (boco->state==0) {
            cgi_error("ReferenceState_t undefined under CGNSBase %d, Zone %d, BC_t %d",B,Z,BC);
            return 0;
        } else return boco->state;
     /* defined under BCDataSet_t */
    } else {
        cgns_dataset *dataset = cgi_get_dataset(cg, B, Z, BC, Dset);
        if (dataset==0) return 0;
        if (dataset->state==0) {
            cgi_error("ReferenceState_t undefined under CGNSBase %d, Zone %d, BC_t %d, BCDataSet %d", B,Z,BC,Dset);
            return 0;
        } else return dataset->state;
    }
}

cgns_subreg *cgi_get_subreg(cgns_file *cg, int B, int Z, int S)
{
    cgns_zone *zone;

    zone = cgi_get_zone(cg, B, Z);
    if (zone==0) return 0;

    if (S > 0 && S <= zone->nsubreg) return &(zone->subreg[S-1]);

    cgi_error("ZoneSubRegion node number %d invalid", S);
    return NULL;
}

/******************* Functions related to cg_goto **********************************/

static int cgi_add_posit(void *pos, char *label, int index, double id)
{
    if (posit_depth == CG_MAX_GOTO_DEPTH) {
        cgi_error("max goto depth exceeded");
        return CG_ERROR;
    }
    posit_stack[posit_depth].posit = pos;
    strcpy (posit_stack[posit_depth].label, label);
    posit_stack[posit_depth].index = index;
    posit_stack[posit_depth].id = id;
    posit = &posit_stack[posit_depth++];
    return CG_OK;
}

static int cgi_next_posit(char *label, int index, char *name)
{
    int n;

    /* CGNSBase_t */

    if (0 == strcmp (posit->label, "CGNSBase_t")) {
        cgns_base *b = (cgns_base *)posit->posit;
        if (0 == strcmp (label, "Zone_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nzones; n++) {
                    if (0 == strcmp (b->zone[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nzones) {
                posit_zone = index + 1;
                return cgi_add_posit((void *)&b->zone[index],
                           label, index + 1, b->zone[index].id);
            }
        }
        else if (0 == strcmp (label, "ReferenceState_t")) {
            if (b->state &&
                (index == 1 || 0 == strcmp (b->state->name, name))) {
                return cgi_add_posit((void *)b->state,
                           label, 1, b->state->id);
            }
        }
        else if (0 == strcmp (label, "Family_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nfamilies; n++) {
                    if (0 == strcmp (b->family[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nfamilies) {
                return cgi_add_posit((void *)&b->family[index],
                           label, index + 1, b->family[index].id);
            }
        }
        else if (0 == strcmp (label, "BaseIterativeData_t")) {
            if (b->biter &&
                (index == 1 || 0 == strcmp (b->biter->name, name))) {
                return cgi_add_posit((void *)b->biter,
                           label, 1, b->biter->id);
            }
        }
        else if (0 == strcmp (label, "ConvergenceHistory_t")) {
            if (b->converg &&
                (index == 1 || 0 == strcmp (b->converg->name, name))) {
                return cgi_add_posit((void *)b->converg,
                           label, 1, b->converg->id);
            }
        }
        else if (0 == strcmp (label, "FlowEquationSet_t")) {
            if (b->equations &&
                (index == 1 || 0 == strcmp (b->equations->name, name))) {
                return cgi_add_posit((void *)b->equations,
                           label, 1, b->equations->id);
            }
        }
        else if (0 == strcmp (label, "IntegralData_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nintegrals; n++) {
                    if (0 == strcmp (b->integral[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nintegrals) {
                return cgi_add_posit((void *)&b->integral[index],
                           label, index + 1, b->integral[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nuser_data; n++) {
                    if (0 == strcmp (b->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nuser_data) {
                return cgi_add_posit((void *)&b->user_data[index],
                           label, index + 1, b->user_data[index].id);
            }
        }
        else if (0 == strcmp (label, "Gravity_t")) {
            if (b->gravity &&
                (index == 1 || 0 == strcmp (b->gravity->name, name))) {
                return cgi_add_posit((void *)b->gravity,
                           label, 1, b->gravity->id);
            }
        }
        else if (0 == strcmp (label, "Axisymmetry_t")) {
            if (b->axisym &&
                (index == 1 || 0 == strcmp (b->axisym->name, name))) {
                return cgi_add_posit((void *)b->axisym,
                           label, 1, b->axisym->id);
            }
        }
        else if (0 == strcmp (label, "RotatingCoordinates_t")) {
            if (b->rotating &&
                (index == 1 || 0 == strcmp (b->rotating->name, name))) {
                return cgi_add_posit((void *)b->rotating,
                           label, 1, b->rotating->id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* Zone_t */

    else if (0 == strcmp (posit->label, "Zone_t")) {
        cgns_zone *z = (cgns_zone *)posit->posit;
        if (0 == strcmp (label, "GridCoordinates_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nzcoor; n++) {
                    if (0 == strcmp (z->zcoor[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index <  z->nzcoor) {
                return cgi_add_posit((void *)&z->zcoor[index],
                           label, index + 1, z->zcoor[index].id);
            }
        }
        else if (0 == strcmp (label, "ZoneIterativeData_t")) {
            if (z->ziter &&
                (index == 1 || 0 == strcmp (z->ziter->name, name))) {
                return cgi_add_posit((void *)z->ziter,
                           label, 1, z->ziter->id);
            }
        }
        else if (0 == strcmp (label, "Elements_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nsections; n++) {
                    if (0 == strcmp (z->section[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nsections) {
                return cgi_add_posit((void *)&z->section[index],
                           label, index + 1, z->section[index].id);
            }
        }
        else if (0 == strcmp (label, "FlowSolution_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nsols; n++) {
                    if (0 == strcmp (z->sol[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nsols) {
                return cgi_add_posit((void *)&z->sol[index],
                           label, index + 1, z->sol[index].id);
            }
        }
        else if (0 == strcmp (label, "RigidGridMotion_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nrmotions; n++) {
                    if (0 == strcmp (z->rmotion[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nrmotions) {
                return cgi_add_posit((void *)&z->rmotion[index],
                           label, index + 1, z->rmotion[index].id);
            }
        }
        else if (0 == strcmp (label, "ArbitraryGridMotion_t")) {
            if (--index < 0) {
                for (n = 0; n < z->namotions; n++) {
                    if (0 == strcmp (z->amotion[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->namotions) {
                return cgi_add_posit((void *)&z->amotion[index],
                           label, index + 1, z->amotion[index].id);
            }
        }
        else if (0 == strcmp (label, "ZoneGridConnectivity_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nzconn; n++) {
                    if (0 == strcmp (z->zconn[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nzconn) {
                return cgi_add_posit((void *)&z->zconn[index],
                           label, index + 1, z->zconn[index].id);
            }
        }
        else if (0 == strcmp (label, "ZoneBC_t")) {
            if (z->zboco &&
                (index == 1 || 0 == strcmp (z->zboco->name, name))) {
                return cgi_add_posit((void *)z->zboco,
                           label, 1, z->zboco->id);
            }
        }
        else if (0 == strcmp (label, "DiscreteData_t")) {
            if (--index < 0) {
                for (n = 0; n < z->ndiscrete; n++) {
                    if (0 == strcmp (z->discrete[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->ndiscrete) {
                return cgi_add_posit((void *)&z->discrete[index],
                           label, index + 1, z->discrete[index].id);
            }
        }
        else if (0 == strcmp (label, "FlowEquationSet_t")) {
            if (z->equations &&
                (index == 1 || 0 == strcmp (z->equations->name, name))) {
                return cgi_add_posit((void *)z->equations,
                           label, 1, z->equations->id);
            }
        }
        else if (0 == strcmp (label, "ConvergenceHistory_t")) {
            if (z->converg &&
                (index == 1 || 0 == strcmp (z->converg->name, name))) {
                return cgi_add_posit((void *)z->converg,
                           label, 1, z->converg->id);
            }
        }
        else if (0 == strcmp (label, "IntegralData_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nintegrals; n++) {
                    if (0 == strcmp (z->integral[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nintegrals) {
                return cgi_add_posit((void *)&z->integral[index],
                           label, index + 1, z->integral[index].id);
            }
        }
        else if (0 == strcmp (label, "ReferenceState_t")) {
            if (z->state &&
                (index == 1 || 0 == strcmp (z->state->name, name))) {
                return cgi_add_posit((void *)z->state,
                           label, 1, z->state->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nuser_data; n++) {
                    if (0 == strcmp (z->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nuser_data) {
                return cgi_add_posit((void *)&z->user_data[index],
                           label, index + 1, z->user_data[index].id);
            }
        }
        else if (0 == strcmp (label, "RotatingCoordinates_t")) {
            if (z->rotating &&
                (index == 1 || 0 == strcmp (z->rotating->name, name))) {
                return cgi_add_posit((void *)z->rotating,
                           label, 1, z->rotating->id);
            }
        }
        else if (0 == strcmp (label, "ZoneSubRegion_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nsubreg; n++) {
                    if (0 == strcmp (z->subreg[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nsubreg) {
                return cgi_add_posit((void *)&z->subreg[index],
                           label, index + 1, z->subreg[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* GridCoordinates_t */

    else if (0 == strcmp (posit->label, "GridCoordinates_t")) {
        cgns_zcoor *z = (cgns_zcoor *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < z->ncoords; n++) {
                    if (0 == strcmp (z->coord[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->ncoords) {
                return cgi_add_posit((void *)&z->coord[index],
                           label, index + 1, z->coord[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nuser_data; n++) {
                    if (0 == strcmp (z->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nuser_data) {
                return cgi_add_posit((void *)&z->user_data[index],
                           label, index + 1, z->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* FlowSolution_t */

    else if (0 == strcmp (posit->label, "FlowSolution_t")) {
        cgns_sol *s = (cgns_sol *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < s->nfields; n++) {
                    if (0 == strcmp (s->field[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < s->nfields) {
                return cgi_add_posit((void *)&s->field[index],
                           label, index + 1, s->field[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < s->nuser_data; n++) {
                    if (0 == strcmp (s->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < s->nuser_data) {
                return cgi_add_posit((void *)&s->user_data[index],
                           label, index + 1, s->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* ZoneGridConnectivity_t */

    else if (0 == strcmp (posit->label, "ZoneGridConnectivity_t")) {
        cgns_zconn *z = (cgns_zconn *)posit->posit;
        if (0 == strcmp (label, "OversetHoles_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nholes; n++) {
                    if (0 == strcmp (z->hole[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nholes) {
                return cgi_add_posit((void *)&z->hole[index],
                           label, index + 1, z->hole[index].id);
            }
        }
        else if (0 == strcmp (label, "GridConnectivity_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nconns; n++) {
                    if (0 == strcmp (z->conn[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nconns) {
                return cgi_add_posit((void *)&z->conn[index],
                           label, index + 1, z->conn[index].id);
            }
        }
        else if (0 == strcmp (label, "GridConnectivity1to1_t")) {
            if (--index < 0) {
                for (n = 0; n < z->n1to1; n++) {
                    if (0 == strcmp (z->one21[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->n1to1) {
                return cgi_add_posit((void *)&z->one21[index],
                           label, index + 1, z->one21[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nuser_data; n++) {
                    if (0 == strcmp (z->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nuser_data) {
                return cgi_add_posit((void *)&z->user_data[index],
                           label, index + 1, z->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* OversetHoles_t */

    else if (0 == strcmp (posit->label, "OversetHoles_t")) {
        cgns_hole *h = (cgns_hole *)posit->posit;
        if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < h->nuser_data; n++) {
                    if (0 == strcmp (h->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < h->nuser_data) {
                return cgi_add_posit((void *)&h->user_data[index],
                           label, index + 1, h->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* GridConnectivity_t */

    else if (0 == strcmp (posit->label, "GridConnectivity_t")) {
        cgns_conn *c = (cgns_conn *)posit->posit;
        if (0 == strcmp (label, "GridConnectivityProperty_t")) {
            if (c->cprop &&
                (index == 1 || 0 == strcmp (c->cprop->name, name))) {
                return cgi_add_posit((void *)c->cprop,
                           label, 1, c->cprop->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < c->nuser_data; n++) {
                    if (0 == strcmp (c->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < c->nuser_data) {
                return cgi_add_posit((void *)&c->user_data[index],
                           label, index + 1, c->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* GridConnectivity1to1_t */

    else if (0 == strcmp (posit->label, "GridConnectivity1to1_t")) {
        cgns_1to1 *c = (cgns_1to1 *)posit->posit;
        if (0 == strcmp (label, "GridConnectivityProperty_t")) {
            if (c->cprop &&
                (index == 1 || 0 == strcmp (c->cprop->name, name))) {
                return cgi_add_posit((void *)c->cprop,
                           label, 1, c->cprop->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < c->nuser_data; n++) {
                    if (0 == strcmp (c->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < c->nuser_data) {
                return cgi_add_posit((void *)&c->user_data[index],
                           label, index + 1, c->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* ZoneBC_t */

    else if (0 == strcmp (posit->label, "ZoneBC_t")) {
        cgns_zboco *z = (cgns_zboco *)posit->posit;
        if (0 == strcmp (label, "BC_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nbocos; n++) {
                    if (0 == strcmp (z->boco[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nbocos) {
                return cgi_add_posit((void *)&z->boco[index],
                           label, index + 1, z->boco[index].id);
            }
        }
        else if (0 == strcmp (label, "ReferenceState_t")) {
            if (z->state &&
                (index == 1 || 0 == strcmp (z->state->name, name))) {
                return cgi_add_posit((void *)z->state,
                           label, 1, z->state->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nuser_data; n++) {
                    if (0 == strcmp (z->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nuser_data) {
                return cgi_add_posit((void *)&z->user_data[index],
                           label, index + 1, z->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* BC_t */

    else if (0 == strcmp (posit->label, "BC_t")) {
        cgns_boco *b = (cgns_boco *)posit->posit;
        if (0 == strcmp (label, "BCDataSet_t")) {
            if (--index < 0) {
                for (n = 0; n < b->ndataset; n++) {
                    if (0 == strcmp (b->dataset[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->ndataset) {
                return cgi_add_posit((void *)&b->dataset[index],
                           label, index + 1, b->dataset[index].id);
            }
        }
        else if (0 == strcmp (label, "BCProperty_t")) {
            if (b->bprop &&
                (index == 1 || 0 == strcmp (b->bprop->name, name))) {
                return cgi_add_posit((void *)b->bprop,
                           label, 1, b->bprop->id);
            }
        }
        else if (0 == strcmp (label, "ReferenceState_t")) {
            if (b->state &&
                (index == 1 || 0 == strcmp (b->state->name, name))) {
                return cgi_add_posit((void *)b->state,
                           label, 1, b->state->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nuser_data; n++) {
                    if (0 == strcmp (b->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nuser_data) {
                return cgi_add_posit((void *)&b->user_data[index],
                           label, index + 1, b->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* BCDataSet_t and FamilyBCDataSet_t */

    else if (0 == strcmp (posit->label, "BCDataSet_t") ||
             0 == strcmp (posit->label, "FamilyBCDataSet_t")) {
        cgns_dataset *d = (cgns_dataset *)posit->posit;
        if (0 == strcmp (label, "BCData_t")) {
            if (d->dirichlet && (index == CGNS_ENUMV(Dirichlet) ||
                0 == strcmp (d->dirichlet->name, name))) {
                return cgi_add_posit((void *)d->dirichlet,
                           label, 1, d->dirichlet->id);
            }
            if (d->neumann && (index == CGNS_ENUMV(Neumann) ||
                0 == strcmp (d->neumann->name, name))) {
                return cgi_add_posit((void *)d->neumann,
                           label, 1, d->neumann->id);
            }
        }
        else if (0 == strcmp (label, "ReferenceState_t")) {
            if (d->state &&
                (index == 1 || 0 == strcmp (d->state->name, name))) {
                return cgi_add_posit((void *)d->state,
                           label, 1, d->state->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < d->nuser_data; n++) {
                    if (0 == strcmp (d->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < d->nuser_data) {
                return cgi_add_posit((void *)&d->user_data[index],
                           label, index + 1, d->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* BCData_t */

    else if (0 == strcmp (posit->label, "BCData_t")) {
        cgns_bcdata *b = (cgns_bcdata *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < b->narrays; n++) {
                    if (0 == strcmp (b->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->narrays) {
                return cgi_add_posit((void *)&b->array[index],
                           label, index + 1, b->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nuser_data; n++) {
                    if (0 == strcmp (b->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nuser_data) {
                return cgi_add_posit((void *)&b->user_data[index],
                           label, index + 1, b->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* DiscreteData_t */

    else if (0 == strcmp (posit->label, "DiscreteData_t")) {
        cgns_discrete *d = (cgns_discrete *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < d->narrays; n++) {
                    if (0 == strcmp (d->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < d->narrays) {
                return cgi_add_posit((void *)&d->array[index],
                           label, index + 1, d->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < d->nuser_data; n++) {
                    if (0 == strcmp (d->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < d->nuser_data) {
                return cgi_add_posit((void *)&d->user_data[index],
                           label, index + 1, d->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* FlowEquationSet_t */

    else if (0 == strcmp (posit->label, "FlowEquationSet_t")) {
        cgns_equations *e = (cgns_equations *)posit->posit;
        if (0 == strcmp (label, "GoverningEquations_t")) {
            if (e->governing &&
                (index == 1 || 0 == strcmp (e->governing->name, name))) {
                return cgi_add_posit((void *)e->governing,
                           label, 1, e->governing->id);
            }
        }
        else if (0 == strcmp (label, "GasModel_t")) {
            if (e->gas &&
                (index == 1 || 0 == strcmp (e->gas->name, name))) {
                return cgi_add_posit((void *)e->gas,
                           label, 1, e->gas->id);
            }
        }
        else if (0 == strcmp (label, "ViscosityModel_t")) {
            if (e->visc &&
                (index == 1 || 0 == strcmp (e->visc->name, name))) {
                return cgi_add_posit((void *)e->visc,
                           label, 1, e->visc->id);
            }
        }
        else if (0 == strcmp (label, "ThermalConductivityModel_t")) {
            if (e->conduct &&
                (index == 1 || 0 == strcmp (e->conduct->name, name))) {
                return cgi_add_posit((void *)e->conduct,
                           label, 1, e->conduct->id);
            }
        }
        else if (0 == strcmp (label, "TurbulenceModel_t")) {
            if (e->turbulence &&
                (index == 1 || 0 == strcmp (e->turbulence->name, name))) {
                return cgi_add_posit((void *)e->turbulence,
                           label, 1, e->turbulence->id);
            }
        }
        else if (0 == strcmp (label, "TurbulenceClosure_t")) {
            if (e->closure &&
                (index == 1 || 0 == strcmp (e->closure->name, name))) {
                return cgi_add_posit((void *)e->closure,
                           label, 1, e->closure->id);
            }
        }
        else if (0 == strcmp (label, "ThermalRelaxationModel_t")) {
            if (e->relaxation &&
                (index == 1 || 0 == strcmp (e->relaxation->name, name))) {
                return cgi_add_posit((void *)e->relaxation,
                           label, 1, e->relaxation->id);
            }
        }
        else if (0 == strcmp (label, "ChemicalKineticsModel_t")) {
            if (e->chemkin &&
                (index == 1 || 0 == strcmp (e->chemkin->name, name))) {
                return cgi_add_posit((void *)e->chemkin,
                           label, 1, e->chemkin->id);
            }
        }
        else if (0 == strcmp (label, "EMConductivityModel_t")) {
            if (e->emconduct &&
                (index == 1 || 0 == strcmp (e->emconduct->name, name))) {
                return cgi_add_posit((void *)e->emconduct,
                           label, 1, e->emconduct->id);
            }
        }
        else if (0 == strcmp (label, "EMElectricFieldModel_t")) {
            if (e->elecfield &&
                (index == 1 || 0 == strcmp (e->elecfield->name, name))) {
                return cgi_add_posit((void *)e->elecfield,
                           label, 1, e->elecfield->id);
            }
        }
        else if (0 == strcmp (label, "EMMagneticFieldModel_t")) {
            if (e->magnfield &&
                (index == 1 || 0 == strcmp (e->magnfield->name, name))) {
                return cgi_add_posit((void *)e->magnfield,
                           label, 1, e->magnfield->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < e->nuser_data; n++) {
                    if (0 == strcmp (e->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < e->nuser_data) {
                return cgi_add_posit((void *)&e->user_data[index],
                           label, index + 1, e->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* GoverningEquations_t */

    else if (0 == strcmp (posit->label, "GoverningEquations_t")) {
        cgns_governing *g = (cgns_governing *)posit->posit;
        if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < g->nuser_data; n++) {
                    if (0 == strcmp (g->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < g->nuser_data) {
                return cgi_add_posit((void *)&g->user_data[index],
                           label, index + 1, g->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* GasModel_t */
    /* ViscosityModel_t */
    /* ThermalConductivityModel_t */
    /* TurbulenceModel_t */
    /* TurbulenceClosure_t */
    /* ThermalRelaxationModel_t */
    /* ChemicalKineticsModel_t */
    /* EMConductivityModel_t */
    /* EMElectricFieldModel_t */
    /* EMMagneticFieldModel_t */

    else if (0 == strcmp (posit->label, "GasModel_t") ||
             0 == strcmp (posit->label, "ViscosityModel_t") ||
             0 == strcmp (posit->label, "ThermalConductivityModel_t") ||
             0 == strcmp (posit->label, "TurbulenceModel_t") ||
             0 == strcmp (posit->label, "TurbulenceClosure_t") ||
             0 == strcmp (posit->label, "ThermalRelaxationModel_t") ||
             0 == strcmp (posit->label, "ChemicalKineticsModel_t") ||
             0 == strcmp (posit->label, "EMConductivityModel_t") ||
             0 == strcmp (posit->label, "EMElectricFieldModel_t") ||
             0 == strcmp (posit->label, "EMMagneticFieldModel_t")) {
        cgns_model *m = (cgns_model *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < m->narrays; n++) {
                    if (0 == strcmp (m->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < m->narrays) {
                return cgi_add_posit((void *)&m->array[index],
                           label, index + 1, m->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < m->nuser_data; n++) {
                    if (0 == strcmp (m->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < m->nuser_data) {
                return cgi_add_posit((void *)&m->user_data[index],
                           label, index + 1, m->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* ConvergenceHistory_t */

    else if (0 == strcmp (posit->label, "ConvergenceHistory_t")) {
        cgns_converg *c = (cgns_converg *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < c->narrays; n++) {
                    if (0 == strcmp (c->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < c->narrays) {
                return cgi_add_posit((void *)&c->array[index],
                           label, index + 1, c->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < c->nuser_data; n++) {
                    if (0 == strcmp (c->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < c->nuser_data) {
                return cgi_add_posit((void *)&c->user_data[index],
                           label, index + 1, c->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* IntegralData_t */

    else if (0 == strcmp (posit->label, "IntegralData_t")) {
        cgns_integral *i = (cgns_integral *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < i->narrays; n++) {
                    if (0 == strcmp (i->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < i->narrays) {
                return cgi_add_posit((void *)&i->array[index],
                           label, index + 1, i->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < i->nuser_data; n++) {
                    if (0 == strcmp (i->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < i->nuser_data) {
                return cgi_add_posit((void *)&i->user_data[index],
                           label, index + 1, i->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* ReferenceState_t */

    else if (0 == strcmp (posit->label, "ReferenceState_t")) {
        cgns_state *s = (cgns_state *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < s->narrays; n++) {
                    if (0 == strcmp (s->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < s->narrays) {
                return cgi_add_posit((void *)&s->array[index],
                           label, index + 1, s->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < s->nuser_data; n++) {
                    if (0 == strcmp (s->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < s->nuser_data) {
                return cgi_add_posit((void *)&s->user_data[index],
                           label, index + 1, s->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* Elements_t */

    else if (0 == strcmp (posit->label, "Elements_t")) {
        cgns_section *s = (cgns_section *)posit->posit;
        if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < s->nuser_data; n++) {
                    if (0 == strcmp (s->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < s->nuser_data) {
                return cgi_add_posit((void *)&s->user_data[index],
                           label, index + 1, s->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* Family_t */

    else if (0 == strcmp (posit->label, "Family_t")) {
        cgns_family *f = (cgns_family *)posit->posit;
        if (0 == strcmp (label, "GeometryReference_t")) {
            if (--index < 0) {
                for (n = 0; n < f->ngeos; n++) {
                    if (0 == strcmp (f->geo[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < f->ngeos) {
                return cgi_add_posit((void *)&f->geo[index],
                           label, index + 1, f->geo[index].id);
            }
        }
        else if (0 == strcmp (label, "FamilyBC_t")) {
            if (--index < 0) {
                for (n = 0; n < f->nfambc; n++) {
                    if (0 == strcmp (f->fambc[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < f->nfambc) {
                return cgi_add_posit((void *)&f->fambc[index],
                           label, index + 1, f->fambc[index].id);
            }
        }
        else if (0 == strcmp (label, "RotatingCoordinates_t")) {
            if (f->rotating &&
                (index == 1 || 0 == strcmp (f->rotating->name, name))) {
                return cgi_add_posit((void *)f->rotating,
                           label, 1, f->rotating->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < f->nuser_data; n++) {
                    if (0 == strcmp (f->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < f->nuser_data) {
                return cgi_add_posit((void *)&f->user_data[index],
                           label, index + 1, f->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* GeometryReference_t */

    else if (0 == strcmp (posit->label, "GeometryReference_t")) {
        cgns_geo *g = (cgns_geo *)posit->posit;
        if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < g->nuser_data; n++) {
                    if (0 == strcmp (g->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < g->nuser_data) {
                return cgi_add_posit((void *)&g->user_data[index],
                           label, index + 1, g->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* FamilyBC_t */

    else if (0 == strcmp (posit->label, "FamilyBC_t")) {
        cgns_fambc *f = (cgns_fambc *)posit->posit;
        if (0 == strcmp (label, "FamilyBCDataSet_t") ||
            /* backwards compatibily */
            0 == strcmp (label, "BCDataSet_t")) {
            if (--index < 0) {
                for (n = 0; n < f->ndataset; n++) {
                    if (0 == strcmp (f->dataset[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < f->ndataset) {
                return cgi_add_posit((void *)&f->dataset[index],
                           "FamilyBCDataSet_t", index + 1,
                           f->dataset[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* RigidGridMotion_t */

    else if (0 == strcmp (posit->label, "RigidGridMotion_t")) {
        cgns_rmotion *m = (cgns_rmotion *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < m->narrays; n++) {
                    if (0 == strcmp (m->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < m->narrays) {
                return cgi_add_posit((void *)&m->array[index],
                           label, index + 1, m->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < m->nuser_data; n++) {
                    if (0 == strcmp (m->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < m->nuser_data) {
                return cgi_add_posit((void *)&m->user_data[index],
                           label, index + 1, m->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* ArbitraryGridMotion_t */

    else if (0 == strcmp (posit->label, "ArbitraryGridMotion_t")) {
        cgns_amotion *m = (cgns_amotion *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < m->narrays; n++) {
                    if (0 == strcmp (m->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < m->narrays) {
                return cgi_add_posit((void *)&m->array[index],
                           label, index + 1, m->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < m->nuser_data; n++) {
                    if (0 == strcmp (m->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < m->nuser_data) {
                return cgi_add_posit((void *)&m->user_data[index],
                           label, index + 1, m->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* BaseIterativeData_t */

    else if (0 == strcmp (posit->label, "BaseIterativeData_t")) {
        cgns_biter *b = (cgns_biter *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < b->narrays; n++) {
                    if (0 == strcmp (b->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->narrays) {
                return cgi_add_posit((void *)&b->array[index],
                           label, index + 1, b->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nuser_data; n++) {
                    if (0 == strcmp (b->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nuser_data) {
                return cgi_add_posit((void *)&b->user_data[index],
                           label, index + 1, b->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* ZoneIterativeData_t */

    else if (0 == strcmp (posit->label, "ZoneIterativeData_t")) {
        cgns_ziter *z = (cgns_ziter *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < z->narrays; n++) {
                    if (0 == strcmp (z->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->narrays) {
                return cgi_add_posit((void *)&z->array[index],
                           label, index + 1, z->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < z->nuser_data; n++) {
                    if (0 == strcmp (z->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < z->nuser_data) {
                return cgi_add_posit((void *)&z->user_data[index],
                           label, index + 1, z->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* UserDefinedData_t */

    else if (0 == strcmp (posit->label, "UserDefinedData_t")) {
        cgns_user_data *u = (cgns_user_data *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < u->narrays; n++) {
                    if (0 == strcmp (u->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < u->narrays) {
                return cgi_add_posit((void *)&u->array[index],
                           label, index + 1, u->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < u->nuser_data; n++) {
                    if (0 == strcmp (u->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < u->nuser_data) {
                return cgi_add_posit((void *)&u->user_data[index],
                           label, index + 1, u->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* Gravity_t */

    else if (0 == strcmp (posit->label, "Gravity_t")) {
        cgns_gravity *g = (cgns_gravity *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < g->narrays; n++) {
                    if (0 == strcmp (g->vector[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < g->narrays) {
                return cgi_add_posit((void *)&g->vector[index],
                           label, index + 1, g->vector[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < g->nuser_data; n++) {
                    if (0 == strcmp (g->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < g->nuser_data) {
                return cgi_add_posit((void *)&g->user_data[index],
                           label, index + 1, g->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* Axisymmetry_t */

    else if (0 == strcmp (posit->label, "Axisymmetry_t")) {
        cgns_axisym *a = (cgns_axisym *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < a->narrays; n++) {
                    if (0 == strcmp (a->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < a->narrays) {
                return cgi_add_posit((void *)&a->array[index],
                           label, index + 1, a->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < a->nuser_data; n++) {
                    if (0 == strcmp (a->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < a->nuser_data) {
                return cgi_add_posit((void *)&a->user_data[index],
                           label, index + 1, a->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* RotatingCoordinates_t */

    else if (0 == strcmp (posit->label, "RotatingCoordinates_t")) {
        cgns_rotating *r = (cgns_rotating *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < r->narrays; n++) {
                    if (0 == strcmp (r->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < r->narrays) {
                return cgi_add_posit((void *)&r->array[index],
                           label, index + 1, r->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < r->nuser_data; n++) {
                    if (0 == strcmp (r->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < r->nuser_data) {
                return cgi_add_posit((void *)&r->user_data[index],
                           label, index + 1, r->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* BCProperty_t */

    else if (0 == strcmp (posit->label, "BCProperty_t")) {
        cgns_bprop *b = (cgns_bprop *)posit->posit;
        if (0 == strcmp (label, "WallFunction_t")) {
            if (b->bcwall &&
                (index == 1 || 0 == strcmp (b->bcwall->name, name))) {
                return cgi_add_posit((void *)b->bcwall,
                           label, 1, b->bcwall->id);
            }
        }
        else if (0 == strcmp (label, "Area_t")) {
            if (b->bcarea &&
                (index == 1 || 0 == strcmp (b->bcarea->name, name))) {
                return cgi_add_posit((void *)b->bcarea,
                           label, 1, b->bcarea->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < b->nuser_data; n++) {
                    if (0 == strcmp (b->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < b->nuser_data) {
                return cgi_add_posit((void *)&b->user_data[index],
                           label, index + 1, b->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* WallFunction_t */

    else if (0 == strcmp (posit->label, "WallFunction_t")) {
        cgns_bcwall *w = (cgns_bcwall *)posit->posit;
        if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < w->nuser_data; n++) {
                    if (0 == strcmp (w->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < w->nuser_data) {
                return cgi_add_posit((void *)&w->user_data[index],
                           label, index + 1, w->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* Area_t */

    else if (0 == strcmp (posit->label, "Area_t")) {
        cgns_bcarea *a = (cgns_bcarea *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < a->narrays; n++) {
                    if (0 == strcmp (a->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < a->narrays) {
                return cgi_add_posit((void *)&a->array[index],
                           label, index + 1, a->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < a->nuser_data; n++) {
                    if (0 == strcmp (a->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < a->nuser_data) {
                return cgi_add_posit((void *)&a->user_data[index],
                           label, index + 1, a->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* GridConnectivityProperty_t */

    else if (0 == strcmp (posit->label, "GridConnectivityProperty_t")) {
        cgns_cprop *c = (cgns_cprop *)posit->posit;
        if (0 == strcmp (label, "Periodic_t")) {
            if (c->cperio &&
                (index == 1 || 0 == strcmp (c->cperio->name, name))) {
                return cgi_add_posit((void *)c->cperio,
                           label, 1, c->cperio->id);
            }
        }
        else if (0 == strcmp (label, "AverageInterface_t")) {
            if (c->caverage &&
                (index == 1 || 0 == strcmp (c->caverage->name, name))) {
                return cgi_add_posit((void *)c->caverage,
                           label, 1, c->caverage->id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < c->nuser_data; n++) {
                    if (0 == strcmp (c->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < c->nuser_data) {
                return cgi_add_posit((void *)&c->user_data[index],
                           label, index + 1, c->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* Periodic_t */

    else if (0 == strcmp (posit->label, "Periodic_t")) {
        cgns_cperio *p = (cgns_cperio *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < p->narrays; n++) {
                    if (0 == strcmp (p->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < p->narrays) {
                return cgi_add_posit((void *)&p->array[index],
                           label, index + 1, p->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < p->nuser_data; n++) {
                    if (0 == strcmp (p->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < p->nuser_data) {
                return cgi_add_posit((void *)&p->user_data[index],
                           label, index + 1, p->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* AverageInterface_t */

    else if (0 == strcmp (posit->label, "AverageInterface_t")) {
        cgns_caverage *a = (cgns_caverage *)posit->posit;
        if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < a->nuser_data; n++) {
                    if (0 == strcmp (a->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < a->nuser_data) {
                return cgi_add_posit((void *)&a->user_data[index],
                           label, index + 1, a->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* ZoneSubRegion_t */

    else if (0 == strcmp (posit->label, "ZoneSubRegion_t")) {
        cgns_subreg *r = (cgns_subreg *)posit->posit;
        if (0 == strcmp (label, "DataArray_t")) {
            if (--index < 0) {
                for (n = 0; n < r->narrays; n++) {
                    if (0 == strcmp (r->array[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < r->narrays) {
                return cgi_add_posit((void *)&r->array[index],
                           label, index + 1, r->array[index].id);
            }
        }
        else if (0 == strcmp (label, "UserDefinedData_t")) {
            if (--index < 0) {
                for (n = 0; n < r->nuser_data; n++) {
                    if (0 == strcmp (r->user_data[n].name, name)) {
                        index = n;
                        break;
                    }
                }
            }
            if (index >= 0 && index < r->nuser_data) {
                return cgi_add_posit((void *)&r->user_data[index],
                           label, index + 1, r->user_data[index].id);
            }
        }
        else
            return CG_INCORRECT_PATH;
    }

    /* invalid */

    else
        return CG_INCORRECT_PATH;

    return CG_NODE_NOT_FOUND;
}

int cgi_update_posit(int cnt, int *index, char **label)
{
    int n, ierr;
    double pid, id;
    char lab[33], name[33];

    if (posit == 0) {
        cgi_error("goto position not set");
        return CG_ERROR;
    }

    for (n = 0; n < cnt; n++) {
        if (index[n] > 0) {
            strcpy(lab, label[n]);
            *name = 0;
        }
        else if (0 == strcmp(label[n], ".")) {
            continue;
        }
        else if (0 == strcmp(label[n], "..")) {
            if (posit_depth == 1) {
                cgi_error("can't go up beyond CGNSBase_t node");
                posit = 0;
                return CG_ERROR;
            }
            if (0 == strcmp(posit->label, "Zone_t")) posit_zone = 0;
            posit_depth--;
            posit = &posit_stack[posit_depth-1];
            continue;
        }
        else {
            if (cgi_posit_id (&pid)) {
                posit = 0;
                return CG_ERROR;
            }
            strcpy(name, label[n]);
            if (cgio_get_node_id(cg->cgio, pid, name, &id)) {
                posit = 0;
                cgi_error ("goto path not found");
                return CG_NODE_NOT_FOUND;
            }
            if (cgio_get_label(cg->cgio, id, lab)) {
                posit = 0;
                cg_io_error("cgio_get_label");
                return CG_ERROR;
            }
        }
        ierr = cgi_next_posit(lab, index[n], name);
        if (ierr) {
            if (ierr == CG_INCORRECT_PATH) {
                cgi_error("can't go to label '%s' under '%s'",
                    lab, posit->label);
            }
            if (ierr == CG_NODE_NOT_FOUND) {
                if (index[n] > 0)
                    cgi_error("index %d, label '%s' not a child of '%s'",
                        index[n], lab, posit->label);
                else
                    cgi_error("node '%s' not a child of '%s'",
                        name, posit->label);
            }
            posit = 0;
            return ierr;
        }
    }

    return CG_OK;
}

int cgi_set_posit(int fn, int B, int n, int *index, char **label)
{
    cgns_base *base;

    /* initialize */
    posit = 0;
    posit_file = posit_base = posit_zone = posit_depth = 0;

    /* get file pointer */
    cg = cgi_get_file(fn);
    if (cg == 0) return 0;

    base = cgi_get_base(cg, B);
    if (base == 0) return CG_NODE_NOT_FOUND;

    posit_file = fn;
    posit_base = B;
    cgi_add_posit((void *)base, "CGNSBase_t", B, base->id);

    return cgi_update_posit(n, index, label);
}

int cgi_posit_id(double *posit_id)
{
    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        return 1;
    }
    *posit_id = posit->id;
    return 0;
}

cgns_posit *cgi_get_posit()
{
    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        return NULL;
    }
    return posit;
}

int cgi_posit_index_dim()
{
    if (posit_base) {
        if (posit_zone)
            return cg->base[posit_base-1].zone[posit_zone-1].index_dim;
        return cg->base[posit_base-1].cell_dim;
    }
    return 0;
}

/* All cgi_xxxxx_address functions return the memory address of the given *\
 * xxxxx data structure, depending on the parent pointed to by cg_goto.   *
\* All possible parents of a given data structure must be represented.    */

cgns_descr *cgi_descr_address(int local_mode, int given_no,
                              char const *given_name, int *ier)
{
    cgns_descr *descr=0;
    int n, error1=0, error2=0;
    double parent_id=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of Descriptor_t node:
 *  CGNSBase_t, Zone_t, GridCoordinates_t, Elements_t, FlowSolution_t,
 *  DiscreteData_t, ZoneGridConnectivity_t, GridConnectivity1to1_t,
 *  GridConnectivity_t, OversetHoles_t, ZoneBC_t, BC_t, BCDataSet_t,
 *  BCData_t, FlowEquationSet_t, GoverningEquations_t, GasModel_t,
 *  ViscosityModel_t, ThermalConductivityModel_t, TurbulenceClosure_t,
 *  TurbulenceModel_t, ThermalRelaxationModel_t, ChemicalKineticsModel_t,
 *  EMElectricFieldModel_t, EMMagneticFieldModel_t,
 *  ConvergenceHistory_t, IntegralData_t, ReferenceState_t,
 *  DataArray_t, Family_t, GeometryReference_t, RigidGridMotion_t,
 *  ArbitraryGridMotion_t, BaseIterativeData_t, ZoneIterativeData_t,
 *  UserDefinedData_t, Gravity_t, Axisymmetry_t, RotatingCoordinates_t,
 *  BCProperty_t, WallFunction_t, Area_t,
 *  GridConnectivityProperty_t, Periodic_t, AverageInterface_t
 *  FamilyBCDataSet_t
 */

    if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4MULTIPLE(cgns_base, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4MULTIPLE(cgns_zone, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"GridCoordinates_t")==0)
        ADDRESS4MULTIPLE(cgns_zcoor, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"Elements_t")==0)
        ADDRESS4MULTIPLE(cgns_section, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"FlowSolution_t")==0)
        ADDRESS4MULTIPLE(cgns_sol, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"DiscreteData_t")==0)
        ADDRESS4MULTIPLE(cgns_discrete, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"ZoneGridConnectivity_t")==0)
        ADDRESS4MULTIPLE(cgns_zconn, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"GridConnectivity1to1_t")==0)
        ADDRESS4MULTIPLE(cgns_1to1, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"GridConnectivity_t")==0)
        ADDRESS4MULTIPLE(cgns_conn, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"OversetHoles_t")==0)
        ADDRESS4MULTIPLE(cgns_hole, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"ZoneBC_t")==0)
        ADDRESS4MULTIPLE(cgns_zboco, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4MULTIPLE(cgns_boco, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"BCDataSet_t")==0 ||
             strcmp(posit->label,"FamilyBCDataSet_t")==0)
        ADDRESS4MULTIPLE(cgns_dataset, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"BCData_t")==0)
        ADDRESS4MULTIPLE(cgns_bcdata, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"FlowEquationSet_t")==0)
        ADDRESS4MULTIPLE(cgns_equations, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"GoverningEquations_t")==0)
        ADDRESS4MULTIPLE(cgns_governing, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"GasModel_t")==0 ||
         strcmp(posit->label,"ViscosityModel_t")==0 ||
         strcmp(posit->label,"ThermalConductivityModel_t")==0 ||
         strcmp(posit->label,"TurbulenceModel_t")==0 ||
         strcmp(posit->label,"TurbulenceClosure_t")==0 ||
         strcmp(posit->label,"ThermalRelaxationModel_t")==0 ||
         strcmp(posit->label,"ChemicalKineticsModel_t")==0 ||
         strcmp(posit->label,"EMElectricFieldModel_t")==0 ||
         strcmp(posit->label,"EMMagneticFieldModel_t")==0 ||
         strcmp(posit->label,"EMConductivityModel_t")==0)
        ADDRESS4MULTIPLE(cgns_model, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"ConvergenceHistory_t")==0)
        ADDRESS4MULTIPLE(cgns_converg, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"IntegralData_t")==0)
        ADDRESS4MULTIPLE(cgns_integral, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"ReferenceState_t")==0)
        ADDRESS4MULTIPLE(cgns_state, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"DataArray_t")==0)
        ADDRESS4MULTIPLE(cgns_array, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"Family_t")==0)
        ADDRESS4MULTIPLE(cgns_family, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"GeometryReference_t")==0)
        ADDRESS4MULTIPLE(cgns_geo, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"RigidGridMotion_t")==0)
        ADDRESS4MULTIPLE(cgns_rmotion, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"ArbitraryGridMotion_t")==0)
        ADDRESS4MULTIPLE(cgns_amotion, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"BaseIterativeData_t")==0)
        ADDRESS4MULTIPLE(cgns_biter, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"ZoneIterativeData_t")==0)
        ADDRESS4MULTIPLE(cgns_ziter, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"UserDefinedData_t")==0)
        ADDRESS4MULTIPLE(cgns_user_data, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"Gravity_t")==0)
        ADDRESS4MULTIPLE(cgns_gravity, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"Axisymmetry_t")==0)
        ADDRESS4MULTIPLE(cgns_axisym, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"RotatingCoordinates_t")==0)
        ADDRESS4MULTIPLE(cgns_rotating, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"BCProperty_t")==0)
        ADDRESS4MULTIPLE(cgns_bprop, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"WallFunction_t")==0)
        ADDRESS4MULTIPLE(cgns_bcwall, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"Area_t")==0)
        ADDRESS4MULTIPLE(cgns_bcarea, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"GridConnectivityProperty_t")==0)
        ADDRESS4MULTIPLE(cgns_cprop, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"Periodic_t")==0)
        ADDRESS4MULTIPLE(cgns_cperio, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"AverageInterface_t")==0)
        ADDRESS4MULTIPLE(cgns_caverage, ndescr, descr, cgns_descr)
    else if (strcmp(posit->label,"ZoneSubRegion_t")==0)
        ADDRESS4MULTIPLE(cgns_subreg, ndescr, descr, cgns_descr)
    else {
        cgi_error("Descriptor_t node not supported under '%s' type node (cgi_descr_address)",
            posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }

    if (error1) {
        cgi_error("Duplicate child name found (%s) found under %s",
            given_name, posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (error2) {
        cgi_error("Descriptor number %d doesn't exist under %s",
               given_no, posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {    /* parent_id!=0 only when overwriting */
        if (cgi_delete_node (parent_id, descr->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_descr(descr);
    }
    return descr;
}

char *cgi_famname_address(int local_mode, int *ier)
{
    double *id, parent_id;
    char *family_name=0;
    int nnod;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of FamilyName_t node:
 *  Zone_t, BC_t, ZoneSubRegion_t, UserDefinedData_t
 */
    if (strcmp(posit->label,"Zone_t")==0) {
        cgns_zone *zone = (cgns_zone *)posit->posit;
        family_name = zone->family_name;
        parent_id = zone->id;
    } else if (strcmp(posit->label,"BC_t")==0) {
        cgns_boco *boco = (cgns_boco *)posit->posit;
        family_name = boco->family_name;
        parent_id = boco->id;
    } else if (strcmp(posit->label,"UserDefinedData_t")==0) {
        cgns_user_data *user_data = (cgns_user_data *)posit->posit;
        family_name = user_data->family_name;
        parent_id = user_data->id;
    } else if (strcmp(posit->label,"ZoneSubRegion_t")==0) {
        cgns_subreg *subreg = (cgns_subreg *)posit->posit;
        family_name = subreg->family_name;
        parent_id = subreg->id;
    } else {
        cgi_error("FamilyName_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (cg->mode == CG_MODE_MODIFY && local_mode == CG_MODE_WRITE) {
        if (cgi_get_nodes(parent_id, "FamilyName_t", &nnod, &id)) {
            *ier = CG_ERROR;
            return 0;
        }
        if (nnod>0) {
            if (cgi_delete_node (parent_id, id[0])) {
                (*ier) = CG_ERROR;
                return 0;
            }
            free(id);
        }
    }
    return family_name;
}

cgns_famname *cgi_multfam_address(int local_mode, int given_no,
                                  char const *given_name, int *ier)
{
    cgns_famname *famname=0;
    int n, error1=0, error2=0;
    double parent_id=0;

    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }
    if (0 == strcmp(posit->label, "Zone_t"))
        ADDRESS4MULTIPLE(cgns_zone, nfamname, famname, cgns_famname)
    else if (0 == strcmp(posit->label, "BC_t"))
        ADDRESS4MULTIPLE(cgns_boco, nfamname, famname, cgns_famname)
    else if (0 == strcmp(posit->label, "ZoneSubRegion_t"))
        ADDRESS4MULTIPLE(cgns_subreg, nfamname, famname, cgns_famname)
    else if (0 == strcmp(posit->label, "UserDefinedData_t"))
        ADDRESS4MULTIPLE(cgns_user_data, nfamname, famname, cgns_famname)
    else {
        cgi_error("AdditionalFamilyName_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1) {
        cgi_error("Duplicate child name found (%s) found under %s",
            given_name, posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (error2) {
        cgi_error("AdditionalFamilyName index number %d doesn't exist under %s",
            given_no, posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {     /* parent_id!=0 only when overwriting */
        if (cgi_delete_node (parent_id, famname->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
    }
    return famname;
}

CGNS_ENUMV(DataClass_t) *cgi_dataclass_address(int local_mode, int *ier)
{
    double *id, parent_id;
    CGNS_ENUMV( DataClass_t ) *data_class=0;
    int nnod;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of DataClass_t node:
 *  CGNSBase_t, Zone_t, GridCoordinates_t, FlowSolution_t, DiscreteData_t,
 *  ZoneBC_t, BC_t, BCDataSet_t, BCData_t, FlowEquationSet_t, GasModel_t,
 *  ViscosityModel_t, ThermalConductivityModel_t, TurbulenceClosure_t,
 *  TurbulenceModel_t, ThermalRelaxationModel_t, ChemicalKineticsModel_t,
 *  EMElectricFieldModel_t, EMMagneticFieldModel_t,
 *  ConvergenceHistory_t, IntegralData_t, ReferenceState_t,
 *  DataArray_t, RigidGridMotion_t, ArbitraryGridMotion_t, BaseIterativeData_t,
 *  ZoneIterativeData_t, UserDefinedData_t, Gravity_t, Axisymmetry_t
 *  RotatingCoordinates_t, Periodic_t, FamilyBCDataSet_t
 */
    if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_base, data_class)
    else if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_zone, data_class)
    else if (strcmp(posit->label,"GridCoordinates_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_zcoor, data_class)
    else if (strcmp(posit->label,"FlowSolution_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_sol, data_class)
    else if (strcmp(posit->label,"DiscreteData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_discrete, data_class)
    else if (strcmp(posit->label,"ZoneBC_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_zboco, data_class)
    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_boco, data_class)
    else if (strcmp(posit->label,"BCDataSet_t")==0 ||
             strcmp(posit->label,"FamilyBCDataSet_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_dataset, data_class)
    else if (strcmp(posit->label,"BCData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_bcdata, data_class)
    else if (strcmp(posit->label,"FlowEquationSet_t")==0)
            ADDRESS4SINGLE_ALLOC(cgns_equations, data_class)
    else if (strcmp(posit->label,"GasModel_t")==0 ||
         strcmp(posit->label,"ViscosityModel_t")==0 ||
             strcmp(posit->label,"ThermalConductivityModel_t")==0 ||
         strcmp(posit->label,"TurbulenceModel_t")==0 ||
         strcmp(posit->label,"TurbulenceClosure_t")==0 ||
         strcmp(posit->label,"ThermalRelaxationModel_t")==0 ||
         strcmp(posit->label,"ChemicalKineticsModel_t")==0 ||
         strcmp(posit->label,"EMElectricFieldModel_t")==0 ||
         strcmp(posit->label,"EMMagneticFieldModel_t")==0 ||
         strcmp(posit->label,"EMConductivityModel_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_model, data_class)
    else if (strcmp(posit->label,"ConvergenceHistory_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_converg, data_class)
    else if (strcmp(posit->label,"IntegralData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_integral, data_class)
    else if (strcmp(posit->label,"ReferenceState_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_state, data_class)
    else if (strcmp(posit->label,"DataArray_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_array, data_class)
    else if (strcmp(posit->label,"RigidGridMotion_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_rmotion, data_class)
    else if (strcmp(posit->label,"ArbitraryGridMotion_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_amotion, data_class)
    else if (strcmp(posit->label,"BaseIterativeData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_biter, data_class)
    else if (strcmp(posit->label,"ZoneIterativeData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_ziter, data_class)
    else if (strcmp(posit->label,"UserDefinedData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_user_data, data_class)
    else if (strcmp(posit->label,"Gravity_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_gravity, data_class)
    else if (strcmp(posit->label,"Axisymmetry_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_axisym, data_class)
    else if (strcmp(posit->label,"RotatingCoordinates_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_rotating, data_class)
    else if (strcmp(posit->label,"Periodic_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_cperio, data_class)
    else if (strcmp(posit->label,"ZoneSubRegion_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_subreg, data_class)
    else {
        cgi_error("DataClass_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (cg->mode == CG_MODE_MODIFY && local_mode == CG_MODE_WRITE) {
        if (cgi_get_nodes(parent_id, "DataClass_t", &nnod, &id)) return 0;
        if (nnod>0) {
            if (cgi_delete_node (parent_id, id[0])) {
                (*ier) = CG_ERROR;
                return 0;
            }
            free(id);
        }
    }
    return data_class;
}

cgns_units *cgi_units_address(int local_mode, int *ier)
{
    cgns_units *units=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of DimensionalUnits_t node:
 *  CGNSBase_t, Zone_t, GridCoordinates_t, FlowSolution_t, DiscreteData_t,
 *  ZoneBC_t, BC_t, BCDataSet_t, BCData_t, FlowEquationSet_t, GasModel_t,
 *  ViscosityModel_t, ThermalConductivityModel_t, TurbulenceClosure_t,
 *  TurbulenceModel_t, ThermalRelaxationModel_t, ChemicalKineticsModel_t,
 *  EMElectricFieldModel_t, EMMagneticFieldModel_t,
 *  ConvergenceHistory_t, IntegralData_t, ReferenceState_t,
 *  DataArray_t, RigidGridMotion_t, ArbitraryGridMotion_t, BaseIterativeData_t,
 *  ZoneIterativeData_t, UserDefinedData_t, Gravity_t, Axisymmetry_t
 *  RotatingCoordinates_t, Periodic_t, FamilyBCDataSet_t
 */
    if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4SINGLE(cgns_base, units, cgns_units, 1)
    else if  (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4SINGLE(cgns_zone, units, cgns_units, 1)
    else if (strcmp(posit->label,"GridCoordinates_t")==0)
        ADDRESS4SINGLE(cgns_zcoor, units, cgns_units, 1)
    else if (strcmp(posit->label,"FlowSolution_t")==0)
        ADDRESS4SINGLE(cgns_sol, units, cgns_units, 1)
    else if (strcmp(posit->label,"DiscreteData_t")==0)
        ADDRESS4SINGLE(cgns_discrete, units, cgns_units, 1)
    else if (strcmp(posit->label,"ZoneBC_t")==0)
        ADDRESS4SINGLE(cgns_zboco, units, cgns_units, 1)
    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4SINGLE(cgns_boco, units, cgns_units, 1)
    else if (strcmp(posit->label,"BCDataSet_t")==0 ||
             strcmp(posit->label,"FamilyBCDataSet_t")==0)
        ADDRESS4SINGLE(cgns_dataset, units, cgns_units, 1)
    else if (strcmp(posit->label,"BCData_t")==0)
        ADDRESS4SINGLE(cgns_bcdata, units, cgns_units, 1)
    else if (strcmp(posit->label,"FlowEquationSet_t")==0)
        ADDRESS4SINGLE(cgns_equations, units, cgns_units, 1)
    else if (strcmp(posit->label,"GasModel_t")==0 ||
        strcmp(posit->label,"ViscosityModel_t")==0 ||
        strcmp(posit->label,"ThermalConductivityModel_t")==0 ||
        strcmp(posit->label,"TurbulenceModel_t")==0 ||
        strcmp(posit->label,"TurbulenceClosure_t")==0 ||
        strcmp(posit->label,"ThermalRelaxationModel_t")==0 ||
        strcmp(posit->label,"ChemicalKineticsModel_t")==0 ||
        strcmp(posit->label,"EMElectricFieldModel_t")==0 ||
        strcmp(posit->label,"EMMagneticFieldModel_t")==0 ||
        strcmp(posit->label,"EMConductivityModel_t")==0)
        ADDRESS4SINGLE(cgns_model, units, cgns_units, 1)
    else if (strcmp(posit->label,"ConvergenceHistory_t")==0)
        ADDRESS4SINGLE(cgns_converg, units, cgns_units, 1)
    else if (strcmp(posit->label,"IntegralData_t")==0)
        ADDRESS4SINGLE(cgns_integral, units, cgns_units, 1)
    else if (strcmp(posit->label,"ReferenceState_t")==0)
        ADDRESS4SINGLE(cgns_state, units, cgns_units, 1)
    else if (strcmp(posit->label,"DataArray_t")==0)
        ADDRESS4SINGLE(cgns_array, units, cgns_units, 1)
    else if (strcmp(posit->label,"RigidGridMotion_t")==0)
        ADDRESS4SINGLE(cgns_rmotion, units, cgns_units, 1)
    else if (strcmp(posit->label,"ArbitraryGridMotion_t")==0)
        ADDRESS4SINGLE(cgns_amotion, units, cgns_units, 1)
    else if (strcmp(posit->label,"BaseIterativeData_t")==0)
        ADDRESS4SINGLE(cgns_biter, units, cgns_units, 1)
    else if (strcmp(posit->label,"ZoneIterativeData_t")==0)
        ADDRESS4SINGLE(cgns_ziter, units, cgns_units, 1)
    else if (strcmp(posit->label,"UserDefinedData_t")==0)
        ADDRESS4SINGLE(cgns_user_data, units, cgns_units, 1)
    else if (strcmp(posit->label,"Gravity_t")==0)
        ADDRESS4SINGLE(cgns_gravity, units, cgns_units, 1)
    else if (strcmp(posit->label,"Axisymmetry_t")==0)
        ADDRESS4SINGLE(cgns_axisym, units, cgns_units, 1)
    else if (strcmp(posit->label,"RotatingCoordinates_t")==0)
        ADDRESS4SINGLE(cgns_rotating, units, cgns_units, 1)
    else if (strcmp(posit->label,"Periodic_t")==0)
        ADDRESS4SINGLE(cgns_cperio, units, cgns_units, 1)
    else if (strcmp(posit->label,"ZoneSubRegion_t")==0)
        ADDRESS4SINGLE(cgns_subreg, units, cgns_units, 1)

    else {
        cgi_error("DimensionalUnits_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("DimensionalUnits_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!units && local_mode == CG_MODE_READ) {
        cgi_error("DimensionalUnits_t Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, units->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_units(units);
    }
    return units;
}

int *cgi_ordinal_address(int local_mode, int *ier)
{
    double *id;
    int nnod;
    int *ordinal;
    double parent_id;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of Ordinal_t node:
 *  Zone_t, GridConnectivity1to1_t, GridConnectivity_t, BC_t, Family_t,
 *      UserDefinedData_t
 */
    if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_zone, ordinal)

    else if (strcmp(posit->label,"GridConnectivity1to1_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_1to1, ordinal)

    else if (strcmp(posit->label,"GridConnectivity_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_conn, ordinal)

    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_boco, ordinal)

    else if (strcmp(posit->label,"Family_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_family, ordinal)
    else if (strcmp(posit->label,"UserDefinedData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_user_data, ordinal)
    else {
        cgi_error("Ordinal_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (cg->mode == CG_MODE_MODIFY && local_mode == CG_MODE_WRITE) {
        if (cgi_get_nodes(parent_id, "Ordinal_t", &nnod, &id)) return 0;
        if (nnod>0) {
            if (cgi_delete_node (parent_id, id[0])) {
                (*ier) = CG_ERROR;
                return 0;
            }
            free(id);
        }
    }
/*    if ((*ordinal)==0) (*ier)= CG_NODE_NOT_FOUND;*/
    return ordinal;
}

int *cgi_rind_address(int local_mode, int *ier)
{
    int *rind_planes=0, nnod;
    double parent_id=0, *id;
    int error1=0, index_dim;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

    if (posit_base && posit_zone) {
        index_dim = cg->base[posit_base-1].zone[posit_zone-1].index_dim;
    } else {
        cgi_error("Can't find IndexDimension in cgi_rind_address");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of Rind_t:
 * GridCoordinates_t, FlowSolution_t,DiscreteData_t, ArbitraryGridMotion_t
 */
    if (strcmp(posit->label,"GridCoordinates_t")==0)
        ADDRESS4SINGLE(cgns_zcoor, rind_planes, int, 2*index_dim)
    else if (strcmp(posit->label,"FlowSolution_t")==0)
        ADDRESS4SINGLE(cgns_sol, rind_planes, int, 2*index_dim)
    else if (strcmp(posit->label,"DiscreteData_t")==0)
        ADDRESS4SINGLE(cgns_discrete, rind_planes, int, 2*index_dim)
    else if (strcmp(posit->label,"ArbitraryGridMotion_t")==0)
        ADDRESS4SINGLE(cgns_amotion, rind_planes, int, 2*index_dim)
    else if (strcmp(posit->label,"Elements_t")==0)
        ADDRESS4SINGLE(cgns_section, rind_planes, int, 2*index_dim)
    else if (strcmp(posit->label,"ZoneSubRegion_t")==0)
        ADDRESS4SINGLE(cgns_subreg, rind_planes, int, 2*index_dim)

    else {
        cgi_error("Rind_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }

/* Corrected on July 27 2001 by Diane Poirier
    if (error1==1) {
        cgi_error("Rind_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
*/
    if (!rind_planes && local_mode == CG_MODE_READ) {
        cgi_error("Rind_t node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id && cg->mode==CG_MODE_MODIFY) {
        if (cgi_get_nodes(parent_id, "Rind_t", &nnod, &id)) return 0;
        if (nnod>0) {
            if (cgi_delete_node (parent_id, id[0])) {
                (*ier) = CG_ERROR;
                return 0;
            }
            free(id);
        }
    }
    return rind_planes;
}

CGNS_ENUMT(GridLocation_t) *cgi_location_address(int local_mode, int *ier)
{
    double *id, parent_id;
    CGNS_ENUMV( GridLocation_t ) *location=0;
    int nnod;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents for GridLocation_t:
 * FlowSolution_t, DiscreteData_t, GridConnectivity_t, OversetHoles_t, BC_t,
 * ArbitraryGridMotion_t, UserDefinedData_t
 */
    if (strcmp(posit->label,"FlowSolution_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_sol, location)
    else if (strcmp(posit->label,"DiscreteData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_discrete, location)
    else if (strcmp(posit->label,"GridConnectivity_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_conn, location)
    else if (strcmp(posit->label,"OversetHoles_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_hole, location)
    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_boco, location)
    else if (strcmp(posit->label,"ArbitraryGridMotion_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_amotion, location)
    else if (strcmp(posit->label,"UserDefinedData_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_user_data, location)
    else if (strcmp(posit->label,"BCDataSet_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_dataset, location)
    else if (strcmp(posit->label,"ZoneSubRegion_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_subreg, location)
    else {
        cgi_error("GridLocation_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (cg->mode == CG_MODE_MODIFY && local_mode == CG_MODE_WRITE) {
        if (cgi_get_nodes(parent_id, "GridLocation_t", &nnod, &id)) return 0;
        if (nnod>0) {
            if (cgi_delete_node (parent_id, id[0])) {
                (*ier) = CG_ERROR;
                return 0;
            }
            free(id);
        }
    }
    return location;
}

cgns_conversion *cgi_conversion_address(int local_mode, int *ier)
{
    cgns_conversion *convert=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parent: DataArray_t
 */
    if (strcmp(posit->label,"DataArray_t")==0)
        ADDRESS4SINGLE(cgns_array,convert, cgns_conversion, 1)

    else {
        cgi_error("DataConversion_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("DataConversion_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!convert && local_mode == CG_MODE_READ) {
        cgi_error("DataConversion_t node does not exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, convert->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_convert(convert);
    }
    return convert;
}

cgns_exponent *cgi_exponent_address(int local_mode, int *ier)
{
    cgns_exponent *exponents=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parent: DataArray_t
 */
    if (strcmp(posit->label,"DataArray_t")==0)
        ADDRESS4SINGLE(cgns_array, exponents, cgns_exponent, 1)

    else {
        cgi_error("DimensionalExponents_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("DimensionalExponents_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!exponents && local_mode == CG_MODE_READ) {
        cgi_error("DimensionalExponents_t node does not exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, exponents->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_exponents(exponents);
    }
    return exponents;
}

cgns_integral *cgi_integral_address(int local_mode, int given_no,
                                    char const *given_name, int *ier)
{
    cgns_integral *integral=0;
    int n, error1=0, error2=0;
    double parent_id=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of IntegralData_t node:
 *  CGNSBase_t, Zone_t
 */
    if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4MULTIPLE(cgns_base, nintegrals, integral, cgns_integral)
    else if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4MULTIPLE(cgns_zone, nintegrals, integral, cgns_integral)
    else {
        cgi_error("IntegralData_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1) {
        cgi_error("Duplicate child name found (%s) found under %s",
            given_name, posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (error2) {
        cgi_error("IntegralData index number %d doesn't exist under %s",
            given_no, posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {     /* parent_id!=0 only when overwriting */
        if (cgi_delete_node (parent_id, integral->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_integral(integral);
    }
    return integral;
}

cgns_equations *cgi_equations_address(int local_mode, int *ier)
{
    cgns_equations *equations=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents: CGNSBase_t, Zone_t
 */
    if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4SINGLE(cgns_base, equations, cgns_equations, 1)

    else if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4SINGLE(cgns_zone, equations, cgns_equations, 1)

    else {
        cgi_error("FlowEquationSet_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("FlowEquationSet_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!equations && local_mode == CG_MODE_READ) {
        cgi_error("FlowEquationSet_t Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, equations->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_equations(equations);
    }
    return equations;
}

cgns_state *cgi_state_address(int local_mode, int *ier)
{
    cgns_state *state=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents: CGNSBase_t, Zone_t, ZoneBC_t, BC_t
 *           BCDataSet_t, FamilyBCDataSet_t
 */
    if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4SINGLE(cgns_base, state, cgns_state, 1)

    else if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4SINGLE(cgns_zone, state, cgns_state, 1)

    else if (strcmp(posit->label,"ZoneBC_t")==0)
        ADDRESS4SINGLE(cgns_zboco, state, cgns_state, 1)

    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4SINGLE(cgns_boco, state, cgns_state, 1)

    else if (strcmp(posit->label,"BCDataSet_t")==0 ||
             strcmp(posit->label,"FamilyBCDataSet_t")==0)
        ADDRESS4SINGLE(cgns_dataset, state, cgns_state, 1)

    else {
        cgi_error("ReferenceState_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("ReferenceState_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!state && local_mode == CG_MODE_READ) {
        cgi_error("ReferenceState_t Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, state->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_state(state);
    }
    return state;
}

cgns_converg *cgi_converg_address(int local_mode, int *ier)
{
    cgns_converg *converg=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents for xxxConvergenceHistory_t node:
    CGNSBase_t, Zone_t
 */
    if (strcmp(posit->label,"CGNSBase_t")==0) {
        ADDRESS4SINGLE(cgns_base, converg, cgns_converg, 1)
        if (local_mode==CG_MODE_WRITE)
        strcpy(converg->name,"GlobalConvergenceHistory");

    } else if (strcmp(posit->label,"Zone_t")==0) {
        ADDRESS4SINGLE(cgns_zone, converg, cgns_converg, 1)
        if (local_mode==CG_MODE_WRITE)
        strcpy(converg->name,"ZoneConvergenceHistory");

    } else {
        cgi_error("ConvergenceHistory_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("ConvergenceHistory_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!converg && local_mode == CG_MODE_READ) {
        cgi_error("ConvergenceHistory_t Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, converg->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_converg(converg);
    }
    return converg;
}

cgns_governing *cgi_governing_address(int local_mode, int *ier)
{
    cgns_governing *governing;
    int error1=0;
    double parent_id=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents for GoverningEquations_t:
    FlowEquationSet_t
 */
    if (strcmp(posit->label,"FlowEquationSet_t")==0)
        ADDRESS4SINGLE(cgns_equations, governing, cgns_governing,1)
    else {
        cgi_error("GoverningEquations_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("GoverningEquations_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!governing && local_mode == CG_MODE_READ) {
        cgi_error("ConvergenceHistory_t Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, governing->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_governing(governing);
    }
    return governing;
}

int *cgi_diffusion_address(int local_mode, int *ier)
{
    int *diffusion_model=0, error1=0, nnod;
    double parent_id=0, *id;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* possible parents for DiffusionModel:
    GoverningEquations_t, TurbulenceModel_t
 */
    if (strcmp(posit->label,"GoverningEquations_t")==0)
        ADDRESS4SINGLE(cgns_governing, diffusion_model, int, 6)

    else if (strcmp(posit->label,"TurbulenceModel_t")==0)
        ADDRESS4SINGLE(cgns_model, diffusion_model, int, 6)

    else {
        cgi_error("Diffusion Model node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("Diffusion Model already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!diffusion_model && local_mode == CG_MODE_READ) {
        cgi_error("Diffusion Model Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_get_nodes(parent_id, "\"int[1+...+IndexDimension]\"", &nnod, &id)) return 0;
        if (nnod>0) {
            if (cgi_delete_node (parent_id, id[0])) {
                (*ier) = CG_ERROR;
                return 0;
            }
            free(id);
        }
        free(diffusion_model);
    }
    return diffusion_model;
}

cgns_array *cgi_array_address(int local_mode, int given_no,
                              char const *given_name, int *ier)
{
    cgns_array *array=0, *coord=0;
    int n, error1=0, error2=0;
    double parent_id=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of DataArray_t node:
 *  GridCoordinates_t, Elements_t, FlowSolution_t, DiscreteData_t, GridConnectivity_t, BC_t,
 *  BCData_t, GasModel_t, ViscosityModel_t, ThermalConductivityModel_t, TurbulenceClosure_t,
 *  TurbulenceModel_t, ThermalRelaxationModel_t, ChemicalKineticsModel_t,
 *  EMElectricFieldModel_t, EMMagneticFieldModel_t,
 *  ConvergenceHistory_t, IntegralData_t, ReferenceState_t,
 *  RigidGridMotion_t, ArbitraryGridMotion_t, BaseIterativeData_t, ZoneIterativeData_t,
 *  UserDefinedData_t, Gravity_t, Axisymmetry_t, RotatingCoordinates_t
 *  Area_t, Periodic_t, ZoneSubRegion_t
 */

     /* 0,N DataArray_t under GridCoordinates_t */
    if (strcmp(posit->label,"GridCoordinates_t")==0) {
        ADDRESS4MULTIPLE(cgns_zcoor, ncoords, coord, cgns_array)
        array = coord;

     /* 2 DataArray_t under Elements_t: connect and parent */
    } else if (strcmp(posit->label,"Elements_t")==0) {
        cgns_section *section= (cgns_section *)posit->posit;
        if (local_mode==CG_MODE_WRITE) {
            if (strcmp(given_name,"ElementConnectivity") &&
		strcmp(given_name,"ParentElements") &&
		strcmp(given_name,"ParentElementsPosition") &&
		strcmp(given_name,"ParentData")) {
                cgi_error("User defined DataArray_t node not supported under '%s' type node",posit->label);
                (*ier) = CG_ERROR;
                return 0;
            }
            if (section->connect==0 && strcmp(given_name,"ElementConnectivity")==0) {
                section->connect = CGNS_NEW(cgns_array, 1);
                array = section->connect;
            } else if (section->parelem==0 && (strcmp(given_name,"ParentElements")==0 ||
                       0 == strcmp(given_name, "ParentData"))) {
                section->parelem = CGNS_NEW(cgns_array, 1);
                array = section->parelem;
            } else if (section->parface==0 && strcmp(given_name,"ParentElementsPosition")==0) {
                section->parface = CGNS_NEW(cgns_array, 1);
                array = section->parface;
            } else {
                if (cg->mode == CG_MODE_WRITE) error1=1;
                else {
                    parent_id = section->id;
                    if (section->connect && strcmp(given_name,"ElementConnectivity")==0)
                        array = section->connect;
                    else if (section->parelem && (strcmp(given_name,"ParentElements")==0 ||
                             0 == strcmp(given_name,"ParentData")))
                        array = section->parelem;
                    else if (section->parface && strcmp(given_name,"ParentElementsPosition")==0)
                        array = section->parface;
                }
            }
        } else if (local_mode == CG_MODE_READ) {
            if (section->connect && strcmp(given_name,"ElementConnectivity")==0)
                array = section->connect;
            else if (section->parelem && (strcmp(given_name,"ParentElements")==0 ||
                     0 == strcmp(given_name,"ParentData")))
                array = section->parelem;
            else if (section->parface && strcmp(given_name,"ParentElementsPosition")==0)
                array = section->parface;
        }

     /* 0,N DataArray_t under FlowSolution_t */
    } else if (strcmp(posit->label,"FlowSolution_t")==0) {
        cgns_array *field;
        ADDRESS4MULTIPLE(cgns_sol, nfields, field, cgns_array)
        array = field;

     /* 0,N DataArray_t under DiscreteData_t */
    } else if (strcmp(posit->label,"DiscreteData_t")==0) {
        ADDRESS4MULTIPLE(cgns_discrete, narrays, array, cgns_array)

     /* 0,1 DataArray_t under GridConnectivity_t */
    } else if (strcmp(posit->label,"GridConnectivity_t")==0) {
        cgns_array *interpolants;
        if (local_mode==CG_MODE_WRITE && strcmp(given_name,"InterpolantsDonor")) {
            cgi_error("User defined DataArray_t node not supported under '%s' type node",posit->label);
            (*ier) = CG_ERROR;
            return 0;
        }
        ADDRESS4SINGLE(cgns_conn, interpolants, cgns_array, 1)
        array = interpolants;

     /* 0,1 DataArray_t (in SIDS is IndexArray_t) for InwardNormalList */
    } else if (strcmp(posit->label,"BC_t")==0) {
        cgns_array *normal;
        ADDRESS4SINGLE(cgns_boco, normal, cgns_array, 1)
        array = normal;

     /* 0,N DataArray_t under BCData_t  */
    } else if (strcmp(posit->label,"BCData_t")==0) {
        ADDRESS4MULTIPLE(cgns_bcdata, narrays, array, cgns_array)

     /* 0,N DataArray_t under all Model_t */
    } else if (strcmp(posit->label,"GasModel_t")==0 ||
        strcmp(posit->label,"ViscosityModel_t")==0 ||
        strcmp(posit->label,"ThermalConductivityModel_t")==0 ||
        strcmp(posit->label,"TurbulenceModel_t")==0 ||
        strcmp(posit->label,"TurbulenceClosure_t")==0 ||
        strcmp(posit->label,"ThermalRelaxationModel_t")==0 ||
        strcmp(posit->label,"ChemicalKineticsModel_t")==0 ||
        strcmp(posit->label,"EMElectricFieldModel_t")==0 ||
        strcmp(posit->label,"EMMagneticFieldModel_t")==0 ||
        strcmp(posit->label,"EMConductivityModel_t")==0) {
        ADDRESS4MULTIPLE(cgns_model, narrays, array, cgns_array)

     /* 0,N DataArray_t under ConvergenceHistory_t <any name> */
    }  else if (strcmp(posit->label,"ConvergenceHistory_t")==0) {
        ADDRESS4MULTIPLE(cgns_converg, narrays, array, cgns_array)

     /* 0,N DataArray_t under IntegralData_t <any name> */
    } else if (strcmp(posit->label,"IntegralData_t")==0) {
        ADDRESS4MULTIPLE(cgns_integral, narrays, array, cgns_array)

     /* 0,N DataArray_t under ReferenceState_t <any name> */
    } else if (strcmp(posit->label,"ReferenceState_t")==0) {
        ADDRESS4MULTIPLE(cgns_state, narrays, array, cgns_array)

     /* 0,N DataArray_t under RigidGridMotion_t:  <any name> */
    } else if (strcmp(posit->label, "RigidGridMotion_t")==0) {
        ADDRESS4MULTIPLE(cgns_rmotion, narrays, array, cgns_array)

     /* 0,N DataArray_t under ArbitraryGridMotion_t:  <any name> */
    } else if (strcmp(posit->label, "ArbitraryGridMotion_t")==0) {
        ADDRESS4MULTIPLE(cgns_amotion, narrays, array, cgns_array)

     /* 0,N DataArray_t under BaseIterativeData_t:  <any name> */
    } else if (strcmp(posit->label, "BaseIterativeData_t")==0) {
        ADDRESS4MULTIPLE(cgns_biter, narrays, array, cgns_array)

     /* 0,N DataArray_t under ZoneIterativeData_t:  <any name> */
    } else if (strcmp(posit->label, "ZoneIterativeData_t")==0) {
        ADDRESS4MULTIPLE(cgns_ziter, narrays, array, cgns_array)

     /* 0,N DataArray_t under UserDefinedData_t:  <any name> */
    } else if (strcmp(posit->label, "UserDefinedData_t")==0) {
        ADDRESS4MULTIPLE(cgns_user_data, narrays, array, cgns_array)

     /* 0,1 DataArray_t for GravityVector */
    } else if (strcmp(posit->label,"Gravity_t")==0) {
        cgns_array *vector;
        if (local_mode==CG_MODE_WRITE && strcmp(given_name,"GravityVector")) {
            cgi_error("User defined DataArray_t node not supported under '%s' type node",posit->label);
            (*ier) = CG_ERROR;
            return 0;
        }
        ADDRESS4SINGLE(cgns_gravity, vector, cgns_array, 1)
        array = vector;

     /* 2,4 DataArray_t for Axisymmetry_t */
    } else if (strcmp(posit->label,"Axisymmetry_t")==0) {
        if (local_mode==CG_MODE_WRITE && strcmp(given_name,"AxisymmetryReferencePoint") &&
            strcmp(given_name,"AxisymmetryAxisVector") &&
            strcmp(given_name,"AxisymmetryAngle") &&
            strcmp(given_name,"CoordinateNames")) {
            cgi_error("User defined DataArray_t node not supported under '%s' type node",posit->label);
            (*ier) = CG_ERROR;
            return 0;
        }
        ADDRESS4MULTIPLE(cgns_axisym, narrays, array, cgns_array)

     /* 2 DataArray_t for RotatingCoordinates_t */
    } else if (strcmp(posit->label,"RotatingCoordinates_t")==0) {
        if (local_mode==CG_MODE_WRITE && strcmp(given_name,"RotationCenter") &&
            strcmp(given_name,"RotationRateVector")) {
            cgi_error("User defined DataArray_t node not supported under '%s' type node",posit->label);
            (*ier) = CG_ERROR;
            return 0;
        }
        ADDRESS4MULTIPLE(cgns_rotating, narrays, array, cgns_array)

     /* 2 DataArray_t for Area_t:  SurfaceArea, RegionName */
    } else if (strcmp(posit->label,"Area_t")==0) {
        if (local_mode==CG_MODE_WRITE && strcmp(given_name,"SurfaceArea") &&
            strcmp(given_name,"RegionName")) {
            cgi_error("User defined DataArray_t node not supported under '%s' type node",posit->label);
            (*ier) = CG_ERROR;
            return 0;
        }
        ADDRESS4MULTIPLE(cgns_bcarea, narrays, array, cgns_array)

     /* 3 DataArray_t for Periodic_t: RotationCenter, RotationAngle, Translation */
    } else if (strcmp(posit->label,"Periodic_t")==0) {
        if (local_mode==CG_MODE_WRITE && strcmp(given_name,"RotationCenter") &&
            strcmp(given_name,"RotationAngle") && strcmp(given_name,"Translation")) {
            cgi_error("User defined DataArray_t node not supported under '%s' type node",posit->label);
            (*ier) = CG_ERROR;
            return 0;
        }
        ADDRESS4MULTIPLE(cgns_cperio, narrays, array, cgns_array)

     /* 0,N DataArray_t under ZoneSubRegion_t */
    } else if (strcmp(posit->label, "ZoneSubRegion_t")==0) {
        ADDRESS4MULTIPLE(cgns_subreg, narrays, array, cgns_array)

    } else {
        cgi_error("DataArray_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1) {
        cgi_error("Duplicate child name found (%s) found under %s",
            given_name, posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (error2) {
        cgi_error("DataArray_t index number %d doesn't exist under %s",
            given_no, posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {    /* parent_id!=0 only when overwriting */
        if (cgi_delete_node (parent_id, array->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_array(array);
    }
    return array;
}

cgns_model *cgi_model_address(int local_mode, char const *ModelLabel, int *ier)
{
    cgns_model *model=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents for all xxxModel_t and TurbulenceClosure_t:
    FlowEquationSet_t
 */
    if (strcmp(posit->label,"FlowEquationSet_t")==0) {
        if (strcmp(ModelLabel, "GasModel_t")==0) {
            cgns_model *gas;
            ADDRESS4SINGLE(cgns_equations, gas, cgns_model, 1)
            model = gas;

        } else if (strcmp(ModelLabel, "ViscosityModel_t")==0) {
            cgns_model *visc;
            ADDRESS4SINGLE(cgns_equations, visc, cgns_model, 1)
            model = visc;

        } else if (strcmp(ModelLabel, "ThermalConductivityModel_t")==0) {
            cgns_model *conduct;
            ADDRESS4SINGLE(cgns_equations, conduct, cgns_model, 1)
            model = conduct;

        } else if (strcmp(ModelLabel, "TurbulenceClosure_t")==0) {
            cgns_model *closure;
            ADDRESS4SINGLE(cgns_equations, closure, cgns_model, 1)
            model = closure;

        } else if (strcmp(ModelLabel, "TurbulenceModel_t")==0) {
            cgns_model *turbulence;
            ADDRESS4SINGLE(cgns_equations, turbulence, cgns_model, 1)
            model = turbulence;

        } else if (strcmp(ModelLabel, "ThermalRelaxationModel_t")==0) {
            cgns_model *relaxation;
            ADDRESS4SINGLE(cgns_equations, relaxation, cgns_model, 1)
            model = relaxation;

        } else if (strcmp(ModelLabel, "ChemicalKineticsModel_t")==0) {
            cgns_model *chemkin;
            ADDRESS4SINGLE(cgns_equations, chemkin, cgns_model, 1)
            model = chemkin;
        } else if (strcmp(ModelLabel, "EMElectricFieldModel_t")==0) {
            cgns_model *elecfield;
            ADDRESS4SINGLE(cgns_equations, elecfield, cgns_model, 1)
            model = elecfield;

        } else if (strcmp(ModelLabel, "EMMagneticFieldModel_t")==0) {
            cgns_model *magnfield;
            ADDRESS4SINGLE(cgns_equations, magnfield, cgns_model, 1)
            model = magnfield;

        } else if (strcmp(ModelLabel, "EMConductivityModel_t")==0) {
            cgns_model *emconduct;
            ADDRESS4SINGLE(cgns_equations, emconduct, cgns_model, 1)
            model = emconduct;
        } else {
            cgi_error("Incorrect model type %s",ModelLabel);
            (*ier) = CG_ERROR;
            return 0;
        }
    } else {
        cgi_error("%s node not supported under '%s' type node",ModelLabel,posit->label);
        (*ier)=CG_INCORRECT_PATH;
        return 0;
    }
    if (!model && local_mode == CG_MODE_READ) {
        cgi_error("%s node doesn't exist under %s",ModelLabel,posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (error1) {
        cgi_error("%s node already defined under %s",ModelLabel,posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, model->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_model(model);
    }
    return model;
}


cgns_user_data *cgi_user_data_address(int local_mode, int given_no,
                                      char const *given_name, int *ier)
{
    cgns_user_data *user_data=0;
    int n, error1=0, error2=0;
    double parent_id=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of UserDefinedData_t node:
 *  IntegralData_t, DiscreteData_t, ConvergenceHistory_t, ReferenceState_t,
 *  xxxModel_t, GoverningEquations_t, FlowEquationSet_t, BCData_t, BCDataSet_t,
 *  Elements_t, BC_t, ZoneBC_t, OversetHoles_t, GridConnectivity_t,
 *  GridConnectivity1to1_t, ZoneGridConnectivity_t, FlowSolution_t,
 *  GridCoordinates_t, RigidGridMotion_t, ArbitraryGridMotion_t,
 *  ZoneIterativeData_t, BaseIterativeData_t, Zone_t, GeometryReference_t,
 *  Family_t, CGNSBase_t, Gravity_t, Axisymmetry_t, RotatingCoordinates_t
 *  BCProperty_t, WallFunction_t, Area_t,
 *  GridConnectivityProperty_t, Periodic_t, AverageInterface_t,
 *  UserDefinedData_t, ZoneSubRegion_t, FamilyBCDataSet_t
 */
    if (strcmp(posit->label,"IntegralData_t")==0)
        ADDRESS4MULTIPLE(cgns_integral, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"DiscreteData_t")==0)
        ADDRESS4MULTIPLE(cgns_discrete, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"ConvergenceHistory_t")==0)
        ADDRESS4MULTIPLE(cgns_converg, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"ReferenceState_t")==0)
        ADDRESS4MULTIPLE(cgns_state, nuser_data, user_data, cgns_user_data)
    else if ( (strcmp(posit->label,"GasModel_t")==0)
        || (strcmp(posit->label,"ViscosityModel_t")==0)
        || (strcmp(posit->label,"ThermalConductivityModel_t")==0)
        || (strcmp(posit->label,"TurbulenceModel_t")==0)
        || (strcmp(posit->label,"TurbulenceClosureModel_t")==0)
        || (strcmp(posit->label,"ThermalRelaxationModel_t")==0)
        || (strcmp(posit->label,"ChemicalKineticsModel_t")==0)
        || (strcmp(posit->label,"EMElectricFieldModel_t")==0)
        || (strcmp(posit->label,"EMMagneticFieldModel_t")==0)
        || (strcmp(posit->label,"EMConductivityModel_t")==0) )
        ADDRESS4MULTIPLE(cgns_model, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"GoverningEquations_t")==0)
        ADDRESS4MULTIPLE(cgns_governing, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"FlowEquationSet_t")==0)
        ADDRESS4MULTIPLE(cgns_equations, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"BCData_t")==0)
        ADDRESS4MULTIPLE(cgns_bcdata, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"BCDataSet_t")==0 ||
             strcmp(posit->label,"FamilyBCDataSet_t")==0)
        ADDRESS4MULTIPLE(cgns_dataset, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"Elements_t")==0)
        ADDRESS4MULTIPLE(cgns_section, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4MULTIPLE(cgns_boco, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"ZoneBC_t")==0)
        ADDRESS4MULTIPLE(cgns_zboco, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"OversetHoles_t")==0)
        ADDRESS4MULTIPLE(cgns_hole, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"GridConnectivity_t")==0)
        ADDRESS4MULTIPLE(cgns_conn, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"GridConnectivity1to1_t")==0)
        ADDRESS4MULTIPLE(cgns_1to1, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"ZoneGridConnectivity_t")==0)
        ADDRESS4MULTIPLE(cgns_zconn, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"FlowSolution_t")==0)
        ADDRESS4MULTIPLE(cgns_sol, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"GridCoordinates_t")==0)
        ADDRESS4MULTIPLE(cgns_zcoor, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"RigidGridMotion_t")==0)
        ADDRESS4MULTIPLE(cgns_rmotion, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"ArbitraryGridMotion_t")==0)
        ADDRESS4MULTIPLE(cgns_amotion, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"ZoneIterativeData_t")==0)
        ADDRESS4MULTIPLE(cgns_ziter, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"BaseIterativeData_t")==0)
        ADDRESS4MULTIPLE(cgns_biter, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4MULTIPLE(cgns_zone, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"GeometryReference_t")==0)
        ADDRESS4MULTIPLE(cgns_geo, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"Family_t")==0)
        ADDRESS4MULTIPLE(cgns_family, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4MULTIPLE(cgns_base, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"Gravity_t")==0)
        ADDRESS4MULTIPLE(cgns_gravity, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"Axisymmetry_t")==0)
        ADDRESS4MULTIPLE(cgns_axisym, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"RotatingCoordinates_t")==0)
        ADDRESS4MULTIPLE(cgns_rotating, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"BCProperty_t")==0)
        ADDRESS4MULTIPLE(cgns_bprop, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"WallFunction_t")==0)
        ADDRESS4MULTIPLE(cgns_bcwall, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"Area_t")==0)
        ADDRESS4MULTIPLE(cgns_bcarea, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"GridConnectivityProperty_t")==0)
        ADDRESS4MULTIPLE(cgns_cprop, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"Periodic_t")==0)
        ADDRESS4MULTIPLE(cgns_cperio, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"AverageInterface_t")==0)
        ADDRESS4MULTIPLE(cgns_caverage, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"UserDefinedData_t")==0)
        ADDRESS4MULTIPLE(cgns_user_data, nuser_data, user_data, cgns_user_data)
    else if (strcmp(posit->label,"ZoneSubRegion_t")==0)
        ADDRESS4MULTIPLE(cgns_subreg, nuser_data, user_data, cgns_user_data)
    else {
        cgi_error("UserDefinedData_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1) {
        cgi_error("Duplicate child name found (%s) found under %s",
            given_name, posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (error2) {
        cgi_error("UserDefinedData index number %d doesn't exist under %s",
            given_no, posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {     /* parent_id!=0 only when overwriting */
        if (cgi_delete_node (parent_id, user_data->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_user_data(user_data);
    }
    return user_data;
}

cgns_rotating *cgi_rotating_address(int local_mode, int *ier)
{
    cgns_rotating *rotating=0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents: CGNSBase_t, Zone_t, Family_t
 */
    if (strcmp(posit->label,"CGNSBase_t")==0)
        ADDRESS4SINGLE(cgns_base, rotating, cgns_rotating, 1)

    else if (strcmp(posit->label,"Zone_t")==0)
        ADDRESS4SINGLE(cgns_zone, rotating, cgns_rotating, 1)
    else if (strcmp(posit->label,"Family_t")==0)
        ADDRESS4SINGLE(cgns_family, rotating, cgns_rotating, 1)
    else {
        cgi_error("RotatingCoordinates_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1==1) {
        cgi_error("RotatingCoordinates_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!rotating && local_mode == CG_MODE_READ) {
        cgi_error("RotatingCoordinates_t Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, rotating->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_rotating(rotating);
    }
    return rotating;
}

cgns_dataset *cgi_bcdataset_address(int local_mode, int given_no,
                                    char const *given_name, int *ier)
{
    cgns_dataset *dataset=0;
    int n, error1=0, error2=0;
    double parent_id=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

    /* Possible parents of FamilyBCDataSet_t node:
     *          FamilyBC_t
     */
    if (strcmp(posit->label,"FamilyBC_t")==0)
        ADDRESS4MULTIPLE(cgns_fambc, ndataset, dataset, cgns_dataset)
    else {
        cgi_error("FamilyBCDataSet_t node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }
    if (error1) {
        cgi_error("Duplicate child name found (%s) found under %s",
            given_name, posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (error2) {
        cgi_error("BCDataSet index number %d doesn't exist under %s",
            given_no, posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {     /* parent_id!=0 only when overwriting */
        if (cgi_delete_node (parent_id, dataset->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_dataset(dataset);
    }

    return dataset;
}

cgns_ptset *cgi_ptset_address(int local_mode, int *ier)
{
    cgns_ptset *ptset = 0;
    double parent_id=0;
    int error1=0;

    /* check for valid posit */
    if (posit == 0) {
        cgi_error("No current position set by cg_goto\n");
        (*ier) = CG_ERROR;
        return 0;
    }

/* Possible parents of a PointSet (i.e., either an IndexArray_t or
 *                      IndexRange_t) node:
 *  UserDefinedData_t, BCDataSet_t, BC_t, OversetHoles_t, GridConnectivity_t
 *  GridConnectivity1to1_t
 */
    if (strcmp(posit->label,"UserDefinedData_t")==0)
        ADDRESS4SINGLE(cgns_user_data, ptset, cgns_ptset, 1)

    else if (strcmp(posit->label,"BCDataSet_t")==0)
        ADDRESS4SINGLE(cgns_dataset, ptset, cgns_ptset, 1)

    else if (strcmp(posit->label,"BC_t")==0)
        ADDRESS4SINGLE(cgns_boco, ptset, cgns_ptset, 1)

    else if (strcmp(posit->label,"OversetHoles_t")==0)
        ADDRESS4SINGLE(cgns_hole, ptset, cgns_ptset, 1)

    else if (strcmp(posit->label,"GridConnectivity_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_conn, ptset)

    else if (strcmp(posit->label,"GridConnectivity1to1_t")==0)
        ADDRESS4SINGLE_ALLOC(cgns_1to1, ptset)

    else if (strcmp(posit->label,"ZoneSubRegion_t")==0)
        ADDRESS4SINGLE(cgns_subreg, ptset, cgns_ptset, 1)

    else if (strcmp(posit->label,"FlowSolution_t")==0)
        ADDRESS4SINGLE(cgns_sol, ptset, cgns_ptset, 1)

    else if (strcmp(posit->label,"DiscreteData_t")==0)
        ADDRESS4SINGLE(cgns_discrete, ptset, cgns_ptset, 1)

    else {
        cgi_error("PointSet node not supported under '%s' type node",posit->label);
        (*ier) = CG_INCORRECT_PATH;
        return 0;
    }

    if (error1==1) {
        cgi_error("IndexArray/Range_t already defined under %s",posit->label);
        (*ier) = CG_ERROR;
        return 0;
    }
    if (!ptset && local_mode == CG_MODE_READ) {
        cgi_error("IndexArray/Range_t Node doesn't exist under %s",posit->label);
        (*ier) = CG_NODE_NOT_FOUND;
        return 0;
    }
    if (parent_id) {
        if (cgi_delete_node (parent_id, ptset->id)) {
            (*ier) = CG_ERROR;
            return 0;
        }
        cgi_free_ptset(ptset);
    }

    return ptset;
}

/***********************************************************************\
 *            Free memory                      *
\***********************************************************************/

void cgi_free_file(cgns_file *cg)
{
    int b;

    free(cg->filename);
    if (cg->nbases) {
        for (b=0; b<cg->nbases; b++)
            cgi_free_base(&cg->base[b]);
        free(cg->base);
    }
}

void cgi_free_base(cgns_base *base)
{
    int n;

    if (base->nzones) {
        for (n=0; n<base->nzones; n++)
            cgi_free_zone(&base->zone[n]);
        free(base->zone);
    }
    if (base->ndescr) {
        for (n=0; n<base->ndescr; n++)
            cgi_free_descr(&base->descr[n]);
        free(base->descr);
    }
    if (base->state) {
        cgi_free_state(base->state);
        free(base->state);
    }
    if (base->units) {
        cgi_free_units(base->units);
        free(base->units);
    }
    if (base->equations) {
        cgi_free_equations(base->equations);
        free(base->equations);
    }
    if (base->converg) {
        cgi_free_converg(base->converg);
        free(base->converg);
    }
    if (base->nintegrals) {
        for (n=0; n<base->nintegrals; n++)
            cgi_free_integral(&base->integral[n]);
        free(base->integral);
    }
    if (base->nfamilies) {
        for (n=0; n<base->nfamilies; n++)
            cgi_free_family(&base->family[n]);
        free(base->family);
    }
    if (base->biter) {
        cgi_free_biter(base->biter);
        free(base->biter);
    }
    if (base->nuser_data) {
        for (n=0; n<base->nuser_data; n++)
            cgi_free_user_data(&base->user_data[n]);
        free(base->user_data);
    }
    if (base->gravity) {
        cgi_free_gravity(base->gravity);
        free(base->gravity);
    }
    if (base->axisym) {
        cgi_free_axisym(base->axisym);
        free(base->axisym);
    }
    if (base->rotating) {
        cgi_free_rotating(base->rotating);
        free(base->rotating);
    }
}

void cgi_free_zone(cgns_zone *zone)
{
    int n;

    if (zone->link) free(zone->link);
    free(zone->nijk);
    if (zone->ndescr) {
        for (n=0; n<zone->ndescr; n++)
            cgi_free_descr(&zone->descr[n]);
        free(zone->descr);
    }
    if (zone->nzcoor) {
        for (n=0; n<zone->nzcoor; n++)
            cgi_free_zcoor(&zone->zcoor[n]);
        free(zone->zcoor);
    }
    if (zone->nsections) {
        for (n=0; n<zone->nsections; n++)
            cgi_free_section(&zone->section[n]);
        free(zone->section);
    }
    if (zone->nsols) {
        for (n=0; n<zone->nsols; n++)
            cgi_free_sol(&zone->sol[n]);
        free(zone->sol);
    }
    if (zone->ndiscrete) {
        for (n=0; n<zone->ndiscrete; n++)
            cgi_free_discrete(&zone->discrete[n]);
        free(zone->discrete);
    }
    if (zone->nintegrals) {
        for (n=0; n<zone->nintegrals; n++)
            cgi_free_integral(&zone->integral[n]);
        free(zone->integral);
    }
    if (zone->nzconn) {
        for (n=0; n<zone->nzconn; n++)
            cgi_free_zconn(&zone->zconn[n]);
        free(zone->zconn);
    }
    if (zone->zboco) {
        cgi_free_zboco(zone->zboco);
        free(zone->zboco);
    }
    if (zone->state) {
        cgi_free_state(zone->state);
        free(zone->state);
    }
    if (zone->units) {
        cgi_free_units(zone->units);
        free(zone->units);
    }
    if (zone->equations) {
        cgi_free_equations(zone->equations);
        free(zone->equations);
    }
    if (zone->converg) {
        cgi_free_converg(zone->converg);
        free(zone->converg);
    }
    if (zone->nrmotions) {
        for (n=0; n<zone->nrmotions; n++)
            cgi_free_rmotion(&zone->rmotion[n]);
        free(zone->rmotion);
    }
    if (zone->namotions) {
        for (n=0; n<zone->namotions; n++)
            cgi_free_amotion(&zone->amotion[n]);
        free(zone->amotion);
    }
    if (zone->ziter) {
        cgi_free_ziter(zone->ziter);
        free(zone->ziter);
    }
    if (zone->nuser_data) {
        for (n=0; n<zone->nuser_data; n++)
            cgi_free_user_data(&zone->user_data[n]);
        free(zone->user_data);
    }
    if (zone->rotating) {
        cgi_free_rotating(zone->rotating);
        free(zone->rotating);
    }
    if (zone->nsubreg) {
        for (n=0; n<zone->nsubreg; n++)
            cgi_free_subreg(&zone->subreg[n]);
        free(zone->subreg);
    }
    if (zone->nfamname) {
        for (n = 0; n < zone->nfamname; n++)
            cgi_free_famname(&zone->famname[n]);
        free(zone->famname);
    }
}

void cgi_free_section(cgns_section *section)
{
    int n;
    if (section->link) free(section->link);
    if (section->ndescr) {
        for (n=0; n<section->ndescr; n++)
            cgi_free_descr(&section->descr[n]);
        free(section->descr);
    }
    if (section->rind_planes) free(section->rind_planes);
    if (section->connect) {
        cgi_free_array(section->connect);
        free(section->connect);
    }
    if (section->parelem) {
        cgi_free_array(section->parelem);
        free(section->parelem);
    }
    if (section->parface) {
        cgi_free_array(section->parface);
        free(section->parface);
    }
    if (section->nuser_data) {
        for (n=0; n<section->nuser_data; n++)
            cgi_free_user_data(&section->user_data[n]);
        free(section->user_data);
    }
}

void cgi_free_family(cgns_family *family)
{
    int n;
    if (family->link) free(family->link);
    if (family->ndescr) {
        for (n=0; n<family->ndescr; n++)
            cgi_free_descr(&family->descr[n]);
        free(family->descr);
    }
    if (family->nfambc) {
        for (n=0; n<family->nfambc; n++)
            cgi_free_fambc(&family->fambc[n]);
        free(family->fambc);
    }
    if (family->ngeos) {
        for (n=0; n<family->ngeos; n++)
            cgi_free_geo(&family->geo[n]);
        free(family->geo);
    }
    if (family->nuser_data) {
        for (n=0; n<family->nuser_data; n++)
            cgi_free_user_data(&family->user_data[n]);
        free(family->user_data);
    }
    if (family->rotating) {
        cgi_free_rotating(family->rotating);
        free(family->rotating);
    }
    if (family->nfamname) {
        for (n = 0; n < family->nfamname; n++)
            cgi_free_famname(&family->famname[n]);
        free(family->famname);
    }
}

void cgi_free_fambc(cgns_fambc *fambc)
{
    if (fambc->link) free(fambc->link);
    if (fambc->ndataset) {
        int n;
        for (n=0; n<fambc->ndataset; n++)
            cgi_free_dataset(&fambc->dataset[n]);
        free(fambc->dataset);
    }
}

/* currently here only to support delete */
void cgi_free_famname(cgns_famname *famname)
{
    famname->name[0] = 0;
    famname->family[0] = 0;
}

void cgi_free_geo(cgns_geo *geo)
{
    int n;
    if (geo->link) free(geo->link);
    if (geo->ndescr) {
        for (n=0; n<geo->ndescr; n++)
            cgi_free_descr(&geo->descr[n]);
        free(geo->descr);
    }
    if (geo->file) free(geo->file);
    if (geo->npart) {
        for (n=0; n<geo->npart; n++)
            cgi_free_part(&geo->part[n]);
        free(geo->part);
    }
    if (geo->nuser_data) {
        for (n=0; n<geo->nuser_data; n++)
            cgi_free_user_data(&geo->user_data[n]);
        free(geo->user_data);
    }
}

void cgi_free_part(cgns_part *part)
{
    if (part->link) free(part->link);
}

void cgi_free_zcoor(cgns_zcoor *zcoor)
{
    int n;
    if (zcoor->link) free(zcoor->link);
    if (zcoor->ndescr) {
        for (n=0; n<zcoor->ndescr; n++)
            cgi_free_descr(&zcoor->descr[n]);
        free(zcoor->descr);
    }
    if (zcoor->rind_planes) free(zcoor->rind_planes);
    if (zcoor->ncoords) {
        for (n=0; n<zcoor->ncoords; n++)
            cgi_free_array(&zcoor->coord[n]);
        free(zcoor->coord);
    }
    if (zcoor->units) {
        cgi_free_units(zcoor->units);
        free(zcoor->units);
    }
    if (zcoor->nuser_data) {
        for (n=0; n<zcoor->nuser_data; n++)
            cgi_free_user_data(&zcoor->user_data[n]);
        free(zcoor->user_data);
    }
}

void cgi_free_zboco(cgns_zboco *zboco)
{
    int n;
    if (zboco->link) free(zboco->link);
    if (zboco->ndescr) {
        for (n=0; n<zboco->ndescr; n++)
            cgi_free_descr(&zboco->descr[n]);
        free(zboco->descr);
    }
    if (zboco->nbocos) {
        for (n=0; n<zboco->nbocos; n++)
            cgi_free_boco(&zboco->boco[n]);
        free(zboco->boco);
    }
    if (zboco->state) {
        cgi_free_state(zboco->state);
        free(zboco->state);
    }
    if (zboco->units) {
        cgi_free_units(zboco->units);
        free(zboco->units);
    }
    if (zboco->nuser_data) {
        for (n=0; n<zboco->nuser_data; n++)
            cgi_free_user_data(&zboco->user_data[n]);
        free(zboco->user_data);
    }
}

void cgi_free_zconn(cgns_zconn *zconn)
{
    int n;
    if (zconn->link) free(zconn->link);
    if (zconn->ndescr) {
        for (n=0; n<zconn->ndescr; n++)
            cgi_free_descr(&zconn->descr[n]);
        free(zconn->descr);
    }
    if (zconn->n1to1) {
        for (n=0; n<zconn->n1to1; n++)
            cgi_free_1to1(&zconn->one21[n]);
        free(zconn->one21);
    }
    if (zconn->nconns) {
        for (n=0; n<zconn->nconns; n++)
            cgi_free_conn(&zconn->conn[n]);
        free(zconn->conn);
    }
    if (zconn->nholes) {
        for (n=0; n<zconn->nholes; n++)
            cgi_free_hole(&zconn->hole[n]);
        free(zconn->hole);
    }
    if (zconn->nuser_data) {
        for (n=0; n<zconn->nuser_data; n++)
            cgi_free_user_data(&zconn->user_data[n]);
        free(zconn->user_data);
    }
}

void cgi_free_sol(cgns_sol *sol)
{
    int n;
    if (sol->link) free(sol->link);
    if (sol->ndescr) {
        for (n=0; n<sol->ndescr; n++)
            cgi_free_descr(&sol->descr[n]);
        free(sol->descr);
    }
    if (sol->nfields) {
        for (n=0; n<sol->nfields; n++)
            cgi_free_array(&sol->field[n]);
        free(sol->field);
    }
    if (sol->rind_planes) free(sol->rind_planes);
    if (sol->units) {
        cgi_free_units(sol->units);
        free(sol->units);
    }
    if (sol->nuser_data) {
        for (n=0; n<sol->nuser_data; n++)
            cgi_free_user_data(&sol->user_data[n]);
        free(sol->user_data);
    }
    if (sol->ptset) {
        cgi_free_ptset(sol->ptset);
        free(sol->ptset);
    }
}

void cgi_free_1to1(cgns_1to1 *one21)
{
    int n;
    if (one21->link) free(one21->link);
    free(one21->transform);
    if (one21->ndescr) {
        for (n=0; n<one21->ndescr; n++)
            cgi_free_descr(&one21->descr[n]);
        free(one21->descr);
    }
    if (one21->nuser_data) {
        for (n=0; n<one21->nuser_data; n++)
            cgi_free_user_data(&one21->user_data[n]);
        free(one21->user_data);
    }
    if (one21->cprop) {
        cgi_free_cprop(one21->cprop);
        free(one21->cprop);
    }
}

void cgi_free_hole(cgns_hole *hole)
{
    int n;
    if (hole->link) free(hole->link);
    if (hole->ndescr) {
        for (n=0; n<hole->ndescr; n++)
            cgi_free_descr(&hole->descr[n]);
        free(hole->descr);
    }
    if (hole->nptsets) {
        for (n=0; n<hole->nptsets; n++)
            cgi_free_ptset(&hole->ptset[n]);
        free(hole->ptset);
    }
    if (hole->nuser_data) {
        for (n=0; n<hole->nuser_data; n++)
            cgi_free_user_data(&hole->user_data[n]);
        free(hole->user_data);
    }
}

void cgi_free_conn(cgns_conn *conn)
{
    int n;
    if (conn->link) free(conn->link);
    if (conn->ndescr) {
        for (n=0; n<conn->ndescr; n++)
            cgi_free_descr(&conn->descr[n]);
        free(conn->descr);
    }
    if (conn->interpolants) {
        cgi_free_array(conn->interpolants);
        free(conn->interpolants);
    }
    if (conn->nuser_data) {
        for (n=0; n<conn->nuser_data; n++)
            cgi_free_user_data(&conn->user_data[n]);
        free(conn->user_data);
    }
    if (conn->cprop) {
        cgi_free_cprop(conn->cprop);
        free(conn->cprop);
    }
}

void cgi_free_boco(cgns_boco *boco)
{
    int n;
    if (boco->link) free(boco->link);
    if (boco->ndescr) {
        for (n=0; n<boco->ndescr; n++)
            cgi_free_descr(&boco->descr[n]);
        free(boco->descr);
    }
    if (boco->ptset) {
        cgi_free_ptset(boco->ptset);
        free(boco->ptset);
    }
    if (boco->Nindex) free(boco->Nindex);
    if (boco->normal) {
        cgi_free_array(boco->normal);
        free(boco->normal);
    }
    if (boco->ndataset) {
        for (n=0; n<boco->ndataset; n++)
        {
            /* If dataset[n].ptset came from boco->ptset, don't want to
             * attempt to free it. This is stuff Ken put in here. I don't
             * think this every happens - but just in case
             */
            if(boco->dataset[n].ptset == boco->ptset)
                boco->dataset[n].ptset = 0;
            cgi_free_dataset(&boco->dataset[n]);
        }
        free(boco->dataset);
    }
    if (boco->state) {
        cgi_free_state(boco->state);
        free(boco->state);
    }
    if (boco->units) {
        cgi_free_units(boco->units);
        free(boco->units);
    }
    if (boco->nuser_data) {
        for (n=0; n<boco->nuser_data; n++)
            cgi_free_user_data(&boco->user_data[n]);
        free(boco->user_data);
    }
    if (boco->bprop) {
        cgi_free_bprop(boco->bprop);
        free(boco->bprop);
    }
    if (boco->nfamname) {
        for (n = 0; n < boco->nfamname; n++)
            cgi_free_famname(&boco->famname[n]);
        free(boco->famname);
    }
}

void cgi_free_dataset(cgns_dataset *dataset)
{
    int n;
    if (dataset->link) free(dataset->link);
    if (dataset->ndescr) {
        for (n=0; n<dataset->ndescr; n++)
            cgi_free_descr(&dataset->descr[n]);
        free(dataset->descr);
    }
    if (dataset->dirichlet) {
       cgi_free_bcdata(dataset->dirichlet);
       free(dataset->dirichlet);
    }
    if (dataset->neumann) {
        cgi_free_bcdata(dataset->neumann);
        free(dataset->neumann);
    }
    if (dataset->state) {
        cgi_free_state(dataset->state);
        free(dataset->state);
    }
    if (dataset->units) {
        cgi_free_units(dataset->units);
        free(dataset->units);
    }
    if (dataset->nuser_data) {
        for (n=0; n<dataset->nuser_data; n++)
            cgi_free_user_data(&dataset->user_data[n]);
        free(dataset->user_data);
    }
    if (dataset->ptset) {
        cgi_free_ptset(dataset->ptset);
        free(dataset->ptset);
    }
}

void cgi_free_bcdata(cgns_bcdata *bcdata)
{
    int n;
    if (bcdata->link) free(bcdata->link);
    if (bcdata->ndescr) {
        for (n=0; n<bcdata->ndescr; n++)
            cgi_free_descr(&bcdata->descr[n]);
        free(bcdata->descr);
    }
    if (bcdata->narrays) {
        for (n=0; n<bcdata->narrays; n++)
            cgi_free_array(&bcdata->array[n]);
        free(bcdata->array);
    }
    if (bcdata->units) {
        cgi_free_units(bcdata->units);
        free(bcdata->units);
    }
    if (bcdata->nuser_data) {
        for (n=0; n<bcdata->nuser_data; n++)
            cgi_free_user_data(&bcdata->user_data[n]);
        free(bcdata->user_data);
    }
}

void cgi_free_ptset(cgns_ptset *ptset)
{
    if (ptset->link) free(ptset->link);
    if (ptset->data) free(ptset->data);
}

void cgi_free_equations(cgns_equations *equations)
{
    int n;
    if (equations->link) free(equations->link);
    if (equations->ndescr) {
        for (n=0; n<equations->ndescr; n++)
            cgi_free_descr(&equations->descr[n]);
        free(equations->descr);
    }
    if (equations->governing) {
        cgi_free_governing(equations->governing);
        free(equations->governing);
    }
    if (equations->gas) {
        cgi_free_model(equations->gas);
        free(equations->gas);
    }
    if (equations->visc) {
        cgi_free_model(equations->visc);
        free(equations->visc);
    }
    if (equations->conduct) {
        cgi_free_model(equations->conduct);
        free(equations->conduct);
    }
    if (equations->closure) {
        cgi_free_model(equations->closure);
        free(equations->closure);
    }
    if (equations->turbulence) {
        if (equations->turbulence->diffusion_model)
            free(equations->turbulence->diffusion_model);
        cgi_free_model(equations->turbulence);
        free(equations->turbulence);
    }
    if (equations->relaxation) {
        cgi_free_model(equations->relaxation);
        free(equations->relaxation);
    }
    if (equations->chemkin) {
        cgi_free_model(equations->chemkin);
        free(equations->chemkin);
    }
    if (equations->units) {
        cgi_free_units(equations->units);
        free(equations->units);
    }
    if (equations->nuser_data) {
        for (n=0; n<equations->nuser_data; n++)
            cgi_free_user_data(&equations->user_data[n]);
        free(equations->user_data);
    }
    if (equations->elecfield) {
        cgi_free_model(equations->elecfield);
        free(equations->elecfield);
    }
    if (equations->magnfield) {
        cgi_free_model(equations->magnfield);
        free(equations->magnfield);
    }
    if (equations->emconduct) {
        cgi_free_model(equations->emconduct);
        free(equations->emconduct);
    }
}

void cgi_free_governing(cgns_governing *governing)
{
    int n;
    if (governing->link) free(governing->link);
    if (governing->ndescr) {
        for (n=0; n<governing->ndescr; n++)
            cgi_free_descr(&governing->descr[n]);
        free(governing->descr);
    }
    if (governing->diffusion_model) free(governing->diffusion_model);
    if (governing->nuser_data) {
        for (n=0; n<governing->nuser_data; n++)
            cgi_free_user_data(&governing->user_data[n]);
        free(governing->user_data);
    }
}

void cgi_free_model(cgns_model *model)
{
    int n;
    if (model->link) free(model->link);
    if (model->ndescr) {
        for (n=0; n<model->ndescr; n++)
            cgi_free_descr(&model->descr[n]);
        free(model->descr);
    }
    if (model->narrays) {
        for (n=0; n<model->narrays; n++)
            cgi_free_array(&model->array[n]);
        free(model->array);
    }
    if (model->units) {
        cgi_free_units(model->units);
        free(model->units);
    }
    if (model->nuser_data) {
        for (n=0; n<model->nuser_data; n++)
            cgi_free_user_data(&model->user_data[n]);
        free(model->user_data);
    }
}

void cgi_free_state(cgns_state *state)
{
    int n;
    if (state->link) free(state->link);
    if (state->ndescr) {
        for (n=0; n<state->ndescr; n++)
            cgi_free_descr(&state->descr[n]);
        free(state->descr);
    }
    if (state->StateDescription) {
        cgi_free_descr(state->StateDescription);
        free(state->StateDescription);
    }
    if (state->narrays) {
        for (n=0; n<state->narrays; n++)
            cgi_free_array(&state->array[n]);
        free(state->array);
    }
    if (state->units) {
        cgi_free_units(state->units);
        free(state->units);
    }
    if (state->nuser_data) {
        for (n=0; n<state->nuser_data; n++)
            cgi_free_user_data(&state->user_data[n]);
        free(state->user_data);
    }
}

void cgi_free_converg(cgns_converg *converg)
{
    int n;
    if (converg->link) free(converg->link);
    if (converg->ndescr) {
        for (n=0; n<converg->ndescr; n++)
            cgi_free_descr(&converg->descr[n]);
        free(converg->descr);
    }
    if (converg->NormDefinitions) {
        cgi_free_descr(converg->NormDefinitions);
        free(converg->NormDefinitions);
    }
    if (converg->narrays) {
        for (n=0; n<converg->narrays; n++)
            cgi_free_array(&converg->array[n]);
        free(converg->array);
    }
    if (converg->units) {
        cgi_free_units(converg->units);
        free(converg->units);
    }
    if (converg->nuser_data) {
        for (n=0; n<converg->nuser_data; n++)
            cgi_free_user_data(&converg->user_data[n]);
        free(converg->user_data);
    }
}

void cgi_free_discrete(cgns_discrete *discrete)
{
    int n;
    if (discrete->link) free(discrete->link);
    if (discrete->ndescr) {
        for (n=0; n<discrete->ndescr; n++)
            cgi_free_descr(&discrete->descr[n]);
        free(discrete->descr);
    }
    if (discrete->rind_planes) free(discrete->rind_planes);
    if (discrete->narrays) {
        for (n=0; n<discrete->narrays; n++)
            cgi_free_array(&discrete->array[n]);
        free(discrete->array);
    }
    if (discrete->units) {
        cgi_free_units(discrete->units);
        free(discrete->units);
    }
    if (discrete->nuser_data) {
        for (n=0; n<discrete->nuser_data; n++)
            cgi_free_user_data(&discrete->user_data[n]);
        free(discrete->user_data);
    }
    if (discrete->ptset) {
        cgi_free_ptset(discrete->ptset);
        free(discrete->ptset);
    }
}

void cgi_free_integral(cgns_integral *integral)
{
    int n;
    if (integral->link) free(integral->link);
    if (integral->ndescr) {
        for (n=0; n<integral->ndescr; n++)
            cgi_free_descr(&integral->descr[n]);
        free(integral->descr);
    }
    if (integral->narrays) {
        for (n=0; n<integral->narrays; n++)
            cgi_free_array(&integral->array[n]);
        free(integral->array);
    }
    if (integral->units) {
        cgi_free_units(integral->units);
        free(integral->units);
    }
    if (integral->nuser_data) {
        for (n=0; n<integral->nuser_data; n++)
            cgi_free_user_data(&integral->user_data[n]);
        free(integral->user_data);
    }
}

void cgi_free_array(cgns_array *array)
{
    int n;
    if (array->link) free(array->link);
    if (array->data) free(array->data);
    if (array->ndescr) {
        for (n=0; n<array->ndescr; n++)
            cgi_free_descr(&array->descr[n]);
        free(array->descr);
    }
    if (array->units) {
        cgi_free_units(array->units);
        free(array->units);
    }
    if (array->exponents) {
        cgi_free_exponents(array->exponents);
        free(array->exponents);
    }
    if (array->convert) {
        cgi_free_convert(array->convert);
        free(array->convert);
    }
}

void cgi_free_convert(cgns_conversion *convert)
{
    if (convert->link) free(convert->link);
    free(convert->data);
}

void cgi_free_exponents(cgns_exponent *exponents)
{
    if (exponents->link) free(exponents->link);
    free(exponents->data);
}

void cgi_free_units(cgns_units *units)
{
    if (units->link) free(units->link);
}

void cgi_free_descr(cgns_descr *descr)
{
    if (descr->link) free(descr->link);
    if (descr->text) free(descr->text);
}

void cgi_free_rmotion(cgns_rmotion *rmotion)
{
    int n;
    if (rmotion->link) free(rmotion->link);
    if (rmotion->ndescr) {
        for (n=0; n<rmotion->ndescr; n++)
            cgi_free_descr(&rmotion->descr[n]);
        free(rmotion->descr);
    }
    if (rmotion->narrays) {
        for (n=0; n<rmotion->narrays; n++)
            cgi_free_array(&rmotion->array[n]);
        free(rmotion->array);
    }
    if (rmotion->units) {
        cgi_free_units(rmotion->units);
        free(rmotion->units);
    }
    if (rmotion->nuser_data) {
        for (n=0; n<rmotion->nuser_data; n++)
            cgi_free_user_data(&rmotion->user_data[n]);
        free(rmotion->user_data);
    }
}

void cgi_free_amotion(cgns_amotion *amotion)
{
    int n;
    if (amotion->link) free(amotion->link);
    if (amotion->ndescr) {
        for (n=0; n<amotion->ndescr; n++)
            cgi_free_descr(&amotion->descr[n]);
        free(amotion->descr);
    }
    if (amotion->rind_planes) free(amotion->rind_planes);
    if (amotion->narrays) {
        for (n=0; n<amotion->narrays; n++)
            cgi_free_array(&amotion->array[n]);
        free(amotion->array);
    }
    if (amotion->units) {
        cgi_free_units(amotion->units);
        free(amotion->units);
    }
    if (amotion->nuser_data) {
        for (n=0; n<amotion->nuser_data; n++)
            cgi_free_user_data(&amotion->user_data[n]);
        free(amotion->user_data);
    }
}

void cgi_free_biter(cgns_biter *biter)
{
    int n;
    if (biter->link) free(biter->link);
    if (biter->ndescr) {
        for (n=0; n<biter->ndescr; n++)
            cgi_free_descr(&biter->descr[n]);
        free(biter->descr);
    }
    if (biter->narrays) {
        for (n=0; n<biter->narrays; n++)
            cgi_free_array(&biter->array[n]);
        free(biter->array);
    }
    if (biter->units) {
        cgi_free_units(biter->units);
        free(biter->units);
    }
    if (biter->nuser_data) {
        for (n=0; n<biter->nuser_data; n++)
            cgi_free_user_data(&biter->user_data[n]);
        free(biter->user_data);
    }
}

void cgi_free_ziter(cgns_ziter *ziter)
{
    int n;
    if (ziter->link) free(ziter->link);
    if (ziter->ndescr) {
        for (n=0; n<ziter->ndescr; n++)
            cgi_free_descr(&ziter->descr[n]);
        free(ziter->descr);
    }
    if (ziter->narrays) {
        for (n=0; n<ziter->narrays; n++)
            cgi_free_array(&ziter->array[n]);
        free(ziter->array);
    }
    if (ziter->units) {
        cgi_free_units(ziter->units);
        free(ziter->units);
    }
    if (ziter->nuser_data) {
        for (n=0; n<ziter->nuser_data; n++)
            cgi_free_user_data(&ziter->user_data[n]);
        free(ziter->user_data);
    }
}

void cgi_free_gravity(cgns_gravity *gravity)
{
    int n;
    if (gravity->link) free(gravity->link);
    if (gravity->ndescr) {
        for (n=0; n<gravity->ndescr; n++)
            cgi_free_descr(&gravity->descr[n]);
        free(gravity->descr);
    }
    if (gravity->vector) {
        cgi_free_array(gravity->vector);
        free(gravity->vector);
    }
    if (gravity->units) {
        cgi_free_units(gravity->units);
        free(gravity->units);
    }
    if (gravity->nuser_data) {
        for (n=0; n<gravity->nuser_data; n++)
            cgi_free_user_data(&gravity->user_data[n]);
        free(gravity->user_data);
    }
}

void cgi_free_axisym(cgns_axisym *axisym)
{
    int n;
    if (axisym->link) free(axisym->link);
    if (axisym->ndescr) {
        for (n=0; n<axisym->ndescr; n++)
            cgi_free_descr(&axisym->descr[n]);
        free(axisym->descr);
    }
    if (axisym->units) {
        cgi_free_units(axisym->units);
        free(axisym->units);
    }
    if (axisym->narrays) {
        for (n=0; n<axisym->narrays; n++)
            cgi_free_array(&axisym->array[n]);
        free(axisym->array);
    }
    if (axisym->nuser_data) {
        for (n=0; n<axisym->nuser_data; n++)
            cgi_free_user_data(&axisym->user_data[n]);
        free(axisym->user_data);
    }
}

void cgi_free_rotating(cgns_rotating *rotating)
{
    int n;
    if (rotating->link) free(rotating->link);
    if (rotating->ndescr) {
        for (n=0; n<rotating->ndescr; n++)
            cgi_free_descr(&rotating->descr[n]);
        free(rotating->descr);
    }
    if (rotating->units) {
        cgi_free_units(rotating->units);
        free(rotating->units);
    }
    if (rotating->narrays) {
        for (n=0; n<rotating->narrays; n++)
            cgi_free_array(&rotating->array[n]);
        free(rotating->array);
    }
    if (rotating->nuser_data) {
        for (n=0; n<rotating->nuser_data; n++)
            cgi_free_user_data(&rotating->user_data[n]);
        free(rotating->user_data);
    }
}

void cgi_free_bprop(cgns_bprop *bprop)
{
    int n;
    if (bprop->link) free(bprop->link);
    if (bprop->ndescr) {
        for (n=0; n<bprop->ndescr; n++)
            cgi_free_descr(&bprop->descr[n]);
        free(bprop->descr);
    }
    if (bprop->bcwall) {
        cgi_free_bcwall(bprop->bcwall);
        free(bprop->bcwall);
    }
    if (bprop->bcarea) {
        cgi_free_bcarea(bprop->bcarea);
        free(bprop->bcarea);
    }
    if (bprop->nuser_data) {
        for (n=0; n<bprop->nuser_data; n++)
            cgi_free_user_data(&bprop->user_data[n]);
        free(bprop->user_data);
    }
}

void cgi_free_cprop(cgns_cprop *cprop)
{
    int n;
    if (cprop->link) free(cprop->link);
    if (cprop->ndescr) {
        for (n=0; n<cprop->ndescr; n++)
            cgi_free_descr(&cprop->descr[n]);
        free(cprop->descr);
    }
    if (cprop->cperio) {
        cgi_free_cperio(cprop->cperio);
        free(cprop->cperio);
    }
    if (cprop->caverage) {
        cgi_free_caverage(cprop->caverage);
        free(cprop->caverage);
    }
    if (cprop->nuser_data) {
        for (n=0; n<cprop->nuser_data; n++)
            cgi_free_user_data(&cprop->user_data[n]);
        free(cprop->user_data);
    }
}

void cgi_free_bcwall(cgns_bcwall *bcwall)
{
    int n;
    if (bcwall->link) free(bcwall->link);
    if (bcwall->ndescr) {
        for (n=0; n<bcwall->ndescr; n++)
            cgi_free_descr(&bcwall->descr[n]);
        free(bcwall->descr);
    }
    if (bcwall->nuser_data) {
        for (n=0; n<bcwall->nuser_data; n++)
            cgi_free_user_data(&bcwall->user_data[n]);
        free(bcwall->user_data);
    }
}

void cgi_free_bcarea(cgns_bcarea *bcarea)
{
    int n;
    if (bcarea->link) free(bcarea->link);
    if (bcarea->ndescr) {
        for (n=0; n<bcarea->ndescr; n++)
            cgi_free_descr(&bcarea->descr[n]);
        free(bcarea->descr);
    }
    if (bcarea->narrays) {
        for (n=0; n<bcarea->narrays; n++)
            cgi_free_array(&bcarea->array[n]);
        free(bcarea->array);
    }
    if (bcarea->nuser_data) {
        for (n=0; n<bcarea->nuser_data; n++)
            cgi_free_user_data(&bcarea->user_data[n]);
        free(bcarea->user_data);
    }
}

void cgi_free_cperio(cgns_cperio *cperio)
{
    int n;
    if (cperio->link) free(cperio->link);
    if (cperio->ndescr) {
        for (n=0; n<cperio->ndescr; n++)
            cgi_free_descr(&cperio->descr[n]);
        free(cperio->descr);
    }
    if (cperio->narrays) {
        for (n=0; n<cperio->narrays; n++)
            cgi_free_array(&cperio->array[n]);
        free(cperio->array);
    }
    if (cperio->units) {
        cgi_free_units(cperio->units);
        free(cperio->units);
    }
    if (cperio->nuser_data) {
        for (n=0; n<cperio->nuser_data; n++)
            cgi_free_user_data(&cperio->user_data[n]);
        free(cperio->user_data);
    }
}

void cgi_free_caverage(cgns_caverage *caverage)
{
    int n;
    if (caverage->link) free(caverage->link);
    if (caverage->ndescr) {
        for (n=0; n<caverage->ndescr; n++)
            cgi_free_descr(&caverage->descr[n]);
        free(caverage->descr);
    }
    if (caverage->nuser_data) {
        for (n=0; n<caverage->nuser_data; n++)
            cgi_free_user_data(&caverage->user_data[n]);
        free(caverage->user_data);
    }
}

void cgi_free_user_data(cgns_user_data *user_data)
{
    int n;
    if (user_data->link) free(user_data->link);
    if (user_data->ndescr) {
        for (n=0; n<user_data->ndescr; n++)
            cgi_free_descr(&user_data->descr[n]);
        free(user_data->descr);
    }
    if (user_data->narrays) {
        for (n=0; n<user_data->narrays; n++)
            cgi_free_array(&user_data->array[n]);
        free(user_data->array);
    }
    if (user_data->ptset) {
        cgi_free_ptset(user_data->ptset);
        free(user_data->ptset);
    }
    if (user_data->units) {
        cgi_free_units(user_data->units);
        free(user_data->units);
    }
    if (user_data->nuser_data) {
        for (n=0; n < user_data->nuser_data; n++)
            cgi_free_user_data(&user_data->user_data[n]);
        free(user_data->user_data);
    }
    if (user_data->nfamname) {
        for (n = 0; n < user_data->nfamname; n++)
            cgi_free_famname(&user_data->famname[n]);
        free(user_data->famname);
    }
}

void cgi_free_subreg(cgns_subreg *subreg)
{
    int n;
    if (subreg->link) free(subreg->link);
    if (subreg->ndescr) {
        for (n=0; n<subreg->ndescr; n++)
            cgi_free_descr(&subreg->descr[n]);
        free(subreg->descr);
    }
    if (subreg->narrays) {
        for (n=0; n<subreg->narrays; n++)
            cgi_free_array(&subreg->array[n]);
        free(subreg->array);
    }
    if (subreg->ptset) {
        cgi_free_ptset(subreg->ptset);
        free(subreg->ptset);
    }
    if (subreg->bcname) cgi_free_descr(subreg->bcname);
    if (subreg->gcname) cgi_free_descr(subreg->gcname);
    if (subreg->units) {
        cgi_free_units(subreg->units);
        free(subreg->units);
    }
    if (subreg->rind_planes) free(subreg->rind_planes);
    if (subreg->nuser_data) {
        for (n=0; n < subreg->nuser_data; n++)
            cgi_free_user_data(&subreg->user_data[n]);
        free(subreg->user_data);
    }
    if (subreg->nfamname) {
        for (n = 0; n < subreg->nfamname; n++)
            cgi_free_famname(&subreg->famname[n]);
        free(subreg->famname);
    }
}

/***********************************************************************\
 *            Return the string from enumeration           *
\***********************************************************************/

int cgi_GridLocation(char *LocationName, CGNS_ENUMT(GridLocation_t) *type)
{
    int i;
    for (i=0; i<NofValidGridLocation; i++) {
    if (strcmp(LocationName, GridLocationName[i])==0) {
      (*type) = (CGNS_ENUMV( GridLocation_t ))i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( GridLocationUserDefined );
        cgi_warning("Unrecognized Grid Location Type '%s' replaced with 'UserDefined'",LocationName);
        return 0;
    }
    cgi_error("Unrecognized GridLocation: %s", LocationName);
    return 1;
}

int cgi_GridConnectivityType(char *GridConnectivityName, CGNS_ENUMT(GridConnectivityType_t) *type)
{
    int i;
    for (i=0; i<NofValidGridConnectivityTypes; i++) {
        if (strcmp(GridConnectivityName, GridConnectivityTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( GridConnectivityType_t ))i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( GridConnectivityTypeUserDefined );
        cgi_warning("Unrecognized Grid Connectivity Type '%s' replaced with 'UserDefined'",GridConnectivityName);
        return 0;
    }
    cgi_error("Unrecognized GridConnectivityType: %s", GridConnectivityName);
    return 1;
}

int cgi_PointSetType(char *PointSetName, CGNS_ENUMT(PointSetType_t) *type)
{
    int i;
    for (i=0; i<NofValidPointSetTypes; i++) {
        if (strcmp(PointSetName, PointSetTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( PointSetType_t ))i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( PointSetTypeUserDefined );
        cgi_warning("Unrecognized Point Set Type '%s' replaced with 'UserDefined'",PointSetName);
        return 0;
    }
    cgi_error("Unrecognized PointSetType: %s", PointSetName);
    return 1;
}

int cgi_BCType(char *BCName, CGNS_ENUMT(BCType_t) *type)
{
    int i;
    for (i=0; i<NofValidBCTypes; i++) {
        if (strcmp(BCName, BCTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( BCType_t ))i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( BCTypeUserDefined );
        cgi_warning("Unrecognized BCType '%s' replaced with 'UserDefined'",BCName);
        return 0;
    }
    cgi_error("Unrecognized BCType: %s", BCName);
    return 1;
}

int cgi_DataClass(char *Name, CGNS_ENUMT(DataClass_t) *data_class)
{
    int i;
    for (i=0; i<NofValidDataClass; i++) {
        if (strcmp(Name, DataClassName[i])==0) {
          (*data_class) = (CGNS_ENUMV( DataClass_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*data_class) = CGNS_ENUMV( DataClassUserDefined );
        cgi_warning("Unrecognized Data Class '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Data Class: %s",Name);
    return 1;
}

int cgi_MassUnits(char *Name, CGNS_ENUMT(MassUnits_t) *mass_unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';

    for (i=0; i<NofValidMassUnits; i++) {
        if (strcmp(Name, MassUnitsName[i])==0) {
          (*mass_unit) = (CGNS_ENUMV( MassUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*mass_unit) = CGNS_ENUMV( MassUnitsUserDefined );
        cgi_warning("Unrecognized Mass Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*mass_unit) = CGNS_ENUMV( MassUnitsNull );
    cgi_error("Unrecognized Mass Units Name: %s", Name);
    return 1;
}

int cgi_LengthUnits(char *Name, CGNS_ENUMT(LengthUnits_t) *length_unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';

    for (i=0; i<NofValidLengthUnits; i++) {
        if (strcmp(Name, LengthUnitsName[i])==0) {
          (*length_unit) = (CGNS_ENUMV( LengthUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*length_unit) = CGNS_ENUMV( LengthUnitsUserDefined );
        cgi_warning("Unrecognized Length Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*length_unit) = CGNS_ENUMV( LengthUnitsNull );
    cgi_error("Unrecognized Length Units Name: %s", Name);
    return 1;
}

int cgi_TimeUnits(char *Name, CGNS_ENUMT(TimeUnits_t) *time_unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';

    for (i=0; i<NofValidTimeUnits; i++) {
        if (strcmp(Name, TimeUnitsName[i])==0) {
          (*time_unit) = (CGNS_ENUMV( TimeUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*time_unit) = CGNS_ENUMV( TimeUnitsUserDefined );
        cgi_warning("Unrecognized Time Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*time_unit) = CGNS_ENUMV( TimeUnitsNull );
    cgi_error("Unrecognized Time Units Name: %s", Name);
    return 1;
}

int cgi_TemperatureUnits(char *Name, CGNS_ENUMT(TemperatureUnits_t) *temperature_unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';
    if (0 == strcmp(Name, "Celcius")) {
      *temperature_unit = CGNS_ENUMV( Celsius );
        return 0;
    }

    for (i=0; i<NofValidTemperatureUnits; i++) {
        if (strcmp(Name, TemperatureUnitsName[i])==0) {
          (*temperature_unit) = (CGNS_ENUMV( TemperatureUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*temperature_unit) = CGNS_ENUMV( TemperatureUnitsUserDefined );
        cgi_warning("Unrecognized Temperature Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*temperature_unit) = CGNS_ENUMV( TemperatureUnitsNull );
    cgi_error("Unrecognized Temperature Units Name: %s", Name);
    return 1;
}

int cgi_AngleUnits(char *Name, CGNS_ENUMT(AngleUnits_t) *angle_unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';

    for (i=0; i<NofValidAngleUnits; i++) {
        if (strcmp(Name, AngleUnitsName[i])==0) {
          (*angle_unit) = (CGNS_ENUMV( AngleUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*angle_unit) = CGNS_ENUMV( AngleUnitsUserDefined );
        cgi_warning("Unrecognized Angle Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*angle_unit) = CGNS_ENUMV( AngleUnitsNull );
    cgi_error("Unrecognized Angle Units Name: %s", Name);
    return 1;
}

int cgi_ElectricCurrentUnits(char *Name, CGNS_ENUMT(ElectricCurrentUnits_t) *unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';

    for (i=0; i<NofValidElectricCurrentUnits; i++) {
        if (strcmp(Name, ElectricCurrentUnitsName[i])==0) {
          (*unit) = (CGNS_ENUMV( ElectricCurrentUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*unit) = CGNS_ENUMV( ElectricCurrentUnitsUserDefined );
        cgi_warning("Unrecognized ElectricCurrent Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*unit) = CGNS_ENUMV( ElectricCurrentUnitsNull );
    cgi_error("Unrecognized ElectricCurrent Units Name: %s", Name);
    return 1;
}

int cgi_SubstanceAmountUnits(char *Name, CGNS_ENUMT(SubstanceAmountUnits_t) *unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';

    for (i=0; i<NofValidSubstanceAmountUnits; i++) {
        if (strcmp(Name, SubstanceAmountUnitsName[i])==0) {
          (*unit) = (CGNS_ENUMV( SubstanceAmountUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*unit) = CGNS_ENUMV( SubstanceAmountUnitsUserDefined );
        cgi_warning("Unrecognized SubstanceAmount Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*unit) = CGNS_ENUMV( SubstanceAmountUnitsNull );
    cgi_error("Unrecognized SubstanceAmount Units Name: %s", Name);
    return 1;
}

int cgi_LuminousIntensityUnits(char *Name, CGNS_ENUMT(LuminousIntensityUnits_t) *unit)
{
    int i;

    for (i=31; i>=0 && Name[i]==' '; i--);
    Name[i+1]='\0';

    for (i=0; i<NofValidLuminousIntensityUnits; i++) {
        if (strcmp(Name, LuminousIntensityUnitsName[i])==0) {
          (*unit) = (CGNS_ENUMT( LuminousIntensityUnits_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*unit) = CGNS_ENUMV( LuminousIntensityUnitsUserDefined );
        cgi_warning("Unrecognized LuminousIntensity Unit '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    (*unit) = CGNS_ENUMV( LuminousIntensityUnitsNull );
    cgi_error("Unrecognized LuminousIntensity Units Name: %s", Name);
    return 1;
}

int cgi_GoverningEquationsType(char *Name, CGNS_ENUMT(GoverningEquationsType_t) *type)
{
    int i;
    for (i=0; i<NofValidGoverningEquationsTypes; i++) {
        if (strcmp(Name, GoverningEquationsTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( GoverningEquationsType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( GoverningEquationsUserDefined );
        cgi_warning("Unrecognized Governing Equations Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Governing Equations Type: %s", Name);
    return 1;
}

int cgi_ModelType(char *Name, CGNS_ENUMT(ModelType_t) *type)
{
    int i;
    for (i=0; i<NofValidModelTypes; i++) {
        if (strcmp(Name, ModelTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( ModelType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( ModelTypeUserDefined );
        cgi_warning("Unrecognized Model Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Model Type : %s", Name);
    return 1;
}

int cgi_ZoneType(char *Name, CGNS_ENUMT(ZoneType_t) *type)
{
    int i;
    for (i=0; i<NofValidZoneTypes; i++) {
        if (strcmp(Name, ZoneTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( ZoneType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( ZoneTypeUserDefined );
        cgi_warning("Unrecognized Zone Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Zone Type : %s", Name);
    return 1;
}

int cgi_RigidGridMotionType(char *Name, CGNS_ENUMT(RigidGridMotionType_t) *type)
{
    int i;
    for (i=0; i<NofValidRigidGridMotionTypes; i++) {
        if (strcmp(Name, RigidGridMotionTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( RigidGridMotionType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( RigidGridMotionTypeUserDefined );
        cgi_warning("Unrecognized Rigid Grid Motion Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Rigid Grid Motion Type: %s", Name);
    return 1;
}

int cgi_ArbitraryGridMotionType(char *Name, CGNS_ENUMT(ArbitraryGridMotionType_t) *type)
{
    int i;
    for (i=0; i<NofValidArbitraryGridMotionTypes; i++) {
        if (strcmp(Name, ArbitraryGridMotionTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( ArbitraryGridMotionType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( ArbitraryGridMotionTypeUserDefined );
        cgi_warning("Unrecognized Arbitrary Grid Motion Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Arbitrary Grid Motion Type: %s", Name);
    return 1;
}

int cgi_SimulationType(char *Name, CGNS_ENUMT(SimulationType_t) *type)
{
    int i;
    for (i=0; i<NofValidSimulationTypes; i++) {
        if (strcmp(Name, SimulationTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( SimulationType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( SimulationTypeUserDefined );
        cgi_warning("Unrecognized Simulation Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Simulation Type: %s", Name);
    return 1;
}

int cgi_WallFunctionType(char *Name, CGNS_ENUMT(WallFunctionType_t) *type)
{
    int i;
    for (i=0; i<NofValidWallFunctionTypes; i++) {
        if (strcmp(Name, WallFunctionTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( WallFunctionType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( WallFunctionTypeUserDefined );
        cgi_warning("Unrecognized Wall Function Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Wall Function Type: %s", Name);
    return 1;
}

int cgi_AreaType(char *Name, CGNS_ENUMT(AreaType_t) *type)
{
    int i;
    for (i=0; i<NofValidAreaTypes; i++) {
        if (strcmp(Name, AreaTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( AreaType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( AreaTypeUserDefined );
        cgi_warning("Unrecognized Area Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Area Type: %s", Name);
    return 1;
}

int cgi_AverageInterfaceType(char *Name, CGNS_ENUMT(AverageInterfaceType_t) *type)
{
    int i;
    for (i=0; i<NofValidAverageInterfaceTypes; i++) {
        if (strcmp(Name, AverageInterfaceTypeName[i])==0) {
          (*type) = (CGNS_ENUMV( AverageInterfaceType_t )) i;
            return 0;
        }
    }
    if (cg->version > CGNSLibVersion) {
      (*type) = CGNS_ENUMV( AverageInterfaceTypeUserDefined );
        cgi_warning("Unrecognized Average Interface Type '%s' replaced with 'UserDefined'",Name);
        return 0;
    }
    cgi_error("Unrecognized Average Interface Type: %s", Name);
    return 1;
}

void cgi_array_print(char *routine, cgns_array *array)
{
    int n;

    printf("In %s:\n", routine);
    printf("\t array->name='%s'\n",array->name);
    printf("\t array->dim_vals=");
    for (n=0; n<array->data_dim; n++)
        printf("%ld ",(long)array->dim_vals[n]);
    printf("\n");
    printf("\t array->data_type='%s'\n",DataTypeName[cgi_datatype(array->data_type)]);
    printf("\t array->id=%13.6e\n",array->id);
    printf("\t array->ndescr=%d\n",array->ndescr);
    for (n=0; n<array->ndescr; n++) printf("%s\n",array->descr->text);
    if (array->data_class)
        printf("\t array->data_class=%s\n",DataClassName[array->data_class]);
    for (n=0; n<(array->dim_vals[0]*array->dim_vals[1]); n++)
        printf("%d ", *((int *)array->data+n));

    return;
}

