/**
*
* @File : RandomAccess.cxx
*
* @Authors : D. Mathieu
* M. Laporte
*
* @Date : 08/03/2001
*
* @Version : V1.0
*
* @Synopsis :
*
**/
#include <iostream>
#include <string>
#include <exception>
#include <algorithm> // max()
#include <fstream>
#include <cstdio> // tmpnam(), tempnam()
#include <fcntl.h> // O_RDWR, O_EXCL
#include <unistd.h> // SEEK_SET, off_t
#include <climits> // L_tmpnam
#include "CExc.h"
#include "CExcFctSyst.h"
#include "nsSysteme.h"
using namespace nsSysteme;
namespace
{
class CRandomAccess
{
public :
enum { CstMaxSize = 100 };
private :
struct SLignes
{
unsigned long m_Offset;
unsigned m_Size;
SLignes (off_t Offset = 0L, unsigned Size = 0)
: m_Offset (Offset), m_Size (Size) {}
}; // SLignes
string m_NomFich;
int m_fd;
unsigned m_NbreLignes;
SLignes m_Index [CstMaxSize];
public :
CRandomAccess (const string & NomFich);
~CRandomAccess (void);
string Get (unsigned i) const;
void Set (const string & Str, unsigned i);
}; // CRandomAccess
CRandomAccess::CRandomAccess (const string & NomFich)
: m_NomFich (NomFich), m_NbreLignes (0)
{
m_fd = Open (NomFich.c_str(), O_RDWR | O_CREAT, 0700);
ifstream is (m_fd);
string Str;
// en C++ standard, le délimiteur n'a pas de valeur par défaut
for (unsigned long Offset = 0L; getline (is, Str, '\n'); )
{
cout << Str << " Taille = " << Str.length () << endl;
m_Index [m_NbreLignes++] = SLignes (Offset, Str.length ());
Offset += Str.length () + 1;
}
} // CRandomAccess()
CRandomAccess::~CRandomAccess (void)
{
char * NomTemp = ::tempnam ("./", 0);
const int fdTemp = Open (NomTemp,
O_WRONLY | O_CREAT | O_TRUNC, 0700);
const string CstStrVide;
const char LF = '\n';
for (unsigned i = 0; i < m_NbreLignes; ++i)
{
if (m_Index [i].m_Size)
Write (fdTemp, Get (i).c_str (), m_Index [i].m_Size);
Write (fdTemp, &LF, 1);
}
Close (fdTemp);
Close (m_fd);
Rename (NomTemp, m_NomFich.c_str ());
} // ~CRandomAccess()
string CRandomAccess::Get (unsigned i) const
{
const string CstStrVide;
if (0 == m_Index [i].m_Size) return CstStrVide;
Lseek (m_fd, m_Index [i].m_Offset, SEEK_SET);
char * Chaine = new char [m_Index [i].m_Size + 1];
Chaine [Read (m_fd, Chaine, m_Index [i].m_Size)] = '\0';
string Str (Chaine);
delete [] Chaine;
return Str;
} // Get ()
void CRandomAccess::Set (const string & Str, unsigned i)
{
if (0 == Str.length ())
{
m_Index [i] = SLignes();
return;
}
m_Index [i] = SLignes ((Str.length () <= m_Index [i].m_Size
? Lseek (m_fd, m_Index [i].m_Offset, SEEK_SET)
: Lseek (m_fd, 0, SEEK_END)),
Str.length ());
Write (m_fd, Str.c_str(), Str.length ());
const char LF = '\n';
Write (m_fd, &LF, 1);
m_NbreLignes = max (m_NbreLignes, i + 1);
} // Set ()
} // namespace anonyme
int std::ppal (int argc, char * argv []) throw (exception)
{
if (2 != argc) throw CExc (string ("Usage : ") + argv [0] + " <fichier>");
CRandomAccess Fich (argv [1]);
cout << "Taper Ctrl + D pour terminer la saisie\n" << endl;
cout << "Taper l'indice suivi, séparé par un espace, "
"de la ligne à saisir :" << endl;
for (int i; cin >> i; )
{
// Suppression du séparateur espace
char Car;
cin.get (Car);
string Str;
getline (cin, Str, '\n');
cout << "Ajout de " << Str << " en position " << i << endl;
Fich.Set (Str, i);
cout << "Taper l'indice suivi, séparé par un espace, "
"de la ligne à saisir :" << endl;
}
return 0;
} // ppal()