PDA

View Full Version : [C] svuotare stdin


trallallero
16-12-2008, 12:42
Argomento già trattato sicuramente, ma non riesco a trovare un modo per svuotare lo stdin.

Ho fatto una funzione che non aspetta l'invio (come il getch della Borland) ma se premo per sbaglio 2 volte un tasto, alla prossima getch mi prende il carattere nel buffer.

Io usavo fflush(stdin) che, giustamente, non funziona più sull'input (come da specifiche).

Quindi ? che posso fare ?

trallallero
16-12-2008, 13:10
:doh:

Che pirla! avevo già risolto il problema qualche anno fa ma mi ero dimenticato :stordita:

Vabbè, se a qualcuno serve posto la soluzione (che non è breve).

banryu79
16-12-2008, 13:13
:doh:

Che pirla! avevo già risolto il problema qualche anno fa ma mi ero dimenticato :stordita:

Vabbè, se a qualcuno serve posto la soluzione (che non è breve).

Posta pure, io sono interessato :)

trallallero
16-12-2008, 13:33
Allora, visto che sto lavorando in C++ ho "tradotto" velocemente il codice in C++ (in pratica ho fatto una classe all static :D

Header file:
#ifndef KB_UTILS_H_
#define KB_UTILS_H_

namespace AutoTesterSpace
{

#define IOERROR (-1)
#define ESC 0X1B
#define TIMEOUT_SEC 0
#define TIMEOUT_USEC 0

class KB_utils
{
public:
static int getch ();

private:
static int KbdHit ();
static int TimeOut ();

static int no_block;
};

}

#endif /*KB_UTILS_H_*/


Il cpp file:
#include <termios.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <sys/select.h>

#include "KB_utils.h"

using namespace AutoTesterSpace;
////////////////////////////////////////////////////////////////////

int KB_utils::no_block = 0;

/** \brief
*
* \post
*/
int KB_utils::getch()
{
struct termios org_opts,
new_opts;
int res = 0,
c = 0;

//----- store old settings -----------
res = tcgetattr(STDIN_FILENO, &org_opts);
assert(res == 0);

//---- set new terminal parms --------
memcpy( &new_opts, &org_opts, sizeof(new_opts) );
new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
tcsetattr(STDIN_FILENO, TCSANOW, &new_opts);

while( KbdHit() )
; // QUÌ SVUOTA LO STDIN !!!

c = getchar();

//------ restore old settings ---------
res = tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);
assert(res == 0);

return(c);
}
////////////////////////////////////////////////////////////////////

/** \brief
*
* \post
*/
int KB_utils::KbdHit()
{
struct termios oattr,
attr ;

int n ,
retval;

unsigned char ch;


if ( (tcgetattr)(STDIN_FILENO, &oattr) < 0 )
return IOERROR;

attr = oattr;

attr.c_lflag &= ~(ICANON | ECHO);
attr.c_cc[ VMIN] = 1;
attr.c_cc[VTIME] = 0;

if ( (tcsetattr)(STDIN_FILENO, TCSAFLUSH, &attr) < 0 )
return IOERROR;
else if ( !(isatty)(STDIN_FILENO) )
return IOERROR;

no_block = 1;

if ( (n = TimeOut()) < 0 )
return IOERROR;

retval = n;

if (retval)
{
if ( (read)(STDIN_FILENO, &ch, 1) != 1 )
return IOERROR;

if ( ch == ESC )
{
if ( (n = TimeOut()) < 0 )
return IOERROR;

if (n)
{
do
{
if ( (read)(STDIN_FILENO, &ch, 1) != 1 )
return IOERROR;
if ( (n = TimeOut()) < 0 )
return IOERROR;
} while(n);
}
}
}

if ( (tcsetattr)(STDIN_FILENO, TCSAFLUSH, &oattr) < 0 )
return IOERROR;

return retval;
}
////////////////////////////////////////////////////////////////////

/** \brief
*
* \post
*/
int KB_utils::TimeOut()
{
struct timeval tv;

fd_set readfds;

int n;

if ( !(isatty)(STDIN_FILENO) )
return IOERROR;

FD_ZERO(&readfds);
FD_SET(STDIN_FILENO,&readfds);

tv.tv_sec = TIMEOUT_SEC;
tv.tv_usec = TIMEOUT_USEC + no_block;

if ( (n = (select)(1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &tv)) < 0 )
return IOERROR;

return n;
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////


Quindi per usare la funzione getch da un'altra classe basta fare:
int res = KB_utils::getch();

Lo stdin viene svuotato dalla funzione KbdHit() con un
while( KbdHit() )
;

Non è roba tutta mia ma cose trovate anni fa in rete e poi modificate all'occorrenza.

banryu79
16-12-2008, 13:45
Non è roba tutta mia ma cose trovate anni fa in rete e poi modificate all'occorrenza.

Alla faccia :sofico:... Complimenti!
Appena ho tempo spulcio tutto con calma per capire bene come funziona, anche se ho appena dato una letta veloce.

Grazie per lo spirito di condivisione :)

trallallero
16-12-2008, 13:51
Alla faccia :sofico:... Complimenti!
Appena ho tempo spulcio tutto con calma per capire bene come funziona, anche se ho appena dato una letta veloce.
Devi avere un po di dimestichezza coi termios.

Grazie per lo spirito di condivisione :)
A buon rendere :read:

:D


PS: ma ci si può dimenticare una cosa del genere ??? dopo 2 ore di googlate ed un 3d aperto mi son ritrovato a parlarne con un collega e li mi è venuto in mente che lo avevo già risolto :fagiano: