/*   Ce fichier contient les fonctions de creation, et de lecture */
/*   du fichier de suivi des etoiles                              */
/*                                      R. Ansari Mars 92         */
 
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "machdefs.h"
#include "swapbytes.h"

#include "fsvcache.h"
#include "filecache.h"

/*   SOPHYA V >= 2.130 , SWAPDEFAUT n'est plus defini */
#if ( IS_BIG_ENDIAN == 0 ) 
#define SWAPDEFAUT 1
#else
#define SWAPDEFAUT 0
#endif

#ifdef RFIO
#include <shift.h>
#endif
 
/* 
++ 
  Module 	Gestion des Suivis (C)
  Lib	fsv
  include	fsvcache.h

	Ce groupe de fonctions permettent de manipuler les fichiers de 
	suivi. Les données sont stockées sous format binaire dans le
	fichier et les fonctions de lecture/ écriture assure le 
	changement de l'ordre des octets en fonction de l'architecture 
	de la machine (Little Endian, Big Endian), à l'odre d'écriture des 
	octets dans le fichier, et du format des données déclaré à la 
	création du suivi. L'ordre d'écriture des octets dans le fichier
	correspond à celui de la machine où a lieu la création du fichier.
	Une description plus detaillée se trouve dans la note Peida No 1.
--
*/

/*  declaration des fonctions privees de ce fichier  */
 
#ifdef IBMVM
#define FindSizeofRec FndSzRec
#endif
 
int_4 FindSizeofRec(char *fmt);
void SwapSuiviEntete(ENTETESUIVI *hp);
void SwapSuiviRecord(char* rec, char* fmt, int fmtl, int nr);

static int sv_prtlev = 0;
/* Nouvelle-Fonction */
void SuiviSetPrtLevel(int lev)
{
sv_prtlev = lev;
zfSetPrtLevel(lev);
}
 
 
/*
++
Titre	Création des fichiers de suivi 
--
*/
/*
++
int SuiviCreate(char *filename, int typ, int rec0size, char *rec1fmt, -
                char *rec2fmt, char *rec3fmt, char *rec4fmt, int nitem)

	Cette fonction crée la structure d'entete avec 
	la définition des formats des enregistrements (record). 
|	filename : Nom de fichier 
|	typ : Identificateur de type de fichier de suivi
|	rec0size : Taille de la zone commentaire (Rec-0) en octets
|	recifmt : (i=1..4) Format des records Rec-i (i=1..4) 
|	nitem : facteur de groupement des mesures
	Les formats sont spécifiés sous forme d'une chaine de caractère décrivant
	la succession de valeurs constituant un record (Ex: "IIFFS").
|	I ou L : entier (4 octets)
|	S : entier (2 octets)
|	F : Reel (4 octets)
|	D : Double precision (8 octets)
	Le code de retour est nul (0) en cas de succès.
--
*/ 

/* Nouvelle-Fonction */
int SuiviCreate(char *filename, int typ, int rec0size, char *rec1fmt,
                char *rec2fmt, char *rec3fmt, char *rec4fmt, int nitem)
 
/*  Cette fonction permet la creation d'un fichier de suivi  */
/*  Retourne 0 si OK  -  Non-nul si probleme.                */
/*  Arguments :                                              */
/*     - filename : Nom de fichier.                          */
/*     - typ : valeur stockee ds l'entete (Type)             */
/*     - rec0size : Taille de la zone comment (Rec0) en byte */
/*     - rec1/2/3/4fmt : Format des records type 1,2,3,4     */
/*     Les formats sont specifies sous forme d'une chaines   */
/*     de charactere avec le codage suivant:                 */
/*       I S L : Entiers short int  et long int (L=I)        */
/*       F D   : float et double                             */
/*     - nitem : Nb de mesures / record   (def = 10)         */
 
{
 
int i;
ENTETESUIVI head;
FILE *fip;
char fiac[80];
 
 
if (rec0size < 0) rec0size=0;
if (nitem <= 0)  nitem = 10;
 
head.RecSize[0] = rec0size;
head.NItem = nitem;
head.NbMesTot = head.NbStars = (int_4)0;
head.Swap = 0;
head.Type = typ;
head.FgCorrupt = 0;
/*  Pour le Byte-Swap  */
if (SWAPDEFAUT)  head.Swap = 0xFFFF;
else head.Swap = 0;
 
/*  Analyse des formats   */
if ( (head.RecSize[1] = FindSizeofRec(rec1fmt)) <= 0 )
  { printf("  SuiviCreate-Erreur ds format Rec_1 \n"); return(1); }
if ( (head.RecSize[2] = FindSizeofRec(rec2fmt)) <= 0 )
  { printf("  SuiviCreate-Erreur ds format Rec_2 \n"); return(2); }
if ( (head.RecSize[3] = FindSizeofRec(rec3fmt)) <= 0 )
  { printf("  SuiviCreate-Erreur ds format Rec_3 \n"); return(3); }
if ( (head.RecSize[4] = FindSizeofRec(rec4fmt)) <= 0 )
  { printf("  SuiviCreate-Erreur ds format Rec_4 \n"); return(4); }
 
head.RecSize[3] *= head.NItem;
head.RecSize[4] *= head.NItem;
 
 
head.FmtSize[0] = 0;
head.FmtSize[1] = strlen(rec1fmt);
head.FmtSize[2] = strlen(rec2fmt);
head.FmtSize[3] = strlen(rec3fmt);
head.FmtSize[4] = strlen(rec4fmt);
 
 
head.HSize = sizeof(ENTETESUIVI);
for(i=0; i<5; i++)  head.HSize += head.FmtSize[i];
head.FileSize = head.HSize;
 
#ifndef IBMVM
strcpy(fiac,"wb");
#else
strcpy(fiac,"wb, recfm=FS, lrecl=1024");
#endif
 
if ((fip=fopen(filename,fiac)) == NULL)
  { printf("  SuiviCreate-Erreur ouverture fichier \n"); return(10); }
 
 
fwrite(&head,sizeof(ENTETESUIVI),1,fip);
fwrite(rec1fmt,1,head.FmtSize[1],fip);
fwrite(rec2fmt,1,head.FmtSize[2],fip);
fwrite(rec3fmt,1,head.FmtSize[3],fip);
fwrite(rec4fmt,1,head.FmtSize[4],fip);
 
fclose(fip);
 
return(0);
}
 
