<commit_before>

/*----------------------------------------------------------*/
/*                                                          */
/*                        LIBMESH V 7.21                    */
/*                                                          */
/*----------------------------------------------------------*/
/*                                                          */
/*    Description:        handle .meshb file format I/O     */
/*    Author:             <NAME>                     */
/*    Creation date:      dec 09 1999                       */
/*    Last modification:  dec 07 2016                       */
/*                                                          */
/*----------------------------------------------------------*/

/*----------------------------------------------------------*/
/* Headers' macros                                          */
/*----------------------------------------------------------*/

#ifdef F77API

#ifdef F77_NO_UNDER_SCORE
#define NAMF77(c,f) f
#define APIF77(x) x
#else
#define NAMF77(c,f) f ## _
#define APIF77(x) x ## _
#endif

#define VALF77(v) *v
#define TYPF77(t) t*
#define PRCF77(p) *((int *)p)

#else

#define NAMF77(c,f) c
#define VALF77(v) v
#define TYPF77(t) t
#define PRCF77(p) p

#endif


/*----------------------------------------------------------*/
/* Includes                                                 */
/*----------------------------------------------------------*/

#define _XOPEN_SOURCE 500

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
#include <math.h>
#include <ctype.h>
#include <setjmp.h>
#include <fcntl.h>

 
/*
 * [Bruno] include the headers with the prototypes for 
 *  open()/close()/write()/lseek() 
 *  and define the constants to be used to open() a file. 
 *    Under Windows, 
 *  1)   _O_BINARY should be set in the flags.
 *  2) 'mode' has a completely different meaning
 */

#if defined(__unix__) || defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)

#include <unistd.h>

#define OPEN_READ_FLAGS    O_RDONLY
#define OPEN_WRITE_FLAGS   O_CREAT | O_WRONLY | O_TRUNC
#define OPEN_READ_MODE     0666
#define OPEN_WRITE_MODE    0666    
    
#elif defined(WIN32) || defined(_WIN64)

#define GMF_WINDOWS

#include <windows.h>
#include <io.h>
#include <sys/stat.h>

#define OPEN_READ_FLAGS   O_RDONLY | _O_BINARY
#define OPEN_WRITE_FLAGS  O_CREAT | O_WRONLY | O_TRUNC | _O_BINARY
#define OPEN_READ_MODE    _S_IREAD
#define OPEN_WRITE_MODE   _S_IREAD | S_IWRITE 

#endif

#include <errno.h>
#include "libmeshb7.h"

/* [Bruno] Using portable printf modifier from pstdint.h        */
/* (alternative: use "%zd" under Linux and "%Id" under Windows) */

#ifdef PRINTF_INT64_MODIFIER
#define INT64_T_FMT "%" PRINTF_INT64_MODIFIER "d"
#else
#   ifdef GMF_WINDOWS
#     define INT64_T_FMT "%Id"
#   else
#     define INT64_T_FMT "%lld"
#   endif
#endif

/* [Bruno] Made asynchronous I/O optional */
#ifdef WITH_AIO
#include <aio.h>
#else

struct aiocb
{
        FILE            *aio_fildes;            /* File descriptor */
        off_t           aio_offset;             /* File offset */
        void            *aio_buf;               /* Location of buffer */
        size_t          aio_nbytes;             /* Length of transfer */
        int             aio_lio_opcode;         /* Operation to be performed */
};

int aio_error( const struct aiocb * aiocbp )
{
            return(aiocbp->aio_lio_opcode);
}

int aio_read( struct aiocb * aiocbp )
{
    if(fread(aiocbp->aio_buf, 1, aiocbp->aio_nbytes, aiocbp->aio_fildes) == aiocbp->aio_nbytes)
        aiocbp->aio_lio_opcode = 0;
    else
        aiocbp->aio_lio_opcode = -1;

    return(aiocbp->aio_lio_opcode);
}

ssize_t aio_return( struct aiocb * aiocbp )
{
    return(aiocbp->aio_nbytes);
}

int aio_write( struct aiocb * aiocbp )
{
    if(fwrite(aiocbp->aio_buf, 1, aiocbp->aio_nbytes, aiocbp->aio_fildes) == aiocbp->aio_nbytes)
        aiocbp->aio_lio_opcode = 0;
    else
        aiocbp->aio_lio_opcode = -1;

    return(aiocbp->aio_lio_opcode);
}

#endif



/*----------------------------------------------------------*/
/* Defines                                                  */
/*----------------------------------------------------------*/

#define Asc 1
#define Bin 2
#define MshFil 4
#define SolFil 8
#define InfKwd 1
#define RegKwd 2
#define SolKwd 3
#define CmtKwd 4
#define WrdSiz 4
#define FilStrSiz 64
#define BufSiz 10000
#define MaxArg 20


/*----------------------------------------------------------*/
/* Structures                                               */
/*----------------------------------------------------------*/

typedef struct
{
    int typ, SolSiz, NmbWrd, NmbTyp, TypTab[ GmfMaxTyp ];
    int64_t NmbLin, pos;
    char fmt[ GmfMaxTyp*9 ];
}KwdSct;

typedef struct
{
    int dim, ver, mod, typ, cod, FilDes;
    int64_t NexKwdPos, siz, pos;
    jmp_buf err;
    KwdSct KwdTab[ GmfMaxKwd + 1 ];
    FILE *hdl;
    int *IntBuf;
    float *FltBuf;
    char *buf;
    char FilNam[ GmfStrSiz ];
    double DblBuf[1000/8];
    unsigned char blk[ BufSiz + 1000 ];
}GmfMshSct;


/*----------------------------------------------------------*/
/* Global variables                                         */
/*----------------------------------------------------------*/

