static int64_t GetFilSiz(GmfMshSct *msh)
{
   int64_t CurPos, EndPos = 0;

   if(msh->typ & Bin)
   {
#ifdef WITH_GMF_AIO
      CurPos = lseek(msh->FilDes, 0, 1);
      EndPos = lseek(msh->FilDes, 0, 2);
      lseek(msh->FilDes, (off_t)CurPos, 0);
#else
      CurPos = MYFTELL(msh->hdl);

      if(MYFSEEK(msh->hdl, 0, SEEK_END) != 0)
         longjmp(msh->err, -32);

      EndPos = MYFTELL(msh->hdl);

      if(MYFSEEK(msh->hdl, (off_t)CurPos, SEEK_SET) != 0)
         longjmp(msh->err, -33);
#endif
   }
   else
   {
      CurPos = MYFTELL(msh->hdl);

      if(MYFSEEK(msh->hdl, 0, SEEK_END) != 0)
         longjmp(msh->err, -34);

      EndPos = MYFTELL(msh->hdl);

      if(MYFSEEK(msh->hdl, (off_t)CurPos, SEEK_SET) != 0)
         longjmp(msh->err, -35);
   }

   return(EndPos);
}


char *GmfReadByteFlow(int64_t MshIdx, int *NmbByt)
{
   int         cod, *WrdTab;
   size_t      i, NmbWrd;
   GmfMshSct   *msh = (GmfMshSct *)MshIdx;

   // Read and allocate the number of 4-byte words in the byteflow
   if(!(NmbWrd = GmfStatKwd(MshIdx, GmfByteFlow)))
      return(NULL);

   if(!(WrdTab = malloc(NmbWrd * WrdSiz)))
      return(NULL);

   // Disable the endianess conversion
   cod = msh->cod;
   msh->cod = 1;

   // Read the exact number of bytes in the byteflow
   GmfGotoKwd(MshIdx, GmfByteFlow);
   GmfGetLin(MshIdx, GmfByteFlow, NmbByt);

   // Read the byteflow as 4-byte blocks
   for(i=0;i<NmbWrd;i++)
      GmfGetLin(MshIdx, GmfByteFlow, &WrdTab[i]);

   // Enable endianess convertion
   msh->cod = cod;

   return((char *)WrdTab);
}


static void SetPos(GmfMshSct *msh, int64_t pos)
{
   int IntVal;

   if(msh->ver >= 3)
      RecDblWrd(msh, (unsigned char*)&pos);
   else
   {
      IntVal = (int)pos;
      RecWrd(msh, (unsigned char*)&IntVal);
   }
}


static int64_t GetFilPos(GmfMshSct *msh)
{
#ifdef WITH_GMF_AIO
   if(msh->typ & Bin)
      return(lseek(msh->FilDes, 0, 1));
   else
      return(MYFTELL(msh->hdl));
#else
   return(MYFTELL(msh->hdl));
#endif
}


int GmfGetFloatPrecision(int64_t MshIdx)
{
   int FltSiz;
   GmfMshSct *msh = (GmfMshSct *)MshIdx;

   if(GmfStatKwd(MshIdx, GmfFloatingPointPrecision))
   {
      GmfGotoKwd(MshIdx, GmfFloatingPointPrecision);
      GmfGetLin(MshIdx, GmfFloatingPointPrecision, &FltSiz);

      if(FltSiz == 32 || FltSiz == 64)
         msh->FltSiz = FltSiz;
   }

   return(msh->FltSiz);
}


int NAMF77(GmfSetBlock, gmfsetblock)(  TYPF77(int64_t) MshIdx,
                                       TYPF77(int)     KwdCod,
                                       TYPF77(int64_t) BegIdx,
                                       TYPF77(int64_t) EndIdx,
                                       TYPF77(int)     MapTyp,
                                       void           *MapTab,
                                       void           *prc, ... )
{
   char        *UsrDat[ GmfMaxTyp ], *UsrBas[ GmfMaxTyp ];
   char        *StrTab[5] = { "", "%.9g", "%.17g", "%d", "%lld" }, *FilPos;
   char        *FilBuf = NULL, *FrtBuf = NULL, *BckBuf = NULL;
   char        **BegTab, **EndTab, *BegUsrDat, *EndUsrDat;
   int         i, j, *FilPtrI32, *UsrPtrI32, FilTyp[ GmfMaxTyp ];
   int         UsrTyp[ GmfMaxTyp ], TypSiz[5] = {0,4,8,4,8};
   int         err, *IntMapTab = NULL, typ, mod = GmfArgLst;
   int         *TypTab, *SizTab, IniFlg = 1, TotSiz = 0, VecCnt, ArgCnt = 0;
   float       *FilPtrR32, *UsrPtrR32;
   double      *FilPtrR64, *UsrPtrR64;
   int64_t     UsrNmbLin, BlkNmbLin = 0, BlkBegIdx, BlkEndIdx = 0;
   int64_t     *FilPtrI64, *UsrPtrI64, *LngMapTab = NULL, OldIdx = 0;
   size_t      FilBegIdx = VALF77(BegIdx), FilEndIdx = VALF77(EndIdx);
   void        (*UsrPrc)(int64_t, int64_t, void *) = NULL;
   size_t      UsrLen[ GmfMaxTyp ], ret, LinSiz, VecLen, s, b, NmbBlk;
   va_list     VarArg;
   GmfMshSct   *msh = (GmfMshSct *) VALF77(MshIdx);
   KwdSct      *kwd = &msh->KwdTab[ VALF77(KwdCod) ];
   struct      aiocb aio;
#ifdef F77API
   int         NmbArg = 0;
   void        *ArgTab[ MaxArg ];
#else
   char        *UsrArg = NULL;
#endif

   // Save the current stack environment for longjmp
   if( (err = setjmp(msh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", msh, err);
#endif
      if(FilBuf)
         free(FilBuf);

      return(0);
   }

   // Check mesh and keyword
   if( (VALF77(KwdCod) < 1) || (VALF77(KwdCod) > GmfMaxKwd) || !kwd->NmbLin )
      return(0);

   // Make sure it's not a simple information keyword
   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Temporarily overwright the given begin and end values
   // as arbitrary position block write is not yet implemented
   FilBegIdx = 1;
   FilEndIdx = kwd->NmbLin;

   // Check user's bounds
   if( (FilBegIdx < 1) || (FilBegIdx > FilEndIdx) || (FilEndIdx > (size_t)kwd->NmbLin) )
      return(0);

   // Compute the number of lines to be written
   UsrNmbLin = FilEndIdx - FilBegIdx + 1;

   // Get the renumbering map if any
   if(VALF77(MapTyp) == GmfInt)
      IntMapTab = (int *)MapTab;
   else if(VALF77(MapTyp) == GmfLong)
      LngMapTab = (int64_t *)MapTab;

   // Start decoding the arguments
   va_start(VarArg, prc);
   LinSiz = 0;

   // Get the user's postprocessing procedure and argument adresses, if any
#ifdef F77API
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      NmbArg = *(va_arg(VarArg, int *));

      for(i=0;i<NmbArg;i++)
         ArgTab[i] = va_arg(VarArg, void *);
   }
#else
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      UsrArg = va_arg(VarArg, void *);
   }
#endif

   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Read the first data type to select between list and table mode
   typ = VALF77(va_arg(VarArg, TYPF77(int)));

   // If the table mode is selected, read the four additional tables
   // containing the arguments: type, vector size, begin and end pointers
   if(typ == GmfArgTab)
   {
      mod = GmfArgTab;
      TypTab = va_arg(VarArg, int *);
      SizTab = va_arg(VarArg, int *);
      BegTab = va_arg(VarArg, char **);
      EndTab = va_arg(VarArg, char **);
   }

   // Read the arguments until to total size reaches the keyword's size
   while(TotSiz < kwd->SolSiz)
   {
      // In list mode all arguments are read from the variable argument buffer
      if(mod == GmfArgLst)
      {
         // Do not read the type argument for the first iteration because
         // it was read befeore the loop begins to get the argument mode
         if(IniFlg)
            IniFlg = 0;
         else
            typ = VALF77(va_arg(VarArg, TYPF77(int)));

         // In case the type is a vector. get its size and change the type
         // for the corresponding scalar type
         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = VALF77(va_arg(VarArg, TYPF77(int)));
         }
         else
            VecCnt = 1;

         BegUsrDat = va_arg(VarArg, char *);
         EndUsrDat = va_arg(VarArg, char *);
      }
      else
      {
         // Do exactly the same as above but the arguments are read from
         // the tables instead of VarArgs
         typ = TypTab[ ArgCnt ];

         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = SizTab[ ArgCnt ];
         }
         else
            VecCnt = 1;

         BegUsrDat = (char *)BegTab[ ArgCnt ];
         EndUsrDat = (char *)EndTab[ ArgCnt ];
         ArgCnt++;
      }

      if(UsrNmbLin > 1)
         VecLen = (size_t)(EndUsrDat - BegUsrDat) / (UsrNmbLin - 1);
      else
         VecLen = 0;

      // Compute the consecutive begin / end adresses for vector data types
      for(i=0;i<VecCnt;i++)
      {
         UsrTyp[ TotSiz ]  = typ;
         UsrBas[ TotSiz ]  = BegUsrDat + i * TypSiz[ typ ];
         UsrDat[ TotSiz ]  = UsrBas[ TotSiz ];
         UsrLen[ TotSiz ]  = VecLen;
         TotSiz++;
      }
   }

   // Get the file's data type
   for(i=0;i<kwd->SolSiz;i++)
   {
      if(kwd->fmt[i] == 'r')
         if(msh->FltSiz == 32)
            FilTyp[i] = GmfFloat;
         else
            FilTyp[i] = GmfDouble;
      else
         if(msh->ver <= 3)
            FilTyp[i] = GmfInt;
         else
            FilTyp[i] = GmfLong;

      // Compute the file stride
      LinSiz += TypSiz[ FilTyp[i] ];
   }

   va_end(VarArg);

   // Write the whole kwd data
   if(msh->typ & Asc)
   {
      if(UsrPrc)
#ifdef F77API
         CalF77Prc(1, kwd->NmbLin, UsrPrc, NmbArg, ArgTab);
#else
         UsrPrc(1, kwd->NmbLin, UsrArg);
#endif

      for(s=FilBegIdx; s<=FilEndIdx; s++)
         for(j=0;j<kwd->SolSiz;j++)
         {
            if(UsrTyp[j] == GmfFloat)
            {
               UsrPtrR32 = (float *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], (double)*UsrPtrR32);
            }
            else if(UsrTyp[j] == GmfDouble)
            {
               UsrPtrR64 = (double *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], *UsrPtrR64);
            }
            else if(UsrTyp[j] == GmfInt)
            {
               UsrPtrI32 = (int *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], *UsrPtrI32);
            }
            else if(UsrTyp[j] == GmfLong)
            {
               UsrPtrI64 = (int64_t *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], *UsrPtrI64);
            }

            if(j < kwd->SolSiz -1)
               fprintf(msh->hdl, " ");
            else
               fprintf(msh->hdl, "\n");

            //UsrDat[j] += UsrLen[j];
            if(IntMapTab)
               UsrDat[j] = UsrBas[j] + IntMapTab[s] * UsrLen[j];
            else if(LngMapTab)
               UsrDat[j] = UsrBas[j] + LngMapTab[s] * UsrLen[j];
            else
               UsrDat[j] = UsrBas[j] + s * UsrLen[j];
         }
   }
   else
   {
      // Allocate the front and back buffers
      if(!(BckBuf = malloc(BufSiz * LinSiz)))
         return(0);

      if(!(FrtBuf = malloc(BufSiz * LinSiz)))
         return(0);

      // Setup the asynchronous parameters
      memset(&aio, 0, sizeof(struct aiocb));
      FilBuf = BckBuf;
#ifdef WITH_GMF_AIO
      aio.aio_fildes = msh->FilDes;
#else
      aio.aio_fildes = msh->hdl;
#endif
      aio.aio_offset = (off_t)GetFilPos(msh);

      NmbBlk = UsrNmbLin / BufSiz;

      // Loop over N+1 blocks
      for(b=0;b<=NmbBlk+1;b++)
      {
         // Launch an asynchronous block write
         // except for the first loop iteration
         if(b)
         {
            aio.aio_nbytes = BlkNmbLin * LinSiz;

            if(my_aio_write(&aio) == -1)
            {
#ifdef WITH_GMF_AIO
               printf("aio_fildes = %d\n",aio.aio_fildes);
#else
               printf("aio_fildes = %p\n",aio.aio_fildes);
#endif
               printf("aio_buf    = %p\n",aio.aio_buf);
               printf("aio_offset = " INT64_T_FMT "\n",(int64_t)aio.aio_offset);
               printf("aio_nbytes = " INT64_T_FMT "\n",(int64_t)aio.aio_nbytes);
               printf("errno      = %d\n",errno);
               exit(1);
            }
         }

         // Parse the block data except at the last loop iteration
         if(b<=NmbBlk)
         {
            // The last block is shorter
            if(b == NmbBlk)
               BlkNmbLin = UsrNmbLin - b * BufSiz;
            else
               BlkNmbLin = BufSiz;

            FilPos = FilBuf;
            BlkBegIdx = BlkEndIdx+1;
            BlkEndIdx += BlkNmbLin;

            // Call user's preprocessing first
            if(UsrPrc)
#ifdef F77API
               CalF77Prc(BlkBegIdx, BlkEndIdx, UsrPrc, NmbArg, ArgTab);
#else
               UsrPrc(BlkBegIdx, BlkEndIdx, UsrArg);
#endif

            // Then copy it's data to the file buffer
            for(i=0;i<BlkNmbLin;i++)
            {
               OldIdx++;

               for(j=0;j<kwd->SolSiz;j++)
               {
                  if(IntMapTab)
                     UsrDat[j] = UsrBas[j] + (IntMapTab[ OldIdx ] - 1) * UsrLen[j];
                  else if(LngMapTab)
                     UsrDat[j] = UsrBas[j] + (LngMapTab[ OldIdx ] - 1) * UsrLen[j];
                  else
                     UsrDat[j] = UsrBas[j] + (OldIdx - 1) * UsrLen[j];

                  if(FilTyp[j] == GmfInt)
                  {
                     FilPtrI32 = (int *)FilPos;

                     if(UsrTyp[j] == GmfInt)
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *FilPtrI32 = *UsrPtrI32;
                     }
                     else
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *FilPtrI32 = (int)*UsrPtrI64;
                     }
                  }
                  else if(FilTyp[j] == GmfLong)
                  {
                     FilPtrI64 = (int64_t *)FilPos;

                     if(UsrTyp[j] == GmfLong)
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *FilPtrI64 = *UsrPtrI64;
                     }
                     else
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *FilPtrI64 = (int64_t)*UsrPtrI32;
                     }
                  }
                  else if(FilTyp[j] == GmfFloat)
                  {
                     FilPtrR32 = (float *)FilPos;

                     if(UsrTyp[j] == GmfFloat)
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *FilPtrR32 = *UsrPtrR32;
                     }
                     else
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *FilPtrR32 = (float)*UsrPtrR64;
                     }
                  }
                  else if(FilTyp[j] == GmfDouble)
                  {
                     FilPtrR64 = (double *)FilPos;

                     if(UsrTyp[j] == GmfDouble)
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *FilPtrR64 = *UsrPtrR64;
                     }
                     else
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *FilPtrR64 = (double)*UsrPtrR32;
                     }
                  }

                  FilPos += TypSiz[ FilTyp[j] ];
               }
            }
         }

         // Wait for write completion execpt at the first loop iteration
         if(b)
         {
            while(my_aio_error(&aio) == EINPROGRESS);

            err = my_aio_error(&aio);
            ret = my_aio_return(&aio);

            if (err != 0) {
              printf (" Error at aio_error() : %s\n", strerror (err));
              exit(1);
            }

            if (ret != aio.aio_nbytes) {
              printf(" Error at aio_return()\n");
              exit(1);
            }

            // Move the write position
            aio.aio_offset += (off_t)aio.aio_nbytes;
         }

         // Swap the buffers
         if(FilBuf == BckBuf)
         {
            aio.aio_buf = BckBuf;
            FilBuf = FrtBuf;
         }
         else
         {
            aio.aio_buf = FrtBuf;
            FilBuf = BckBuf;
         }
      }

      SetFilPos(msh, aio.aio_offset);
      free(BckBuf);
      free(FrtBuf);
   }

   return(1);
}