#ifdef IBMVM
int NPg[5]={0,50,100,150,200};
int PgSz[5]={0,4096,8092,16184,32768};
#else
int NPg[5]={0,10,50,100,200};
int PgSz[5]={0,2048,2048,4096,8092};
#endif
 
/*
++
Titre	Ouverture, fermeture des suivis
	Le pointeur (l'identificateur) de fichier renvoyé par 
	"SuiviOpen()" est le premier argument de toutes les autres 
	fonctions "(suivifip)".
--
*/

/*
++
SUIVIFIP *SuiviOpen(char * filename, int rw)
	Ouverture du fichier en mode lecture "rw=SUOF_RO" ou 
	lecture/ecriture "rw=SUOF_RW". L'activation de la
	memoire cache se fait aussi a travers l'argument "rw"
|	SUOF_RW_MEM, SUOF_RO_MEM
|	ou MEM2 , MEM3, MEM4

int SuiviClose(SUIVIFIP *suivfip)
	fermeture du fichier de suivi. Le fichier peut être corrompu s'il est 
	ouvert en écriture et si "SuiviClose()" n'est pas appelé.  

void SuiviSetPrtLevel(int lev)
	Modification du niveau d'impression des messages d'informations/debug
	
--
*/

/* Nouvelle-Fonction */ 
SUIVIFIP *SuiviOpen(char * filename, int rw)
 
/* Fonction d'ouverture de fichier de suivi pour lecture/ecriture   */
/* Retourne un pointeur sur la structure SUIVIFIP - NULL si Pb.     */
/*    rw : Flag d'ouverture fichier en Read/Write  SUOF_RW          */
/*                                 ou en ReadOnly  SUOF_RO          */
 