const char *GmfKwdFmt[ GmfMaxKwd + 1 ][4] = 
{    {"Reserved", "", "", ""},
    {"MeshVersionFormatted", "", "", "i"},
    {"Reserved", "", "", ""},
    {"Dimension", "", "", "i"},
    {"Vertices", "Vertex", "i", "dri"},
    {"Edges", "Edge", "i", "iii"},
    {"Triangles", "Triangle", "i", "iiii"},
    {"Quadrilaterals", "Quadrilateral", "i", "iiiii"},
    {"Tetrahedra", "Tetrahedron", "i", "iiiii"},
    {"Prisms", "Prism", "i", "iiiiiii"},
    {"Hexahedra", "Hexahedron", "i", "iiiiiiiii"},
    {"IterationsAll", "IterationAll","","i"},
    {"TimesAll", "TimeAll","","r"},                    
    {"Corners", "Corner", "i", "i"},
    {"Ridges", "Ridge", "i", "i"},
    {"RequiredVertices", "RequiredVertex", "i", "i"},
    {"RequiredEdges", "RequiredEdge", "i", "i"},
    {"RequiredTriangles", "RequiredTriangle", "i", "i"},
    {"RequiredQuadrilaterals", "RequiredQuadrilateral", "i", "i"},
    {"TangentAtEdgeVertices", "TangentAtEdgeVertex", "i", "iii"},
    {"NormalAtVertices", "NormalAtVertex", "i", "ii"},
    {"NormalAtTriangleVertices", "NormalAtTriangleVertex", "i", "iii"},
    {"NormalAtQuadrilateralVertices", "NormalAtQuadrilateralVertex", "i", "iiii"},
    {"AngleOfCornerBound", "", "", "r"},
    {"TrianglesP2", "TriangleP2", "i", "iiiiiii"},
    {"EdgesP2", "EdgeP2", "i", "iiii"},
    {"SolAtPyramids", "SolAtPyramid", "i", "sr"},
    {"QuadrilateralsQ2", "QuadrilateralQ2", "i", "iiiiiiiiii"},
    {"ISolAtPyramids", "ISolAtPyramid", "i", "iiiii"},
    {"SubDomainFromGeom", "SubDomainFromGeom", "i", "iii"},
    {"TetrahedraP2", "TetrahedronP2", "i", "iiiiiiiiiii"},
    {"Fault_NearTri", "Fault_NearTri", "i", "i"},
    {"Fault_Inter", "Fault_Inter", "i", "i"},
    {"HexahedraQ2", "HexahedronQ2", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiii"},
    {"ExtraVerticesAtEdges", "ExtraVerticesAtEdge", "i", "in"},
    {"ExtraVerticesAtTriangles", "ExtraVerticesAtTriangle", "i", "in"},
    {"ExtraVerticesAtQuadrilaterals", "ExtraVerticesAtQuadrilateral", "i", "in"},
    {"ExtraVerticesAtTetrahedra", "ExtraVerticesAtTetrahedron", "i", "in"},
    {"ExtraVerticesAtPrisms", "ExtraVerticesAtPrism", "i", "in"},
    {"ExtraVerticesAtHexahedra", "ExtraVerticesAtHexahedron", "i", "in"},
    {"VerticesOnGeometricVertices", "VertexOnGeometricVertex", "i", "iir"},
    {"VerticesOnGeometricEdges", "VertexOnGeometricEdge", "i", "iirr"},
    {"VerticesOnGeometricTriangles", "VertexOnGeometricTriangle", "i", "iirrr"},
    {"VerticesOnGeometricQuadrilaterals", "VertexOnGeometricQuadrilateral", "i", "iirrr"},
    {"EdgesOnGeometricEdges", "EdgeOnGeometricEdge", "i", "iir"},
    {"Fault_FreeEdge", "Fault_FreeEdge", "i", "i"},
    {"Polyhedra", "Polyhedron", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"},
    {"Polygons", "Polygon", "", "iiiiiiiii"},
    {"Fault_Overlap", "Fault_Overlap", "i", "i"},
    {"Pyramids", "Pyramid", "i", "iiiiii"},
    {"BoundingBox", "", "", "drdr"},
    {"Body","i", "drdrdrdr"},
    {"PrivateTable", "PrivateTable", "i", "i"},
    {"Fault_BadShape", "Fault_BadShape", "i", "i"},
    {"End", "", "", ""},
    {"TrianglesOnGeometricTriangles", "TriangleOnGeometricTriangle", "i", "iir"},
    {"TrianglesOnGeometricQuadrilaterals", "TriangleOnGeometricQuadrilateral", "i", "iir"},
    {"QuadrilateralsOnGeometricTriangles", "QuadrilateralOnGeometricTriangle", "i", "iir"},
    {"QuadrilateralsOnGeometricQuadrilaterals", "QuadrilateralOnGeometricQuadrilateral", "i", "iir"},
    {"Tangents", "Tangent", "i", "dr"},
    {"Normals", "Normal", "i", "dr"},
    {"TangentAtVertices", "TangentAtVertex", "i", "ii"},
    {"SolAtVertices", "SolAtVertex", "i", "sr"},
    {"SolAtEdges", "SolAtEdge", "i", "sr"},
    {"SolAtTriangles", "SolAtTriangle", "i", "sr"},
    {"SolAtQuadrilaterals", "SolAtQuadrilateral", "i", "sr"},
    {"SolAtTetrahedra", "SolAtTetrahedron", "i", "sr"},
    {"SolAtPrisms", "SolAtPrism", "i", "sr"},
    {"SolAtHexahedra", "SolAtHexahedron", "i", "sr"},
    {"DSolAtVertices", "DSolAtVertex", "i", "sr"},
    {"ISolAtVertices", "ISolAtVertex", "i", "i"},
    {"ISolAtEdges", "ISolAtEdge", "i", "ii"},
    {"ISolAtTriangles", "ISolAtTriangle", "i", "iii"},
    {"ISolAtQuadrilaterals", "ISolAtQuadrilateral", "i", "iiii"},
    {"ISolAtTetrahedra", "ISolAtTetrahedron", "i", "iiii"},
    {"ISolAtPrisms", "ISolAtPrism", "i", "iiiiii"},
    {"ISolAtHexahedra", "ISolAtHexahedron", "i", "iiiiiiii"},
    {"Iterations", "","","i"},
    {"Time", "","","r"},
    {"Fault_SmallTri", "Fault_SmallTri","i","i"},
    {"CoarseHexahedra", "CoarseHexahedron", "i", "i"},
    {"Comments", "Comment", "i", "c"},
    {"PeriodicVertices", "PeriodicVertex", "i", "ii"},
    {"PeriodicEdges", "PeriodicEdge", "i", "ii"},
    {"PeriodicTriangles", "PeriodicTriangle", "i", "ii"},
    {"PeriodicQuadrilaterals", "PeriodicQuadrilateral", "i", "ii"},
    {"PrismsP2", "PrismP2", "i", "iiiiiiiiiiiiiiiiiii"},
    {"PyramidsP2", "PyramidP2", "i", "iiiiiiiiiiiiiii"},
    {"QuadrilateralsQ3", "QuadrilateralQ3", "i", "iiiiiiiiiiiiiiiii"},
    {"QuadrilateralsQ4", "QuadrilateralQ4", "i", "iiiiiiiiiiiiiiiiiiiiiiiiii"},
    {"TrianglesP3", "TriangleP3", "i", "iiiiiiiiiii"},
    {"TrianglesP4", "TriangleP4", "i", "iiiiiiiiiiiiiiii"},
    {"EdgesP3", "EdgeP3", "i", "iiiii"},
    {"EdgesP4", "EdgeP4", "i", "iiiiii"},
    {"IRefGroups", "IRefGroup", "i", "c,i,i,i"},
    {"DRefGroups", "DRefGroup", "i", "i,i"}
 };

#ifdef TRANSMESH
int GmfMaxRefTab[ GmfMaxKwd + 1 ];
#endif


/*----------------------------------------------------------*/
/* Prototypes of local procedures                           */
/*----------------------------------------------------------*/

static void ScaWrd(GmfMshSct *, void *);
static void ScaDblWrd(GmfMshSct *, void *);
static int64_t GetPos(GmfMshSct *);
static void RecWrd(GmfMshSct *, const void *);
static void RecDblWrd(GmfMshSct *, const void *);
static void RecBlk(GmfMshSct *, const void *, int);
static void SetPos(GmfMshSct *, int64_t);
static int ScaKwdTab(GmfMshSct *);
static void ExpFmt(GmfMshSct *, int);
static void ScaKwdHdr(GmfMshSct *, int);
static void SwpWrd(char *, int);
static int SetFilPos(GmfMshSct *, int64_t);
static int64_t GetFilPos(GmfMshSct *msh);
static int64_t GetFilSiz(GmfMshSct *);
#ifdef F77API
static void CalF77Prc(int64_t, int64_t, void *, int, void **);
#endif


/*----------------------------------------------------------*/
/* Fscanf and fgets checking for errors                     */
/*----------------------------------------------------------*/

#define safe_fscanf(hdl, format, ptr, JmpErr) \
    do { \
        if( fscanf(hdl, format, ptr) != 1 ) \
            longjmp( JmpErr, -1); \
    } while(0)


#define safe_fgets(ptr, siz, hdl, JmpErr) \
    do { \
        if( fgets(ptr, siz, hdl) == NULL ) \
            longjmp( JmpErr, -1); \
    } while(0)


/*----------------------------------------------------------*/
/* Open a mesh file in read or write mod                    */
/*----------------------------------------------------------*/

int64_t GmfOpenMesh(const char *FilNam, int mod, ...)
{
    int KwdCod, res, *PtrVer, *PtrDim;
    int64_t MshIdx;
    char str[ GmfStrSiz ];
    va_list VarArg;
    GmfMshSct *msh;

    /*---------------------*/
    /* MESH STRUCTURE INIT */
    /*---------------------*/

    if(!(msh = calloc(1, sizeof(GmfMshSct))))
        return(0);

    MshIdx = (int64_t)msh;

    /* Save the current stack environment for longjmp */

    if(setjmp(msh->err) != 0)
    {
        if(msh->hdl != NULL)
            fclose(msh->hdl);

        if(msh->FilDes != 0)
            close(msh->FilDes);

        free(msh);
        return(0);
    }

    /* Copy the FilNam into the structure */

    if(strlen(FilNam) + 7 >= GmfStrSiz)
        longjmp(msh->err, -1);

    strcpy(msh->FilNam, FilNam);

    /* Store the opening mod (read or write) and guess the filetype 
        (binary or ascii) depending on the extension */

    msh->mod = mod;
    msh->buf = (void *)msh->DblBuf;
    msh->FltBuf = (void *)msh->DblBuf;
    msh->IntBuf = (void *)msh->DblBuf;

    if(strstr(msh->FilNam, ".meshb"))
        msh->typ |= (Bin | MshFil);
    else if(strstr(msh->FilNam, ".mesh"))
        msh->typ |= (Asc | MshFil);
    else if(strstr(msh->FilNam, ".solb"))
        msh->typ |= (Bin | SolFil);
    else if(strstr(msh->FilNam, ".sol"))
        msh->typ |= (Asc | SolFil);
    else
        longjmp(msh->err, -1);

    /* Open the file in the required mod and initialyse the mesh structure */

    if(msh->mod == GmfRead)
    {

        /*-----------------------*/
        /* OPEN FILE FOR READING */
        /*-----------------------*/

        va_start(VarArg, mod);
        PtrVer = va_arg(VarArg, int *);
        PtrDim = va_arg(VarArg, int *);
        va_end(VarArg);

        /* Read the endian coding tag, the mesh version and the mesh dimension (mandatory kwd) */

        if(msh->typ & Bin)
        {
            /* Create the name string and open the file */

#ifdef WITH_AIO
            /* [Bruno] added binary flag (necessary under Windows) */
            msh->FilDes = open(msh->FilNam, OPEN_READ_FLAGS, OPEN_READ_MODE);

            if(msh->FilDes <= 0)
                longjmp(msh->err, -1);

            /* Read the endian coding tag */
            if(read(msh->FilDes, &msh->cod, WrdSiz) != WrdSiz)
                longjmp(msh->err, -1);
#else
            /* [Bruno] added binary flag (necessary under Windows) */
            if(!(msh->hdl = fopen(msh->FilNam, "rb")))
                longjmp(msh->err, -1);

            /* Read the endian coding tag */
			if( fread(&msh->cod, WrdSiz, 1, msh->hdl) != 1 )
                longjmp(msh->err, -1);
#endif

            /* Read the mesh version and the mesh dimension (mandatory kwd) */

            if( (msh->cod != 1) && (msh->cod != 16777216) )
                longjmp(msh->err, -1);

            ScaWrd(msh, (unsigned char *)&msh->ver);

            if( (msh->ver < 1) || (msh->ver > 4) )
                longjmp(msh->err, -1);

            if( (msh->ver >= 3) && (sizeof(int64_t) != 8) )
                longjmp(msh->err, -1);

            ScaWrd(msh, (unsigned char *)&KwdCod);

            if(KwdCod != GmfDimension)
                longjmp(msh->err, -1);

            GetPos(msh);
            ScaWrd(msh, (unsigned char *)&msh->dim);
        }
        else
        {
            /* Create the name string and open the file */

            if(!(msh->hdl = fopen(msh->FilNam, "rb")))
                longjmp(msh->err, -1);

            do
            {
                res = fscanf(msh->hdl, "%s", str);
            }while( (res != EOF) && strcmp(str, "MeshVersionFormatted") );

            if(res == EOF)
                longjmp(msh->err, -1);

            safe_fscanf(msh->hdl, "%d", &msh->ver, msh->err);

            if( (msh->ver < 1) || (msh->ver > 4) )
                longjmp(msh->err, -1);

            do
            {
                res = fscanf(msh->hdl, "%s", str);
            }while( (res != EOF) && strcmp(str, "Dimension") );

            if(res == EOF)
                longjmp(msh->err, -1);

            safe_fscanf(msh->hdl, "%d", &msh->dim, msh->err);
        }

        if( (msh->dim != 2) && (msh->dim != 3) )
            longjmp(msh->err, -1);

        (*PtrVer) = msh->ver;
        (*PtrDim) = msh->dim;

        /*------------*/
        /* KW READING */
        /*------------*/

        /* Read the list of kw present in the file */

        if(!ScaKwdTab(msh))
            return(0);

        return(MshIdx);
    }
    else if(msh->mod == GmfWrite)
    {

        /*-----------------------*/
        /* OPEN FILE FOR WRITING */
        /*-----------------------*/

        msh->cod = 1;

        /* Check if the user provided a valid version number and dimension */

        va_start(VarArg, mod);
        msh->ver = va_arg(VarArg, int);
        msh->dim = va_arg(VarArg, int);
        va_end(VarArg);

        if( (msh->ver < 1) || (msh->ver > 4) )
            longjmp(msh->err, -1);

        if( (msh->ver >= 3) && (sizeof(int64_t) != 8) )
            longjmp(msh->err, -1);

        if( (msh->dim != 2) && (msh->dim != 3) )
            longjmp(msh->err, -1);

        /* Create the mesh file */

        if(msh->typ & Bin) 
        {
            /* 
             * [Bruno] replaced previous call to creat():
             * with a call to open(), because Windows needs the
             * binary flag to be specified.
             */
#ifdef WITH_AIO
            msh->FilDes = open(msh->FilNam, OPEN_WRITE_FLAGS, OPEN_WRITE_MODE);

            if(msh->FilDes <= 0)
                longjmp(msh->err, -1);
#else
            if(!(msh->hdl = fopen(msh->FilNam, "wb")))
                longjmp(msh->err, -1);
#endif
        }
        else if(!(msh->hdl = fopen(msh->FilNam, "wb")))
            longjmp(msh->err, -1);


        /*------------*/
        /* KW WRITING */
        /*------------*/

        /* Write the mesh version and dimension */

        if(msh->typ & Asc)
        {
            fprintf(msh->hdl, "%s %d\n\n", GmfKwdFmt[ GmfVersionFormatted ][0], msh->ver);
            fprintf(msh->hdl, "%s %d\n", GmfKwdFmt[ GmfDimension ][0], msh->dim);
        }
        else
        {
            RecWrd(msh, (unsigned char *)&msh->cod);
            RecWrd(msh, (unsigned char *)&msh->ver);
            GmfSetKwd(MshIdx, GmfDimension, 0);
            RecWrd(msh, (unsigned char *)&msh->dim);
        }

        return(MshIdx);
    }
    else
    {
        free(msh);
        return(0);
    }
}


/*----------------------------------------------------------*/
/* Close a meshfile in the right way                        */
/*----------------------------------------------------------*/

int GmfCloseMesh(int64_t MshIdx)
{
    int res = 1;
    GmfMshSct *msh = (GmfMshSct *)MshIdx;

    RecBlk(msh, msh->buf, 0);

    /* In write down the "End" kw in write mode */

    if(msh->mod == GmfWrite)
    {
        if(msh->typ & Asc)
            fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ GmfEnd ][0]);
        else
            GmfSetKwd(MshIdx, GmfEnd, 0);
    }

    /* Close the file and free the mesh structure */

    if(msh->typ & Bin)
#ifdef WITH_AIO
        close(msh->FilDes);
#else
        fclose(msh->hdl);
#endif
    else if(fclose(msh->hdl))
        res = 0;

    free(msh);

    return(res);
}


/*----------------------------------------------------------*/
/* Read the number of lines and set the position to this kwd*/
/*----------------------------------------------------------*/

int64_t GmfStatKwd(int64_t MshIdx, int KwdCod, ...)
{
    int i, *PtrNmbTyp, *PtrSolSiz, *TypTab;
    GmfMshSct *msh = (GmfMshSct *)MshIdx;
    KwdSct *kwd;
    va_list VarArg;

    if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
        return(0);

    kwd = &msh->KwdTab[ KwdCod ];

    if(!kwd->NmbLin)
        return(0);

    /* Read further arguments if this kw is a sol */

    if(kwd->typ == SolKwd)
    {
        va_start(VarArg, KwdCod);

        PtrNmbTyp = va_arg(VarArg, int *);
        *PtrNmbTyp = kwd->NmbTyp;

        PtrSolSiz = va_arg(VarArg, int *);
        *PtrSolSiz = kwd->SolSiz;

        TypTab = va_arg(VarArg, int *);

        for(i=0;i<kwd->NmbTyp;i++)
            TypTab[i] = kwd->TypTab[i];

        va_end(VarArg);
    }

    return(kwd->NmbLin);
}


/*----------------------------------------------------------*/
/* Set the current file position to a given kwd              */
/*----------------------------------------------------------*/

int GmfGotoKwd(int64_t MshIdx, int KwdCod)
{
    GmfMshSct *msh = (GmfMshSct *)MshIdx;
    KwdSct *kwd = &msh->KwdTab[ KwdCod ];

    if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) || !kwd->NmbLin )
        return(0);

    return(SetFilPos(msh, kwd->pos));
}


/*----------------------------------------------------------*/
/* Write the kwd and set the number of lines                */
/*----------------------------------------------------------*/