int APIF77(gmfsetkwd)(  int64_t *MshIdx, int *KwdIdx, int *NmbLin,
                        int *NmbTyp, int *TypTab, int *deg, int *NmbNod)
{
   if(!strcmp(GmfKwdFmt[ *KwdIdx ][2], "hr"))
      return(GmfSetKwd(*MshIdx, *KwdIdx, *NmbLin, *NmbTyp, TypTab, *deg, *NmbNod));
   else if(!strcmp(GmfKwdFmt[ *KwdIdx ][2], "sr"))
      return(GmfSetKwd(*MshIdx, *KwdIdx, *NmbLin, *NmbTyp, TypTab));
   else
      return(GmfSetKwd(*MshIdx, *KwdIdx, *NmbLin));
}


size_t my_aio_return(struct aiocb *aiocbp)
{
   return(aiocbp->aio_nbytes);
}


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


int GmfCloseMesh(int64_t MshIdx)
{
   int i, 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_GMF_AIO
      close(msh->FilDes);
#else
      fclose(msh->hdl);
#endif
   else if(fclose(msh->hdl))
      res = 0;

   // Free optional H.O. renumbering tables
   for(i=0;i<GmfLastKeyword;i++)
      if(msh->KwdTab[i].OrdTab)
         free(msh->KwdTab[i].OrdTab);

   free(msh);

   return(res);
}


static void ScaKwdHdr(GmfMshSct *msh, int KwdCod)
{
   int      i;
   KwdSct   *kwd = &msh->KwdTab[ KwdCod ];

   if(!strcmp("i", GmfKwdFmt[ KwdCod ][1]))
      if(msh->typ & Asc)
         safe_fscanf(msh->hdl, INT64_T_FMT, &kwd->NmbLin, msh->err);
      else
         if(msh->ver <= 3)
         {
            ScaWrd(msh, (unsigned char *)&i);
            kwd->NmbLin = i;
         }
         else
            ScaDblWrd(msh, (unsigned char *)&kwd->NmbLin);
   else
      kwd->NmbLin = 1;

   if(!strcmp("sr", GmfKwdFmt[ KwdCod ][2])
   || !strcmp("hr", GmfKwdFmt[ KwdCod ][2]) )
   {
      if(msh->typ & Asc)
      {
         safe_fscanf(msh->hdl, "%d", &kwd->NmbTyp, msh->err);

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

         // Scan two extra fields for HO solutions: deg and nmb Nodes
         if(!strcmp("hr", GmfKwdFmt[ KwdCod ][2]))
         {
            safe_fscanf(msh->hdl, "%d", &kwd->deg, msh->err);
            safe_fscanf(msh->hdl, "%d", &kwd->NmbNod, msh->err);
         }
         else
         {
            kwd->deg = 0;
            kwd->NmbNod = 1;
         }

      }
      else
      {
         ScaWrd(msh, (unsigned char *)&kwd->NmbTyp);

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

         // Scan two extra fields for HO solutions: deg and nmb Nodes
         if(!strcmp("hr", GmfKwdFmt[ KwdCod ][2]))
         {
            ScaWrd(msh, (unsigned char *)&kwd->deg);
            ScaWrd(msh, (unsigned char *)&kwd->NmbNod);
         }
         else
         {
            kwd->deg = 0;
            kwd->NmbNod = 1;
         }
      }
   }

   ExpFmt(msh, KwdCod);
   kwd->pos = GetFilPos(msh);
}


int APIF77(gmfgotokwd)(int64_t *MshIdx, int *KwdIdx)
{
   return(GmfGotoKwd(*MshIdx, *KwdIdx));
}


int64_t APIF77(gmfopenmesh)(  char *FilNam, int *mod,
                              int *ver, int *dim, int StrSiz )
{
   int   i = 0;
   char  TmpNam[ GmfStrSiz ];

   if(StrSiz <= 0)
      return(0);

   // Trim trailing spaces from the fortran string
   while(isspace(FilNam[ StrSiz-1 ]))
      StrSiz--;

   for(i=0;i<StrSiz;i++)
      TmpNam[i] = FilNam[i];

   TmpNam[ StrSiz ] = 0;

   if(*mod == GmfRead)
      return(GmfOpenMesh(TmpNam, *mod, ver, dim));
   else
      return(GmfOpenMesh(TmpNam, *mod, *ver, *dim));
}


static int ScaKwdTab(GmfMshSct *msh)
{
   int      KwdCod, c;
   int64_t  NexPos, EndPos, LstPos;
   char     str[ GmfStrSiz ];

   if(msh->typ & Asc)
   {
      // Scan each string in the file until the end
      while(fscanf(msh->hdl, "%100s", str) != EOF)
      {
         // Fast test in order to reject quickly the numeric values
         if(isalpha(str[0]))
         {
            // Search which kwd code this string is associated with, then get its
            // header and save the curent position in file (just before the data)
            for(KwdCod=1; KwdCod<= GmfMaxKwd; KwdCod++)
               if(!strcmp(str, GmfKwdFmt[ KwdCod ][0]))
               {
                  ScaKwdHdr(msh, KwdCod);
                  break;
               }
         }
         else if(str[0] == '#')
            while((c = fgetc(msh->hdl)) != '\n' && c != EOF);
      }
   }
   else
   {
      // Get file size
      EndPos = GetFilSiz(msh);
      LstPos = -1;

      // Jump through kwd positions in the file
      do
      {
         // Get the kwd code and the next kwd position
         ScaWrd(msh, ( char *)&KwdCod);
         NexPos = GetPos(msh);

         // Make sure the flow does not move beyond the file size
         if(NexPos > EndPos)
            longjmp(msh->err, -24);

         // And check that it does not move back
         if(NexPos && (NexPos <= LstPos))
            longjmp(msh->err, -30);

         LstPos = NexPos;

         // Check if this kwd belongs to this mesh version
         if( (KwdCod >= 1) && (KwdCod <= GmfMaxKwd) )
            ScaKwdHdr(msh, KwdCod);

         // Go to the next kwd
         if(NexPos && !(SetFilPos(msh, NexPos)))
            longjmp(msh->err, -25);

      }while(NexPos && (KwdCod != GmfEnd));
   }

   return(1);
}