{
SUIVIFIP *sfip;
char *po;
char fiac[20];
int mopt;
FILE *fip;
int_4 res2;
char* fmtspace; 
int i,lfmt,rsz;
 
if ((po=(char *)malloc(sizeof(SUIVIFIP)+strlen(filename)+1)) == NULL)
  { printf(" SuiviOpen_Erreur : Pb malloc() \n"); return(NULL); }
sfip = (SUIVIFIP *)(po);
sfip->Nom = po+sizeof(SUIVIFIP);
 
mopt = rw/10;
if ( (mopt<0) || (mopt>4) )   mopt=0;
rw = rw%10;
 
if ( rw == SUOF_RW )  { strcpy(fiac,"rb+"); sfip->FgRW = SUOF_RW ; }
else { strcpy(fiac,"rb");  sfip->FgRW = rw = SUOF_RO ; }
 
#ifdef IBMVM
strcat(fiac,"b");
#endif

/*  Lecture entete  - En cas de d'ouverture en RW, on reecrit l'entete  */
/*  en utilisant le mot FgCorrupt qui passe a negatif -                 */
/*  Head.FgCorrupt = Flag FileCorrupted                                 */ 
/*  OK -> FgCorrupt == NbMesTot , Negatif -> -(Derniere mesure OK)      */
/*  ou -99999999                  Reza 10/12/96                         */

if ( (fip = fopen(filename,fiac)) == NULL )  
  { printf("SuiviOpen_Erreur : Pb fopen(%s) \n",filename); 
  free(po); return(NULL); }

fseek(fip, (long)0, SEEK_SET);
fread(&(sfip->Head),sizeof(ENTETESUIVI),1,fip);

/*  On verifie avant tout si le fichier doit etre byte-swape  */
if ( (sfip->Head.Swap != 0)  &&  (SWAPDEFAUT != 0) )  sfip->FgSwap = 0;
else if ( (sfip->Head.Swap == 0)  &&  (SWAPDEFAUT == 0) )  sfip->FgSwap = 0;
else { 
  sfip->FgSwap = 1;
  if (sv_prtlev > 3) printf("SuiviOpen_Warning: ByteSwap[%x,%x] de Suivi(%s) \n", 
                           (int)SWAPDEFAUT, (int)sfip->Head.Swap, filename);
  SwapSuiviEntete(&(sfip->Head));
}

/*  Allocation d'espace pour les formats */
lfmt = 0;
for(i=1;i<5;i++)  lfmt += (sfip->Head.FmtSize[i]+1);

fmtspace = (char *)malloc(lfmt);
if (fmtspace == NULL) { 
  printf(" SuiviOpen_Erreur : Pb. malloc fmtspace \n");
  free(po); return(NULL); }

sfip->RecFmt[0] = fmtspace;
/*  Lecture des elements de formats   */ 
for(i=1;i<5;i++) {
  sfip->RecFmt[i] = fmtspace;
  if ( (rsz=sfip->Head.FmtSize[i]) <= 0)  continue;
  fread(sfip->RecFmt[i], 1, rsz, fip);  
  *(sfip->RecFmt[i]+rsz) = '\0';
  fmtspace += rsz;
  }
 
res2 = sfip->Head.FgCorrupt;
/* NbMesTot < 0 ne devrait pas arriver ! */
if (sfip->Head.NbMesTot < 0) {
  printf("SuiviOpen_Erreur: NMes<0 File=%s (FgCorrupt=%d NMes=%d) !?\n",
         filename, res2, sfip->Head.NbMesTot); 
  free(fmtspace); free(po); 
  fclose(fip); return(NULL); 
}
  
if (res2 != sfip->Head.NbMesTot)  
  printf("SuiviOpen_Warning : file %s corrompu  (FgCorrupt=%d NMes=%d) !?\n",
         filename, res2, sfip->Head.NbMesTot); 
if ( (rw == SUOF_RW) && (res2 >= 0) )
  {
  sfip->Head.FgCorrupt = -res2;
  if (sfip->Head.FgCorrupt == 0)  sfip->Head.FgCorrupt = -99999999;
  if (sfip->Head.Swap)    SwapSuiviEntete(&(sfip->Head));  /* Avant ecriture */
  fseek(fip, (long)0, SEEK_SET);
  fwrite(&(sfip->Head),sizeof(ENTETESUIVI),1,fip);
  if (sfip->Head.Swap)    SwapSuiviEntete(&(sfip->Head));  /* Reswap apres ecriture */
  sfip->Head.FgCorrupt = res2;
  }
fclose(fip);

/*   Ouverture fichier  */
if ( (sfip->fcp = zfopen(filename,fiac,NPg[mopt],PgSz[mopt])) == NULL )
  { printf("SuiviOpen_Erreur : Pb zfopen(%s) \n",filename); 
  free(fmtspace); free(po); return(NULL); }
 
sfip->fip = sfip->fcp->fip;  
strcpy(sfip->Nom,filename);
sfip->OffsetMes = sfip->Head.HSize + sfip->Head.RecSize[0] +
                  sfip->Head.RecSize[1] +
                  sfip->Head.NbStars*sfip->Head.RecSize[2];
 
/*  Impression de debug   */
if (sv_prtlev > 3)
  { 
  printf(" SuiviOpen_Debug : File= %s , TotSize,Hsize= %ld , %ld  Offset= %ld Swap=%x\n",
    sfip->Nom,(long)sfip->Head.FileSize, (long)sfip->Head.HSize, 
    (long)sfip->OffsetMes, (int)sfip->Head.Swap);
  printf(" SuiviOpen_Debug : RecSize[0..4] %d %d %d %d %d\n",sfip->Head.RecSize[0],
   sfip->Head.RecSize[1],sfip->Head.RecSize[2],sfip->Head.RecSize[3],sfip->Head.RecSize[4]);
  printf(" SuiviOpen_Debug : FmtSize[0..4] %d %d %d %d %d\n",sfip->Head.FmtSize[0],
   sfip->Head.FmtSize[1],sfip->Head.FmtSize[2],sfip->Head.FmtSize[3],sfip->Head.FmtSize[4]);
  printf(" SuiviOpen_Debug : NItem,NbStars,NbMesTot %d %d %d Type=%d (FgCorrupt= %d)\n",
    sfip->Head.NItem,sfip->Head.NbStars,sfip->Head.NbMesTot,
    (int)sfip->Head.Type, sfip->Head.FgCorrupt);
  } 
 
 
return(sfip);
}
 
/*
++
Titre	Accès aux informations de l'entête
	Les fonctions suivantes permettent d'accéder a certaines 
	informations sauvegardées dans l'entête (Nb. d'étoiles, 
	de mesures, ...)
--
*/

/*
++
int_4 SuiviGetNbStars(SUIVIFIP *suivfip)
	Retourne le nombre d'étoiles dans le fichier.

int_4 SuiviGetNbMesures(SUIVIFIP *suivfip)
	Retourne le nombre de mesures dans le fichier.

int_4 SuiviGetType(SUIVIFIP *suivfip)
	Retourne le type déclaré à la création du fichier.

int_4 SuiviGetSize(SUIVIFIP *suivfip)
	Retourne la taille actuelle du fichier de suivi.

int_4 SuiviPredictSize(SUIVIFIP *suivfip, int nbst, int nbmes)
	Retourne la taille calculée pour le fichier avec "nbst" étoiles
	et "nbmes" mesures.
--
*/

 
/* Nouvelle-Fonction */
int_4 SuiviGetNbytStars(SUIVIFIP *suivfip)
/*  Retourne le nombre d'item pour chaque mesure ds le fichier   */
{  return ( suivfip->Head.RecSize[4] / suivfip->Head.NItem ) ; }
 
 
/* Nouvelle-Fonction */
int_4 SuiviGetNbStars(SUIVIFIP *suivfip)
/*  Retourne le nombre d'etoiles ds le fichier   */
{  return ( suivfip->Head.NbStars ) ; }
 
/* Nouvelle-Fonction */
int_4 SuiviGetNbMesures(SUIVIFIP *suivfip)
/*  Retourne le nb de mesures ds le fichier   */
{  return ( suivfip->Head.NbMesTot ) ; }
 
/* Nouvelle-Fonction */
int_4 SuiviGetType(SUIVIFIP *suivfip)
/*  Retourne le type de fichier declare ds l'entete le fichier   */
{  return ( suivfip->Head.Type ) ; }
 