int GmfSetKwd(int64_t MshIdx, int KwdCod, ...)
{
    int i, *TypTab;
    int64_t NmbLin=0, CurPos;
    va_list VarArg;
    GmfMshSct *msh = (GmfMshSct *)MshIdx;
    KwdSct *kwd;

    RecBlk(msh, msh->buf, 0);

    if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
        return(0);

    kwd = &msh->KwdTab[ KwdCod ];

    /* Read further arguments if this kw has a header */

    if(strlen(GmfKwdFmt[ KwdCod ][2]))
    {
        va_start(VarArg, KwdCod);
        NmbLin = va_arg(VarArg, int64_t);

        if(!strcmp(GmfKwdFmt[ KwdCod ][3], "sr"))
        {
            kwd->NmbTyp = va_arg(VarArg, int);
            TypTab = va_arg(VarArg, int *);

            for(i=0;i<kwd->NmbTyp;i++)
                kwd->TypTab[i] = TypTab[i];
        }

        va_end(VarArg);
    }

    /* Setup the kwd info */

    ExpFmt(msh, KwdCod);

    if(!kwd->typ)
        return(0);
    else if(kwd->typ == InfKwd)
        kwd->NmbLin = 1;
    else
        kwd->NmbLin = NmbLin;

    /* Store the next kwd position in binary file */

    if( (msh->typ & Bin) && msh->NexKwdPos )
    {
        CurPos = GetFilPos(msh);

        if(!SetFilPos(msh, msh->NexKwdPos))
            return(0);

        SetPos(msh, CurPos);

        if(!SetFilPos(msh, CurPos))
            return(0);
    }

    /* Write the header */

    if(msh->typ & Asc)
    {
        fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ KwdCod ][0]);

        if(kwd->typ != InfKwd)
            fprintf(msh->hdl, INT64_T_FMT"\n", kwd->NmbLin);

        /* In case of solution field, write the extended header */

        if(kwd->typ == SolKwd)
        {
            fprintf(msh->hdl, "%d ", kwd->NmbTyp);

            for(i=0;i<kwd->NmbTyp;i++)
                fprintf(msh->hdl, "%d ", kwd->TypTab[i]);

            fprintf(msh->hdl, "\n\n");
        }
    }
    else
    {
        RecWrd(msh, (unsigned char *)&KwdCod);
        msh->NexKwdPos = GetFilPos(msh);
        SetPos(msh, 0);

        if(kwd->typ != InfKwd)
        {
            if(msh->ver < 4)
            {
                i = (int)kwd->NmbLin;
                RecWrd(msh, (unsigned char *)&i);
            }
            else
                RecDblWrd(msh, (unsigned char *)&kwd->NmbLin);
        }

        /* In case of solution field, write the extended header at once */

        if(kwd->typ == SolKwd)
        {
            RecWrd(msh, (unsigned char *)&kwd->NmbTyp);

            for(i=0;i<kwd->NmbTyp;i++)
                RecWrd(msh, (unsigned char *)&kwd->TypTab[i]);
        }
    }

    /* Reset write buffer position */
    msh->pos = 0;

    /* Estimate the total file size and check whether it crosses the 2GB threshold */
    msh->siz += kwd->NmbLin * kwd->NmbWrd * WrdSiz;

    return(1);
}


/*----------------------------------------------------------*/
/* Read a full line from the current kwd                    */
/*----------------------------------------------------------*/

int NAMF77(GmfGetLin, gmfgetlin)(TYPF77(int64_t) MshIdx, TYPF77(int) KwdCod, ...)
{
    int i, j;
    float *FltSolTab;
    double *DblSolTab;
    va_list VarArg;
    GmfMshSct *msh = (GmfMshSct *) VALF77(MshIdx);
    KwdSct *kwd = &msh->KwdTab[ VALF77(KwdCod) ];

    if( (VALF77(KwdCod) < 1) || (VALF77(KwdCod) > GmfMaxKwd) )
        return(0);

    /* Save the current stack environment for longjmp */

    if(setjmp(msh->err) != 0)
        return(0);

    /* Start decoding the arguments */

    va_start(VarArg, KwdCod);

    switch(kwd->typ)
    {
        case InfKwd : case RegKwd : case CmtKwd :
        {
            if(msh->typ & Asc)
            {
                for(i=0;i<kwd->SolSiz;i++)
                    if(kwd->fmt[i] == 'r')
                        if(msh->ver <= 1)
                            safe_fscanf(msh->hdl, "%f", va_arg(VarArg, float *), msh->err);
                        else
                            safe_fscanf(msh->hdl, "%lf", va_arg(VarArg, double *), msh->err);
                    else if(kwd->fmt[i] == 'i')
                        if(msh->ver <= 3)
                            safe_fscanf(msh->hdl, "%d", va_arg(VarArg, int *), msh->err);
                        else
                            /* [Bruno] %ld -> INT64_T_FMT */
                            safe_fscanf(msh->hdl, INT64_T_FMT, va_arg(VarArg, int64_t *), msh->err);
                    else if(kwd->fmt[i] == 'c')
                        safe_fgets(va_arg(VarArg, char *), WrdSiz * FilStrSiz, msh->hdl, msh->err);
            }
            else
            {
                for(i=0;i<kwd->SolSiz;i++)
                    if(kwd->fmt[i] == 'r')
                        if(msh->ver <= 1)
                            ScaWrd(msh, (unsigned char *)va_arg(VarArg, float *));
                        else
                            ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, double *));
                    else if(kwd->fmt[i] == 'i')
                        if(msh->ver <= 3)
                            ScaWrd(msh, (unsigned char *)va_arg(VarArg, int *));
                        else
                            ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, int64_t *));
                    else if(kwd->fmt[i] == 'c')
                        /* [Bruno] added error control */
                        if(fread(va_arg(VarArg, char *), WrdSiz, FilStrSiz, msh->hdl) != FilStrSiz) {
                            longjmp(msh->err, -1);
                        }
            }
        }break;

        case SolKwd :
        {
            if(msh->ver == 1)
            {
                FltSolTab = va_arg(VarArg, float *);

                if(msh->typ & Asc)
                    for(j=0;j<kwd->SolSiz;j++)
                        safe_fscanf(msh->hdl, "%f", &FltSolTab[j], msh->err);
                else
                    for(j=0;j<kwd->SolSiz;j++)
                        ScaWrd(msh, (unsigned char *)&FltSolTab[j]);
            }
            else
            {
                DblSolTab = va_arg(VarArg, double *);

                if(msh->typ & Asc)
                    for(j=0;j<kwd->SolSiz;j++)
                        safe_fscanf(msh->hdl, "%lf", &DblSolTab[j], msh->err);
                else
                    for(j=0;j<kwd->SolSiz;j++)
                        ScaDblWrd(msh, (unsigned char *)&DblSolTab[j]);
            }
        }break;
    }

    va_end(VarArg);

    return(1);
}


/*----------------------------------------------------------*/
/* Write a full line from the current kwd                   */
/*----------------------------------------------------------*/

