Compare commits
42 Commits
f0313dc338
...
master
Author | SHA1 | Date | |
---|---|---|---|
291a727dd3 | |||
a565c7ef29 | |||
fa1e8610f8 | |||
9c87de7196 | |||
34861b4644 | |||
a83338e8db | |||
5bc6c575fc | |||
c8c9a34aab | |||
868aaccf28 | |||
97d1c9153b | |||
2c46754cb4 | |||
ad70f43da9 | |||
df9a05a56e | |||
1456b60ad9 | |||
6be0bd8ce2 | |||
d46d250b84 | |||
70ecbae964 | |||
ace4e3c8e5 | |||
3e07370f31 | |||
3125dd48d6 | |||
5bf131d00c | |||
42e12def81 | |||
a5ac16f884 | |||
768d3fcedf | |||
65f731651b | |||
84a2a79b89 | |||
3b71854b62 | |||
d294a4411f | |||
770c03cf76 | |||
a940d7acad | |||
67466ade6e | |||
eefe9fbf1b | |||
ba35b8acdd | |||
cfc8fbbb7b | |||
d0c624e319 | |||
f3f66297c2 | |||
13858dc352 | |||
e5e3e8db72 | |||
423404826e | |||
06b44d17c7 | |||
7b55d84171 | |||
d6db6ad33b |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
main
|
||||
user_file.txt
|
||||
*.o
|
||||
|
34
Makefile
Normal file
34
Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
EXEC_FILE=main
|
||||
TARGETS=$(EXEC_FILE).o message.o user.o message_helpers.o file_helpers.o stack.o
|
||||
CFLAGS=
|
||||
|
||||
|
||||
all: $(EXEC_FILE)
|
||||
|
||||
$(EXEC_FILE): $(TARGETS)
|
||||
gcc $(CFLAGS) -o $(EXEC_FILE) $^ -leasysock
|
||||
|
||||
|
||||
$(EXEC_FILE).o: $(EXEC_FILE).c
|
||||
message.o: message.c
|
||||
user.o: user.c
|
||||
message_helpers.o: message_helpers.c
|
||||
file_helpers.o: file_helpers.c
|
||||
stack.o: stack.c
|
||||
$(TARGETS):
|
||||
gcc $(CFLAGS) -c -o $@ $^
|
||||
|
||||
|
||||
.PHONY: debug
|
||||
debug: CFLAGS+=-g
|
||||
debug: $(EXEC_FILE)
|
||||
|
||||
|
||||
.PHONY: allwarn
|
||||
allwarn: CFLAGS+=-Wall -Wextra -pedantic
|
||||
allwarn: $(EXEC_FILE)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm $(TARGETS)
|
||||
rm $(EXEC_FILE)
|
14
README.md
Normal file
14
README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## Chat server
|
||||
This is a simple, barely-working chat server (which uses a custom protocol). It is written in C, and relies on BSD sockets.
|
||||
|
||||
##Usage
|
||||
To use it, compile the program with `make`.
|
||||
|
||||
|
||||
|
||||
|
||||
TODO:
|
||||
- Finish README
|
||||
- Implement password authentication
|
||||
- Fix bugs with message string manipulation (the actual message isn't being stored correctly, and contains extra characters).
|
||||
- Do additional testing to ensure that everything works correctly (it probably doesn't).
|
53
file_helpers.c
Normal file
53
file_helpers.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "file_helpers.h"
|
||||
|
||||
|
||||
char* file_to_string(char* filename) {
|
||||
FILE* fp = fopen(filename,"r");
|
||||
|
||||
fseek(fp,0,SEEK_END);
|
||||
long file_size = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
char* buffer = calloc(sizeof(char),file_size+1);
|
||||
|
||||
fread(buffer,1,file_size,fp);
|
||||
|
||||
rewind(fp);
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Finds the number of lines in a file (Which MUST end in a new-line, if the last
|
||||
line is to be counted) */
|
||||
|
||||
int num_of_lines(char* filename) {
|
||||
|
||||
int num_lines = 0;
|
||||
FILE* fp = fopen(filename,"r");
|
||||
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
for (int c = getc(fp); c != EOF; c = getc(fp)) {
|
||||
if (c == '\n') {
|
||||
num_lines++;
|
||||
}
|
||||
}
|
||||
|
||||
rewind(fp);
|
||||
fclose(fp);
|
||||
|
||||
return num_lines;
|
||||
|
||||
}
|
11
file_helpers.h
Normal file
11
file_helpers.h
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
/* Takes a string that represents a filename, and converts the contents
|
||||
of the file into a string */
|
||||
char* file_to_string(char* filename);
|
||||
|
||||
|
||||
|
||||
|
||||
/*Finds the number of new-line characters in the given file */
|
||||
int num_of_lines(char* filename);
|
299
main.c
299
main.c
@@ -1,25 +1,229 @@
|
||||
#include "message.h"
|
||||
#include "user.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
int num_of_lines(char* filename);
|
||||
char* file_to_string(char* filename);
|
||||
User* create_user_list(char* filename);
|
||||
#include "message.h"
|
||||
#include "user.h"
|
||||
#include "easysock.h"
|
||||
#include "file_helpers.h"
|
||||
#include "message_helpers.h"
|
||||
#include "stack.h"
|
||||
|
||||
#define BUFFER_SIZE 10000
|
||||
#define MAX_CONNECTIONS 100
|
||||
#define DATA_SIZE 50000
|
||||
#define MESSAGE_SIZE 50000
|
||||
|
||||
User** create_user_list(char* filename);
|
||||
void sigint_handler(int dummy);
|
||||
User* fetch_user(char* username);
|
||||
int user_to_index(User* user);
|
||||
bool user_equals(User* this, User* other);
|
||||
|
||||
User** users;
|
||||
int num_users;
|
||||
|
||||
bool stop_running;
|
||||
|
||||
int main() {
|
||||
stop_running = false;
|
||||
|
||||
User* users = create_user_list("user_file.txt");
|
||||
signal(SIGINT,sigint_handler);
|
||||
|
||||
Message message = new_message("Hello, this is a text message",users[0],users[1]);
|
||||
struct sockaddr temp_addr;
|
||||
socklen_t temp_addrlen;
|
||||
|
||||
printf("Message was: %s\nSentfrom: %s\nSent to: %s\nWith password: %s\nSent at: %s\n",message.text, message.sender.username, message.recipient.username, message.recipient.password, asctime(&message.timeinfo));
|
||||
fd_set read_fd_set;
|
||||
int conn_sockets[MAX_CONNECTIONS] = {-1};
|
||||
User* to_user[MAX_CONNECTIONS] = {NULL};
|
||||
User* from_user[MAX_CONNECTIONS] = {NULL};
|
||||
FD_ZERO(&read_fd_set); char buffer[BUFFER_SIZE];
|
||||
char data[DATA_SIZE];
|
||||
|
||||
num_users = num_of_lines("user_file.txt");
|
||||
users = create_user_list("user_file.txt");
|
||||
|
||||
Stack* message_stack[num_users];
|
||||
|
||||
for (int i=0;i < num_users; i++) {
|
||||
message_stack[i] = new_stack(10);
|
||||
}
|
||||
|
||||
struct sockaddr addr_struct;
|
||||
int server_sock = create_local(4,'T',"127.0.0.1",30000,&addr_struct);
|
||||
conn_sockets[0] = server_sock;
|
||||
|
||||
assert(listen(server_sock,MAX_CONNECTIONS) == 0);
|
||||
|
||||
while (true) {
|
||||
FD_ZERO(&read_fd_set);
|
||||
for (int i=0; i < MAX_CONNECTIONS; i++) {
|
||||
if (conn_sockets[i] > 0) {
|
||||
FD_SET(conn_sockets[i],&read_fd_set);
|
||||
}
|
||||
}
|
||||
|
||||
int num_conns = select(FD_SETSIZE, &read_fd_set, NULL, NULL, NULL);
|
||||
|
||||
if (num_conns > 0) {
|
||||
if (FD_ISSET(conn_sockets[0],&read_fd_set)) {
|
||||
int client_sock = accept(conn_sockets[0],&temp_addr,&temp_addrlen);
|
||||
for (int i=0;i < MAX_CONNECTIONS; i++) {
|
||||
if (conn_sockets[i] <= 0) {
|
||||
conn_sockets[i] = client_sock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=1; i < MAX_CONNECTIONS; i++) {
|
||||
|
||||
memset(data,0x00,DATA_SIZE);
|
||||
|
||||
if (FD_ISSET(conn_sockets[i],&read_fd_set)) {
|
||||
|
||||
while ( strstr(buffer,"END_OF_DATA") == NULL ) {
|
||||
int num_bytes_read = recv(conn_sockets[i],buffer,sizeof(buffer),0);
|
||||
if (num_bytes_read <= 0) {
|
||||
close(conn_sockets[i]);
|
||||
conn_sockets[i] = 0;
|
||||
to_user[i] = NULL;
|
||||
goto continue_for_loop;
|
||||
}
|
||||
strcat(data, buffer);
|
||||
}
|
||||
strcat(data,"\0");
|
||||
|
||||
buffer[0] = '\0'; /* Clear the buffer */
|
||||
|
||||
char* send_or_receive = malloc(10);
|
||||
int k=0;
|
||||
while (*(data + k) != '\n') {
|
||||
k++;
|
||||
}
|
||||
memcpy(send_or_receive,data,k);
|
||||
|
||||
if (strstr(send_or_receive, "SENDING") != NULL) {
|
||||
if (from_user[i] == NULL) {
|
||||
from_user[i] = fetch_user(fetch_from_string(data,"IAM"));
|
||||
if (from_user[i] == NULL) {
|
||||
printf("Please identify yourself.\n");
|
||||
close(conn_sockets[i]);
|
||||
continue;
|
||||
} else {
|
||||
printf("You are %s\n",from_user[i]->username);
|
||||
}
|
||||
}
|
||||
|
||||
if (to_user[i] == NULL) {
|
||||
to_user[i] = fetch_user(fetch_from_string(data,"TO"));
|
||||
if (to_user[i] == NULL) {
|
||||
printf("Invalid user or message format.\n");
|
||||
close(conn_sockets[i]);
|
||||
continue;
|
||||
} else {
|
||||
printf("Message intended for %s\n",to_user[i]->username);
|
||||
}
|
||||
}
|
||||
|
||||
char* message_string = malloc(sizeof(char) * MESSAGE_SIZE);
|
||||
memset(message_string, 0x00, MESSAGE_SIZE);
|
||||
message_string = fetch_message_string(data);
|
||||
if (message_string == NULL) {
|
||||
printf("Invalid message.\n");
|
||||
return -10;
|
||||
}
|
||||
|
||||
printf("Your message is: \n------------------\n%s\n------------------\n",message_string);
|
||||
|
||||
if (user_to_index(to_user[i]) < 0) {
|
||||
printf("Recipient user does not exist!\n");
|
||||
return -20;
|
||||
}
|
||||
|
||||
Message* message = new_message(message_string,from_user[i],to_user[i]);
|
||||
stack_push( message_stack[user_to_index(to_user[i])],message );
|
||||
|
||||
printf("Message has been pushed onto stack for %s\n",to_user[i]->username);
|
||||
|
||||
} else if (strstr(send_or_receive, "RECEIVING") != NULL) {
|
||||
|
||||
if (from_user[i] == NULL) {
|
||||
from_user[i] = fetch_user(fetch_from_string(data,"IAM"));
|
||||
if (from_user[i] == NULL) {
|
||||
printf("Please identify yourself.\n");
|
||||
close(conn_sockets[i]);
|
||||
continue;
|
||||
} else {
|
||||
printf("You are %s\n",from_user[i]->username);
|
||||
}
|
||||
}
|
||||
|
||||
int num_of_messages;
|
||||
char* num_of_messages_string = fetch_from_string(data,"GETLAST");
|
||||
|
||||
if (num_of_messages_string == NULL) {
|
||||
printf("Invalid GET request.\n");
|
||||
return -30;
|
||||
} else {
|
||||
if (strstr(num_of_messages_string,"ALL") != NULL) {
|
||||
num_of_messages = stack_size(message_stack[user_to_index(from_user[i])]);
|
||||
} else {
|
||||
num_of_messages = atoi(num_of_messages_string);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_of_messages > stack_size(message_stack[user_to_index(from_user[i])])) {
|
||||
num_of_messages = stack_size(message_stack[user_to_index(from_user[i])]);
|
||||
}
|
||||
|
||||
for (int k=0;k<num_of_messages;k++) {
|
||||
Message* message = stack_pop(message_stack[user_to_index(from_user[i])]);
|
||||
printf("You have a message from %s"
|
||||
", sent at %s"
|
||||
": \"%s\"\n",
|
||||
message->sender->username,
|
||||
asctime(message->timeinfo),
|
||||
message->text);
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("You are not sending or receiving.\n");
|
||||
}
|
||||
close(conn_sockets[i]);
|
||||
conn_sockets[i] = -1;
|
||||
|
||||
continue_for_loop:
|
||||
memset(data,0,DATA_SIZE);
|
||||
memset(buffer,0,BUFFER_SIZE);
|
||||
to_user[i] = NULL;
|
||||
from_user[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (stop_running == true) {
|
||||
printf("Stopping...\n");
|
||||
for (int i=MAX_CONNECTIONS-1; i>= 0; i--) {
|
||||
close(i);
|
||||
close(conn_sockets[i]);
|
||||
}
|
||||
return 130;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
User* create_user_list(char* filename) {
|
||||
User** create_user_list(char* filename) {
|
||||
|
||||
/* Structure of user file - <username> <password> on every line */
|
||||
|
||||
@@ -27,13 +231,17 @@ User* create_user_list(char* filename) {
|
||||
char* file_str = file_to_string(filename);
|
||||
|
||||
char* token = malloc(sizeof(char) * 30);
|
||||
User* users = calloc(num_users, sizeof(User));
|
||||
User** users = malloc (num_users * sizeof(User*));
|
||||
|
||||
for (int i=0;i<num_users;i++) {
|
||||
(*(users+i)) = malloc(sizeof(User));
|
||||
}
|
||||
|
||||
token = strtok(file_str," \r\n");
|
||||
for (int i=0;i<num_users;i++) {
|
||||
users[i].username = token;
|
||||
(*(users + i))->username = strdup(token);
|
||||
token = strtok(NULL," \r\n");
|
||||
users[i].password = token;
|
||||
(*(users + i))->password = strdup(token);
|
||||
token = strtok(NULL," \r\n");
|
||||
}
|
||||
|
||||
@@ -41,50 +249,43 @@ User* create_user_list(char* filename) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
char* file_to_string(char* filename) {
|
||||
FILE* fp = fopen(filename,"r");
|
||||
|
||||
fseek(fp,0,SEEK_END);
|
||||
long file_size = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
char* buffer = calloc(sizeof(char),file_size+1);
|
||||
|
||||
fread(buffer,1,file_size,fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
|
||||
void sigint_handler(int dummy) {
|
||||
stop_running = true;
|
||||
printf("sigint_handler is stopping...\n");
|
||||
exit(130);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Finds the number of lines in a file (Which MUST end in a new-line, if the last
|
||||
line is to be counted) */
|
||||
|
||||
int num_of_lines(char* filename) {
|
||||
|
||||
int num_lines = 0;
|
||||
FILE* fp = fopen(filename,"r");
|
||||
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
User* fetch_user(char* username) {
|
||||
if (username == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
for (int c = getc(fp); c != EOF; c = getc(fp)) {
|
||||
if (c == '\n') {
|
||||
num_lines++;
|
||||
for (int i=0;i<num_users;i++) {
|
||||
if (strcmp(users[i]->username, username) == 0) {
|
||||
return users[i];
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return num_lines;
|
||||
int user_to_index(User* user) {
|
||||
int index = -1;
|
||||
for (int i=0;i < num_users; i++) {
|
||||
if (user_equals(users[i],user) == true) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
|
||||
}
|
||||
|
||||
bool user_equals(User* this, User* other) {
|
||||
if (( strcmp(this->username,other->username) == 0 ) && ( strcmp(this->password,other->password) == 0 )) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
26
message.c
26
message.c
@@ -4,22 +4,30 @@
|
||||
#include <time.h>
|
||||
#include "message.h"
|
||||
|
||||
Message new_message(char* string, User from, User to) {
|
||||
Message new_message;
|
||||
Message* new_message(char* string, User* from, User* to) {
|
||||
Message* new_message;
|
||||
|
||||
new_message.text = malloc((strlen(string)+1)*sizeof(char));
|
||||
strcpy(new_message.text,string);
|
||||
new_message = malloc(sizeof(Message));
|
||||
new_message->text = malloc((strlen(string)+1)*sizeof(char));
|
||||
strcpy(new_message->text,string);
|
||||
|
||||
new_message.sender = from;
|
||||
new_message.recipient = to;
|
||||
new_message->sender = malloc(sizeof(User));
|
||||
new_message->recipient = malloc(sizeof(User));
|
||||
|
||||
memcpy(new_message->sender, from, sizeof(User));
|
||||
memcpy(new_message->recipient, to, sizeof(User));
|
||||
|
||||
|
||||
// *(new_message->sender) = *from;
|
||||
// *(new_message->recipient) = *to;
|
||||
|
||||
time_t rawtime;
|
||||
struct tm timeinfo;
|
||||
struct tm* timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = *localtime(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
new_message.timeinfo = timeinfo;
|
||||
new_message->timeinfo = timeinfo;
|
||||
|
||||
return new_message;
|
||||
|
||||
|
@@ -10,11 +10,11 @@ typedef struct Message_s Message;
|
||||
|
||||
struct Message_s {
|
||||
char* text;
|
||||
struct tm timeinfo;
|
||||
User sender;
|
||||
User recipient;
|
||||
struct tm* timeinfo;
|
||||
User* sender;
|
||||
User* recipient;
|
||||
};
|
||||
|
||||
Message new_message(char* text,User from,User to);
|
||||
Message* new_message(char* text,User* from,User* to);
|
||||
|
||||
#endif
|
||||
|
81
message_helpers.c
Normal file
81
message_helpers.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <easysock.h>
|
||||
|
||||
#include "message_helpers.h"
|
||||
|
||||
char* fetch_from_string(char* message, char* indicator) {
|
||||
|
||||
char* message_copy = malloc(strlen(message));
|
||||
strcpy(message_copy,message);
|
||||
|
||||
char* token = malloc (sizeof(char) * strlen(message_copy));
|
||||
|
||||
char* string_to_search = malloc(strlen(indicator) + 1);
|
||||
strcpy(string_to_search,indicator);
|
||||
strcat(string_to_search,":");
|
||||
token = strtok(message_copy," r\n");
|
||||
while (strcmp(token,string_to_search) != 0) {
|
||||
token = strtok(NULL," \r\n");
|
||||
if (token == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
token = strtok(NULL," \r\n");
|
||||
return token;
|
||||
|
||||
}
|
||||
|
||||
char* fetch_message_string(char* message) {
|
||||
|
||||
char* message_copy = malloc(strlen(message));
|
||||
strcpy(message_copy,message);
|
||||
|
||||
int num_of_terminators = 0;
|
||||
int start_index = 0;
|
||||
int end_index = 0;
|
||||
int message_length = 0;
|
||||
|
||||
|
||||
char* start = strstr(message_copy,"START_OF_MESSAGE");
|
||||
if (start == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
start_index = start - message_copy;
|
||||
start_index += strlen("START_OF_MESSAGE");
|
||||
|
||||
while (*(message_copy + start_index) == '\n' || *(message_copy + start_index) == '\r') {
|
||||
start_index++;
|
||||
}
|
||||
|
||||
char* end = strstr(message_copy,"END_OF_MESSAGE");
|
||||
if (end == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
end_index = end - message_copy;
|
||||
|
||||
if (*(message_copy + end_index-2) == '\r') {
|
||||
num_of_terminators = 2;
|
||||
} else {
|
||||
num_of_terminators = 1;
|
||||
}
|
||||
|
||||
end_index -= num_of_terminators;
|
||||
|
||||
message_length = end_index - start_index;
|
||||
char* message_string = malloc(message_length + 2);
|
||||
|
||||
printf("Message goes from %d to %d\n",start_index,end_index);
|
||||
|
||||
for (int i=0; i<message_length; i++) { /* The reason the upper-bound is message_length-1 is because the last
|
||||
character is a new-line, which the user would not have typed. */
|
||||
|
||||
*(message_string + i) = *(message_copy + start_index + i);
|
||||
printf("%c",*(message_string + i));
|
||||
}
|
||||
|
||||
strcat(message_string,"\0");
|
||||
|
||||
// printf("%s\n",message_string);
|
||||
|
||||
// *(message_string + (message_length - num_of_terminators)) = '\0';
|
||||
return message_string;
|
||||
}
|
12
message_helpers.h
Normal file
12
message_helpers.h
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
/* If the message contains a string of the form:
|
||||
<Indicator>: <Value>
|
||||
Then return 'value' */
|
||||
char* fetch_from_string(char* message, char* indicator);
|
||||
|
||||
/* If the message contains a string of the form:
|
||||
START_OF_MESSAGE
|
||||
<text>
|
||||
END_OF_MESSAGE
|
||||
Then return <text> */
|
||||
char* fetch_message_string(char* message);
|
@@ -1,16 +0,0 @@
|
||||
#include <ncurses.h>
|
||||
|
||||
int getmaxy(WINDOW* window) {
|
||||
int y;
|
||||
int x;
|
||||
getmaxyx(window,y,x);
|
||||
return y;
|
||||
|
||||
}
|
||||
|
||||
int getmaxx(WINDOW* window) {
|
||||
int y;
|
||||
int x;
|
||||
getmaxyx(window,y,x);
|
||||
return x;
|
||||
}
|
62
stack.c
Normal file
62
stack.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "stack.h"
|
||||
|
||||
struct Stack {
|
||||
void** data;
|
||||
int top_index;
|
||||
int capacity;
|
||||
int curr_size;
|
||||
};
|
||||
|
||||
Stack* new_stack(int stack_size) {
|
||||
assert(stack_size > 0);
|
||||
Stack* my_stack = malloc(sizeof(Stack));
|
||||
my_stack->capacity = stack_size;
|
||||
my_stack->data = malloc(stack_size);
|
||||
my_stack->top_index = 0;
|
||||
my_stack->curr_size = 0;
|
||||
return my_stack;
|
||||
}
|
||||
|
||||
void stack_push(Stack* stack,void* element) {
|
||||
if (stack->curr_size >= stack->capacity-1) {
|
||||
stack->data = realloc(stack->data, stack->capacity*2);
|
||||
stack->capacity *= 2;
|
||||
}
|
||||
*(stack->data + stack->top_index) = element;
|
||||
stack->top_index++;
|
||||
stack->curr_size++;
|
||||
return;
|
||||
}
|
||||
|
||||
void* stack_pop(Stack* stack) {
|
||||
assert( !(stack_isEmpty(stack)) );
|
||||
// free(stack->data + stack->top_index);
|
||||
stack->top_index--;
|
||||
void* to_return = *(stack->data + stack->top_index);
|
||||
*(stack->data + stack->top_index) = NULL;
|
||||
|
||||
stack->curr_size--;
|
||||
|
||||
return to_return;
|
||||
}
|
||||
|
||||
void* stack_peek(Stack* stack) {
|
||||
void* to_return = *(stack->data + stack->top_index - 1);
|
||||
return to_return;
|
||||
}
|
||||
|
||||
int stack_size(Stack* stack) {
|
||||
return (stack->curr_size);
|
||||
}
|
||||
|
||||
bool stack_isEmpty(Stack* stack) {
|
||||
if (stack_size(stack) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
11
stack.h
Normal file
11
stack.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct Stack Stack;
|
||||
|
||||
Stack* new_stack(int stack_size);
|
||||
|
||||
void stack_push(Stack* stack, void* element);
|
||||
void* stack_pop(Stack* stack);
|
||||
void* stack_peek(Stack* stack);
|
||||
int stack_size(Stack* stack);
|
||||
bool stack_isEmpty(Stack* stack);
|
Reference in New Issue
Block a user