int    my_aio_read  (      struct aiocb *aiocbp){return(aio_read  (aiocbp));}


static void ExpFmt(GmfMshSct *msh, int KwdCod)
{
   int         i, j, TmpSiz=0, IntWrd, FltWrd;
   char        chr;
   const char  *InpFmt = GmfKwdFmt[ KwdCod ][2];
   KwdSct      *kwd = &msh->KwdTab[ KwdCod ];

   // Set the kwd's type
   if(!strlen(GmfKwdFmt[ KwdCod ][1]))
      kwd->typ = InfKwd;
   else if( !strcmp(InpFmt, "sr") || !strcmp(InpFmt, "hr") )
      kwd->typ = SolKwd;
   else
      kwd->typ = RegKwd;

   // Get the solution-field's size
   if(kwd->typ == SolKwd)
      for(i=0;i<kwd->NmbTyp;i++)
         switch(kwd->TypTab[i])
         {
            case GmfSca    : TmpSiz += 1; break;
            case GmfVec    : TmpSiz += msh->dim; break;
            case GmfSymMat : TmpSiz += (msh->dim * (msh->dim+1)) / 2; break;
            case GmfMat    : TmpSiz += msh->dim * msh->dim; break;
         }

   // Scan each character from the format string
   i = kwd->SolSiz = kwd->NmbWrd = 0;

   while(i < (int)strlen(InpFmt))
   {
      chr = InpFmt[ i++ ];

      if(chr == 'd')
      {
         chr = InpFmt[i++];

         for(j=0;j<msh->dim;j++)
            kwd->fmt[ kwd->SolSiz++ ] = chr;
      }
      else if((chr == 's')||(chr == 'h'))
      {
         chr = InpFmt[i++];

         for(j=0;j<TmpSiz;j++)
            kwd->fmt[ kwd->SolSiz++ ] = chr;
      }
      else
         kwd->fmt[ kwd->SolSiz++ ] = chr;
   }

   if(msh->FltSiz == 32)
      FltWrd = 1;
   else
      FltWrd = 2;

   if(msh->ver <= 3)
      IntWrd = 1;
   else
      IntWrd = 2;

   for(i=0;i<kwd->SolSiz;i++)
      switch(kwd->fmt[i])
      {
         case 'i' : kwd->NmbWrd += IntWrd; break;
         case 'c' : kwd->NmbWrd += FilStrSiz; break;
         case 'r' : kwd->NmbWrd += FltWrd;break;
      }

   // HO solution: duplicate the format as many times as the number of nodes
   if( !strcmp(InpFmt, "hr") && (kwd->NmbNod > 1) )
   {
      for(i=1;i<=kwd->NmbNod;i++)
         for(j=0;j<kwd->SolSiz;j++)
            kwd->fmt[ i * kwd->SolSiz + j ] = kwd->fmt[j];

      kwd->SolSiz *= kwd->NmbNod;
      kwd->NmbWrd *= kwd->NmbNod;
   }
}


int my_aio_write(struct aiocb *aiocbp)
{
   if( (MYFSEEK(aiocbp->aio_fildes, (off_t)aiocbp->aio_offset, SEEK_SET) == 0)
   &&  (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);
}


int NAMF77(GmfGetBlock, gmfgetblock)(  TYPF77(int64_t) MshIdx,
                                       TYPF77(int)     KwdCod,
                                       TYPF77(int64_t) BegIdx,
                                       TYPF77(int64_t) EndIdx,
                                       TYPF77(int)     MapTyp,
                                       void           *MapTab,
                                       void           *prc, ... )
{
   char        *UsrDat[ GmfMaxTyp ], *UsrBas[ GmfMaxTyp ], *FilPos, *EndUsrDat;
   char        *FilBuf = NULL, *FrtBuf = NULL, *BckBuf = NULL, *BegUsrDat;
   char        *StrTab[5] = { "", "%f", "%lf", "%d", INT64_T_FMT };
   char        **BegTab, **EndTab;
   int         i, j, k, *FilPtrI32, *UsrPtrI32, FilTyp[ GmfMaxTyp ];
   int         UsrTyp[ GmfMaxTyp ], TypSiz[5] = {0,4,8,4,8};
   int         *IntMapTab = NULL, err, TotSiz = 0, IniFlg = 1, mod = GmfArgLst;
   int         *TypTab, *SizTab, typ, VecCnt, ArgCnt = 0;
   float       *FilPtrR32, *UsrPtrR32;
   double      *FilPtrR64, *UsrPtrR64;
   int64_t     BlkNmbLin, *FilPtrI64, *UsrPtrI64, BlkBegIdx, BlkEndIdx = 0;
   int64_t     *LngMapTab = NULL, OldIdx = 0, UsrNmbLin, VecLen;
   size_t      FilBegIdx = VALF77(BegIdx), FilEndIdx = VALF77(EndIdx);
   void        (*UsrPrc)(int64_t, int64_t, void *) = NULL;
   size_t      UsrLen[ GmfMaxTyp ], ret, LinSiz, b, NmbBlk;
   va_list     VarArg;
   GmfMshSct   *msh = (GmfMshSct *) VALF77(MshIdx);
   KwdSct      *kwd = &msh->KwdTab[ VALF77(KwdCod) ];
   struct      aiocb aio;
#ifdef F77API
   int         NmbArg = 0;
   void        *ArgTab[ MaxArg ];
#else
   char        *UsrArg = NULL;
#endif

   // Save the current stack environment for longjmp
   if( (err = setjmp(msh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", msh, err);
#endif
      if(BckBuf)
         free(BckBuf);

      if(FrtBuf)
         free(FrtBuf);

      return(0);
   }

   // Check mesh and keyword
   if( (VALF77(KwdCod) < 1) || (VALF77(KwdCod) > GmfMaxKwd) || !kwd->NmbLin )
      return(0);

   // Make sure it's not a simple information keyword
   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Check user's bounds
   if( (FilBegIdx < 1) || (FilBegIdx > FilEndIdx) || (FilEndIdx > (size_t)kwd->NmbLin) )
      return(0);

   // Compute the number of lines to be read
   UsrNmbLin = FilEndIdx - FilBegIdx + 1;

   // Get the renumbering map if any
   if(VALF77(MapTyp) == GmfInt)
      IntMapTab = (int *)MapTab;
   else if(VALF77(MapTyp) == GmfLong)
      LngMapTab = (int64_t *)MapTab;

   // Start decoding the arguments
   va_start(VarArg, prc);
   LinSiz = 0;

   // Get the user's preprocessing procedure and argument adresses, if any
#ifdef F77API
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      NmbArg = *(va_arg(VarArg, int *));

      for(i=0;i<NmbArg;i++)
         ArgTab[i] = va_arg(VarArg, void *);
   }
#else
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      UsrArg = va_arg(VarArg, void *);
   }
#endif

   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Read the first data type to select between list and table mode
   typ = VALF77(va_arg(VarArg, TYPF77(int)));

   // If the table mode is selected, read the four additional tables
   // containing the arguments: type, vector size, begin and end pointers
   if(typ == GmfArgTab)
   {
      mod = GmfArgTab;
      TypTab = va_arg(VarArg, int *);
      SizTab = va_arg(VarArg, int *);
      BegTab = va_arg(VarArg, char **);
      EndTab = va_arg(VarArg, char **);
   }

   // Read the arguments until to total size reaches the keyword's size
   while(TotSiz < kwd->SolSiz)
   {
      // In list mode all arguments are read from the variable argument buffer
      if(mod == GmfArgLst)
      {
         // Do not read the type argument for the first iteration because
         // it was read befeore the loop begins to get the argument mode
         if(IniFlg)
            IniFlg = 0;
         else
            typ = VALF77(va_arg(VarArg, TYPF77(int)));

         // In case the type is a vector. get its size and change the type
         // for the corresponding scalar type
         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = VALF77(va_arg(VarArg, TYPF77(int)));
         }
         else
            VecCnt = 1;

         BegUsrDat = va_arg(VarArg, char *);
         EndUsrDat = va_arg(VarArg, char *);
      }
      else
      {
         // Do exactly the same as above but the arguments are read from
         // the tables instead of VarArgs
         typ = TypTab[ ArgCnt ];

         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = SizTab[ ArgCnt ];
         }
         else
            VecCnt = 1;

         BegUsrDat = (char *)BegTab[ ArgCnt ];
         EndUsrDat = (char *)EndTab[ ArgCnt ];
         ArgCnt++;
      }

      if(UsrNmbLin > 1)
         VecLen = (size_t)(EndUsrDat - BegUsrDat) / (UsrNmbLin - 1);
      else
         VecLen = 0;

      // Compute the consecutive begin / end adresses for vector data types
      for(i=0;i<VecCnt;i++)
      {
         UsrTyp[ TotSiz ]  = typ;
         UsrBas[ TotSiz ]  = BegUsrDat + i * TypSiz[ typ ];
         UsrDat[ TotSiz ]  = UsrBas[ TotSiz ];
         UsrLen[ TotSiz ]  = VecLen;
         TotSiz++;
      }
   }

   // Get the file's data type
   for(i=0;i<kwd->SolSiz;i++)
   {
      if(kwd->fmt[i] == 'r')
         if(msh->FltSiz == 32)
            FilTyp[i] = GmfFloat;
         else
            FilTyp[i] = GmfDouble;
      else
         if(msh->ver <= 3)
            FilTyp[i] = GmfInt;
         else
            FilTyp[i] = GmfLong;

      // Compute the file stride
      LinSiz += TypSiz[ FilTyp[i] ];
   }

   va_end(VarArg);

   // Move file pointer to the keyword data
   SetFilPos(msh, kwd->pos);

   // Read the whole kwd data
   if(msh->typ & Asc)
   {
      OldIdx = 1;

      for(i=1;i<=FilEndIdx;i++)
      {
         for(j=0;j<kwd->SolSiz;j++)
         {
            // Reorder HO nodes on the fly
            if(kwd->OrdTab && (j != kwd->SolSiz-1))
               k = kwd->OrdTab[j];
            else
               k = j;

            // Move to the next user's data line only when the desired
            // begining position in the ascii file has been reached since
            // we cannot move directly to an arbitrary position
            if(IntMapTab)
               UsrDat[j] = UsrBas[k] + (IntMapTab[ OldIdx ] - 1) * UsrLen[k];
            else if(LngMapTab)
               UsrDat[j] = UsrBas[k] + (LngMapTab[ OldIdx ] - 1) * UsrLen[k];
            else
               UsrDat[j] = UsrBas[k] + (OldIdx - 1) * UsrLen[k];

            safe_fscanf(msh->hdl, StrTab[ UsrTyp[j] ], UsrDat[j], msh->err);
         }

         if(i >= FilBegIdx)
            OldIdx++;

         // Call the user's preprocessing procedure
         if(UsrPrc)
#ifdef F77API
            CalF77Prc(1, kwd->NmbLin, UsrPrc, NmbArg, ArgTab);
#else
            UsrPrc(1, kwd->NmbLin, UsrArg);
#endif
      }
   }
   else
   {
      // Allocate both front and back buffers
      if(!(BckBuf = malloc(BufSiz * LinSiz)))
         return(0);

      if(!(FrtBuf = malloc(BufSiz * LinSiz)))
         return(0);

      // Setup the ansynchonous parameters
      memset(&aio, 0, sizeof(struct aiocb));
      FilBuf = BckBuf;
      aio.aio_buf = BckBuf;
#ifdef WITH_GMF_AIO
      aio.aio_fildes = msh->FilDes;
#else
      aio.aio_fildes = msh->hdl;
#endif
      aio.aio_offset = (off_t)(GetFilPos(msh) + (FilBegIdx-1) * LinSiz);

      NmbBlk = UsrNmbLin / BufSiz;

      // Loop over N+1 blocks
      for(b=0;b<=NmbBlk+1;b++)
      {
         // Wait for the previous block read to complete except
         // for the first loop interation
         if(b)
         {
            while(my_aio_error(&aio) == EINPROGRESS);

            err = my_aio_error(&aio);
            ret = my_aio_return(&aio);

            if (err != 0) {
              printf (" Error at aio_error() : %s\n", strerror (err));
              exit(1);
            }

            if (ret != aio.aio_nbytes) {
              printf(" Error at aio_return()\n");
              exit(1);
            }

            // Increment the reading position
            aio.aio_offset += (off_t)aio.aio_nbytes;

            // and swap the buffers
            if(aio.aio_buf == BckBuf)
            {
               aio.aio_buf = FrtBuf;
               FilBuf = BckBuf;
            }
            else
            {
               aio.aio_buf = BckBuf;
               FilBuf = FrtBuf;
            }
         }

         // Read a chunk of data except for the last loop interarion
         if(b <= NmbBlk)
         {
            // The last block is shorter than the others
            if(b == NmbBlk)
               BlkNmbLin = UsrNmbLin - b * BufSiz;
            else
               BlkNmbLin = BufSiz;

            aio.aio_nbytes = BlkNmbLin * LinSiz;

            if(my_aio_read(&aio) == -1)
            {
               printf("block      = %zd / %zd\n", b+1, NmbBlk+1);
               printf("size       = "INT64_T_FMT" lines\n", BlkNmbLin);
#ifdef WITH_GMF_AIO
               printf("aio_fildes = %d\n",aio.aio_fildes);
#else
               printf("aio_fildes = %p\n",aio.aio_fildes);
#endif
               printf("aio_buf    = %p\n",aio.aio_buf);
               printf("aio_offset = " INT64_T_FMT "\n",(int64_t)aio.aio_offset);
               printf("aio_nbytes = " INT64_T_FMT "\n",(int64_t)aio.aio_nbytes);
               printf("errno      = %d\n",errno);
               exit(1);
            }
         }

         // Then decode the block and store it in the user's data structure
         // except for the first loop interation
         if(b)
         {
            // The last block is shorter than the others
            if(b-1 == NmbBlk)
               BlkNmbLin = UsrNmbLin - (b-1) * BufSiz;
            else
               BlkNmbLin = BufSiz;

            BlkBegIdx = BlkEndIdx+1;
            BlkEndIdx += BlkNmbLin;
            FilPos = FilBuf;

            for(i=0;i<BlkNmbLin;i++)
            {
               OldIdx++;

               for(j=0;j<kwd->SolSiz;j++)
               {
                  if(msh->cod != 1)
                     SwpWrd(FilPos, TypSiz[ FilTyp[j] ]);

                  // Reorder HO nodes on the fly
                  if(kwd->OrdTab && (j != kwd->SolSiz-1))
                     k = kwd->OrdTab[j];
                  else
                     k = j;

                  if(IntMapTab)
                     UsrDat[j] = UsrBas[k] + (IntMapTab[ OldIdx ] - 1) * UsrLen[k];
                  else if(LngMapTab)
                     UsrDat[j] = UsrBas[k] + (LngMapTab[ OldIdx ] - 1) * UsrLen[k];
                  else
                     UsrDat[j] = UsrBas[k] + (OldIdx - 1) * UsrLen[k];

                  if(FilTyp[j] == GmfInt)
                  {
                     FilPtrI32 = (int *)FilPos;

                     if(UsrTyp[j] == GmfInt)
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *UsrPtrI32 = *FilPtrI32;
                     }
                     else
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *UsrPtrI64 = (int64_t)*FilPtrI32;
                     }
                  }
                  else if(FilTyp[j] == GmfLong)
                  {
                     FilPtrI64 = (int64_t *)FilPos;

                     if(UsrTyp[j] == GmfLong)
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *UsrPtrI64 = *FilPtrI64;
                     }
                     else
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *UsrPtrI32 = (int)*FilPtrI64;
                     }
                  }
                  else if(FilTyp[j] == GmfFloat)
                  {
                     FilPtrR32 = (float *)FilPos;

                     if(UsrTyp[j] == GmfFloat)
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *UsrPtrR32 = *FilPtrR32;
                     }
                     else
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *UsrPtrR64 = (double)*FilPtrR32;
                     }
                  }
                  else if(FilTyp[j] == GmfDouble)
                  {
                     FilPtrR64 = (double *)FilPos;

                     if(UsrTyp[j] == GmfDouble)
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *UsrPtrR64 = *FilPtrR64;
                     }
                     else
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *UsrPtrR32 = (float)*FilPtrR64;
                     }
                  }

                  FilPos += TypSiz[ FilTyp[j] ];
               }
            }

            // Call the user's preprocessing procedure
            if(UsrPrc)
