Skip to content

Instantly share code, notes, and snippets.

@krisdb2009
Created April 30, 2018 06:32
Show Gist options
  • Save krisdb2009/c9d7c328c3b1af57450b771774b545df to your computer and use it in GitHub Desktop.
Save krisdb2009/c9d7c328c3b1af57450b771774b545df to your computer and use it in GitHub Desktop.
/*!
Chat++ The best UNIX chat program at BGSU probbably.
Author: Dylan Bickerstaff
Date: 4/30/2018
Description: This chat program allows multiple users to chat over a UNIX terminal.
*/
#include <iostream>
#include <fstream> //Library used for file access.
#include <unistd.h> //Library used for sleep function.
#include <cctype> //Library used for input validation.
#include <ctime> //Library used for the date/time.
using namespace std;
/* Constants */
const string CHAT_FILE = "chatData.txt";
/* Global Variables */
int pastChatCount = 0;
string username = "";
/* Global function prototypes */
void goto_menu_main();
void goto_chat_display();
void goto_chat_input();
void goto_set_username();
void do_output_chat_difference();
void do_clear_chat();
void remove_ctrl_characters(string &input);
/* Global fstream object */
fstream chatData;
/*
main(): First entry point for Chat++
*/
int main()
{
goto_menu_main();
return 0;
}
/*
goto_menu_main(): Displays the main menu for Chat++.
*/
void goto_menu_main() {
int choice = 0;
do {
cout << "\f" //Clear the screen.
<< "Chat++ Main Menu\n" //Output the menu options.
<< "----------------\n\n"
<< "Pick a number:\n\n"
<< "1) Chat Display Screen...\n"
<< "2) Chat Input Screen...\n"
<< "3) Exit Chat++\n\n"
<< "> ";
cin >> choice; //Capture the user's choice.
if(cin.fail()) { //Check if input is the same as type as choice.
cin.clear(); //Clear the warning flags on cin.
cin.ignore(1000, '\n'); //Flush the input.
}
} while(choice > 3 || choice < 1); //While choice is invalid.
switch(choice) {
case 1: {
goto_chat_display();
return;
}
case 2: {
goto_chat_input();
return;
}
}
}
/*
goto_chat_display(): Displays and checks for updates in the chat every second. This screen allows the user to view the chat.
*/
void goto_chat_display() {
cout << "\nPress \"Ctrl\" + \"C\" to quit.\n\n"; //Output instructions on how to quit the program in this mode.
usleep(1000 * 1000); //Wait 1 second to allow time for the user to read the above instruction.
fflush(stdout); //Flush the output.
while(true) { //Every second check the chat difference on file and output it to the user.
do_output_chat_difference();
fflush(stdout);
usleep(1000 * 1000);
}
}
/*
goto_chat_input(): Displays the chat input screen. This screen allows the user to input messages or commands.
*/
void goto_chat_input() {
/* Local Variables */
bool loop = true;
bool firstLoop = true;
string input; //Used to capture the user's input.
string message; //Used to send the user's message to chat.
string control; //Used to send control keys, and global messages to chat.
string oldName; //Used to store the user's old username if the user decides to change their username.
if(username == "") { //If username is not set, display the username prompt.
goto_set_username();
}
control = username + " has joined the chat"; //Prepare an announcement to chat that a user has joined.
while(loop) {
cout << "\f" //Clear the screen.
<< "Chat Input Commands:\n\n" //Display the commands
<< "/quit - Returns to the main menu.\n"
<< "/clear - Clears the chat.\n"
<< "/changename - Changes your username.\n"
<< "/bell - Produces an audible sound on every terminal.\n\n"
<< "Type a message, then press \"Enter\" to send:\n\n"
<< message << "\n\n" //Display a message to the user.
<< username << "> "; //Show the user's current username.
message = ""; //Clear the message.
if(!firstLoop) { //Skip input capture on first loop.
getline(cin, input); //Capture the user's input including spaces.
remove_ctrl_characters(input); //Remove ctrl characters from the input.
}
time_t now = time(0);
tm *time = localtime(&now);
if(input[0] == '/') { //If the first character is a forward slash.
if(input == "/quit") { //Announce to chat that the user has left the chat, then stop the loop.
control = username + " has left the chat";
loop = false;
} else if(input == "/clear") { //Call the clear chat function, then announce to the chat that the user has cleared the chat.
do_clear_chat();
control = username + " has cleared the chat";
} else if(input == "/changename") { //Show the username prompt, then announce the username change to chat.
oldName = username;
goto_set_username();
control = oldName + " changed their username to " + username;
} else if(input == "/bell") { //Announce that a bell was sent to chat and send a bell to chat.
control = username + " has sent a bell\a";
} else { //Otherwise, tell the user that their input was not a valid command.
message = "Warning: Not a valid command!";
}
input = ""; //Clear the input.
}
if(input != "" || control != "") { //If there is an input or control set.
if(control == "") { //If control is empty, substitute if for the username.
control = username;
}
chatData.open(CHAT_FILE, fstream::app); //Open the chat file in append mode.
chatData
<< "[" << 1 + time->tm_mon << "/" << time->tm_mday << "/" << 1900 + time->tm_year << " " << time->tm_hour << ":" << time->tm_min << "]" //Append the date/time to chat.
<< "<" << control << "> " << input << endl; //Append the control and input to the chat file.
chatData.close(); //Close the file.
control = ""; //Clear the control.
} else if(message == "") { //If the message is empty, show a warning to the user.
message = "Warning: Cannot send empty message!";
}
firstLoop = false;
}
goto_menu_main(); //If the loop exits, show the main menu.
}
/*
goto_set_username(): Displays the username prompt.
*/
void goto_set_username() {
/* Local Variable */
string input;
cout << "\fEnter a username: "; //Clear the screen and ask the user to input a username.
cin >> input; //Capture the input.
remove_ctrl_characters(input); //Remove control characters from the input.
if(input != "") { //If the input is not empty
username = input; //Set the username.
}
cin.ignore(100000, '\n'); //Flush the input buffer.
}
/*
do_output_chat_difference(): This function pulls the chat from file, then only outputs the new chat lines.
*/
void do_output_chat_difference() {
/* Local Variables */
string chatLine;
string output = "";
int count = 0;
chatData.open(CHAT_FILE); //Open the chat file.
while(getline(chatData, chatLine)) { //For each line in the chat file.
if(count >= pastChatCount) { //If a new line.
output.append(chatLine + "\n"); //Append to a string instead of cout-ing every line, then cout later to improve console / network performance with large chat history.
}
count++;
}
chatData.close(); //Close the chat file.
cout << output; //Output the new chat lines to the user.
if(pastChatCount > count) { //If there are less lines than before, assume the chat has been cleared.
cout << "\f" << chatLine; //Clear the user's screen.
pastChatCount = 0; //Reset past chat count to zero.
} else { //Otherwise set the past chat count to the current chat count.
pastChatCount = count;
}
}
/*
do_clear_chat(): This function clears out the chat file on disk.
*/
void do_clear_chat() {
chatData.open(CHAT_FILE, ofstream::out | fstream::trunc); //Clear the chat file.
chatData.close(); //Close the chat file.
}
/*
remove_ctrl_characters(): This function will remove all ctrl sequences from a string.
*/
void remove_ctrl_characters(string &input) {
for(unsigned int count = 0; input.length() > count; count++) { //For each character.
if(iscntrl(input[count])) { //If the character is a ctrl character.
input[count] = '\0'; //Set it to null.
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment