Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Proposition pour la FAQ (Definir ses propres streams)

10 views
Skip to first unread message

Jean-Marc Bourguet

unread,
May 28, 2001, 4:05:21 AM5/28/01
to
J'ai modifie mon exemple precedent sur la maniere de definir un
streambuf pour
tenir compte des remarques de James.

-- Jean-Marc

Comment definir ses propres streams?

Les streams sont les objets qui servent aux entrees/sorties en C++. Ces
classes sont responsables du formattage et deleguent aux descendants de
basic_streambuf les E/S proprement dites.

Donc pour definir ses propres streams, il faut principalement se definir
un
descendant de basic_streambuf qui effectue les E/S comme on le desire et
eventuellement un descendant de {i,o,io}stream qui s'initialise
automatiquement avec notre streambuf.

Voici un petit exemple qui encapsule proprement un FILE* dans un
streambuf
et definit un istream et un ostream pour utiliser facilement ce
streambuf.

Notez que le concept de stream existe depuis a peut pres le debut du C++
mais a evolue pas mal. Les streams initiales ont ete remplacees par les
IOStreams vers 1989 et cette version dite << IOStreams classiques >> a
ete
modifiee lors de la normalisation. Cet exemple a ete concu pour montrer
comment definir un streambuf en suivant la norme (et ne sera donc pas
utilisable avec une implementation non conforme) tout en prenant
certaines
precautions de maniere a etre utilisable par du code ecrit pour les
IOStreams classiques. Il y a moyen de definir des streambufs qui sont
portables entre les IOStreams classiques et standards (voir par exemple
la
page de James)

#include <stdio.h>
#include <assert.h>

#include <iostream>
#include <streambuf>

// streambuf minimal encapsulant un FILE*
// - utilise les tampons de FILE donc n'a pas de tampon interne en
// sortie et a un tampon interne de taille 1 en entree car
l'interface
// de streambuf ne permet pas de faire moins;
// - ne permet pas la mise en place d'un tampon
// - une version plus complete devrait permettre d'acceder aux
// informations d'erreur plus precises de FILE* et interfacer aussi
// les autres possibilites de FILE* (entre autres synchroniser les
// sungetc/sputbackc avec la possibilite correspondante de FILE*)

class FILEbuf: public std::streambuf
{
public:

explicit FILEbuf(FILE* cstream);
// cstream doit etre non NULL.

private:

std::streambuf* setbuf(char_type* s, std::streamsize n);

int_type overflow(int_type c);
int sync();

int_type underflow();

FILE* cstream_;
char inputBuffer_[1];
};

FILEbuf::FILEbuf(FILE* cstream)
: cstream_(cstream)
{
// le constructeur de streambuf equivaut a
// setp(0, 0);
// setg(0, 0);
assert(cstream != NULL);
}

std::streambuf* FILEbuf::setbuf(char_type* s, std::streamsize n)
{
// ne fait rien, ce qui est autorise. Une version plus complete
// devrait vraissemblablement utiliser setvbuf
return NULL;
}

FILEbuf::int_type FILEbuf::overflow(int_type c)
{
if (traits_type::eq_int_type(c, traits_type::eof())) {
// la norme ne le demande pas exactement, mais si on nous passe eof
// la coutume est de faire la meme chose que sync()
return (sync() == 0
? traits_type::not_eof(c)
: traits_type::eof());
} else {
return ((fputc(c, cstream_) != EOF)
? traits_type::not_eof(c)
: traits_type::eof());
}
}

int FILEbuf::sync()
{
return (fflush(cstream_) == 0
? 0
: -1);
}


FILEbuf::int_type FILEbuf::underflow()
{
// Assurance contre des implementations pas strictement conformes a la
// norme qui guaranti que le test est vrai. Cette guarantie
n'existait
// pas dans les IOStream classiques.
if (gptr() == NULL || gptr() >= egptr()) {
int gotted = fgetc(cstream_);
if (gotted == EOF) {
return traits_type::eof();
} else {
*inputBuffer_ = gotted;
setg(inputBuffer_, inputBuffer_, inputBuffer_+1);
return traits_type::to_int_type(*inputBuffer_);
}
} else {
return traits_type::to_int_type(*inputBuffer_);
}
}

// ostream minimal facilitant l'utilisation d'un FILEbuf
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer
// qu'il est bien initialise avant std::ostream

class oFILEstream: private FILEbuf, public std::ostream
{
public:
explicit oFILEstream(FILE* cstream);
// cstream doit etre non NULL
};

oFILEstream::oFILEstream(FILE* cstream)
: FILEbuf(cstream), std::ostream(this)
{
}

// istream minimal facilitant l'utilisation d'un FILEbuf
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer
// qu'il est bien initialise avant std::istream

class iFILEstream: private FILEbuf, public std::istream
{
public:
explicit iFILEstream(FILE* cstream);
// cstream doit etre non NULL
};

iFILEstream::iFILEstream(FILE* cstream)
: FILEbuf(cstream), std::istream(this)
{
}

0 new messages