Created
April 30, 2018 06:32
-
-
Save krisdb2009/c9d7c328c3b1af57450b771774b545df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
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