J'ai un post qui n'est pas à 100% du C++, mais qui est je pense utile pour des débutants en C++ sous windows (mais la faq windows n'a pas l'air orientée programmation).
Un des problèmes de programmes console est les accents. En effet, pour de sombres histoires d'encodage différent sous windows et en mode console, du code aussi simple que :
cout << "Bonjour à tous !" << endl;
Ne donnera pas à l'écran le résultat escompté.
J'ai fait un petit programme qui corrige ça. Un exemple d'utilisation :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream>
#include <string>
#include <cstdlib>
#include "WinConsoleStreamBuf.h"
using namespace std;
int main()
{
cout << "Test : éàùçï" << endl; // Pas bon
{
loic::AccentsInMsWindowsConsoleHandler toto;
cout << "Test : éàùçï" << endl; // Bon
cout << "Bonjour à toi, quel est ton nom ? "; // Bon
string nom;
cin >> nom; // Bon
cout << "\nBonjour, " << nom << " !" << endl; // Bon
}
cout << "Test : éàùçï" << endl; // Pas bon
cin.ignore();
} |
Voici les fichiers nécessaires si ça intéresse quelqu'un (code placé dans le domaine public, testé avec Visual C++, mais qui devrait marcher avec Borland ou autre...) :
WinConsoleStreamBuf.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include <streambuf>
#include <ostream>
#ifndef _WIN32
#error This file is only designed (and useful) on MsWindows
#endif
namespace loic
{
class WinConsoleStreamBuf: public std::streambuf
{
public:
explicit WinConsoleStreamBuf(std::streambuf *buf);
~WinConsoleStreamBuf();
std::streambuf *setUnderlyingBuffer(std::streambuf *newBuf);
private:
WinConsoleStreamBuf(WinConsoleStreamBuf &);
WinConsoleStreamBuf& operator=(WinConsoleStreamBuf&);
virtual std::streambuf* setbuf(char_type* s, std::streamsize n);
virtual int_type overflow(int_type c);
virtual int sync();
virtual int_type underflow();
std::streambuf *myBuf;
char myInputBuffer[2];
};
/**
* This class is aimed to be used following the RAII idiom
*/
struct AccentsInMsWindowsConsoleHandler
{
AccentsInMsWindowsConsoleHandler();
~AccentsInMsWindowsConsoleHandler();
};
} // namespace loic |
Et WinConsoleStreamBuf.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| #include "WinConsoleStreamBuf.h"
#include <iostream>
#include <ios>
#include <windows.h>
namespace loic
{
WinConsoleStreamBuf::WinConsoleStreamBuf(std::streambuf *buf):
myBuf(buf)
{
}
WinConsoleStreamBuf::~WinConsoleStreamBuf()
{
delete myBuf;
}
std::streambuf* WinConsoleStreamBuf::setbuf(char_type* s, std::streamsize n)
{
// ne fait rien, ce qui est autorisé. Une version plus complète
// devrait vraissemblablement utiliser setvbuf
return NULL;
}
WinConsoleStreamBuf::int_type WinConsoleStreamBuf::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
{
char charBuffer[2];
charBuffer[0] = static_cast<char>(c);
charBuffer[1] = 0;
char OEMBuffer[2];
CharToOem(charBuffer, OEMBuffer);
//std::cout << OEMBuffer;
myBuf->sputc(OEMBuffer[0]);
return true;
}
}
WinConsoleStreamBuf::int_type WinConsoleStreamBuf::underflow()
{
// Assurance contre des implementations pas strictement conformes à 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 = myBuf->sbumpc();
if (gotted == EOF)
{
return traits_type::eof();
}
else
{
char OEMBuffer[2];
OEMBuffer[0] = static_cast<char>(gotted);
OEMBuffer[1] = 0;
OemToChar(OEMBuffer, myInputBuffer);
setg(myInputBuffer, myInputBuffer, myInputBuffer+1);
return traits_type::to_int_type(*myInputBuffer);
}
}
else
{
return traits_type::to_int_type(*myInputBuffer);
}
}
int WinConsoleStreamBuf::sync()
{
return myBuf->pubsync();
}
std::streambuf* WinConsoleStreamBuf::setUnderlyingBuffer(std::streambuf* newBuf)
{
std::swap(newBuf, myBuf);
return newBuf;
}
AccentsInMsWindowsConsoleHandler::AccentsInMsWindowsConsoleHandler()
{
std::cout.rdbuf(new WinConsoleStreamBuf(std::cout.rdbuf()));
std::cin.rdbuf(new WinConsoleStreamBuf(std::cin.rdbuf()));
}
namespace
{
void restoreDefaultBuffer(std::basic_ios<char> &s)
{
WinConsoleStreamBuf *oldBuf = dynamic_cast<WinConsoleStreamBuf*>(s.rdbuf());
if (oldBuf)
{
s.rdbuf(oldBuf->setUnderlyingBuffer(NULL));
delete oldBuf;
}
}
}
AccentsInMsWindowsConsoleHandler::~AccentsInMsWindowsConsoleHandler()
{
restoreDefaultBuffer(std::cout);
restoreDefaultBuffer(std::cin);
}
} // namespace loic |
Partager