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

Proposition pour la FAQ (Definir ses propres streams)

7 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