From e93746054bf38e1b73f308fabd503c76b977c0d5 Mon Sep 17 00:00:00 2001
From: SasikaSankalana <79664299+SasikaSankalana@users.noreply.github.com>
Date: Sat, 30 Sep 2023 23:23:32 +0530
Subject: [PATCH] Add Chat room using C
---
c/Chat-room/README.md | 23 +++
c/Chat-room/client.c | 389 +++++++++++++++++++++++++++++++++++
c/Chat-room/server.c | 466 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 878 insertions(+)
create mode 100644 c/Chat-room/README.md
create mode 100644 c/Chat-room/client.c
create mode 100644 c/Chat-room/server.c
diff --git a/c/Chat-room/README.md b/c/Chat-room/README.md
new file mode 100644
index 0000000..6ca9641
--- /dev/null
+++ b/c/Chat-room/README.md
@@ -0,0 +1,23 @@
+# Chat-room
+A Simple Network Chat (SNC) built in C programming language. The program has two files - server.c and client.c. The program uses multithreading for handling multiple clients.
+
+# Compile the program
+Just simply run the Makefile using this command.
+$ make Makefile compile
+
+# Run the Server
+The server can be run using below command.
+$ ./server
+
+Maximum number of clients - Should be in range of 1 to 10
+Maximum idle time - Should be in range of 1 to 300 seconds
+
+eg:- $ ./server 5 200
+
+# Run the Client
+The client can be run using below command.
+$ ./client
+
+In here server IP is set to be - 127.0.0.1 and port is set to be 4444
+
+eg:- $ ./client 127.0.0.1 4444
diff --git a/c/Chat-room/client.c b/c/Chat-room/client.c
new file mode 100644
index 0000000..ecb04aa
--- /dev/null
+++ b/c/Chat-room/client.c
@@ -0,0 +1,389 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define LENGTH 256
+#define ID "123"
+
+// Global variables
+volatile sig_atomic_t flag = 0;
+int sockfd = 0;
+char input_text[LENGTH + 100];
+
+struct snc_command_holder
+{
+ char command[50];
+ char sub_command[50];
+ char sub_text[LENGTH];
+} snc_command;
+
+char upper_text[50];
+
+char name[20];
+
+void str_overwrite_stdout()
+{
+ printf("%s > ", ID);
+ fflush(stdout);
+}
+
+void SNC_command_retriever()
+{
+
+ snc_command.command[0] = 0;
+ snc_command.sub_command[0] = 0;
+ snc_command.sub_text[0] = 0;
+ str_overwrite_stdout();
+ fgets(input_text, LENGTH, stdin);
+ str_trim_lf(input_text, LENGTH);
+ sscanf(input_text, "%s %s %[^\n]", snc_command.command, snc_command.sub_command, snc_command.sub_text);
+ toUpper(snc_command.command);
+ strcpy(snc_command.command, upper_text);
+}
+
+int SNC_command_validator()
+{
+ if (strcmp(snc_command.command, "JOIN") == 0)
+ {
+
+
+ if (strlen(snc_command.sub_command) > 20)
+ {
+ printf("Only 20 characters allowed for the nick name \n ");
+ return 0;
+ }
+
+ if (!(strlen(snc_command.sub_command) > 0))
+ {
+ printf("Nickname cannot be empty \n ");
+ return 0;
+ }
+
+ if (strlen(snc_command.sub_text) > 20)
+ {
+ printf("Only 20 characters allowed for the name \n ");
+ return 0;
+ }
+
+ if (!(strlen(snc_command.sub_text) > 0))
+ {
+ printf("Name cannot be empty \n ");
+ return 0;
+ }
+
+ return 1;
+ }
+ else if (strcmp(snc_command.command, "WHOIS") == 0)
+ {
+ if (strlen(snc_command.sub_command) > 20)
+ {
+ printf("Nickname should be under 20 characters \n ");
+ return 0;
+ }
+
+ if (!(strlen(snc_command.sub_command) > 0))
+ {
+ printf("Enter a nickname \n ");
+ return 0;
+ }
+
+ if ((strlen(snc_command.sub_text) > 0))
+ {
+ printf("Invalid argument. Please check again \n ");
+ return 0;
+ }
+
+ return 1;
+ }
+ else if (strcmp(snc_command.command, "MSG") == 0)
+ {
+ if (strlen(snc_command.sub_command) > 20)
+ {
+ printf("Nickname should be under 20 characters \n ");
+ return 0;
+ }
+
+ if (!(strlen(snc_command.sub_command) > 0))
+ {
+ printf("Enter a nickname \n ");
+ return 0;
+ }
+
+ if (strlen(snc_command.sub_text) > 250)
+ {
+ printf("Only 256 characters allowed in a message \n ");
+ return 0;
+ }
+
+ if (!(strlen(snc_command.sub_text) > 0))
+ {
+ printf("Message cannot be empty \n ");
+ return 0;
+ }
+
+ return 1;
+ }
+ else if (strcmp(snc_command.command, "TIME") == 0)
+ {
+ if ((strlen(snc_command.sub_command) > 0) || (strlen(snc_command.sub_text) > 0))
+ {
+ printf("Invalid argument. Please check again \n ");
+ return 0;
+ }
+
+ return 1;
+ }
+ else if (strcmp(snc_command.command, "ALIVE") == 0)
+ {
+ if ((strlen(snc_command.sub_command) > 0) || (strlen(snc_command.sub_text) > 0))
+ {
+ printf("Invalid argument. Please check again \n ");
+ return 0;
+ }
+
+ return 1;
+ }
+ else if (strcmp(snc_command.command, "QUIT") == 0)
+ {
+ if ((strlen(snc_command.sub_command) > 0) || (strlen(snc_command.sub_text) > 0))
+ {
+ printf("Invalid argument. Please check again \n ");
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ // printf("%s",snc_command.command);
+ printf("Invalid Command. Please check again \n ");
+ return 0;
+ }
+}
+
+void str_trim_lf(char *arr, int length)
+{
+ int i;
+ for (i = 0; i < length; i++)
+ { // trim \n
+ if (arr[i] == '\n')
+ {
+ arr[i] = '\0';
+ break;
+ }
+ }
+}
+
+void catch_ctrl_c_and_exit(int sig)
+{
+ flag = 1;
+}
+
+void send_msg_handler()
+{
+ // char message[LENGTH] = {};
+ char buffer[LENGTH + 32] = {};
+
+ while (1)
+ {
+ SNC_command_retriever();
+ if (SNC_command_validator() == 0)
+ {
+ continue;
+ }
+
+ // str_overwrite_stdout();
+ // fgets(message, LENGTH, stdin);
+ // str_trim_lf(message, LENGTH);
+
+ if (strcmp(snc_command.command, "QUIT") == 0)
+ {
+ break;
+ }
+ else
+ {
+
+
+ send(sockfd, buffer, strlen(buffer), 0);
+ }
+
+ // bzero(message, LENGTH);
+ bzero(buffer, LENGTH + 32);
+ }
+ catch_ctrl_c_and_exit(2);
+}
+
+void recv_msg_handler()
+{
+ char message[LENGTH] = {};
+ while (1)
+ {
+ int receive = recv(sockfd, message, LENGTH, 0);
+ if (receive > 0)
+ {
+ printf("%s", message);
+ str_overwrite_stdout();
+ }
+ else if (receive == 0)
+ {
+ break;
+ }
+ else
+ {
+ // -1
+ }
+ memset(message, 0, sizeof(message));
+ }
+}
+
+void toUpper(char *text)
+{
+
+ for (int i = 0; i < 51; i++)
+ {
+ upper_text[i] = '\0';
+ }
+ for (int i = 0; text[i] != '\0'; i++)
+ {
+ if (text[i] >= 'a' && text[i] <= 'z')
+ {
+ upper_text[i] = text[i] - 32;
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 3)
+ {
+ printf("Insufficient parameters supplied to the command.\n");
+ return EXIT_FAILURE;
+ }
+
+ char *ip = argv[1];
+ int port = atoi(argv[2]);
+
+ signal(SIGINT, catch_ctrl_c_and_exit);
+
+retrieve_again:
+ SNC_command_retriever();
+
+ if (SNC_command_validator == 0)
+ {
+ goto retrieve_again;
+ }
+
+ if (strcmp(snc_command.command, "JOIN") == 0)
+ {
+
+ strcpy(name, snc_command.sub_command);
+ // str_trim_lf(name, strlen(name));
+
+ struct sockaddr_in server_address;
+
+ /* Socket settings */
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ server_address.sin_family = AF_INET;
+ server_address.sin_addr.s_addr = inet_addr(ip);
+ server_address.sin_port = htons(port);
+
+ // Connect to Server
+ int connect_error = connect(sockfd, (struct sockaddr *)&server_address, sizeof(server_address));
+ if (connect_error == -1)
+ {
+ printf("ERROR: connect\n");
+ return EXIT_FAILURE;
+ }
+ char name_buffer[50];
+
+ sprintf(name_buffer, "%s %s", name, snc_command.sub_text);
+
+ // Send name
+ send(sockfd, name_buffer, 50, 0);
+
+
+ //printf("=== WELCOME TO THE CHATROOM ===\n");
+
+ pthread_t send_msg_thread;
+ if (pthread_create(&send_msg_thread, NULL, (void *)send_msg_handler, NULL) != 0)
+ {
+ printf("ERROR: pthread\n");
+ return EXIT_FAILURE;
+ }
+
+ pthread_t receive_msg_thread;
+ if (pthread_create(&receive_msg_thread, NULL, (void *)recv_msg_handler, NULL) != 0)
+ {
+ printf("ERROR: pthread\n");
+ return EXIT_FAILURE;
+ }
+
+ }
+
+ // // printf("Current Time : %s\n", time_str);
+ // }
+ // else if (strcmp(upText, "ALIVE") == 0)
+ // {
+ // // do something else
+ // }
+ // else if (strcmp(upText, "QUIT") == 0)
+ // {
+ // is_joined = 0;
+ // }
+ else /* default: */
+ {
+
+ printf("Please Join the Server\n");
+ goto retrieve_again;
+ }
+
+ // printf("Please enter your name: ");
+ // fgets(name, 32, stdin);
+ // str_trim_lf(name, strlen(name));
+
+ // if (strlen(name) > 32 || strlen(name) < 2)
+ // {
+ // printf("Name must be less than 30 and more than 2 characters.\n");
+ // return EXIT_FAILURE;
+ // }
+
+ // struct sockaddr_in server_address;
+
+ // /* Socket settings */
+ // sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ // server_address.sin_family = AF_INET;
+ // server_address.sin_addr.s_addr = inet_addr(ip);
+ // server_address.sin_port = htons(port);
+
+ // // Connect to Server
+ // int connect_error = connect(sockfd, (struct sockaddr *)&server_address, sizeof(server_address));
+ // if (connect_error == -1)
+ // {
+ // printf("ERROR: connect\n");
+ // return EXIT_FAILURE;
+ // }
+
+ // // Send name
+ // send(sockfd, name, 32, 0);
+
+ // printf("=== WELCOME TO THE CHATROOM ===\n");
+
+ while (1)
+ {
+ if (flag)
+ {
+ printf("\nBye\n");
+ break;
+ }
+ }
+
+ close(sockfd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/c/Chat-room/server.c b/c/Chat-room/server.c
new file mode 100644
index 0000000..e6dbb2f
--- /dev/null
+++ b/c/Chat-room/server.c
@@ -0,0 +1,466 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define BUFFER_SZ 288
+#define MAX_CLIENTS 10
+
+static _Atomic unsigned int client_count = 0;
+static int uid = 10;
+char upper_text[50];
+int user_check = 0;
+int max_no_of_clients;
+
+/* Client structure */
+typedef struct
+{
+ struct sockaddr_in address;
+ int sockfd;
+ int uid;
+ char fullname[20];
+ char name[20];
+} client_t;
+
+struct snc_command_holder
+{
+ char nick_name[20];
+ char command[50];
+ char sub_command[50];
+ char sub_text[256];
+} snc_command;
+
+client_t *clients[MAX_CLIENTS];
+
+pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void toUpper(char *text)
+{
+
+ for (int i = 0; i < 51; i++)
+ {
+ upper_text[i] = '\0';
+ }
+ for (int i = 0; text[i] != '\0'; i++)
+ {
+ if (text[i] >= 'a' && text[i] <= 'z')
+ {
+ upper_text[i] = text[i] - 32;
+ }
+ }
+}
+
+void str_overwrite_stdout()
+{
+ printf("\r%s", "> ");
+ fflush(stdout);
+}
+
+void str_trim_lf(char *arr, int length)
+{
+ int i;
+ for (i = 0; i < length; i++)
+ { // trim \n
+ if (arr[i] == '\n')
+ {
+ arr[i] = '\0';
+ break;
+ }
+ }
+}
+
+void print_client_addr(struct sockaddr_in addr)
+{
+ printf("%d.%d.%d.%d",
+ addr.sin_addr.s_addr & 0xff,
+ (addr.sin_addr.s_addr & 0xff00) >> 8,
+ (addr.sin_addr.s_addr & 0xff0000) >> 16,
+ (addr.sin_addr.s_addr & 0xff000000) >> 24);
+}
+
+/* Add clients to queue */
+void queue_add(client_t *cl)
+{
+ pthread_mutex_lock(&clients_mutex);
+
+ for (int i = 0; i < max_no_of_clients; ++i)
+ {
+ // printf("%d\t%d\t%s\t%s", clients[i]->sockfd, clients[i]->uid, clients[i]->name, clients[i]->fullname);
+ if (!clients[i])
+ {
+ clients[i] = cl;
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&clients_mutex);
+}
+
+/* Remove clients to queue */
+void queue_remove(int uid)
+{
+ pthread_mutex_lock(&clients_mutex);
+
+ for (int i = 0; i < max_no_of_clients; ++i)
+ {
+ if (clients[i])
+ {
+ if (clients[i]->uid == uid)
+ {
+ clients[i] = NULL;
+ break;
+ }
+ }
+ }
+
+ pthread_mutex_unlock(&clients_mutex);
+}
+
+/* Send message to all clients except sender */
+void broadcast(char *s, int uid)
+{
+ pthread_mutex_lock(&clients_mutex);
+
+ for (int i = 0; i < max_no_of_clients; ++i)
+ {
+ if (clients[i])
+ {
+ if (clients[i]->uid != uid)
+ {
+ if (write(clients[i]->sockfd, s, strlen(s)) < 0)
+ {
+ perror("ERROR: write to descriptor failed");
+ break;
+ }
+ }
+ }
+ }
+
+ pthread_mutex_unlock(&clients_mutex);
+}
+
+/* Send message to target */
+void send_message(char *s, int uid)
+{
+ pthread_mutex_lock(&clients_mutex);
+
+ for (int i = 0; i < max_no_of_clients; ++i)
+ {
+ if (clients[i])
+ {
+ if (clients[i]->uid == uid)
+ {
+ if (write(clients[i]->sockfd, s, strlen(s)) < 0)
+ {
+ perror("ERROR: write to descriptor failed");
+ break;
+ }
+ }
+ }
+ }
+
+ pthread_mutex_unlock(&clients_mutex);
+}
+
+char *get_time()
+{
+ time_t current_time = time(NULL);
+ char *time_str = ctime(¤t_time);
+ time_str[strlen(time_str) - 1] = '\0';
+
+ return time_str;
+}
+
+/* Handle all communication with the client */
+void *handle_client(void *arg)
+{
+ char buff_out[BUFFER_SZ];
+ char name[50];
+ char fullname[20];
+ char nickname[20];
+ int leave_flag = 0;
+
+ client_count++;
+ client_t *cli = (client_t *)arg;
+
+ // Name
+ if (recv(cli->sockfd, name, 50, 0) <= 0 || strlen(name) <= 0)
+ {
+ printf("Didn't enter the name.\n");
+ leave_flag = 1;
+ }
+ else
+ {
+ sscanf(name, "%s %[^\n]", nickname, fullname);
+
+ for (int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (clients[i])
+ {
+ if (strcmp(clients[i]->fullname, fullname) == 0)
+ {
+ sprintf(buff_out, "SERVER : NAME ALREADY EXIST.\n");
+ send_message(buff_out, cli->uid);
+ leave_flag = 1;
+ break;
+ } else if (strcmp(clients[i]->name, nickname) == 0)
+ {
+ sprintf(buff_out, "SERVER : NICKNAME ALREADY TAKEN. CHOOSE A DIFFERENT NICKNAME AND JOIN.\n");
+ send_message(buff_out, cli->uid);
+ leave_flag = 1;
+ break;
+ }
+ }
+ }
+
+ if(!leave_flag) {
+ strcpy(cli->name, nickname);
+ strcpy(cli->fullname, fullname);
+ sprintf(buff_out, "%s has joined\n", cli->name);
+
+ broadcast(buff_out, cli->uid);
+ user_check = 1;
+ }
+ }
+
+ bzero(buff_out, BUFFER_SZ);
+
+ while (1)
+ {
+ if (leave_flag)
+ {
+ break;
+ }
+
+ int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0);
+ if (receive >= 0)
+ {
+ printf("check 1\n");
+
+ sscanf(buff_out, "%s %s %s %[^\n]", snc_command.nick_name, snc_command.command, snc_command.sub_command, snc_command.sub_text);
+ // bzero(buff_out, BUFFER_SZ);
+ toUpper(snc_command.command);
+ }
+
+ if (receive > 0)
+ {
+
+ if (strcmp(upper_text, "JOIN") == 0 ){
+
+ if(!user_check){
+ sscanf(name, "%s %[^\n]", nickname, fullname);
+
+ for (int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (clients[i])
+ {
+ if (strcmp(clients[i]->fullname, fullname) == 0)
+ {
+ sprintf(buff_out, "SERVER : NAME ALREADY EXIST.\n");
+ send_message(buff_out, cli->uid);
+ leave_flag = 1;
+ break;
+ } else if (strcmp(clients[i]->name, nickname) == 0)
+ {
+ sprintf(buff_out, "SERVER : NICKNAME ALREADY TAKEN. CHOOSE A DIFFERENT NICKNAME AND JOIN.\n");
+ send_message(buff_out, cli->uid);
+ leave_flag = 1;
+ break;
+ }
+ }
+ }}else{
+
+ sprintf(buff_out, "SERVER : ALREADY JOINED\n");
+ send_message(buff_out, cli->uid);
+ }
+
+
+ if(!leave_flag) {
+ strcpy(cli->name, nickname);
+ strcpy(cli->fullname, fullname);
+ sprintf(buff_out, "%s has joined\n", cli->name);
+
+ broadcast(buff_out, cli->uid);
+ user_check = 1;
+ }
+
+ }
+ else if (strcmp(upper_text, "MSG") == 0)
+ {
+ int check = 0;
+ for (int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (clients[i])
+ {
+ if (strcmp(snc_command.sub_command, clients[i]->name) == 0)
+ {
+ sprintf(buff_out, "%s : %s\n", cli->name, snc_command.sub_text);
+ send_message(buff_out, clients[i]->uid);
+ check = 1;
+ break;
+ }
+ }
+ }
+ if (!check)
+ {
+ printf("CLIENT \"%s\" NOT REGISTERED\n",snc_command.sub_command);
+ sprintf(buff_out, "SERVER : CHECK THE NICKNAME AGAIN\n");
+ send_message(buff_out, cli->uid);
+ }
+ }
+
+ else if (strcmp(upper_text, "WHOIS") == 0)
+ {
+ int check = 0;
+ for (int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (clients[i])
+ {
+ if (strcmp(snc_command.sub_command, clients[i]->name) == 0)
+ {
+ sprintf(buff_out, "SERVER : NICKNAME -> %s FULL NAME -> \n", clients[i]->name, clients[i]->fullname);
+ send_message(buff_out, cli->uid);
+ check = 1;
+ break;
+ }
+ }
+ }
+ if (!check)
+ {
+ printf("CLIENT \"%s\" NOT REGISTERED\n",snc_command.sub_command);
+ sprintf(buff_out, "SERVER : CHECK THE NICKNAME AGAIN\n");
+ send_message(buff_out, cli->uid);
+ }
+ } else if (strcmp(upper_text, "TIME") == 0)
+ {
+ send_message(get_time(), cli->uid);
+ }
+ }
+ else if (receive == 0 || strcmp(buff_out, "QUIT") == 0)
+ {
+ sprintf(buff_out, "%s has left\n", cli->name);
+ printf("%s", buff_out);
+ broadcast(buff_out, cli->uid);
+ leave_flag = 1;
+ }
+ else
+ {
+ printf("ERROR: -1\n");
+ leave_flag = 1;
+ }
+
+ bzero(buff_out, BUFFER_SZ);
+ }
+
+ /* Delete client from queue and yield thread */
+ close(cli->sockfd);
+ queue_remove(cli->uid);
+ free(cli);
+ client_count--;
+ pthread_detach(pthread_self());
+
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 3)
+ {
+ printf("Insufficient parameters supplied to the command.\n");
+ return EXIT_FAILURE;
+ }
+
+ int max_idle_time = atoi(argv[2]);
+ max_no_of_clients = atoi(argv[1]);
+
+ if (max_idle_time > 100 || max_idle_time < 1)
+ {
+ printf("Invalid parameters supplied to the command\n");
+ return EXIT_FAILURE;
+ }
+
+ if (max_no_of_clients > 10 || max_no_of_clients < 1)
+ {
+ printf("Invalid parameters supplied to the command\n");
+ return EXIT_FAILURE;
+ }
+
+ char *ip = "127.0.0.1";
+ int port = 4444;
+
+ int option = 1;
+ int listenfd = 0, connfd = 0;
+ struct sockaddr_in server_address;
+ struct sockaddr_in client_address;
+ pthread_t thread_id;
+
+ /* Socket settings */
+ listenfd = socket(AF_INET, SOCK_STREAM, 0);
+ server_address.sin_family = AF_INET;
+ server_address.sin_addr.s_addr = inet_addr(ip);
+ server_address.sin_port = htons(port);
+
+ /* Ignore pipe signals */
+ signal(SIGPIPE, SIG_IGN);
+
+ if (setsockopt(listenfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char *)&option, sizeof(option)) < 0)
+ {
+ perror("ERROR: setsockopt failed");
+ return EXIT_FAILURE;
+ }
+
+ /* Bind */
+ if (bind(listenfd, (struct sockaddr *)&server_address, sizeof(server_address)) < 0)
+ {
+ perror("ERROR: Socket binding failed");
+ return EXIT_FAILURE;
+ }
+
+ /* Listen */
+ if (listen(listenfd, 10) < 0)
+ {
+ perror("ERROR: Socket listening failed");
+ return EXIT_FAILURE;
+ }
+
+ printf("=== WELCOME TO THE CHATROOM ===\n");
+
+ while (1)
+ {
+ socklen_t client_length = sizeof(client_address);
+ connfd = accept(listenfd, (struct sockaddr *)&client_address, &client_length);
+
+ /* Check if max clients is reached */
+ if ((client_count + 1) == max_no_of_clients)
+ {
+ printf("Max clients reached. Rejected: ");
+ print_client_addr(client_address);
+ printf(":%d\n", client_address.sin_port);
+ close(connfd);
+ continue;
+ }
+
+ /* Client settings */
+ client_t *cli = (client_t *)malloc(sizeof(client_t));
+ cli->address = client_address;
+ cli->sockfd = connfd;
+ cli->uid = uid++;
+
+ /* Add client to the queue and fork thread */
+ queue_add(cli);
+ user_check = 0;
+ pthread_create(&thread_id, NULL, &handle_client, (void *)cli);
+
+ /* Reduce CPU usage */
+ sleep(1);
+ }
+
+ return EXIT_SUCCESS;
+}