int NAMF77(GmfSetLin, gmfsetlin)(TYPF77(int64_t) MshIdx, TYPF77(int) KwdCod, ...)
{
    int i, j, pos, *IntBuf;
    int64_t *LngBuf;
    float *FltSolTab, *FltBuf;
    double *DblSolTab, *DblBuf;
    va_list VarArg;
    GmfMshSct *msh = (GmfMshSct *) VALF77(MshIdx);
    KwdSct *kwd = &msh->KwdTab[ VALF77(KwdCod) ];

    if( ( VALF77(KwdCod) < 1) || ( VALF77(KwdCod) > GmfMaxKwd) )
        return(0);

    /* Start decoding the arguments */

    va_start(VarArg, KwdCod);

    if(kwd->typ != SolKwd)
    {
        if(msh->typ & Asc)
        {
            for(i=0;i<kwd->SolSiz;i++)
            {
                if(kwd->fmt[i] == 'r')
                {
                    if(msh->ver <= 1)
                        fprintf(msh->hdl, "%g ", VALF77(va_arg(VarArg, TYPF77(double))));
                    else
                        fprintf(msh->hdl, "%.15g ", VALF77(va_arg(VarArg, TYPF77(double))));
                }
                else if(kwd->fmt[i] == 'i')
                {
                    if(msh->ver <= 3)
                        fprintf(msh->hdl, "%d ", VALF77(va_arg(VarArg, TYPF77(int))));
                    else
                        /* [Bruno] %ld -> INT64_T_FMT */
                        fprintf(msh->hdl, INT64_T_FMT " ", VALF77(va_arg(VarArg, TYPF77(int64_t))));
                }
                else if(kwd->fmt[i] == 'c')
                    fprintf(msh->hdl, "%s ", va_arg(VarArg, char *));
            }
        }
        else
        {
            pos = 0;

            for(i=0;i<kwd->SolSiz;i++)
            {
                if(kwd->fmt[i] == 'r')
                {
                    if(msh->ver <= 1)
                    {
                        FltBuf = (void *)&msh->buf[ pos ];
                        *FltBuf = (float) VALF77(va_arg(VarArg, TYPF77(double)));
                        pos += 4;
                    }
                    else
                    {
                        DblBuf = (void *)&msh->buf[ pos ];
                        *DblBuf = VALF77(va_arg(VarArg, TYPF77(double)));
                        pos += 8;
                    }
                }
                else if(kwd->fmt[i] == 'i')<commit_msg>Bug correct: GmfGetLin was not working in Fortran while reading real*4 values.<commit_after>

/*----------------------------------------------------------*/
/*                                                          */
/*                        LIBMESH V 7.22                    */
/*                                                          */
/*----------------------------------------------------------*/
/*                                                          */
/*    Description:        handle .meshb file format I/O     */
/*    Author:             <NAME>                     */
/*    Creation date:      dec 09 1999                       */
/*    Last modification:  dec 15 2016                       */
/*                                                          */
/*----------------------------------------------------------*/

/*----------------------------------------------------------*/
/* Headers' macros                                          */
/*----------------------------------------------------------*/

#ifdef F77API

#ifdef F77_NO_UNDER_SCORE
#define NAMF77(c,f) f
#define APIF77(x) x
#else
#define NAMF77(c,f) f ## _
#define APIF77(x) x ## _
#endif

#define VALF77(v) *v
#define TYPF77(t) t*
#define PRCF77(p) *((int *)p)

#else

#define NAMF77(c,f) c
#define VALF77(v) v
#define TYPF77(t) t
#define PRCF77(p) p

#endif


/*----------------------------------------------------------*/
/* Includes                                                 */
/*----------------------------------------------------------*/

#define _XOPEN_SOURCE 500

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
#include <math.h>
#include <ctype.h>
#include <setjmp.h>
#include <fcntl.h>

 
/*
 * [Bruno] include the headers with the prototypes for 
 *  open()/close()/write()/lseek() 
 *  and define the constants to be used to open() a file. 
 *    Under Windows, 
 *  1)   _O_BINARY should be set in the flags.
 *  2) 'mode' has a completely different meaning
 */

#if defined(__unix__) || defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)

#include <unistd.h>

#define OPEN_READ_FLAGS    O_RDONLY
#define OPEN_WRITE_FLAGS   O_CREAT | O_WRONLY | O_TRUNC
#define OPEN_READ_MODE     0666
#define OPEN_WRITE_MODE    0666    
    
#elif defined(WIN32) || defined(_WIN64)

#define GMF_WINDOWS

#include <windows.h>
#include <io.h>
#include <sys/stat.h>

#define OPEN_READ_FLAGS   O_RDONLY | _O_BINARY
#define OPEN_WRITE_FLAGS  O_CREAT | O_WRONLY | O_TRUNC | _O_BINARY
#define OPEN_READ_MODE    _S_IREAD
#define OPEN_WRITE_MODE   _S_IREAD | S_IWRITE 

#endif

#include <errno.h>
#include "libmeshb7.h"

/* [Bruno] Using portable printf modifier from pstdint.h        */
/* (alternative: use "%zd" under Linux and "%Id" under Windows) */

#ifdef PRINTF_INT64_MODIFIER
#define INT64_T_FMT "%" PRINTF_INT64_MODIFIER "d"
#else
#   ifdef GMF_WINDOWS
#     define INT64_T_FMT "%Id"
#   else
#     define INT64_T_FMT "%lld"
#   endif
#endif

/* [Bruno] Made asynchronous I/O optional */
#ifdef WITH_AIO
#include <aio.h>
#else

struct aiocb
{
        FILE            *aio_fildes;            /* File descriptor */
        off_t           aio_offset;             /* File offset */
        void            *aio_buf;               /* Location of buffer */
        size_t          aio_nbytes;             /* Length of transfer */
        int             aio_lio_opcode;         /* Operation to be performed */
};

int aio_error( const struct aiocb * aiocbp )
{
            return(aiocbp->aio_lio_opcode);
}

int aio_read( struct aiocb * aiocbp )
{
    if(fread(aiocbp->aio_buf, 1, aiocbp->aio_nbytes, aiocbp->aio_fildes) == aiocbp->aio_nbytes)
        aiocbp->aio_lio_opcode = 0;
    else
        aiocbp->aio_lio_opcode = -1;

    return(aiocbp->aio_lio_opcode);
}

ssize_t aio_return( struct aiocb * aiocbp )
{
    return(aiocbp->aio_nbytes);
}

int aio_write( struct aiocb * aiocbp )
{
    if(fwrite(aiocbp->aio_buf, 1, aiocbp->aio_nbytes, aiocbp->aio_fildes) == aiocbp->aio_nbytes)
        aiocbp->aio_lio_opcode = 0;
    else
        aiocbp->aio_lio_opcode = -1;

    return(aiocbp->aio_lio_opcode);
}

#endif



/*----------------------------------------------------------*/
/* Defines                                                  */
/*----------------------------------------------------------*/

#define Asc 1
#define Bin 2
#define MshFil 4
#define SolFil 8
#define InfKwd 1
#define RegKwd 2
#define SolKwd 3
#define CmtKwd 4
#define WrdSiz 4
#define FilStrSiz 64
#define BufSiz 10000
#define MaxArg 20


/*----------------------------------------------------------*/
/* Structures                                               */
/*----------------------------------------------------------*/

typedef struct
{
    int typ, SolSiz, NmbWrd, NmbTyp, TypTab[ GmfMaxTyp ];
    int64_t NmbLin, pos;
    char fmt[ GmfMaxTyp*9 ];
}KwdSct;

typedef struct
{
    int dim, ver, mod, typ, cod, FilDes;
    int64_t NexKwdPos, siz, pos;
    jmp_buf err;
    KwdSct KwdTab[ GmfMaxKwd + 1 ];
    FILE *hdl;
    int *IntBuf;
    float *FltBuf;
    char *buf;
    char FilNam[ GmfStrSiz ];
    double DblBuf[1000/8];
    unsigned char blk[ BufSiz + 1000 ];
}GmfMshSct;


/*----------------------------------------------------------*/
/* Global variables                                         */
/*----------------------------------------------------------*/

const char *GmfKwdFmt[ GmfMaxKwd + 1 ][4] = 
{    {"Reserved", "", "", ""},
    {"MeshVersionFormatted", "", "", "i"},
    {"Reserved", "", "", ""},
    {"Dimension", "", "", "i"},
    {"Vertices", "Vertex", "i", "dri"},
    {"Edges", "Edge", "i", "iii"},
    {"Triangles", "Triangle", "i", "iiii"},
    {"Quadrilaterals", "Quadrilateral", "i", "iiiii"},
    {"Tetrahedra", "Tetrahedron", "i", "iiiii"},
    {"Prisms", "Prism", "i", "iiiiiii"},
    {"Hexahedra", "Hexahedron", "i", "iiiiiiiii"},
    {"IterationsAll", "IterationAll","","i"},
    {"TimesAll", "TimeAll","","r"},                    
    {"Corners", "Corner", "i", "i"},
    {"Ridges", "Ridge", "i", "i"},
    {"RequiredVertices", "RequiredVertex", "i", "i"},
    {"RequiredEdges", "RequiredEdge", "i", "i"},
    {"RequiredTriangles", "RequiredTriangle", "i", "i"},
    {"RequiredQuadrilaterals", "RequiredQuadrilateral", "i", "i"},
    {"TangentAtEdgeVertices", "TangentAtEdgeVertex", "i", "iii"},
    {"NormalAtVertices", "NormalAtVertex", "i", "ii"},
    {"NormalAtTriangleVertices", "NormalAtTriangleVertex", "i", "iii"},
    {"NormalAtQuadrilateralVertices", "NormalAtQuadrilateralVertex", "i", "iiii"},
    {"AngleOfCornerBound", "", "", "r"},
    {"TrianglesP2", "TriangleP2", "i", "iiiiiii"},
    {"EdgesP2", "EdgeP2", "i", "iiii"},
    {"SolAtPyramids", "SolAtPyramid", "i", "sr"},
    {"QuadrilateralsQ2", "QuadrilateralQ2", "i", "iiiiiiiiii"},
    {"ISolAtPyramids", "ISolAtPyramid", "i", "iiiii"},
    {"SubDomainFromGeom", "SubDomainFromGeom", "i", "iii"},
    {"TetrahedraP2", "TetrahedronP2", "i", "iiiiiiiiiii"},
    {"Fault_NearTri", "Fault_NearTri", "i", "i"},
    {"Fault_Inter", "Fault_Inter", "i", "i"},
    {"HexahedraQ2", "HexahedronQ2", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiii"},
    {"ExtraVerticesAtEdges", "ExtraVerticesAtEdge", "i", "in"},
    {"ExtraVerticesAtTriangles", "ExtraVerticesAtTriangle", "i", "in"},
    {"ExtraVerticesAtQuadrilaterals", "ExtraVerticesAtQuadrilateral", "i", "in"},
    {"ExtraVerticesAtTetrahedra", "ExtraVerticesAtTetrahedron", "i", "in"},
    {"ExtraVerticesAtPrisms", "ExtraVerticesAtPrism", "i", "in"},
    {"ExtraVerticesAtHexahedra", "ExtraVerticesAtHexahedron", "i", "in"},
    {"VerticesOnGeometricVertices", "VertexOnGeometricVertex", "i", "iir"},
    {"VerticesOnGeometricEdges", "VertexOnGeometricEdge", "i", "iirr"},
    {"VerticesOnGeometricTriangles", "VertexOnGeometricTriangle", "i", "iirrr"},
    {"VerticesOnGeometricQuadrilaterals", "VertexOnGeometricQuadrilateral", "i", "iirrr"},
    {"EdgesOnGeometricEdges", "EdgeOnGeometricEdge", "i", "iir"},
    {"Fault_FreeEdge", "Fault_FreeEdge", "i", "i"},
    {"Polyhedra", "Polyhedron", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"},
    {"Polygons", "Polygon", "", "iiiiiiiii"},
    {"Fault_Overlap", "Fault_Overlap", "i", "i"},
    {"Pyramids", "Pyramid", "i", "iiiiii"},
    {"BoundingBox", "", "", "drdr"},
    {"Body","i", "drdrdrdr"},
    {"PrivateTable", "PrivateTable", "i", "i"},
    {"Fault_BadShape", "Fault_BadShape", "i", "i"},
    {"End", "", "", ""},
    {"TrianglesOnGeometricTriangles", "TriangleOnGeometricTriangle", "i", "iir"},
    {"TrianglesOnGeometricQuadrilaterals", "TriangleOnGeometricQuadrilateral", "i", "iir"},
    {"QuadrilateralsOnGeometricTriangles", "QuadrilateralOnGeometricTriangle", "i", "iir"},
    {"QuadrilateralsOnGeometricQuadrilaterals", "QuadrilateralOnGeometricQuadrilateral", "i", "iir"},
    {"Tangents", "Tangent", "i", "dr"},
    {"Normals", "Normal", "i", "dr"},
    {"TangentAtVertices", "TangentAtVertex", "i", "ii"},
    {"SolAtVertices", "SolAtVertex", "i", "sr"},
    {"SolAtEdges", "SolAtEdge", "i", "sr"},
    {"SolAtTriangles", "SolAtTriangle", "i", "sr"},
    {"SolAtQuadrilaterals", "SolAtQuadrilateral", "i", "sr"},
    {"SolAtTetrahedra", "SolAtTetrahedron", "i", "sr"},
    {"SolAtPrisms", "SolAtPrism", "i", "sr"},
    {"SolAtHexahedra", "SolAtHexahedron", "i", "sr"},
    {"DSolAtVertices", "DSolAtVertex", "i", "sr"},
    {"ISolAtVertices", "ISolAtVertex", "i", "i"},
    {"ISolAtEdges", "ISolAtEdge", "i", "ii"},
    {"ISolAtTriangles", "ISolAtTriangle", "i", "iii"},
    {"ISolAtQuadrilaterals", "ISolAtQuadrilateral", "i", "iiii"},
    {"ISolAtTetrahedra", "ISolAtTetrahedron", "i", "iiii"},
    {"ISolAtPrisms", "ISolAtPrism", "i", "iiiiii"},
    {"ISolAtHexahedra", "ISolAtHexahedron", "i", "iiiiiiii"},
    {"Iterations", "","","i"},
    {"Time", "","","r"},
    {"Fault_SmallTri", "Fault_SmallTri","i","i"},
    {"CoarseHexahedra", "CoarseHexahedron", "i", "i"},
    {"Comments", "Comment", "i", "c"},
    {"PeriodicVertices", "PeriodicVertex", "i", "ii"},
    {"PeriodicEdges", "PeriodicEdge", "i", "ii"},
    {"PeriodicTriangles", "PeriodicTriangle", "i", "ii"},
    {"PeriodicQuadrilaterals", "PeriodicQuadrilateral", "i", "ii"},
    {"PrismsP2", "PrismP2", "i", "iiiiiiiiiiiiiiiiiii"},
    {"PyramidsP2", "PyramidP2", "i", "iiiiiiiiiiiiiii"},
    {"QuadrilateralsQ3", "QuadrilateralQ3", "i", "iiiiiiiiiiiiiiiii"},
    {"QuadrilateralsQ4", "QuadrilateralQ4", "i", "iiiiiiiiiiiiiiiiiiiiiiiiii"},
    {"TrianglesP3", "TriangleP3", "i", "iiiiiiiiiii"},
    {"TrianglesP4", "TriangleP4", "i", "iiiiiiiiiiiiiiii"},
    {"EdgesP3", "EdgeP3", "i", "iiiii"},
    {"EdgesP4", "EdgeP4", "i", "iiiiii"},
    {"IRefGroups", "IRefGroup", "i", "c,i,i,i"},
    {"DRefGroups", "DRefGroup", "i", "i,i"}
 };

#ifdef TRANSMESH
int GmfMaxRefTab[ GmfMaxKwd + 1 ];
#endif


/*----------------------------------------------------------*/
/* Prototypes of local procedures                           */
/*----------------------------------------------------------*/

static void ScaWrd(GmfMshSct *, void *);
static void ScaDblWrd(GmfMshSct *, void *);
static int64_t GetPos(GmfMshSct *);
static void RecWrd(GmfMshSct *, const void *);
static void RecDblWrd(GmfMshSct *, const void *);
static void RecBlk(GmfMshSct *, const void *, int);
static void SetPos(GmfMshSct *, int64_t);
static int ScaKwdTab(GmfMshSct *);
static void ExpFmt(GmfMshSct *, int);
static void ScaKwdHdr(GmfMshSct *, int);
static void SwpWrd(char *, int);
static int SetFilPos(GmfMshSct *, int64_t);
static int64_t GetFilPos(GmfMshSct *msh);
static int64_t GetFilSiz(GmfMshSct *);
#ifdef F77API
static void CalF77Prc(int64_t, int64_t, void *, int, void **);
#endif


/*----------------------------------------------------------*/
/* Fscanf and fgets checking for errors                     */
/*----------------------------------------------------------*/

#define safe_fscanf(hdl, format, ptr, JmpErr) \
    do { \
        if( fscanf(hdl, format, ptr) != 1 ) \
            longjmp( JmpErr, -1); \
    } while(0)


#define safe_fgets(ptr, siz, hdl, JmpErr) \
    do { \
        if( fgets(ptr, siz, hdl) == NULL ) \
            longjmp( JmpErr, -1); \
    } while(0)


/*----------------------------------------------------------*/
/* Open a mesh file in read or write mod                    */
/*----------------------------------------------------------*/

int64_t GmfOpenMesh(const char *FilNam, int mod, ...)
{
    int KwdCod, res, *PtrVer, *PtrDim;
    int64_t MshIdx;
    char str[ GmfStrSiz ];
    va_list VarArg;
    GmfMshSct *msh;

    /*---------------------*/
    /* MESH STRUCTURE INIT */
    /*---------------------*/

    if(!(msh = calloc(1, sizeof(GmfMshSct))))
        return(0);

    MshIdx = (int64_t)msh;

    /* Save the current stack environment for longjmp */

    if(setjmp(msh->err) != 0)
    {
        if(msh->hdl != NULL)
            fclose(msh->hdl);

        if(msh->FilDes != 0)
            close(msh->FilDes);

        free(msh);
        return(0);
    }

    /* Copy the FilNam into the structure */

    if(strlen(FilNam) + 7 >= GmfStrSiz)
        longjmp(msh->err, -1);

    strcpy(msh->FilNam, FilNam);

    /* Store the opening mod (read or write) and guess the filetype 
        (binary or ascii) depending on the extension */

    msh->mod = mod;
    msh->buf = (void *)msh->DblBuf;
    msh->FltBuf = (void *)msh->DblBuf;
    msh->IntBuf = (void *)msh->DblBuf;

    if(strstr(msh->FilNam, ".meshb"))
        msh->typ |= (Bin | MshFil);
    else if(strstr(msh->FilNam, ".mesh"))
        msh->typ |= (Asc | MshFil);
    else if(strstr(msh->FilNam, ".solb"))
        msh->typ |= (Bin | SolFil);
    else if(strstr(msh->FilNam, ".sol"))
        msh->typ |= (Asc | SolFil);
    else
        longjmp(msh->err, -1);

    /* Open the file in the required mod and initialyse the mesh structure */

    if(msh->mod == GmfRead)
    {

        /*-----------------------*/
        /* OPEN FILE FOR READING */
        /*-----------------------*/

        va_start(VarArg, mod);
        PtrVer = va_arg(VarArg, int *);
        PtrDim = va_arg(VarArg, int *);
        va_end(VarArg);

        /* Read the endian coding tag, the mesh version and the mesh dimension (mandatory kwd) */

        if(msh->typ & Bin)
        {
            /* Create the name string and open the file */

#ifdef WITH_AIO
            /* [Bruno] added binary flag (necessary under Windows) */
            msh->FilDes = open(msh->FilNam, OPEN_READ_FLAGS, OPEN_READ_MODE);

            if(msh->FilDes <= 0)
                longjmp(msh->err, -1);

            /* Read the endian coding tag */
            if(read(msh->FilDes, &msh->cod, WrdSiz) != WrdSiz)
                longjmp(msh->err, -1);
#else
            /* [Bruno] added binary flag (necessary under Windows) */
            if(!(msh->hdl = fopen(msh->FilNam, "rb")))
                longjmp(msh->err, -1);

            /* Read the endian coding tag */
			if( fread(&msh->cod, WrdSiz, 1, msh->hdl) != 1 )
                longjmp(msh->err, -1);
#endif

            /* Read the mesh version and the mesh dimension (mandatory kwd) */

            if( (msh->cod != 1) && (msh->cod != 16777216) )
                longjmp(msh->err, -1);

            ScaWrd(msh, (unsigned char *)&msh->ver);

            if( (msh->ver < 1) || (msh->ver > 4) )
                longjmp(msh->err, -1);

            if( (msh->ver >= 3) && (sizeof(int64_t) != 8) )
                longjmp(msh->err, -1);

            ScaWrd(msh, (unsigned char *)&KwdCod);

            if(KwdCod != GmfDimension)
                longjmp(msh->err, -1);

            GetPos(msh);
            ScaWrd(msh, (unsigned char *)&msh->dim);
        }
        else
        {
            /* Create the name string and open the file */

            if(!(msh->hdl = fopen(msh->FilNam, "rb")))
                longjmp(msh->err, -1);

            do
            {
                res = fscanf(msh->hdl, "%s", str);
            }while( (res != EOF) && strcmp(str, "MeshVersionFormatted") );

            if(res == EOF)
                longjmp(msh->err, -1);

            safe_fscanf(msh->hdl, "%d", &msh->ver, msh->err);

            if( (msh->ver < 1) || (msh->ver > 4) )
                longjmp(msh->err, -1);

            do
            {
                res = fscanf(msh->hdl, "%s", str);
            }while( (res != EOF) && strcmp(str, "Dimension") );

            if(res == EOF)
                longjmp(msh->err, -1);

            safe_fscanf(msh->hdl, "%d", &msh->dim, msh->err);
        }

        if( (msh->dim != 2) && (msh->dim != 3) )
            longjmp(msh->err, -1);

        (*PtrVer) = msh->ver;
        (*PtrDim) = msh->dim;

        /*------------*/
        /* KW READING */
        /*------------*/

        /* Read the list of kw present in the file */

        if(!ScaKwdTab(msh))
            return(0);

        return(MshIdx);
    }
    else if(msh->mod == GmfWrite)
    {

        /*-----------------------*/
        /* OPEN FILE FOR WRITING */
        /*-----------------------*/

        msh->cod = 1;

        /* Check if the user provided a valid version number and dimension */

        va_start(VarArg, mod);
        msh->ver = va_arg(VarArg, int);
        msh->dim = va_arg(VarArg, int);
        va_end(VarArg);

        if( (msh->ver < 1) || (msh->ver > 4) )
            longjmp(msh->err, -1);

        if( (msh->ver >= 3) && (sizeof(int64_t) != 8) )
            longjmp(msh->err, -1);

        if( (msh->dim != 2) && (msh->dim != 3) )
            longjmp(msh->err, -1);

        /* Create the mesh file */

        if(msh->typ & Bin) 
        {
            /* 
             * [Bruno] replaced previous call to creat():
             * with a call to open(), because Windows needs the
             * binary flag to be specified.
             */
#ifdef WITH_AIO
            msh->FilDes = open(msh->FilNam, OPEN_WRITE_FLAGS, OPEN_WRITE_MODE);

            if(msh->FilDes <= 0)
                longjmp(msh->err, -1);
#else
            if(!(msh->hdl = fopen(msh->FilNam, "wb")))
                longjmp(msh->err, -1);
#endif
        }
        else if(!(msh->hdl = fopen(msh->FilNam, "wb")))
            longjmp(msh->err, -1);


        /*------------*/
        /* KW WRITING */
        /*------------*/

        /* Write the mesh version and dimension */

        if(msh->typ & Asc)
        {
            fprintf(msh->hdl, "%s %d\n\n", GmfKwdFmt[ GmfVersionFormatted ][0], msh->ver);
            fprintf(msh->hdl, "%s %d\n", GmfKwdFmt[ GmfDimension ][0], msh->dim);
        }
        else
        {
            RecWrd(msh, (unsigned char *)&msh->cod);
            RecWrd(msh, (unsigned char *)&msh->ver);
            GmfSetKwd(MshIdx, GmfDimension, 0);
            RecWrd(msh, (unsigned char *)&msh->dim);
        }

        return(MshIdx);
    }
    else
    {
        free(msh);
        return(0);
    }
}


/*----------------------------------------------------------*/
/* Close a meshfile in the right way                        */
/*----------------------------------------------------------*/

int GmfCloseMesh(int64_t MshIdx)
{
    int res = 1;
    GmfMshSct *msh = (GmfMshSct *)MshIdx;

    RecBlk(msh, msh->buf, 0);

    /* In write down the "End" kw in write mode */

    if(msh->mod == GmfWrite)
    {
        if(msh->typ & Asc)
            fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ GmfEnd ][0]);
        else
            GmfSetKwd(MshIdx, GmfEnd, 0);
    }

    /* Close the file and free the mesh structure */

    if(msh->typ & Bin)
#ifdef WITH_AIO
        close(msh->FilDes);
#else
        fclose(msh->hdl);
#endif
    else if(fclose(msh->hdl))
        res = 0;

    free(msh);

    return(res);
}


/*----------------------------------------------------------*/
/* Read the number of lines and set the position to this kwd*/
/*----------------------------------------------------------*/

int64_t GmfStatKwd(int64_t MshIdx, int KwdCod, ...)
{
    int i, *PtrNmbTyp, *PtrSolSiz, *TypTab;
    GmfMshSct *msh = (GmfMshSct *)MshIdx;
    KwdSct *kwd;
    va_list VarArg;

    if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
        return(0);

    kwd = &msh->KwdTab[ KwdCod ];

    if(!kwd->NmbLin)
        return(0);

    /* Read further arguments if this kw is a sol */

    if(kwd->typ == SolKwd)
    {
        va_start(VarArg, KwdCod);

        PtrNmbTyp = va_arg(VarArg, int *);
        *PtrNmbTyp = kwd->NmbTyp;

        PtrSolSiz = va_arg(VarArg, int *);
        *PtrSolSiz = kwd->SolSiz;

        TypTab = va_arg(VarArg, int *);

        for(i=0;i<kwd->NmbTyp;i++)
            TypTab[i] = kwd->TypTab[i];

        va_end(VarArg);
    }

    return(kwd->NmbLin);
}


/*----------------------------------------------------------*/
/* Set the current file position to a given kwd              */
/*----------------------------------------------------------*/

int GmfGotoKwd(int64_t MshIdx, int KwdCod)
{
    GmfMshSct *msh = (GmfMshSct *)MshIdx;
    KwdSct *kwd = &msh->KwdTab[ KwdCod ];

    if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) || !kwd->NmbLin )
        return(0);

    return(SetFilPos(msh, kwd->pos));
}


/*----------------------------------------------------------*/
/* Write the kwd and set the number of lines                */
/*----------------------------------------------------------*/

int GmfSetKwd(int64_t MshIdx, int KwdCod, ...)
{
    int i, *TypTab;
    int64_t NmbLin=0, CurPos;
    va_list VarArg;
    GmfMshSct *msh = (GmfMshSct *)MshIdx;
    KwdSct *kwd;

    RecBlk(msh, msh->buf, 0);

    if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
        return(0);

    kwd = &msh->KwdTab[ KwdCod ];

    /* Read further arguments if this kw has a header */

    if(strlen(GmfKwdFmt[ KwdCod ][2]))
    {
        va_start(VarArg, KwdCod);
        NmbLin = va_arg(VarArg, int64_t);

        if(!strcmp(GmfKwdFmt[ KwdCod ][3], "sr"))
        {
            kwd->NmbTyp = va_arg(VarArg, int);
            TypTab = va_arg(VarArg, int *);

            for(i=0;i<kwd->NmbTyp;i++)
                kwd->TypTab[i] = TypTab[i];
        }

        va_end(VarArg);
    }

    /* Setup the kwd info */

    ExpFmt(msh, KwdCod);

    if(!kwd->typ)
        return(0);
    else if(kwd->typ == InfKwd)
        kwd->NmbLin = 1;
    else
        kwd->NmbLin = NmbLin;

    /* Store the next kwd position in binary file */

    if( (msh->typ & Bin) && msh->NexKwdPos )
    {
        CurPos = GetFilPos(msh);

        if(!SetFilPos(msh, msh->NexKwdPos))
            return(0);

        SetPos(msh, CurPos);

        if(!SetFilPos(msh, CurPos))
            return(0);
    }

    /* Write the header */

    if(msh->typ & Asc)
    {
        fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ KwdCod ][0]);

        if(kwd->typ != InfKwd)
            fprintf(msh->hdl, INT64_T_FMT"\n", kwd->NmbLin);

        /* In case of solution field, write the extended header */

        if(kwd->typ == SolKwd)
        {
            fprintf(msh->hdl, "%d ", kwd->NmbTyp);

            for(i=0;i<kwd->NmbTyp;i++)
                fprintf(msh->hdl, "%d ", kwd->TypTab[i]);

            fprintf(msh->hdl, "\n\n");
        }
    }
    else
    {
        RecWrd(msh, (unsigned char *)&KwdCod);
        msh->NexKwdPos = GetFilPos(msh);
        SetPos(msh, 0);

        if(kwd->typ != InfKwd)
        {
            if(msh->ver < 4)
            {
                i = (int)kwd->NmbLin;
                RecWrd(msh, (unsigned char *)&i);
            }
            else
                RecDblWrd(msh, (unsigned char *)&kwd->NmbLin);
        }

        /* In case of solution field, write the extended header at once */

        if(kwd->typ == SolKwd)
        {
            RecWrd(msh, (unsigned char *)&kwd->NmbTyp);

            for(i=0;i<kwd->NmbTyp;i++)
                RecWrd(msh, (unsigned char *)&kwd->TypTab[i]);
        }
    }

    /* Reset write buffer position */
    msh->pos = 0;

    /* Estimate the total file size and check whether it crosses the 2GB threshold */
    msh->siz += kwd->NmbLin * kwd->NmbWrd * WrdSiz;

    return(1);
}


