0

Hi all,
I am a novice c++ programmer with php experience and am trying to learn to do some usefull stuff in c++.
To learn I try to write a chat client with a mySQL backend and so far it works great.
To make it useable I need to get it to autorefresh the "screen" and show any new messages sent. As it is now I need to press ENTER to get it to refresh.

// istream getline
#include <iostream>
#include "util.h"
#include <mysql.h>
#include "functions.h"
#include <time.h>
#include <windows.h>

//-------------------------------------------------------
#define host "localhost"
#define username "root"
#define password ""
#define database "chat"
//-------------------------------------------------------

using namespace std;

int main () {
    MYSQL *conn;
    char message[256];
    char yourname[256];
    char sqlquery[255];
    char listquery[255];
    int seconds;

    //mySQL
    conn = mysql_init(NULL); 
    mysql_real_connect(conn,host,username,password,database,0,NULL,0); 
    MYSQL_RES *res_set;
    MYSQL_ROW row;
    //-------

    if (!mysql_real_connect(conn,host,username,password,database,0,NULL,0))
    {
        fprintf(stderr, "Failed to connect to database: Error: %s\n",
            mysql_error(conn));
    }
    
    clrscr();
    cout << "Enter you alias: ";
    cin >> yourname;
    
    while(strcmp (message,":q") != 0){    
        
        clrscr();
        
        //mysql_query(conn,"SELECT * FROM chatlog");
        mysql_query(conn,"SELECT * FROM (SELECT * FROM chatlog ORDER BY datetime DESC LIMIT 22) t1 ORDER BY datetime ASC;");
        res_set = mysql_store_result(conn); 
        while ((row = mysql_fetch_row(res_set)) != NULL)
            {
                //Konverterar UNIX time till human readable    
                char buffer[32];
                time_t value = strtol(row[1], NULL, 10);
                struct tm *gmt = gmtime(&value);
                if ( gmt )
                   {
                         strftime(buffer, sizeof buffer, "%Y-%m-%d %X", gmt);
                   }
               //-------------------------------------------
                
                HANDLE  hConsole;
                hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
                
                SetConsoleTextAttribute(hConsole, 1);
                cout << "[" << buffer << "] - ";
                SetConsoleTextAttribute(hConsole, 2);
                cout << row[3] << " - ";
                SetConsoleTextAttribute(hConsole, 3);
                cout << row[2] << "\n";
            SetConsoleTextAttribute(hConsole, 6); 
            }
        
        cout << "-----------------------------------------------------------------------------";
        cout << "\nSay (:h for help): ";
        

        cin.getline (message,256,'\n');
        
        if(strcmp (message,":h") == 0){
            clrscr();
            cout << "HELP\n";
            cout << ":q - Quit\n";
            cout << "\n";
            system("PAUSE");
        }else if(strcmp (message,":q") == 0){
            cout << "Quit!\n";
            return 0;
        }else if(strcmp (message,"\n") == 1){
            seconds = time (NULL);
            sprintf(sqlquery, "INSERT INTO chatlog (datetime, message,alias) VALUES ('%i','%s','%s')",seconds ,message,yourname);
            mysql_query(conn,sqlquery);
            printf("\n%ld Rader uppdaterade\n",
                (long) mysql_affected_rows(conn));
                
                fprintf(stderr, "%s",
                 mysql_error(conn));
        }
    }
    
    mysql_close(conn); 
}

What I want is for the line

cin.getline (message,256,'\n');

to timeout and simply put a "\n" in the message variable if nothing is typed within say 5 seconds.

Anyone has an idea on how to go about doing this?

BTW its great fun to program c++, especially with this great community helping.

Thx in advance
/sweRascal

2
Contributors
1
Reply
2
Views
9 Years
Discussion Span
Last Post by Narue
0

>Anyone has an idea on how to go about doing this?
Yes, I have two that come to mind right away.

1) Create a new thread that asks for input. You can specify a timeout for the thread and wait for it in the main program. For example:

#include <cstddef>
#include <iostream>
#include <windows.h>

struct data {
  char *buffer;
  std::size_t size;
};

DWORD WINAPI get_input ( LPVOID arg )
{
  data *buf = (data*)arg;

  return !std::cin.getline ( buf->buffer, buf->size );
} 

int main()
{
  char buffer[256] = {0};

  data arg = {buffer, 256};
  HANDLE h; 
  DWORD id;

  h = CreateThread ( NULL, 0, get_input, &arg, 0, &id );

  if ( h != NULL ) {
    if ( WaitForSingleObjectEx ( h, 5000, FALSE ) == WAIT_TIMEOUT ) {
      std::cout<<"Timeout\n";
      buffer[0] = '\n';
    }

    std::cout<<"buffer: \""<< buffer <<"\"\n";

    CloseHandle ( h );
  }
}

2) Don't use getline. Instead, take input character by character using a non-blocking read and use your own timer. This essentially duplicates the thread solution manually without using threads, but it's still non-portable. For example:

#include <cstddef>
#include <ctime>
#include <iostream>
#include <conio.h>

bool get_input ( char *buffer, std::size_t size, int timeout )
{
  std::time_t start = std::time ( 0 );
  std::size_t n = 0;

  for ( ; ; ) {
    if ( n == 0 && std::difftime ( std::time ( 0 ), start ) >= timeout )
      return false;

    if ( kbhit() ) {
      if ( n == size - 1 )
        break;

      char ch = (int)getche();

      if ( ch == '\r' ) {
        buffer[n++] = '\n';
        break;
      }
      else
        buffer[n++] = ch;
    }
  }

  buffer[n] = '\0';

  return true;
} 

int main()
{
  char buffer[256] = {0};

  if ( !get_input ( buffer, 256, 5 ) ) {
    std::cout<<"Timeout\n";
    buffer[0] = '\n';
  }

  std::cout<<"buffer: \""<< buffer <<"\"\n";
}
This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.