/* Nouvelle-Fonction */
int_4 SuiviGetSize(SUIVIFIP *suivfip)
/*  Retourne la taille actuelle du fichier de suivi */
{  return ( suivfip->Head.FileSize ) ; }
 
/* Nouvelle-Fonction */
int_4 SuiviPredictSize(SUIVIFIP *sfip, int nbst, int nbmes)
/*  Retourne la taille calculee pour le nb d'etoiles (nbst) et mesures (nbmes)   */
{  
int_4 totsz, nbm;
totsz = sfip->Head.HSize + sfip->Head.RecSize[0] + /* Entete+zone commentaire  */
        sfip->Head.RecSize[1] +                    /*  Zone globinfo */
        nbst*sfip->Head.RecSize[2];                /* Les starInfos   */

/*  On calcule le nombre de blocks mesures */
nbm = nbmes / sfip->Head.NItem;  /* Les mesures sont groupees par block de NItem */
if ((nbmes%sfip->Head.NItem) != 0)  nbm++;
totsz += nbm*(sfip->Head.RecSize[3] + nbst*sfip->Head.RecSize[4]);
return ( totsz ) ; 
}
 
 
 
 
/* Nouvelle-Fonction */
 
int SuiviClose(SUIVIFIP *suivfip)
 
/*   Fonction de fermeture de fichier de suivi - Cet appel est obligatoire en */
/* cas de modification (ecriture) du fichier de suivi, avant la fin du prog.  */
/*   Retour 0 OK  -  NonNul-> Erreur                                          */
 
{
if (suivfip == NULL)  return(1);
 
/*  Ecriture entete fichier  */
if (suivfip->FgRW == SUOF_RW)
  {
   if (suivfip->Head.FgCorrupt >= 0)  /*  M.A.J Flag FileCorrupted */
    suivfip->Head.FgCorrupt = suivfip->Head.NbMesTot;
  if (suivfip->FgSwap)   /*  On byte-swap avant ecriture */
    SwapSuiviEntete(&(suivfip->Head));
  if (zfseek(suivfip->fcp, (long)(0), SEEK_SET) != 0)
    { printf(" SuiviClose_Erreur : Pb zfseek() \n"); return(10); }
  zfwrite(&(suivfip->Head),sizeof(ENTETESUIVI),1,suivfip->fcp);
  }
 
zfclose(suivfip->fcp);
free(suivfip->RecFmt[0]);
free(suivfip);
 
return(0);
 
}
 
 
/*
++
Titre	Lecture, écriture
	Pour toutes les fonctions de lecture/ecriture, "buff"
	 désigne le pointeur d'une zone mémoire contenant 
	l'information à écrire ou destinée à recevoir 
	l'information lue dans le fichier de suivi.   
	L'argument "numet" indique le numéro d'étoile (1..NbStars),
	et "numes" le numéro de mesure (1..NbMes).
	Le code de retour est non nul en cas d'erreur. 
--
*/

/*
++
int SuiviWriteComment(SUIVIFIP *suivfip, char *buff)
	Ecriture de la zone commentaire.

int SuiviReadComment(SUIVIFIP *suivfip, char *buff)
	Lecture de la zone commentaire.

--
*/
 
 
/* Nouvelle-Fonction */
 
int SuiviWriteComment(SUIVIFIP *suivfip, char *buff)
 
/*   Cette fonction ecrit les comment ds le fichier de suivi   */
/*  retour 0 OK                                                */
 