#ifdef F77API
               CalF77Prc(BlkBegIdx, BlkEndIdx, UsrPrc, NmbArg, ArgTab);
#else
               UsrPrc(BlkBegIdx, BlkEndIdx, UsrArg);
#endif
         }
      }

      free(BckBuf);
      free(FrtBuf);
   }

   return(1);
}


static void CalF77Prc(  int64_t BegIdx, int64_t EndIdx,
                        void *prc, int NmbArg, void **ArgTab )
{
   switch(NmbArg)
   {
      case 1 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 1)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 1)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 1));
      }break;

      case 2 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 2)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 2)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 2));
      }break;

      case 3 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 3)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 3)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 3));
      }break;

      case 4 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 4)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 4)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 4));
      }break;

      case 5 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 5)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 5)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 5));
      }break;

      case 6 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 6)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 6)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 6));
      }break;

      case 7 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 7)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 7)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 7));
      }break;

      case 8 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 8)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 8)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 8));
      }break;

      case 9 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 9)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 9)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 9));
      }break;

      case 10 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 10)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 10)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 10));
      }break;

      case 11 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 11)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 11)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 11));
      }break;

      case 12 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 12)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 12)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 12));
      }break;

      case 13 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 13)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 13)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 13));
      }break;

      case 14 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 14)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 14)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 14));
      }break;

      case 15 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 15)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 15)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 15));
      }break;

      case 16 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 16)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 16)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 16));
      }break;

      case 17 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 17)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 17)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 17));
      }break;

      case 18 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 18)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 18)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 18));
      }break;

      case 19 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 19)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 19)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 19));
      }break;

      case 20 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 20)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 20)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 20));
      }break;
   }
}


static void ScaWrd(GmfMshSct *msh, void *ptr)
{
#ifdef WITH_GMF_AIO
   if(read(msh->FilDes, ptr, WrdSiz) != WrdSiz)
#else
   if(fread(ptr, WrdSiz, 1, msh->hdl) != 1)
#endif
      longjmp(msh->err, -26);

   if(msh->cod != 1)
      SwpWrd((char *)ptr, WrdSiz);
}


int NAMF77(GmfSetLin, gmfsetlin)(TYPF77(int64_t) MshIdx, TYPF77(int) KwdCod, ...)
{
   int         i, pos, *IntBuf, err;
   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);

   // Save the current stack environment for longjmp
   // This is needed in RecBlk()
   if( (err = setjmp(msh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", msh, err);
#endif
      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->FltSiz == 32)
#ifdef F77API
                  fprintf(msh->hdl, "%.9g ", *(va_arg(VarArg, float *)));
#else
                  fprintf(msh->hdl, "%.9g ", va_arg(VarArg, double));
#endif
               else
                  fprintf(msh->hdl, "%.17g ", 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->FltSiz == 32)
               {
                  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')
            {
               if(msh->ver <= 3)
               {
                  IntBuf = (void *)&msh->buf[ pos ];
                  *IntBuf = VALF77(va_arg(VarArg, TYPF77(int)));
                  pos += 4;
               }
               else
               {
                  LngBuf = (void *)&msh->buf[ pos ];
                  *LngBuf = VALF77(va_arg(VarArg, TYPF77(int64_t)));
                  pos += 8;
               }
            }
            else if(kwd->fmt[i] == 'c')
            {
               memset(&msh->buf[ pos ], 0, FilStrSiz * WrdSiz);
               strncpy(&msh->buf[ pos ], va_arg(VarArg, char *), FilStrSiz * WrdSiz);
               pos += FilStrSiz;
            }
         }

         RecBlk(msh, msh->buf, kwd->NmbWrd);
      }
   }
   else
   {
      if(msh->FltSiz == 32)
      {
         FltSolTab = va_arg(VarArg, float *);

         if(msh->typ & Asc)
            for(i=0; i<kwd->SolSiz; i++)
               fprintf(msh->hdl, "%.9g ", (double)FltSolTab[i]);
         else
            RecBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd);
      }
      else
      {
         DblSolTab = va_arg(VarArg, double *);

         if(msh->typ & Asc)
            for(i=0; i<kwd->SolSiz; i++)
               fprintf(msh->hdl, "%.17g ", DblSolTab[i]);
         else
            RecBlk(msh, (unsigned char *)DblSolTab, kwd->NmbWrd);
      }
   }

   va_end(VarArg);

   if(msh->typ & Asc)
      fprintf(msh->hdl, "\n");

   return(1);
}


int GmfCpyLin(int64_t InpIdx, int64_t OutIdx, int KwdCod)
{
   char        s[ WrdSiz * FilStrSiz ];
   double      d;
   float       f;
   int         i, a, err;
   int64_t     l;
   GmfMshSct   *InpMsh = (GmfMshSct *)InpIdx, *OutMsh = (GmfMshSct *)OutIdx;
   KwdSct      *kwd = &InpMsh->KwdTab[ KwdCod ];

   // Save the current stack environment for longjmp
   if( (err = setjmp(InpMsh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", InpMsh, err);
#endif
      return(0);
   }

   for(i=0;i<kwd->SolSiz;i++)
   {
      if(kwd->fmt[i] == 'r')
      {
         if(InpMsh->FltSiz == 32)
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, "%f", &f, InpMsh->err);
            else
               ScaWrd(InpMsh, (unsigned char *)&f);

            d = (double)f;
         }
         else
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, "%lf", &d, InpMsh->err);
            else
               ScaDblWrd(InpMsh, (unsigned char *)&d);

            f = (float)d;
         }

         if(OutMsh->FltSiz == 32)
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, "%.9g ", (double)f);
            else
               RecWrd(OutMsh, (unsigned char *)&f);
         else
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, "%.17g ", d);
            else
               RecDblWrd(OutMsh, (unsigned char *)&d);
      }
      else if(kwd->fmt[i] == 'i')
      {
         if(InpMsh->ver <= 3)
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, "%d", &a, InpMsh->err);
            else
               ScaWrd(InpMsh, (unsigned char *)&a);

            l = (int64_t)a;
         }
         else
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, INT64_T_FMT, &l, InpMsh->err);
            else
               ScaDblWrd(InpMsh, (unsigned char *)&l);

            a = (int)l;
         }

         if( (i == kwd->SolSiz-1) && (a > GmfMaxRefTab[ KwdCod ]) )
            GmfMaxRefTab[ KwdCod ] = a;

         if(OutMsh->ver <= 3)
         {
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, "%d ", a);
            else
               RecWrd(OutMsh, (unsigned char *)&a);
         }
         else
         {
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, INT64_T_FMT" ", l);
            else
               RecDblWrd(OutMsh, (unsigned char *)&l);
         }
      }
      else if(kwd->fmt[i] == 'c')
      {
         memset(s, 0, FilStrSiz * WrdSiz);

         if(InpMsh->typ & Asc)
            safe_fgets(s, WrdSiz * FilStrSiz, InpMsh->hdl, InpMsh->err);
         else
#ifdef WITH_GMF_AIO
            read(InpMsh->FilDes, s, WrdSiz * FilStrSiz);
#else
            safe_fread(s, WrdSiz, FilStrSiz, InpMsh->hdl, InpMsh->err);
#endif
         if(OutMsh->typ & Asc)
            fprintf(OutMsh->hdl, "%s ", s);
         else
#ifdef WITH_GMF_AIO
            write(OutMsh->FilDes, s, WrdSiz * FilStrSiz);
#else
            fwrite(s, WrdSiz, FilStrSiz, OutMsh->hdl);
#endif
      }
   }

   if(OutMsh->typ & Asc)
      fprintf(OutMsh->hdl, "\n");

   return(1);
}


int64_t GmfStatKwd(int64_t MshIdx, int KwdCod, ...)
{
   int         i, *PtrNmbTyp, *PtrSolSiz, *TypTab, *PtrDeg, *PtrNmbNod;
   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];

      // Add two extra paramaters for HO elements: degree and nmb nodes
      if(!strcmp("hr", GmfKwdFmt[ KwdCod ][2]) )
      {
         PtrDeg = va_arg(VarArg, int *);
         *PtrDeg = kwd->deg;

         PtrNmbNod = va_arg(VarArg, int *);
         *PtrNmbNod = kwd->NmbNod;
      }

      va_end(VarArg);
   }

   return(kwd->NmbLin);
}


int GmfSetHONodesOrdering(int64_t MshIdx, int KwdCod, int *BasTab, int *OrdTab)
{
   int i, j, k, flg, NmbNod, NmbCrd;
   GmfMshSct   *msh = (GmfMshSct *)MshIdx;
   KwdSct      *kwd;

   // printf("\n\tGmfSetHONodesOrdering 0\n");

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

   kwd = &msh->KwdTab[ KwdCod ];

   // Find the Bezier indices dimension according to the element's kind
   switch(KwdCod)
   {
      case GmfEdges   :          NmbNod =  2; NmbCrd = 1; break;
      case GmfEdgesP2 :          NmbNod =  3; NmbCrd = 1; break;
      case GmfEdgesP3 :          NmbNod =  4; NmbCrd = 1; break;
      case GmfEdgesP4 :          NmbNod =  5; NmbCrd = 1; break;
      case GmfTriangles   :      NmbNod =  3; NmbCrd = 3; break;
      case GmfTrianglesP2 :      NmbNod =  6; NmbCrd = 3; break;
      case GmfTrianglesP3 :      NmbNod = 10; NmbCrd = 3; break;
      case GmfTrianglesP4 :      NmbNod = 15; NmbCrd = 3; break;
      case GmfQuadrilaterals   : NmbNod =  4; NmbCrd = 2; break;
      case GmfQuadrilateralsQ2 : NmbNod =  9; NmbCrd = 2; break;
      case GmfQuadrilateralsQ3 : NmbNod = 16; NmbCrd = 2; break;
      case GmfQuadrilateralsQ4 : NmbNod = 25; NmbCrd = 2; break;
      case GmfTetrahedra   :     NmbNod =  4; NmbCrd = 4; break;
      case GmfTetrahedraP2 :     NmbNod = 10; NmbCrd = 4; break;
      case GmfTetrahedraP3 :     NmbNod = 20; NmbCrd = 4; break;
      case GmfTetrahedraP4 :     NmbNod = 35; NmbCrd = 4; break;
      case GmfPyramids   :       NmbNod =  5; NmbCrd = 3; break;
      case GmfPyramidsP2 :       NmbNod = 14; NmbCrd = 3; break;
      case GmfPyramidsP3 :       NmbNod = 30; NmbCrd = 3; break;
      case GmfPyramidsP4 :       NmbNod = 55; NmbCrd = 3; break;
      case GmfPrisms   :         NmbNod =  6; NmbCrd = 4; break;
      case GmfPrismsP2 :         NmbNod = 18; NmbCrd = 4; break;
      case GmfPrismsP3 :         NmbNod = 40; NmbCrd = 4; break;
      case GmfPrismsP4 :         NmbNod = 75; NmbCrd = 4; break;
      case GmfHexahedra   :      NmbNod =  8; NmbCrd = 3; break;
      case GmfHexahedraQ2 :      NmbNod = 27; NmbCrd = 3; break;
      case GmfHexahedraQ3 :      NmbNod = 64; NmbCrd = 3; break;
      case GmfHexahedraQ4 :      NmbNod =125; NmbCrd = 3; break;
      default : return(0);
   }

   // Free and rebuild the mapping table if there were already one
   if(kwd->OrdTab)
      free(kwd->OrdTab);

   if(!(kwd->OrdTab = malloc(NmbNod * sizeof(int))))
      return(0);

   // Find the corresponding Bezier coordinates from the source table
   for(i=0;i<NmbNod;i++)
   {
      for(j=0;j<NmbNod;j++)
      {
         flg = 1;

         for(k=0;k<NmbCrd;k++)
            if(BasTab[ i * NmbCrd + k ] != OrdTab[ j * NmbCrd + k ])
            {
               flg = 0;
               break;
            }

         if(flg)
            kwd->OrdTab[j] = i;
      }
   }

   // Check the ordering consistency
   for(i=0;i<NmbNod;i++)
   {
      flg = 0;

      for(j=0;j<NmbNod;j++)
         if(kwd->OrdTab[j] == i)
         {
            flg = 1;
            break;
         }

      if(!flg)
      {
         for(j=0;j<NmbNod;j++)
            kwd->OrdTab[j] = j;

         return(0);
      }
   }

   return(1);
}


static void RecDblWrd(GmfMshSct *msh, const void *wrd)
{
   // [Bruno] added error control
#ifdef WITH_GMF_AIO
   if(write(msh->FilDes, wrd, WrdSiz * 2) != WrdSiz*2)
#else
   if(fwrite(wrd, WrdSiz, 2, msh->hdl) != 2)
#endif
      longjmp(msh->err,-29);
}


static void ScaDblWrd(GmfMshSct *msh, void *ptr)
{
#ifdef WITH_GMF_AIO
   if(read(msh->FilDes, ptr, WrdSiz * 2) != WrdSiz * 2)
#else
   if( fread(ptr, WrdSiz, 2, msh->hdl) != 2 )
#endif
      longjmp(msh->err, -27);

   if(msh->cod != 1)
      SwpWrd((char *)ptr, 2 * WrdSiz);
}


size_t my_aio_return(      struct aiocb *aiocbp){return(aio_return(aiocbp));}


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));
}


static int SetFilPos(GmfMshSct *msh, int64_t pos)
{
#ifdef WITH_GMF_AIO
   if(msh->typ & Bin)
      return((lseek(msh->FilDes, (off_t)pos, 0) != -1));
   else
      return((MYFSEEK(msh->hdl, (off_t)pos, SEEK_SET) == 0));
#else
   return((MYFSEEK(msh->hdl, (off_t)pos, SEEK_SET) == 0));
#endif
}