/*----------------------------------------------------------*/
/* Read a full line from the current kwd                    */
/*----------------------------------------------------------*/

int NAMF77(GmfGetLin, gmfgetlin)(TYPF77(int64_t)MshIdx, TYPF77(int)KwdCod, ...)
{
    int i, j;
    float *FltSolTab, FltVal, *PtrFlt;
    double *DblSolTab, *PtrDbl;
    va_list VarArg;
    GmfMshSct *msh = (GmfMshSct *) VALF77(MshIdx);
    KwdSct *kwd = &msh->KwdTab[ VALF77(KwdCod) ];

    if( (VALF77(KwdCod) < 1) || (VALF77(KwdCod) > GmfMaxKwd) )
        return(0);

    /* Save the current stack environment for longjmp */

    if(setjmp(msh->err) != 0)
        return(0);

    /* Start decoding the arguments */

    va_start(VarArg, KwdCod);

    switch(kwd->typ)
    {
        case InfKwd : case RegKwd : case CmtKwd :
        {
            if(msh->typ & Asc)
            {
                for(i=0;i<kwd->SolSiz;i++)
                    if(kwd->fmt[i] == 'r')
                        if(msh->ver <= 1)
                        {
                            safe_fscanf(msh->hdl, "%f", &FltVal, msh->err);
                            PtrDbl = va_arg(VarArg, double *);
                            PtrFlt = (float *)PtrDbl;
                            *PtrFlt = FltVal;
                        }                            
                        else
                            safe_fscanf(msh->hdl, "%lf", va_arg(VarArg, double *), msh->err);
                    else if(kwd->fmt[i] == 'i')
                        if(msh->ver <= 3)
                            safe_fscanf(msh->hdl, "%d", va_arg(VarArg, int *), msh->err);
                        else
                            /* [Bruno] %ld -> INT64_T_FMT */
                            safe_fscanf(msh->hdl, INT64_T_FMT, va_arg(VarArg, int64_t *), msh->err);
                    else if(kwd->fmt[i] == 'c')
                        safe_fgets(va_arg(VarArg, char *), WrdSiz * FilStrSiz, msh->hdl, msh->err);
            }
            else
            {
                for(i=0;i<kwd->SolSiz;i++)
                    if(kwd->fmt[i] == 'r')
                        if(msh->ver <= 1)
                            ScaWrd(msh, (unsigned char *)va_arg(VarArg, float *));
                        else
                            ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, double *));
                    else if(kwd->fmt[i] == 'i')
                        if(msh->ver <= 3)
                            ScaWrd(msh, (unsigned char *)va_arg(VarArg, int *));
                        else
                            ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, int64_t *));
                    else if(kwd->fmt[i] == 'c')
                        /* [Bruno] added error control */
                        if(fread(va_arg(VarArg, char *), WrdSiz, FilStrSiz, msh->hdl) != FilStrSiz) {
                            longjmp(msh->err, -1);
                        }
            }
        }break;

        case SolKwd :
        {
            if(msh->ver == 1)
            {
                FltSolTab = va_arg(VarArg, float *);

                if(msh->typ & Asc)
                    for(j=0;j<kwd->SolSiz;j++)
                        safe_fscanf(msh->hdl, "%f", &FltSolTab[j], msh->err);
                else
                    for(j=0;j<kwd->SolSiz;j++)
                        ScaWrd(msh, (unsigned char *)&FltSolTab[j]);
            }
            else
            {
                DblSolTab = va_arg(VarArg, double *);

                if(msh->typ & Asc)
                    for(j=0;j<kwd->SolSiz;j++)
                        safe_fscanf(msh->hdl, "%lf", &DblSolTab[j], msh->err);
                else
                    for(j=0;j<kwd->SolSiz;j++)
                        ScaDblWrd(msh, (unsigned char *)&DblSolTab[j]);
            }
        }break;
    }

    va_end(VarArg);

    return(1);
}