{
int_4 sz;
int rc;
 
if (suivfip == NULL)  return(1);
if (suivfip->FgRW != SUOF_RW)
  {printf(" SuiviWriteComment_Erreur : Fichier ReadOnly \n"); return(2);}
 
/*  Ecriture */
rc = 0;
if (zfseek(suivfip->fcp, (long)suivfip->Head.HSize, SEEK_SET) != 0)
  { printf(" SuiviWriteComment_Erreur : Pb zfseek() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 10; }
else if (zfwrite(buff,1,(size_t)suivfip->Head.RecSize[0],suivfip->fcp) != suivfip->Head.RecSize[0])
  { printf(" SuiviWriteComment_Erreur : Pb zfwrite() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 11; }
 
/*  M.A.J. Entete  */
sz = suivfip->Head.HSize+suivfip->Head.RecSize[0];
if (suivfip->Head.FileSize < sz)  suivfip->Head.FileSize = sz;
 
return(rc);
}
 
 
 
 
/* Nouvelle-Fonction */
 
int SuiviReadComment(SUIVIFIP *suivfip, char *buff)
 
/*   Cette fonction lit les comment ds le fichier de suivi   */
/*       retour 0 OK                                         */
 
{
if (suivfip == NULL)  return(1);
if (zfseek(suivfip->fcp, (long)suivfip->Head.HSize, SEEK_SET) != 0)
  { printf(" SuiviReadComment_Erreur : Pb zfseek() \n"); return(10); }
zfread(buff,1,(size_t)suivfip->Head.RecSize[0],suivfip->fcp);
return(0);
}
 
 
 
/*
++
int SuiviWriteGlobInfo(SUIVIFIP *suivfip, char *buff)
	Ecriture de l'enregistrement GlobInfo.

int SuiviReadGlobInfo(SUIVIFIP *suivfip, char *buff)
	Lecture de l'enregistrement GlobInfo.

--
*/

/* Nouvelle-Fonction */
 
int SuiviWriteGlobInfo(SUIVIFIP *suivfip, char *buff)
 
/*   Cette fonction ecrit l'enregistrement des infos globales   */
/*  retour 0 OK                                                 */
 
{
int_4 sz;
int rc;
 
if (suivfip == NULL)  return(1);
if (suivfip->FgRW != SUOF_RW)
  {printf(" SuiviWriteComment_Erreur : Fichier ReadOnly \n"); return(2);}

if (suivfip->FgSwap)   /*  On byte-swap avant ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[1], suivfip->Head.FmtSize[1], 1);
/*  Ecriture */
rc = 0;
sz = suivfip->Head.HSize+suivfip->Head.RecSize[0];
if (zfseek(suivfip->fcp, (long)sz, SEEK_SET) != 0)
  { printf(" SuiviWriteGlobInfo_Erreur : Pb zfseek() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 10; }
else if (zfwrite(buff,1,(size_t)suivfip->Head.RecSize[1],suivfip->fcp) != suivfip->Head.RecSize[1])
  { printf(" SuiviWriteGlobInfo_Erreur : Pb zfwrite() \n"); 
  suivfip->Head.FgCorrupt = -99999999; rc = 11; }


if (suivfip->FgSwap)   /*  On remet dans le bon sens */
  SwapSuiviRecord(buff, suivfip->RecFmt[1], suivfip->Head.FmtSize[1], 1);
 
/*  M.A.J. Entete  */
sz = suivfip->Head.HSize + suivfip->Head.RecSize[0] +
                           suivfip->Head.RecSize[1];
if (suivfip->Head.FileSize < sz)  suivfip->Head.FileSize = sz;
 
return(rc);
}
 
 
 
 
/* Nouvelle-Fonction */
 
int SuiviReadGlobInfo(SUIVIFIP *suivfip, char *buff)
 
/*   Cette fonction lit l'enregistrement des infos globales   */
/*       retour 0 OK                                          */
 
{
int_4 pos;
if (suivfip == NULL)  return(1);
pos = suivfip->Head.HSize+suivfip->Head.RecSize[0];
if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
  { printf(" SuiviReadGlobInfo_Erreur : Pb zfseek() \n"); return(10); }
zfread(buff,1,(size_t)suivfip->Head.RecSize[1],suivfip->fcp);
if (suivfip->FgSwap)   /*  On byte-swap apres lecture */
  SwapSuiviRecord(buff, suivfip->RecFmt[1], suivfip->Head.FmtSize[1], 1);
return(0);
}
 

/*
++
int SuiviWriteStarInfo(SUIVIFIP *suivfip, int_4 num, char *buff)
	Ecriture de l'enregistrement StarInfo pour l'étoile "num"

int SuiviReadStarInfo(SUIVIFIP *suivfip, int_4 num, char *buff)
	Lecture de l'enregistrement StarInfo pour l'étoile "num"
--
*/
  
 
/* Nouvelle-Fonction */
 
int SuiviWriteStarInfo(SUIVIFIP *suivfip, int_4 num, char *buff)
 
/*   Cette fonction ecrit les infos etoiles pour l'etoile   */
/*  numero num -  Retour 0  OK                              */
 
{
int_4 sz,pos;
int rc;
 
if (suivfip == NULL)  return(1);
if (suivfip->FgRW != SUOF_RW)
  {printf(" SuiviWriteStarInfo_Erreur : Fichier ReadOnly \n");  return(2);}
if (num <= (int_4)0)
  { printf(" SuiviWriteStarInfo_Erreur : Num (=%ld) <= 0 \n",(long)num); return(3); }
 
if ( (suivfip->Head.NbMesTot > 0) && (suivfip->Head.NbStars < num) )
  { printf(" SuiviWriteStarInfo_Erreur : Fichier contient des mesures ! \n");
    return(4); }

if (suivfip->FgSwap)   /*  On byte-swap avant ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[2], suivfip->Head.FmtSize[2], 1);
 
/*  Ecriture */
pos = suivfip->Head.HSize + suivfip->Head.RecSize[0] +
      suivfip->Head.RecSize[1] +
      (num-1)*suivfip->Head.RecSize[2];
rc = 0;
if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
  { printf(" SuiviWriteStarInfo_Erreur : Pb zfseek() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 10; }
else if ( zfwrite(buff,1,(size_t)suivfip->Head.RecSize[2],suivfip->fcp) != suivfip->Head.RecSize[2])
  { printf(" SuiviWriteStarInfo_Erreur : Pb zfwrite() \n"); 
  suivfip->Head.FgCorrupt = -99999999; rc = 11; }

if (suivfip->FgSwap)   /*  On remet dans le bon sens */
  SwapSuiviRecord(buff, suivfip->RecFmt[2], suivfip->Head.FmtSize[2], 1);
 
/*  M.A.J. Entete  */
sz = pos+suivfip->Head.RecSize[2];
if (suivfip->Head.FileSize < sz)  suivfip->Head.FileSize = sz;
if (suivfip->Head.NbStars < num)
  {
  suivfip->Head.NbStars = num;
  suivfip->OffsetMes = suivfip->Head.HSize + suivfip->Head.RecSize[0] +
                       suivfip->Head.RecSize[1] +
                       suivfip->Head.NbStars*suivfip->Head.RecSize[2];
  }
 
return(rc);
}
 
 
 
 
/* Nouvelle-Fonction */
 
int SuiviReadStarInfo(SUIVIFIP *suivfip, int_4 num, char *buff)
 
/*   Cette fonction lit les infos etoiles pour l'etoile   */
/*  numero num -  Retour 0  OK                            */
 
{
int_4 pos;
 
if (suivfip == NULL)  return(1);
if ( (num <= (int_4)0) || (num > suivfip->Head.NbStars) )
  { printf(" SuiviReadStarInfo_Erreur : Num (=%ld) out of range \n",(long)num); return(2); }
 
/*  lecture */
pos = suivfip->Head.HSize + suivfip->Head.RecSize[0] +
      suivfip->Head.RecSize[1] +
      (num-1)*suivfip->Head.RecSize[2];
if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
  { printf(" SuiviReadStarInfo_Erreur : Pb zfseek() \n"); return(10); }
zfread(buff,1,(size_t)suivfip->Head.RecSize[2],suivfip->fcp);

if (suivfip->FgSwap)   /*  On byte-swap apres lecture */
  SwapSuiviRecord(buff, suivfip->RecFmt[2], suivfip->Head.FmtSize[2], 1);
 
 
return(0);
}
 
/*
++
int SuiviAddMesure(SUIVIFIP *suivfip, char *buff)
	Ajoute une nouvelle mesure dans le fichier. "buff" contient
	l'information TimeInfo pour cette mesure.
--
*/
  
 
/* Nouvelle-Fonction */
int SuiviAddMesure(SUIVIFIP *suivfip, char *buff)
 
/*  Cette fonction rajoute une nouvelle mesure ds le fichier de suivi  */
/*  *buff contient l'information temps de cette mesure                 */
/*  Les mesures correspondant a ce temps doivent etre rajoute par      */
/*  SuiviWriteMesure()                                                 */
 
{
int_4 pos,l1;
ENTETESUIVI *head;
int_4 itsiz;
char bidbuf[4] = {'\0','\0','\0','\0'};
int rc;
 
if (suivfip == NULL)  return(1);
if (suivfip->FgRW != SUOF_RW)
  {printf(" SuiviAddMesure_Erreur : Fichier ReadOnly \n");  return(2);}
head = &(suivfip->Head);
 
/*   On verifie voir s'il faut creer de nouveaux records ?   */
if ( (head->NbMesTot % head->NItem) == (int_4)(0) ) {
  pos = suivfip->OffsetMes  +
      ( (head->NbMesTot / head->NItem) + 1) *
      ( head->RecSize[3] + (head->NbStars)*head->RecSize[4] ) - 4 ;
  if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
    { printf(" SuiviAddMesure_Erreur : Pb zfseek() \n");
    suivfip->Head.FgCorrupt = -99999999;  return(10); } 
  if (zfwrite(bidbuf,1, 4, suivfip->fcp) != 4) 
    { printf(" SuiviAddMesure_Erreur : Pb zfwrite() \n");
    suivfip->Head.FgCorrupt = -99999999;  return(11); } 
  head->FileSize = pos+4;       
  }
 
head->NbMesTot++;
 
l1 = (head->NbMesTot-1) / head->NItem;
pos = suivfip->OffsetMes +
      l1 * (head->RecSize[3] +
      head->NbStars*head->RecSize[4]);
itsiz = head->RecSize[3] / head->NItem ;
pos += (head->NbMesTot-1 - l1*head->NItem) * itsiz;

if (suivfip->FgSwap)   /*  On byte-swap avant ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[3], suivfip->Head.FmtSize[3], 1);

rc = 0; 
if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
  { printf(" SuiviAddMesure_Erreur : Pb zfseek() \n"); 
  suivfip->Head.FgCorrupt = -99999999; rc = 10; }
else if (zfwrite(buff,1,(size_t)itsiz,suivfip->fcp) != itsiz)
  { printf(" SuiviAddMesure_Erreur : Pb zfseek() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 11; }
 
if (suivfip->FgSwap)   /*  On remet dans le bon sens apres ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[3], suivfip->Head.FmtSize[3], 1);
 
return(rc);
}
 
 
/*
++
int SuiviWriteTimeInfo(SUIVIFIP *suivfip, int_4 numes, char *buff)
	Ecriture de TimeInfo pour la mesure numéro "numes" (1..NbMes).
--
*/

 
/* Nouvelle-Fonction */ 
int SuiviWriteTimeInfo(SUIVIFIP *suivfip, int_4 numes, char *buff)
 
/*  Cette fonction ecrit l'info temps pour la mesure numero num  */
/*  *buff contient l'information temps - Retour 0 OK             */
 
{
int_4 pos,l1;
ENTETESUIVI *head;
int_4 itsiz;
int rc;
 
if (suivfip == NULL)  return(1);
if (suivfip->FgRW != SUOF_RW)
  {printf(" SuiviWriteTimeInfo_Erreur : Fichier ReadOnly \n");  return(2);}
head = &(suivfip->Head);
 
if ( (numes <= (int_4)0) || (numes > suivfip->Head.NbMesTot) )
  { printf(" SuiviWriteTimeInfo_Erreur : NumMesure (=%ld) out of range \n",(long)numes);
    return(3); }
 
l1 = (numes-1) / head->NItem;
pos = suivfip->OffsetMes +
      l1 * ( head->RecSize[3] +
             head->NbStars*head->RecSize[4] );
itsiz = head->RecSize[3] / head->NItem ;
pos += ( numes-1 - l1*head->NItem ) * itsiz;

if (suivfip->FgSwap)   /*  On byte-swap avant ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[3], suivfip->Head.FmtSize[3], 1);
rc = 0; 
if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
  { printf(" SuiviWriteTimeInfo_Erreur : Pb zfseek() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 10; }
if (zfwrite(buff,1,(size_t)itsiz,suivfip->fcp) != itsiz)
  { printf(" SuiviWriteTimeInfo_Erreur : Pb zfwrite() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 11; }

 
if (suivfip->FgSwap)   /*  On remet dans le bon sens apres ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[3], suivfip->Head.FmtSize[3], 1);
 
return(rc);
}
 
 
 
/*
++
int SuiviWriteMesure(SUIVIFIP *suivfip, int_4 numet, int_4 nummes, char *buff)
	Ecriture de l'infomation Mesure pour l'étoile numéro "numet" 
	et la mesure numéro "numes" 
--
*/
 
/* Nouvelle-Fonction */ 
int SuiviWriteMesure(SUIVIFIP *suivfip, int_4 numet,
                     int_4 nummes, char *buff)
 
/*  Cette fonction ecrit une mesure ds le fichier de suivi    */
/*  numet est le numero d'etoile, nummes le numero de mesure  */
/*  *buff contient l'information mesure - Retour 0 OK         */
 
{
int_4 pos,l1;
ENTETESUIVI *head;
int_4 itsiz;
int rc;
 
if (suivfip == NULL)  return(1);
if (suivfip->FgRW != SUOF_RW)
  {printf(" SuiviWriteMesure_Erreur : Fichier ReadOnly \n");  return(2);}
head = &(suivfip->Head);
 
if ( (numet <= (int_4)0) || (numet > suivfip->Head.NbStars) )
  { printf(" SuiviWriteMesure_Erreur : NumEtoile (=%ld) out of range \n",(long)numet);
    return(2); }
 
if ( (nummes <= (int_4)0) || (nummes > suivfip->Head.NbMesTot) )
  { printf(" SuiviWriteMesure_Erreur : NumMesure (=%ld) out of range \n",(long)nummes);
    return(3); }
 
l1 = (nummes-1) / head->NItem;
pos = suivfip->OffsetMes +
      l1 * (head->RecSize[3] +
      head->NbStars*head->RecSize[4]) +
      head->RecSize[3] + (numet-1)*head->RecSize[4];
itsiz = head->RecSize[4] / head->NItem ;
pos += (nummes-1 - l1*head->NItem) * itsiz;

if (suivfip->FgSwap)   /*  On byte-swap avant ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[4], suivfip->Head.FmtSize[4], 1);

rc = 0; 
if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
  { printf(" SuiviWriteMesure_Erreur : Pb zfseek() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 10; }
else if (zfwrite(buff,1,(size_t)itsiz,suivfip->fcp) != itsiz) 
  { printf(" SuiviWriteMesure_Erreur : Pb zfwrite() \n"); 
  suivfip->Head.FgCorrupt = -99999999;  rc = 11; }

if (suivfip->FgSwap)   /*  On remet dans le bon sens apres ecriture */
  SwapSuiviRecord(buff, suivfip->RecFmt[4], suivfip->Head.FmtSize[4], 1);
 
return(rc);
}
 

/*
++
int SuiviReadTimeInfo(SUIVIFIP *suivfip, int_4 debut, int_4 fin, char *buff)
	Lecture des informations TimeInfo pour "debut <= mes <= fin". 
	Attention : Des erreurs d'alignement d'accès mémoire peuvent 
	avoir lieu en cas de lecture multiple "(fin > debut)" si la taille 
	de la structure TimeInfo ne coincide pas avec celle de l'enregistrement
	correspondant. 
--
*/
 
 
/* Nouvelle-Fonction */ 
int SuiviReadTimeInfo(SUIVIFIP *suivfip, int_4 debut,
                      int_4 fin, char *buff)
 
/*  Cette fonction lit l'information temps pour les mesures  */
/*   debut <= NumMes <= fin         Retour 0  OK             */
 
{
int_4 pos,l1;
ENTETESUIVI *head;
int_4 itsiz;
int_4 fr,to,nit;
char* buff0;
 
if (suivfip == NULL)  return(1);
head = &(suivfip->Head);
 
 
if ( (debut <= (int_4)0) || (debut > head->NbMesTot) )
  { printf(" SuiviReadTimeInfo_Erreur : NumDebut (=%ld) out of range \n",(long)debut);
    return(3); }
 
if ( (fin <= (int_4)0) || (fin > head->NbMesTot) )
  { printf(" SuiviReadTimeInfo_Erreur : NumFin (=%ld) out of range \n",(long)fin);
    return(4); }
 
if ( debut > fin)
  { printf(" SuiviReadTimeInfo_Erreur : NumFin (=%ld) < NumDebut(=%ld) \n",
           (long)fin, (long)debut);
    return(5); }
 
itsiz = head->RecSize[3] / head->NItem ;
 
fr=to=debut;
buff0 = buff;
 
do {
 
  l1 = (fr-1) / head->NItem;
  to = (l1+1) * head->NItem;
  if (to > fin)  nit = fin-fr+1;
  else nit = to-fr+1;
  pos = suivfip->OffsetMes +
        l1 * (head->RecSize[3] +
        head->NbStars*head->RecSize[4]);
  pos += (fr-1 - l1*head->NItem) * itsiz;
  if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
    { printf(" SuiviReadTimeInfo_Erreur : Pb zfseek() \n"); return(10); }
  zfread(buff,(size_t)itsiz,nit,suivfip->fcp);
  fr += nit;  buff += nit * itsiz;
 
} while (fr <= fin);
 
if (suivfip->FgSwap)   /*  On byte-swap apres lecture */
  SwapSuiviRecord(buff0, suivfip->RecFmt[3], suivfip->Head.FmtSize[3], fin-debut+1);
 
return(0);
}
 
 
 
 
/*
++
int SuiviReadMesures(SUIVIFIP *suivfip, int_4 numet, int_4 debut, int_4 fin, char *buff)
	Lecture des informations Mesure pour l'étoile "numet", "debut <= mes <= fin". 
	Attention : Des erreurs d'alignement d'accès mémoire peuvent 
	avoir lieu en cas de lecture multiple "(fin > debut)" si la taille 
	de la structure Mesure ne coincide pas avec celle de l'enregistrement
	correspondant.
--
*/
 
 
/* Nouvelle-Fonction */ 
int SuiviReadMesures(SUIVIFIP *suivfip, int_4 numet,
                     int_4 debut, int_4 fin, char *buff)
 
/*  Cette fonction lit les mesures pour l'etoile numet       */
/*   debut <= NumMes <= fin         Retour 0  OK             */
 
{
int_4 pos,l1;
ENTETESUIVI *head;
int_4 itsiz;
int_4 fr,to,nit;
char* buff0;
 
if (suivfip == NULL)  return(1);
head = &(suivfip->Head);
 
if ( (numet <= (int_4)0) || (numet > head->NbStars) )
  { printf(" SuiviReadMesures_Erreur : NumEtoile (=%ld) out of range \n", (long)numet);
    return(2); }
 
if ( (debut <= (int_4)0) || (debut > head->NbMesTot) )
  { printf(" SuiviReadMesures_Erreur : NumDebut (=%ld) out of range \n", (long)debut);
    return(3); }
 
if ( (fin <= (int_4)0) || (fin > head->NbMesTot) )
  { printf(" SuiviReadMesures_Erreur : NumFin (=%ld) out of range \n", (long)fin);
    return(4); }
 
if ( debut > fin)
  { printf(" SuiviReadMesures_Erreur : NumFin (=%ld) < NumDebut(=%ld) \n", 
           (long)fin, (long)debut);
    return(5); }
 
itsiz = head->RecSize[4] / head->NItem ;
 
fr=to=debut;
buff0 = buff;
 
do {
 
  l1 = (fr-1) / head->NItem;
  to = (l1+1) * head->NItem;
  if (to > fin)  nit = fin-fr+1;
  else nit = to-fr+1;
  pos = suivfip->OffsetMes +
        l1 * (head->RecSize[3] +
        head->NbStars*head->RecSize[4]) +
        head->RecSize[3] + (numet-1)*head->RecSize[4];;
  pos += (fr-1 - l1*head->NItem) * itsiz;
  if (zfseek(suivfip->fcp, (long)pos, SEEK_SET) != 0)
    { printf(" SuiviReadMesures_Erreur : Pb zfseek() \n"); return(10); }
  zfread(buff,(size_t)itsiz,nit,suivfip->fcp);
  fr += nit;  buff += nit * itsiz;
 
} while (fr <= fin);

if (suivfip->FgSwap)   /*  On byte-swap apres lecture */
  SwapSuiviRecord(buff0, suivfip->RecFmt[4], suivfip->Head.FmtSize[4], fin-debut+1);
 
 
return(0);
}
 
 
  
 
/* Nouvelle-Fonction */
int_4 FindSizeofRec(char *fmt)
 
{
int i;
char c;
int sz;
 
i= sz = 0;
while ( (*fmt) != '\0' )
  {
  c = toupper(*fmt);
  switch (c)
    {
    case 'I' :
      sz += sizeof(int_4); i++;
      break;
    case 'L' :
      sz += sizeof(int_4); i++;
      break;
    case 'S' :
      sz += sizeof(int_2); i++;
      break;
    case 'F' :
      sz += sizeof(r_4); i++;
      break;
    case 'D' :
      sz += sizeof(r_8); i++;
      break;
    default :
      printf(" FindSizeofRec_Erreur : Code format inconnu : %c \n",c);
      return(-1);
      break;
    }
  fmt++;
  }
 
/*    printf(" FindSizeofRec_debug : N= %d , size= %d \n",i,sz);   */
 
return(sz);
}

/* Nouvelle-Fonction */
void SwapSuiviEntete(ENTETESUIVI *hp)
{
int i;
Swap_Bytes4( &(hp->FileSize) );
Swap_Bytes4( &(hp->HSize) );
for(i=0; i<5; i++)  Swap_Bytes2( &(hp->RecSize[i]) );
Swap_Bytes2( &(hp->NItem) );
Swap_Bytes4( &(hp->NbStars) );
Swap_Bytes4( &(hp->NbMesTot) );
for(i=0; i<5; i++)  Swap_Bytes2( &(hp->FmtSize[i]) );
Swap_Bytes2(  &(hp->Swap) );
Swap_Bytes2(  &(hp->Type) );
Swap_Bytes4(  &(hp->FgCorrupt) );
}

/* Nouvelle-Fonction */
void SwapSuiviRecord(char* rec, char* fmt, int fmtl, int nr)
{
int i,j;
char *pc;

pc = rec;
for( j = 0 ; j < nr ; j++ ) {
  for ( i = 0 ; i < fmtl ; i++ ) {
    switch( toupper(fmt[i]) )  {
      case 'I' :  
      case 'L' :
        Swap_Bytes4(pc);  
        pc += sizeof(int_4); 
        break;
      case 'S' :
        Swap_Bytes2(pc);  
        pc += sizeof(int_2); 
        break;
      case 'F' :
        Swap_Bytes4(pc);  
        pc += sizeof(r_4); 
        break;
      case 'D' :
        Swap_Bytes8(pc);  
        pc += sizeof(r_8); 
        break;
      default :
        printf(" SwapSuiviRecord_Erreur : Code format inconnu : %c \n",fmt[i]);
        break;
    }
  }
}

return;
}