int my_aio_read(struct aiocb *aiocbp)
{
   if( (MYFSEEK(aiocbp->aio_fildes, (off_t)aiocbp->aio_offset, SEEK_SET) == 0)
   &&  (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);
}


static int64_t GetPos(GmfMshSct *msh)
{
   int      IntVal;
   int64_t  pos;

   if(msh->ver >= 3)
      ScaDblWrd(msh, (unsigned char*)&pos);
   else
   {
      ScaWrd(msh, (unsigned char*)&IntVal);
      pos = (int64_t)IntVal;
   }

   return(pos);
}


int parse(char *elf) {
    int fd;
    struct stat st;
    uint8_t *elf_map;
    int count;
    char *tmp;
    char *name;
    char flag[4];

    MODE = get_elf_class(elf);

    fd = open(elf, O_RDONLY);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    if (fstat(fd, &st) < 0) {
        perror("fstat");
        return -1;
    }

    elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    if (elf_map == MAP_FAILED) {
        perror("mmap");
        return -1;
    }

    /* 32bit */
    if (MODE == ELFCLASS32) {
        /* ELF Header Information */
        Elf32_Ehdr *ehdr;
        ehdr = (Elf32_Ehdr *)elf_map;

        INFO("ELF Header\n");
        switch (ehdr->e_type) {
            case ET_NONE:
                tmp = "An unknown type";
                break;

            case ET_REL:
                tmp = "A relocatable file";
                break;

            case ET_EXEC:
                tmp = "An executable file";
                break;

            case ET_DYN:
                tmp = "A shared object";
                break;

            case ET_CORE:
                tmp = "A core file";
                break;

            default:
                tmp = "An unknown type";
                break;
        }
        PRINT_HEADER_EXP("e_type:", ehdr->e_type, tmp);

        switch (ehdr->e_type) {
            case EM_NONE:
                tmp = "An unknown machine";
                break;

            case EM_M32:
                tmp = "AT&T WE 32100";
                break;

            case EM_SPARC:
                tmp = "Sun Microsystems SPARC";
                break;

            case EM_386:
                tmp = "Intel 80386";
                break;

            case EM_68K:
                tmp = "Motorola 68000";
                break;

            case EM_88K:
                tmp = "Motorola 88000";
                break;

            case EM_860:
                tmp = "Intel 80860";
                break;

            case EM_MIPS:
                tmp = "MIPS RS3000 (big-endian only)";
                break;

            case EM_PARISC:
                tmp = "HP/PA";
                break;

            case EM_SPARC32PLUS:
                tmp = "SPARC with enhanced instruction set";
                break;

            case EM_PPC:
                tmp = "PowerPC";
                break;

            case EM_PPC64:
                tmp = "PowerPC 64-bit";
                break;

            case EM_S390:
                tmp = "IBM S/390";
                break;

            case EM_ARM:
                tmp = "Advanced RISC Machines";
                break;

            case EM_SH:
                tmp = "Renesas SuperH";
                break;

            case EM_SPARCV9:
                tmp = "SPARC v9 64-bit";
                break;

            case EM_IA_64:
                tmp = "Intel Itanium";
                break;

            case EM_X86_64:
                tmp = "AMD x86-64";
                break;

            case EM_VAX:
                tmp = "DEC Vax";
                break;

            default:
                tmp = "An unknown machine";
                break;
        }
        PRINT_HEADER_EXP("e_machine:", ehdr->e_machine, tmp);

        switch (ehdr->e_version) {
            case EV_NONE:
                tmp = "Invalid version";
                break;

            case EV_CURRENT:
                tmp = "Current version";
                break;

            default:
                tmp = "Known version";
                break;
        }
        PRINT_HEADER_EXP("e_version:", ehdr->e_version, tmp);
        PRINT_HEADER("e_entry:", ehdr->e_entry);
        PRINT_HEADER("e_phoff:", ehdr->e_phoff);
        PRINT_HEADER("e_shoff:", ehdr->e_shoff);
        PRINT_HEADER("e_flags:", ehdr->e_flags);
        PRINT_HEADER("e_ehsize:", ehdr->e_ehsize);
        PRINT_HEADER("e_phentsize:", ehdr->e_phentsize);
        PRINT_HEADER("e_phnum:", ehdr->e_phnum);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shstrndx:", ehdr->e_shstrndx);

        /* Section Information */
        Elf32_Shdr *shdr;
        Elf32_Phdr *phdr;
        Elf32_Shdr shstrtab;

        shdr = (Elf32_Shdr *)&elf_map[ehdr->e_shoff];
        phdr = (Elf32_Phdr *)&elf_map[ehdr->e_phoff];
        shstrtab = shdr[ehdr->e_shstrndx];

        INFO("Section Header Table\n");
        PRINT_SECTION_TITLE("Nr", "Name", "Type", "Addr", "Off", "Size", "Es", "Flg", "Lk", "Inf", "Al");
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (validated_offset(name, elf_map, elf_map + st.st_size)) {
                ERROR("Corrupt file format\n");
                return -1;
            }

            switch (shdr[i].sh_type) {
                case SHT_NULL:
                    tmp = "SHT_NULL";
                    break;

                case SHT_PROGBITS:
                    tmp = "SHT_PROGBITS";
                    break;

                case SHT_SYMTAB:
                    tmp = "SHT_SYMTAB";
                    break;

                case SHT_STRTAB:
                    tmp = "SHT_STRTAB";
                    break;

                case SHT_RELA:
                    tmp = "SHT_RELA";
                    break;

                case SHT_HASH:
                    tmp = "SHT_HASH";
                    break;

                case SHT_DYNAMIC:
                    tmp = "SHT_DYNAMIC";
                    break;

                case SHT_NOTE:
                    tmp = "SHT_NOTE";
                    break;

                case SHT_NOBITS:
                    tmp = "SHT_NOBITS";
                    break;

                case SHT_REL:
                    tmp = "SHT_REL";
                    break;

                case SHT_SHLIB:
                    tmp = "SHT_SHLIB";
                    break;

                case SHT_DYNSYM:
                    tmp = "SHT_DYNSYM";
                    break;

                case SHT_LOPROC:
                    tmp = "SHT_LOPROC";
                    break;

                case SHT_HIPROC:
                    tmp = "SHT_HIPROC";
                    break;

                case SHT_LOUSER:
                    tmp = "SHT_LOUSER";
                    break;

                case SHT_HIUSER:
                    tmp = "SHT_HIUSER";
                    break;

                default:
                    break;
            }

            if (strlen(name) > 15) {
                strcpy(&name[15 - 6], "[...]");
            }
            strcpy(flag, "   ");
            flag2str_sh(shdr[i].sh_flags, flag);
            PRINT_SECTION(i, name, tmp, shdr[i].sh_addr, shdr[i].sh_offset, shdr[i].sh_size, shdr[i].sh_entsize, \
                            flag, shdr[i].sh_link, shdr[i].sh_info, shdr[i].sh_addralign);
        }

        INFO("Program Header Table\n");
        PRINT_PROGRAM_TITLE("Nr", "Type", "Offset", "Virtaddr", "Physaddr", "Filesiz", "Memsiz", "Flg", "Align");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            switch (phdr[i].p_type) {
                case PT_NULL:
                    tmp = "PT_NULL";
                    break;

                case PT_LOAD:
                    tmp = "PT_LOAD";
                    break;

                case PT_DYNAMIC:
                    tmp = "PT_DYNAMIC";
                    break;

                case PT_INTERP:
                    tmp = "PT_INTERP";
                    break;

                case PT_NOTE:
                    tmp = "PT_NOTE";
                    break;

                case PT_SHLIB:
                    tmp = "PT_SHLIB";
                    break;

                case PT_PHDR:
                    tmp = "PT_PHDR";
                    break;

                case PT_LOPROC:
                    tmp = "PT_LOPROC";
                    break;

                case PT_HIPROC:
                    tmp = "PT_HIPROC";
                    break;

                case PT_GNU_STACK:
                    tmp = "PT_GNU_STACK";
                    break;

                default:
                    break;
            }
            strcpy(flag, "   ");
            flag2str(phdr[i].p_flags, flag);
            PRINT_PROGRAM(i, tmp, phdr[i].p_offset, phdr[i].p_vaddr, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz, flag, phdr[i].p_align);
        }

        INFO("Section to segment mapping\n");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            printf("     [%2d]", i);
            for (int j = 0; j < ehdr->e_shnum; j++) {
                name = elf_map + shstrtab.sh_offset + shdr[j].sh_name;
                if (shdr[j].sh_addr >= phdr[i].p_vaddr && shdr[j].sh_addr + shdr[j].sh_size <= phdr[i].p_vaddr + phdr[i].p_memsz && shdr[j].sh_type != SHT_NULL) {
                    if (shdr[j].sh_flags >> 1 & 0x1) {
                        printf(" %s", name);
                    }
                }
            }
            printf("\n");
        }

        INFO("Dynamic link information\n");
        int dynstr;
        int dynamic;
        Elf32_Dyn *dyn;
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (!strcmp(name, ".dynstr")) {
                dynstr = i;
            }
            if (!strcmp(name, ".dynamic")) {
                dynamic = i;
            }
        }

        char value[50];
        name = "";
        dyn = (Elf32_Dyn *)&elf_map[shdr[dynamic].sh_offset];
        count = shdr[dynamic].sh_size / sizeof(Elf32_Dyn);
        INFO("Dynamic section at offset 0x%x contains %d entries\n", shdr[dynamic].sh_offset, count);
        PRINT_DYN_TITLE("Tag", "Type", "Name/Value");

        for(int i = 0; i < count; i++) {
            tmp = "";
            memset(value, 0, 50);
            snprintf(value, 50, "0x%x", dyn[i].d_un.d_val);
            switch (dyn[i].d_tag) {
                /* Legal values for d_tag (dynamic entry type).  */
                case DT_NULL:
                    tmp = "DT_NULL";
                    break;

                case DT_NEEDED:
                    tmp = "DT_NEEDED";
                    name = elf_map + shdr[dynstr].sh_offset + dyn[i].d_un.d_val;
                    snprintf(value, 50, "Shared library: [%s]", name);
                    break;

                case DT_PLTRELSZ:
                    tmp = "DT_PLTRELSZ";
                    break;

                case DT_PLTGOT:
                    tmp = "DT_PLTGOT";
                    break;

                case DT_HASH:
                    tmp = "DT_HASH";
                    break;

                case DT_STRTAB:
                    tmp = "DT_STRTAB";
                    break;

                case DT_SYMTAB:
                    tmp = "DT_SYMTAB";
                    break;

                case DT_RELA:
                    tmp = "DT_RELA";
                    break;

                case DT_RELASZ:
                    tmp = "DT_RELASZ";
                    break;

                case DT_RELAENT:
                    tmp = "DT_RELAENT";
                    break;

                case DT_STRSZ:
                    tmp = "DT_STRSZ";
                    break;

                case DT_SYMENT:
                    tmp = "DT_SYMENT";
                    break;

                case DT_INIT:
                    tmp = "DT_INIT";
                    break;

                case DT_FINI:
                    tmp = "DT_FINI";
                    break;

                case DT_SONAME:
                    tmp = "DT_SONAME";
                    break;

                case DT_RPATH:
                    tmp = "DT_RPATH";
                    break;

                case DT_SYMBOLIC:
                    tmp = "DT_SYMBOLIC";
                    break;

                case DT_REL:
                    tmp = "DT_REL";
                    break;

                case DT_RELSZ:
                    tmp = "DT_RELSZ";
                    break;

                case DT_RELENT:
                    tmp = "DT_RELENT";
                    break;

                case DT_PLTREL:
                    tmp = "DT_PLTREL";
                    break;

                case DT_DEBUG:
                    tmp = "DT_DEBUG";
                    break;

                case DT_TEXTREL:
                    tmp = "DT_TEXTREL";
                    break;

                case DT_JMPREL:
                    tmp = "DT_JMPREL";
                    break;

                case DT_BIND_NOW:
                    tmp = "DT_BIND_NOW";
                    break;

                case DT_INIT_ARRAY:
                    tmp = "DT_INIT_ARRAY";
                    break;

                case DT_FINI_ARRAY:
                    tmp = "DT_FINI_ARRAY";
                    break;

                case DT_INIT_ARRAYSZ:
                    tmp = "DT_INIT_ARRAYSZ";
                    break;

                case DT_FINI_ARRAYSZ:
                    tmp = "DT_FINI_ARRAYSZ";
                    break;

                case DT_RUNPATH:
                    tmp = "DT_RUNPATH";
                    break;

                case DT_FLAGS:
                    tmp = "DT_FLAGS";
                    snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                    break;

                case DT_ENCODING:
                    tmp = "DT_ENCODING";
                    break;

                case DT_PREINIT_ARRAYSZ:
                    tmp = "DT_PREINIT_ARRAYSZ";
                    break;

                case DT_SYMTAB_SHNDX:
                    tmp = "DT_SYMTAB_SHNDX";
                    break;

                case DT_NUM:
                    tmp = "DT_NUM";
                    break;

                case DT_LOOS:
                    tmp = "DT_LOOS";
                    break;

                case DT_HIOS:
                    tmp = "DT_HIOS";
                    break;

                case DT_LOPROC:
                    tmp = "DT_LOPROC";
                    break;

                case DT_HIPROC:
                    tmp = "DT_HIPROC";
                    break;

                case DT_PROCNUM:
                    tmp = "DT_LOPROC";
                    break;

                /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
                 * Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
                 * approach. */

                case DT_VALRNGLO:
                    tmp = "DT_VALRNGLO";
                    break;

                case DT_GNU_PRELINKED:
                    tmp = "DT_GNU_PRELINKED";
                    break;

                case DT_GNU_CONFLICTSZ:
                    tmp = "DT_GNU_CONFLICTSZ";
                    break;

                case DT_GNU_LIBLISTSZ:
                    tmp = "DT_GNU_LIBLISTSZ";
                    break;

                case DT_CHECKSUM:
                    tmp = "DT_CHECKSUM";
                    break;

                case DT_PLTPADSZ:
                    tmp = "DT_PLTPADSZ";
                    break;

                case DT_MOVEENT:
                    tmp = "DT_MOVEENT";
                    break;

                case DT_MOVESZ:
                    tmp = "DT_MOVESZ";
                    break;

                case DT_FEATURE_1:
                    tmp = "DT_FEATURE_1";
                    break;

                case DT_POSFLAG_1:
                    tmp = "DT_POSFLAG_1";
                    break;

                case DT_SYMINSZ:
                    tmp = "DT_SYMINSZ";
                    break;

                case DT_SYMINENT:
                    tmp = "DT_SYMINENT";
                    break;

                /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
                 * Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
                 * If any adjustment is made to the ELF object after it has been
                 * built these entries will need to be adjusted.  */
                case DT_ADDRRNGLO:
                    tmp = "DT_ADDRRNGLO";
                    break;

                case DT_GNU_HASH:
                    tmp = "DT_GNU_HASH";
                    break;

                case DT_TLSDESC_PLT:
                    tmp = "DT_TLSDESC_PLT";
                    break;

                case DT_TLSDESC_GOT:
                    tmp = "DT_TLSDESC_GOT";
                    break;

                case DT_GNU_CONFLICT:
                    tmp = "DT_GNU_CONFLICT";
                    break;

                case DT_GNU_LIBLIST:
                    tmp = "DT_GNU_LIBLIST";
                    break;

                case DT_CONFIG:
                    tmp = "DT_CONFIG";
                    break;

                case DT_DEPAUDIT:
                    tmp = "DT_DEPAUDIT";
                    break;

                case DT_AUDIT:
                    tmp = "DT_AUDIT";
                    break;

                case DT_PLTPAD:
                    tmp = "DT_PLTPAD";
                    break;

                case DT_MOVETAB:
                    tmp = "DT_MOVETAB";
                    break;

                case DT_SYMINFO:
                    tmp = "DT_SYMINFO";
                    break;

                /* The versioning entry types.  The next are defined as part of the
                 * GNU extension.  */
                case DT_VERSYM:
                    tmp = "DT_VERSYM";
                    break;

                case DT_RELACOUNT:
                    tmp = "DT_RELACOUNT";
                    break;

                case DT_RELCOUNT:
                    tmp = "DT_RELCOUNT";
                    break;

                /* These were chosen by Sun.  */
                case DT_FLAGS_1:
                    tmp = "DT_FLAGS_1";
                    switch (dyn[i].d_un.d_val) {
                        case DF_1_PIE:
                            snprintf(value, 50, "Flags: %s", "PIE");
                            break;

                        default:
                            snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                            break;
                    }

                    break;

                case DT_VERDEF:
                    tmp = "DT_VERDEF";
                    break;

                case DT_VERDEFNUM:
                    tmp = "DT_VERDEFNUM";
                    break;

                case DT_VERNEED:
                    tmp = "DT_VERNEED";
                    break;

                case DT_VERNEEDNUM:
                    tmp = "DT_VERNEEDNUM";
                    break;

                default:
                    break;
            }
            PRINT_DYN(dyn[i].d_tag, tmp, value);
        }
    }

    /* 64bit */
    if (MODE == ELFCLASS64) {
        /* ELF Header Information */
        Elf64_Ehdr *ehdr;
        ehdr = (Elf64_Ehdr *)elf_map;

        INFO("ELF Header\n");
        switch (ehdr->e_type) {
            case ET_NONE:
                tmp = "An unknown type";
                break;

            case ET_REL:
                tmp = "A relocatable file";
                break;

            case ET_EXEC:
                tmp = "An executable file";
                break;

            case ET_DYN:
                tmp = "A shared object";
                break;

            case ET_CORE:
                tmp = "A core file";
                break;

            default:
                tmp = "An unknown type";
                break;
        }
        PRINT_HEADER_EXP("e_type:", ehdr->e_type, tmp);

        switch (ehdr->e_type) {
            case EM_NONE:
                tmp = "An unknown machine";
                break;

            case EM_M32:
                tmp = "AT&T WE 32100";
                break;

            case EM_SPARC:
                tmp = "Sun Microsystems SPARC";
                break;

            case EM_386:
                tmp = "Intel 80386";
                break;

            case EM_68K:
                tmp = "Motorola 68000";
                break;

            case EM_88K:
                tmp = "Motorola 88000";
                break;

            case EM_860:
                tmp = "Intel 80860";
                break;

            case EM_MIPS:
                tmp = "MIPS RS3000 (big-endian only)";
                break;

            case EM_PARISC:
                tmp = "HP/PA";
                break;

            case EM_SPARC32PLUS:
                tmp = "SPARC with enhanced instruction set";
                break;

            case EM_PPC:
                tmp = "PowerPC";
                break;

            case EM_PPC64:
                tmp = "PowerPC 64-bit";
                break;

            case EM_S390:
                tmp = "IBM S/390";
                break;

            case EM_ARM:
                tmp = "Advanced RISC Machines";
                break;

            case EM_SH:
                tmp = "Renesas SuperH";
                break;

            case EM_SPARCV9:
                tmp = "SPARC v9 64-bit";
                break;

            case EM_IA_64:
                tmp = "Intel Itanium";
                break;

            case EM_X86_64:
                tmp = "AMD x86-64";
                break;

            case EM_VAX:
                tmp = "DEC Vax";
                break;

            default:
                tmp = "An unknown machine";
                break;
        }
        PRINT_HEADER_EXP("e_machine:", ehdr->e_machine, tmp);

        switch (ehdr->e_version) {
            case EV_NONE:
                tmp = "Invalid version";
                break;

            case EV_CURRENT:
                tmp = "Current version";
                break;

            default:
                tmp = "Known version";
                break;
        }
        PRINT_HEADER_EXP("e_version:", ehdr->e_version, tmp);
        PRINT_HEADER("e_entry:", ehdr->e_entry);
        PRINT_HEADER("e_phoff:", ehdr->e_phoff);
        PRINT_HEADER("e_shoff:", ehdr->e_shoff);
        PRINT_HEADER("e_flags:", ehdr->e_flags);
        PRINT_HEADER("e_ehsize:", ehdr->e_ehsize);
        PRINT_HEADER("e_phentsize:", ehdr->e_phentsize);
        PRINT_HEADER("e_phnum:", ehdr->e_phnum);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shstrndx:", ehdr->e_shstrndx);

        /* Section Information */
        Elf64_Shdr *shdr;
        Elf64_Phdr *phdr;
        Elf64_Shdr shstrtab;

        shdr = (Elf64_Shdr *)&elf_map[ehdr->e_shoff];
        phdr = (Elf64_Phdr *)&elf_map[ehdr->e_phoff];
        shstrtab = shdr[ehdr->e_shstrndx];

        INFO("Section Header Table\n");
        PRINT_SECTION_TITLE("Nr", "Name", "Type", "Addr", "Off", "Size", "Es", "Flg", "Lk", "Inf", "Al");
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (validated_offset(name, elf_map, elf_map + st.st_size)) {
                ERROR("Corrupt file format\n");
                return -1;
            }

            switch (shdr[i].sh_type) {
                case SHT_NULL:
                    tmp = "SHT_NULL";
                    break;

                case SHT_PROGBITS:
                    tmp = "SHT_PROGBITS";
                    break;

                case SHT_SYMTAB:
                    tmp = "SHT_SYMTAB";
                    break;

                case SHT_STRTAB:
                    tmp = "SHT_STRTAB";
                    break;

                case SHT_RELA:
                    tmp = "SHT_RELA";
                    break;

                case SHT_HASH:
                    tmp = "SHT_HASH";
                    break;

                case SHT_DYNAMIC:
                    tmp = "SHT_DYNAMIC";
                    break;

                case SHT_NOTE:
                    tmp = "SHT_NOTE";
                    break;

                case SHT_NOBITS:
                    tmp = "SHT_NOBITS";
                    break;

                case SHT_REL:
                    tmp = "SHT_REL";
                    break;

                case SHT_SHLIB:
                    tmp = "SHT_SHLIB";
                    break;

                case SHT_DYNSYM:
                    tmp = "SHT_DYNSYM";
                    break;

                case SHT_LOPROC:
                    tmp = "SHT_LOPROC";
                    break;

                case SHT_HIPROC:
                    tmp = "SHT_HIPROC";
                    break;

                case SHT_LOUSER:
                    tmp = "SHT_LOUSER";
                    break;

                case SHT_HIUSER:
                    tmp = "SHT_HIUSER";
                    break;

                default:
                    break;
            }

            if (strlen(name) > 15) {
                strcpy(&name[15 - 6], "[...]");
            }
            strcpy(flag, "   ");
            flag2str_sh(shdr[i].sh_flags, flag);
            PRINT_SECTION(i, name, tmp, shdr[i].sh_addr, shdr[i].sh_offset, shdr[i].sh_size, shdr[i].sh_entsize, \
                            flag, shdr[i].sh_link, shdr[i].sh_info, shdr[i].sh_addralign);
        }

        INFO("Program Header Table\n");
        PRINT_PROGRAM_TITLE("Nr", "Type", "Offset", "Virtaddr", "Physaddr", "Filesiz", "Memsiz", "Flg", "Align");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            switch (phdr[i].p_type) {
                case PT_NULL:
                    tmp = "PT_NULL";
                    break;

                case PT_LOAD:
                    tmp = "PT_LOAD";
                    break;

                case PT_DYNAMIC:
                    tmp = "PT_DYNAMIC";
                    break;

                case PT_INTERP:
                    tmp = "PT_INTERP";
                    break;

                case PT_NOTE:
                    tmp = "PT_NOTE";
                    break;

                case PT_SHLIB:
                    tmp = "PT_SHLIB";
                    break;

                case PT_PHDR:
                    tmp = "PT_PHDR";
                    break;

                case PT_LOPROC:
                    tmp = "PT_LOPROC";
                    break;

                case PT_HIPROC:
                    tmp = "PT_HIPROC";
                    break;

                case PT_GNU_STACK:
                    tmp = "PT_GNU_STACK";
                    break;

                default:
                    break;
            }
            strcpy(flag, "   ");
            flag2str(phdr[i].p_flags, flag);
            PRINT_PROGRAM(i, tmp, phdr[i].p_offset, phdr[i].p_vaddr, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz, flag, phdr[i].p_align);
        }

        INFO("Section to segment mapping\n");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            printf("     [%2d]", i);
            for (int j = 0; j < ehdr->e_shnum; j++) {
                name = elf_map + shstrtab.sh_offset + shdr[j].sh_name;
                if (shdr[j].sh_addr >= phdr[i].p_vaddr && shdr[j].sh_addr + shdr[j].sh_size <= phdr[i].p_vaddr + phdr[i].p_memsz && shdr[j].sh_type != SHT_NULL) {
                    if (shdr[j].sh_flags >> 1 & 0x1) {
                        printf(" %s", name);
                    }
                }
            }
            printf("\n");
        }

        INFO("Dynamic link information\n");
        int dynstr;
        int dynamic;
        Elf64_Dyn *dyn;
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (!strcmp(name, ".dynstr")) {
                dynstr = i;
            }
            if (!strcmp(name, ".dynamic")) {
                dynamic = i;
            }
        }

        char value[50];
        name = "";
        dyn = (Elf64_Dyn *)&elf_map[shdr[dynamic].sh_offset];
        count = shdr[dynamic].sh_size / sizeof(Elf64_Dyn);
        INFO("Dynamic section at offset 0x%x contains %d entries\n", shdr[dynamic].sh_offset, count);
        PRINT_DYN_TITLE("Tag", "Type", "Name/Value");

        for(int i = 0; i < count; i++) {
            tmp = "";
            memset(value, 0, 50);
            snprintf(value, 50, "0x%x", dyn[i].d_un.d_val);
            switch (dyn[i].d_tag) {
                /* Legal values for d_tag (dynamic entry type).  */
                case DT_NULL:
                    tmp = "DT_NULL";
                    break;

                case DT_NEEDED:
                    tmp = "DT_NEEDED";
                    name = elf_map + shdr[dynstr].sh_offset + dyn[i].d_un.d_val;
                    snprintf(value, 50, "Shared library: [%s]", name);
                    break;

                case DT_PLTRELSZ:
                    tmp = "DT_PLTRELSZ";
                    break;

                case DT_PLTGOT:
                    tmp = "DT_PLTGOT";
                    break;

                case DT_HASH:
                    tmp = "DT_HASH";
                    break;

                case DT_STRTAB:
                    tmp = "DT_STRTAB";
                    break;

                case DT_SYMTAB:
                    tmp = "DT_SYMTAB";
                    break;

                case DT_RELA:
                    tmp = "DT_RELA";
                    break;

                case DT_RELASZ:
                    tmp = "DT_RELASZ";
                    break;

                case DT_RELAENT:
                    tmp = "DT_RELAENT";
                    break;

                case DT_STRSZ:
                    tmp = "DT_STRSZ";
                    break;

                case DT_SYMENT:
                    tmp = "DT_SYMENT";
                    break;

                case DT_INIT:
                    tmp = "DT_INIT";
                    break;

                case DT_FINI:
                    tmp = "DT_FINI";
                    break;

                case DT_SONAME:
                    tmp = "DT_SONAME";
                    break;

                case DT_RPATH:
                    tmp = "DT_RPATH";
                    break;

                case DT_SYMBOLIC:
                    tmp = "DT_SYMBOLIC";
                    break;

                case DT_REL:
                    tmp = "DT_REL";
                    break;

                case DT_RELSZ:
                    tmp = "DT_RELSZ";
                    break;

                case DT_RELENT:
                    tmp = "DT_RELENT";
                    break;

                case DT_PLTREL:
                    tmp = "DT_PLTREL";
                    break;

                case DT_DEBUG:
                    tmp = "DT_DEBUG";
                    break;

                case DT_TEXTREL:
                    tmp = "DT_TEXTREL";
                    break;

                case DT_JMPREL:
                    tmp = "DT_JMPREL";
                    break;

                case DT_BIND_NOW:
                    tmp = "DT_BIND_NOW";
                    break;

                case DT_INIT_ARRAY:
                    tmp = "DT_INIT_ARRAY";
                    break;

                case DT_FINI_ARRAY:
                    tmp = "DT_FINI_ARRAY";
                    break;

                case DT_INIT_ARRAYSZ:
                    tmp = "DT_INIT_ARRAYSZ";
                    break;

                case DT_FINI_ARRAYSZ:
                    tmp = "DT_FINI_ARRAYSZ";
                    break;

                case DT_RUNPATH:
                    tmp = "DT_RUNPATH";
                    break;

                case DT_FLAGS:
                    tmp = "DT_FLAGS";
                    snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                    break;

                case DT_ENCODING:
                    tmp = "DT_ENCODING";
                    break;

                case DT_PREINIT_ARRAYSZ:
                    tmp = "DT_PREINIT_ARRAYSZ";
                    break;

                case DT_SYMTAB_SHNDX:
                    tmp = "DT_SYMTAB_SHNDX";
                    break;

                case DT_NUM:
                    tmp = "DT_NUM";
                    break;

                case DT_LOOS:
                    tmp = "DT_LOOS";
                    break;

                case DT_HIOS:
                    tmp = "DT_HIOS";
                    break;

                case DT_LOPROC:
                    tmp = "DT_LOPROC";
                    break;

                case DT_HIPROC:
                    tmp = "DT_HIPROC";
                    break;

                case DT_PROCNUM:
                    tmp = "DT_LOPROC";
                    break;

                /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
                 * Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
                 * approach. */

                case DT_VALRNGLO:
                    tmp = "DT_VALRNGLO";
                    break;

                case DT_GNU_PRELINKED:
                    tmp = "DT_GNU_PRELINKED";
                    break;

                case DT_GNU_CONFLICTSZ:
                    tmp = "DT_GNU_CONFLICTSZ";
                    break;

                case DT_GNU_LIBLISTSZ:
                    tmp = "DT_GNU_LIBLISTSZ";
                    break;

                case DT_CHECKSUM:
                    tmp = "DT_CHECKSUM";
                    break;

                case DT_PLTPADSZ:
                    tmp = "DT_PLTPADSZ";
                    break;

                case DT_MOVEENT:
                    tmp = "DT_MOVEENT";
                    break;

                case DT_MOVESZ:
                    tmp = "DT_MOVESZ";
                    break;

                case DT_FEATURE_1:
                    tmp = "DT_FEATURE_1";
                    break;

                case DT_POSFLAG_1:
                    tmp = "DT_POSFLAG_1";
                    break;

                case DT_SYMINSZ:
                    tmp = "DT_SYMINSZ";
                    break;

                case DT_SYMINENT:
                    tmp = "DT_SYMINENT";
                    break;

                /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
                 * Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
                 * If any adjustment is made to the ELF object after it has been
                 * built these entries will need to be adjusted.  */
                case DT_ADDRRNGLO:
                    tmp = "DT_ADDRRNGLO";
                    break;

                case DT_GNU_HASH:
                    tmp = "DT_GNU_HASH";
                    break;

                case DT_TLSDESC_PLT:
                    tmp = "DT_TLSDESC_PLT";
                    break;

                case DT_TLSDESC_GOT:
                    tmp = "DT_TLSDESC_GOT";
                    break;

                case DT_GNU_CONFLICT:
                    tmp = "DT_GNU_CONFLICT";
                    break;

                case DT_GNU_LIBLIST:
                    tmp = "DT_GNU_LIBLIST";
                    break;

                case DT_CONFIG:
                    tmp = "DT_CONFIG";
                    break;

                case DT_DEPAUDIT:
                    tmp = "DT_DEPAUDIT";
                    break;

                case DT_AUDIT:
                    tmp = "DT_AUDIT";
                    break;

                case DT_PLTPAD:
                    tmp = "DT_PLTPAD";
                    break;

                case DT_MOVETAB:
                    tmp = "DT_MOVETAB";
                    break;

                case DT_SYMINFO:
                    tmp = "DT_SYMINFO";
                    break;

                /* The versioning entry types.  The next are defined as part of the
                 * GNU extension.  */
                case DT_VERSYM:
                    tmp = "DT_VERSYM";
                    break;

                case DT_RELACOUNT:
                    tmp = "DT_RELACOUNT";
                    break;

                case DT_RELCOUNT:
                    tmp = "DT_RELCOUNT";
                    break;

                /* These were chosen by Sun.  */
                case DT_FLAGS_1:
                    tmp = "DT_FLAGS_1";
                    switch (dyn[i].d_un.d_val) {
                        case DF_1_PIE:
                            snprintf(value, 50, "Flags: %s", "PIE");
                            break;

                        default:
                            snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                            break;
                    }

                    break;

                case DT_VERDEF:
                    tmp = "DT_VERDEF";
                    break;

                case DT_VERDEFNUM:
                    tmp = "DT_VERDEFNUM";
                    break;

                case DT_VERNEED:
                    tmp = "DT_VERNEED";
                    break;

                case DT_VERNEEDNUM:
                    tmp = "DT_VERNEEDNUM";
                    break;

                default:
                    break;
            }
            PRINT_DYN(dyn[i].d_tag, tmp, value);
        }
    }

    return 0;
}


int flag2str_sh(int flag, char *flag_str) {
    if (flag & 0x1)
        flag_str[2] = 'W';
    if (flag >> 1 & 0x1)
        flag_str[1] = 'A';
    if (flag >> 2 & 0x1)
        flag_str[0] = 'E';

    return 0;
}


int validated_offset(uint32_t addr, uint32_t start, uint32_t end){
    return addr <= end && addr >= start? 0:-1;
}


int flag2str(int flag, char *flag_str) {
    if (flag & 0x1)
        flag_str[2] = 'E';
    if (flag >> 1 & 0x1)
        flag_str[1] = 'W';
    if (flag >> 2 & 0x1)
        flag_str[0] = 'R';

    return 0;
}