/*----------------------------------------------------------*/
/* Write a full line from the current kwd                   */
/*----------------------------------------------------------*/

int NAMF77(GmfSetLin, gmfsetlin)(TYPF77(int64_t) MshIdx, TYPF77(int) KwdCod, ...)
{
    int i, j, pos, *IntBuf;
    int64_t *LngBuf;
    float *FltSolTab, *FltBuf;
    double *DblSolTab, *DblBuf;
    va_list VarArg;
    GmfMshSct *msh = (GmfMshSct *) VALF77(MshIdx);
    KwdSct *kwd = &msh->KwdTab[ VALF77(KwdCod) ];

    if( ( VALF77(KwdCod) < 1) || ( VALF77(KwdCod) > GmfMaxKwd) )
        return(0);

    /* Start decoding the arguments */

    va_start(VarArg, KwdCod);

    if(kwd->typ != SolKwd)
    {
        if(msh->typ & Asc)
        {
            for(i=0;i<kwd->SolSiz;i++)
            {
                if(kwd->fmt[i] == 'r')
                {
                    if(msh->ver <= 1)
#ifdef F77API
                        fprintf(msh->hdl, "%g ", *(va_arg(VarArg, float *)));
#else
                        fprintf(msh->hdl, "%g ", va_arg(VarArg, double));
#endif
                    else
                        fprintf(msh->hdl, "%.15g ", VALF77(va_arg(VarArg, TYPF77(double))));
                }
                else if(kwd->fmt[i] == 'i')
                {
                    if(msh->ver <= 3)
                        fprintf(msh->hdl, "%d ", VALF77(va_arg(VarArg, TYPF77(int))));
                    else
                        /* [Bruno] %ld -> INT64_T_FMT */
                        fprintf(msh->hdl, INT64_T_FMT " ", VALF77(va_arg(VarArg, TYPF77(int64_t))));
                }
                else if(kwd->fmt[i] == 'c')
                    fprintf(msh->hdl, "%s ", va_arg(VarArg, char *));
            }
        }
        else
        {
            pos = 0;

            for(i=0;i<kwd->SolSiz;i++)
            {
                if(kwd->fmt[i] == 'r')
                {
                    if(msh->ver <= 1)
                    {
                        FltBuf = (void *)&msh->buf[ pos ];
#ifdef F77API
                        *FltBuf = (float)*(va_arg(VarArg, float *));
#else
                        *FltBuf = (float)va_arg(VarArg, double);
#endif
                        pos += 4;
                    }
                    else
                    {
                        DblBuf = (void *)&msh->buf[ pos ];
                        *DblBuf = VALF77(va_arg(VarArg, TYPF77(double)));
                        pos += 8;
                    }
                }
                else if(kwd->fmt[i] == 'i')
{'fraction_non_alphanumeric': 0.22478040990151718, 'fraction_numerical': 0.012493345754591429, 'mean_word_length': 1.569480658260312, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 526, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 30, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4767989', 'n_tokens_mistral': 21910, 'n_tokens_neox': 20809, 'n_words': 4158}