init commit
This commit is contained in:
commit
9904bd2212
16 changed files with 846 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
*.o
|
||||
1
README.md
Normal file
1
README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Addon Libraries to C Programming Language
|
||||
21
hashtable/Makefile
Normal file
21
hashtable/Makefile
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
CC=gcc
|
||||
CFLAGS=-Wall -Wextra
|
||||
|
||||
OBJS=test.o hashtable.o llist.o
|
||||
|
||||
all: test
|
||||
|
||||
test: $(OBJS)
|
||||
gcc -o $@ $^
|
||||
|
||||
test.o: test.c http.h
|
||||
|
||||
hashtable.o: hashtable.c hashtable.h
|
||||
|
||||
llist.o: llist.c llist.h
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
rm -f test
|
||||
|
||||
.PHONY: all, clean
|
||||
153
hashtable/hashtable.c
Normal file
153
hashtable/hashtable.c
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* hashtable.c - A basic hashtable implementation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "llist.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
#define SIZE 128
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* key;
|
||||
void* data;
|
||||
}
|
||||
HTEntry;
|
||||
|
||||
/**
|
||||
* Simple hash function used
|
||||
*/
|
||||
int hash(char* key, int ht_size)
|
||||
{
|
||||
int h = 0;
|
||||
|
||||
// basic modulo hash
|
||||
for (size_t i = 0; i < strlen(key); i++)
|
||||
{
|
||||
h = (31 * h + key[i]) % ht_size;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare function for searching a bucket
|
||||
*/
|
||||
int compare(void* data, void* arg)
|
||||
{
|
||||
char* key = arg;
|
||||
HTEntry* entry = data;
|
||||
return strcmp(entry->key, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete HT entry from bucket
|
||||
*/
|
||||
int delete_entry(void* data, void* arg)
|
||||
{
|
||||
(void) arg;
|
||||
HTEntry* entry = data;
|
||||
free(entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new hashtable
|
||||
*/
|
||||
HT* ht_create(void)
|
||||
{
|
||||
HT* ht = malloc(sizeof(HT));
|
||||
|
||||
ht->size = SIZE;
|
||||
ht->entries = 0;
|
||||
ht->store = malloc(ht->size * sizeof(LL*));
|
||||
|
||||
for (int i = 0; i < ht->size; i++)
|
||||
{
|
||||
ht->store[i] = ll_create();
|
||||
}
|
||||
|
||||
return ht;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new key value pair to a hashtable
|
||||
*/
|
||||
int ht_put(HT* ht, char* key, void* data)
|
||||
{
|
||||
int addr = hash(key, ht->size);
|
||||
|
||||
LL* bucket = ht->store[addr];
|
||||
|
||||
HTEntry* entry = malloc(sizeof(HTEntry));
|
||||
entry->key = strdup(key);
|
||||
entry->data = data;
|
||||
|
||||
ll_push(bucket, entry);
|
||||
|
||||
ht->entries++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from a hashtable with a key
|
||||
*/
|
||||
void* ht_get(HT* ht, char* key)
|
||||
{
|
||||
int addr = hash(key, ht->size);
|
||||
|
||||
LL* bucket = ht->store[addr];
|
||||
|
||||
HTEntry* entry = ll_search(bucket, compare, (void*) key);
|
||||
|
||||
if (entry == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a key value pair from a hashtable
|
||||
*/
|
||||
void* ht_delete(HT* ht, char* key)
|
||||
{
|
||||
int addr = hash(key, ht->size);
|
||||
|
||||
LL* bucket = ht->store[addr];
|
||||
|
||||
HTEntry* entry = ll_delete(bucket, compare, key);
|
||||
|
||||
if (entry == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ht->entries--;
|
||||
|
||||
return entry->data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy/free an entire hashtable
|
||||
*/
|
||||
int ht_free(HT* ht)
|
||||
{
|
||||
for (int i = 0; i < ht->size; i++)
|
||||
{
|
||||
LL* bucket = ht->store[i];
|
||||
ll_loop(bucket, delete_entry, NULL);
|
||||
ll_free(bucket);
|
||||
}
|
||||
|
||||
free(ht);
|
||||
|
||||
return 0;
|
||||
}
|
||||
24
hashtable/hashtable.h
Normal file
24
hashtable/hashtable.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef _HASHTABLE_H_
|
||||
#define _HASHTABLE_H_
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int size;
|
||||
int entries;
|
||||
LL** store;
|
||||
}
|
||||
HT;
|
||||
|
||||
HT* ht_create(void);
|
||||
|
||||
int ht_put(HT* ht, char* key, void* data);
|
||||
|
||||
void* ht_get(HT* ht, char* key);
|
||||
|
||||
void* ht_delete(HT* ht, char* key);
|
||||
|
||||
int ht_free(HT* ht);
|
||||
|
||||
#endif
|
||||
34
hashtable/test.c
Normal file
34
hashtable/test.c
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "hashtable.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Creating new hashtable...");
|
||||
|
||||
HT* ht = ht_create();
|
||||
|
||||
char* login_data = "This is the login data!";
|
||||
char* register_data = "This is the register data!";
|
||||
|
||||
puts("Putting in some data...");
|
||||
|
||||
ht_put(ht, "/login", login_data);
|
||||
ht_put(ht, "/register", register_data);
|
||||
|
||||
puts("Getting values and asserting they are correct...");
|
||||
|
||||
assert(login_data == ht_get(ht, "/login"));
|
||||
assert(register_data == ht_get(ht, "/register"));
|
||||
|
||||
puts("Checking that delete works...");
|
||||
|
||||
ht_delete(ht, "/login");
|
||||
|
||||
assert(ht_get(ht, "/login") == NULL);
|
||||
|
||||
puts("Tests complete!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
http/Makefile
Normal file
25
http/Makefile
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
CC=gcc
|
||||
CFLAGS=-Wall -Wextra
|
||||
|
||||
OBJS=test.o http.o net.o hashtable.o llist.o
|
||||
|
||||
all: test
|
||||
|
||||
test: $(OBJS)
|
||||
gcc -o $@ $^
|
||||
|
||||
test.o: test.c http.h
|
||||
|
||||
http.o: http.c http.h
|
||||
|
||||
net.o: net.c net.h
|
||||
|
||||
hashtable.o: hashtable.c hashtable.h
|
||||
|
||||
llist.o: llist.c llist.h
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
rm -f test
|
||||
|
||||
.PHONY: all, clean
|
||||
137
http/http.c
Normal file
137
http/http.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* http.c - Basic HTTP framework implentation
|
||||
*
|
||||
* hashtable.c for routing
|
||||
* listen.c for socket creation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "hashtable.h"
|
||||
#include "listen.h"
|
||||
#include "http.h"
|
||||
|
||||
#define BUF_SIZE 65536
|
||||
#define HTTP_RES "HTTP/1.1 %d MESSAGE\n"\
|
||||
"Connection: close\n"\
|
||||
"Content-Length: %d\n"\
|
||||
"Content-Type: %s\n"\
|
||||
"\n"\
|
||||
"%s"
|
||||
|
||||
HT* routes;
|
||||
|
||||
void use(char* path, Handler handler)
|
||||
{
|
||||
if (routes == NULL)
|
||||
{
|
||||
routes = ht_create();
|
||||
}
|
||||
|
||||
// TODO: handle for key exist
|
||||
ht_put(routes, path, (void*) handler);
|
||||
}
|
||||
|
||||
void send_response(int client, Res* res)
|
||||
{
|
||||
char res_raw[BUF_SIZE];
|
||||
|
||||
sprintf( res_raw,
|
||||
HTTP_RES,
|
||||
res->status,
|
||||
res->content_length,
|
||||
res->content_type,
|
||||
res->body) ;
|
||||
|
||||
int num_sent = send(client, res_raw, strlen(res_raw), 0);
|
||||
|
||||
if (num_sent < 0)
|
||||
{
|
||||
perror("send");
|
||||
}
|
||||
}
|
||||
|
||||
void fallback_handler(Res* res)
|
||||
{
|
||||
char* content = "Bad request\n";
|
||||
|
||||
res->status = 400;
|
||||
res->content_length = strlen(content);
|
||||
res->content_type = "text/html";
|
||||
res->body = content;
|
||||
}
|
||||
|
||||
void parse_req_raw(char* raw, Req* req)
|
||||
{
|
||||
printf("%s\n", raw);
|
||||
|
||||
sscanf(raw, "%s %s", req->type, req->path);
|
||||
}
|
||||
|
||||
void handle_request(int client)
|
||||
{
|
||||
char req_raw[BUF_SIZE];
|
||||
Req req;
|
||||
Res res;
|
||||
|
||||
int num_recvd = recv(client, req_raw, BUF_SIZE - 1, 0);
|
||||
|
||||
if (num_recvd < 0)
|
||||
{
|
||||
perror("recv");
|
||||
return;
|
||||
}
|
||||
|
||||
parse_req_raw(req_raw, &req); // TODO: handle for parse.
|
||||
|
||||
printf("Request: %s, %s\n", req.type, req.path);
|
||||
|
||||
Handler handler = ht_get(routes, req.path);
|
||||
|
||||
if (handler == NULL)
|
||||
{
|
||||
fallback_handler(&res);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler(&req, &res);
|
||||
}
|
||||
|
||||
send_response(client, &res);
|
||||
}
|
||||
|
||||
int http_start(char* port)
|
||||
{
|
||||
int client, server;
|
||||
|
||||
if ((server = init_server_socket(port)) < 0)
|
||||
{
|
||||
puts("Error when establishing the server.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Waiting for connections on port %s...\n", port);
|
||||
|
||||
while(1)
|
||||
{
|
||||
client = accept(server, (struct sockaddr*) NULL, NULL);
|
||||
|
||||
if (client == -1)
|
||||
{
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Client connected.\n");
|
||||
|
||||
handle_request(client);
|
||||
close(client);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
http/http.h
Normal file
31
http/http.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _HTTP_H_
|
||||
#define _HTTP_H_
|
||||
|
||||
#define PORT "3000"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char type[100];
|
||||
char path[200];
|
||||
}
|
||||
Req;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int status;
|
||||
char* content_type;
|
||||
int content_length;
|
||||
char* body;
|
||||
}
|
||||
Res;
|
||||
|
||||
/* User defined handlers must be this shape */
|
||||
typedef void (*Handler)(Req* req, Res* res);
|
||||
|
||||
/* Add an api endpoint */
|
||||
void use(char* path, Handler handler);
|
||||
|
||||
/* Start the server */
|
||||
int http_start(char* port);
|
||||
|
||||
#endif
|
||||
62
http/listen.c
Normal file
62
http/listen.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* listen.c - Create and bind a server socket to a port
|
||||
*
|
||||
*/
|
||||
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "listen.h"
|
||||
|
||||
#define QUEUE 8
|
||||
|
||||
|
||||
int init_server_socket(char* port)
|
||||
{
|
||||
int fd, yes = 1;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
getaddrinfo(NULL, port, &hints, &servinfo);
|
||||
|
||||
for (p = servinfo; p != NULL; p = p->ai_next)
|
||||
{
|
||||
if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
|
||||
{
|
||||
close(fd);
|
||||
freeaddrinfo(servinfo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(fd, p->ai_addr, p->ai_addrlen) == -1)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(servinfo);
|
||||
|
||||
if (p == NULL) { return -1; }
|
||||
|
||||
if (listen(fd, QUEUE) == -1)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
6
http/listen.h
Normal file
6
http/listen.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _LISTEN_H_
|
||||
#define _LISTEN_H_
|
||||
|
||||
int init_server_socket(char *port);
|
||||
|
||||
#endif
|
||||
48
http/main.c
Normal file
48
http/main.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* main.c - HTTP server that uses http.c framework
|
||||
*
|
||||
* curl http://localhost:3000/api/login
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "http.h"
|
||||
|
||||
void login(Req* req, Res* res)
|
||||
{
|
||||
(void) req;
|
||||
|
||||
char* content = "Login works!\n";
|
||||
|
||||
res->status = 200;
|
||||
res->content_length = strlen(content);
|
||||
res->content_type = "text/html";
|
||||
res->body = content;
|
||||
}
|
||||
|
||||
void signup(Req* req, Res* res)
|
||||
{
|
||||
(void) req;
|
||||
|
||||
char* content = "Sign Up works!\n";
|
||||
|
||||
res->status = 200;
|
||||
res->content_length = strlen(content);
|
||||
res->content_type = "text/html";
|
||||
res->body = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the endpoints and start the server.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
puts("Registering endpoints");
|
||||
|
||||
use("/signup", &signup);
|
||||
use("/login", &login);
|
||||
|
||||
http_start(PORT);
|
||||
}
|
||||
19
llist/Makefile
Normal file
19
llist/Makefile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
CC=gcc
|
||||
CFLAGS=-Wall -Wextra
|
||||
|
||||
OBJS=test.o llist.o
|
||||
|
||||
all: test
|
||||
|
||||
test: $(OBJS)
|
||||
gcc -o $@ $^
|
||||
|
||||
test.o: test.c
|
||||
|
||||
llist.o: llist.c llist.h
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
rm -f test
|
||||
|
||||
.PHONY: all, clean
|
||||
174
llist/llist.c
Normal file
174
llist/llist.c
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/**
|
||||
* llist.c - a basic linked list implementation.
|
||||
*
|
||||
* Used for the hashtable.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
/**
|
||||
* Node in the linked list
|
||||
*/
|
||||
typedef struct LLNodeT
|
||||
{
|
||||
void* data;
|
||||
struct LLNodeT* next;
|
||||
}
|
||||
LLNode;
|
||||
|
||||
/**
|
||||
* Create a new linked list
|
||||
*/
|
||||
LL* ll_create(void)
|
||||
{
|
||||
LL* ll = malloc(sizeof(LL));
|
||||
ll->entries = 0;
|
||||
return ll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item to beginning of a linked list
|
||||
*/
|
||||
int ll_push(LL* ll, void* data)
|
||||
{
|
||||
LLNode* n = malloc(sizeof(*n));
|
||||
|
||||
n->data = data;
|
||||
|
||||
// Reassign the head
|
||||
n->next = ll->head;
|
||||
ll->head = n;
|
||||
|
||||
ll->entries++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item to end of a linked list
|
||||
*/
|
||||
int ll_append(LL* ll, void* data)
|
||||
{
|
||||
LLNode* tail = ll->head;
|
||||
|
||||
// Just push if there are no nodes yet
|
||||
if (tail == NULL)
|
||||
{
|
||||
return ll_push(ll, data);
|
||||
}
|
||||
|
||||
// Travserse list to find tail
|
||||
while (tail->next != NULL)
|
||||
{
|
||||
tail = tail->next;
|
||||
}
|
||||
|
||||
// Create new node and assign it as tail
|
||||
LLNode* n = malloc(sizeof(LLNode));
|
||||
n->data = data;
|
||||
tail->next = n;
|
||||
|
||||
ll->entries++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from the list via cb function
|
||||
*/
|
||||
void* ll_search(LL* ll, LLCb cb, void* arg)
|
||||
{
|
||||
LLNode* n = ll->head;
|
||||
|
||||
// Keep going until tail is reached
|
||||
while (n != NULL)
|
||||
{
|
||||
if (cb(n->data, arg) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
if (n == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return n->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and delete an entry from a linked list
|
||||
*/
|
||||
void* ll_delete(LL* ll, LLCb cb, void* arg)
|
||||
{
|
||||
LLNode* n = ll->head, *prev = NULL;
|
||||
|
||||
while (n != NULL)
|
||||
{
|
||||
if (cb(n->data, arg) == 0)
|
||||
{
|
||||
void* data = n->data;
|
||||
|
||||
// We are at the head
|
||||
if (prev == NULL)
|
||||
{
|
||||
ll->head = n->next;
|
||||
free(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = n->next;
|
||||
free(n);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
prev = n;
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a function to every node in a linked list
|
||||
*/
|
||||
int ll_loop(LL* ll, LLCb cb, void* arg)
|
||||
{
|
||||
LLNode* n = ll->head, *next;
|
||||
|
||||
while (n != NULL)
|
||||
{
|
||||
next = n->next;
|
||||
cb(n->data, arg);
|
||||
n = next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a linked list
|
||||
*/
|
||||
void ll_free(LL* ll)
|
||||
{
|
||||
LLNode* n = ll->head, *next;
|
||||
|
||||
while (n != NULL)
|
||||
{
|
||||
next = n->next;
|
||||
free(n);
|
||||
n = next;
|
||||
}
|
||||
|
||||
free(ll);
|
||||
}
|
||||
|
||||
27
llist/llist.h
Normal file
27
llist/llist.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef _LLIST_H_
|
||||
#define _LLIST_H_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct LLNodeT* head;
|
||||
int entries;
|
||||
}
|
||||
LL;
|
||||
|
||||
typedef int (*LLCb)(void*, void*);
|
||||
|
||||
LL* ll_create(void);
|
||||
|
||||
int ll_push(LL* ll, void* data);
|
||||
|
||||
int ll_append(LL* ll, void* data);
|
||||
|
||||
void* ll_search(LL* ll, LLCb cb, void* arg);
|
||||
|
||||
void* ll_delete(LL* ll, LLCb cb, void* arg);
|
||||
|
||||
int ll_loop(LL* ll, LLCb cb, void* arg);
|
||||
|
||||
void ll_free(LL* ll);
|
||||
|
||||
#endif
|
||||
83
llist/test.c
Normal file
83
llist/test.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
char* team;
|
||||
int age;
|
||||
}
|
||||
Player;
|
||||
|
||||
Player* create_player(char* name, char* team, int age)
|
||||
{
|
||||
Player* p = malloc(sizeof(*p));
|
||||
p->team = strdup(team);
|
||||
p->name = strdup(name);
|
||||
p->age = age;
|
||||
return p;
|
||||
}
|
||||
|
||||
int find_player(void* data, void* arg)
|
||||
{
|
||||
Player* player = data;
|
||||
return strcmp(player->name, (char*) arg);
|
||||
}
|
||||
|
||||
int change_team(void* data, void* arg)
|
||||
{
|
||||
Player* player = data;
|
||||
player->team = (char*) arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Creating new linked list...");
|
||||
|
||||
LL* ll = ll_create();
|
||||
|
||||
puts("Pushing some data...");
|
||||
|
||||
Player* lebron = create_player("Lebron James", "Lakers", 37);
|
||||
Player* giannis = create_player("Giannis Antetokounmpo", "Bucks", 27);
|
||||
|
||||
ll_push(ll, lebron);
|
||||
ll_push(ll, giannis);
|
||||
|
||||
puts("Finding the data that was pushed...");
|
||||
|
||||
assert(ll_search(ll, find_player, "Lebron James") == lebron);
|
||||
|
||||
puts("Appending some data...");
|
||||
|
||||
Player* kd = create_player("Kevin Durant", "Nets", 33);
|
||||
|
||||
ll_append(ll, kd);
|
||||
|
||||
puts("Finding the data that was appended...");
|
||||
|
||||
assert(ll_search(ll, find_player, "Kevin Durant") == kd);
|
||||
|
||||
puts("Looping over linked list and applying change...");
|
||||
|
||||
ll_loop(ll, change_team, "Bucks");
|
||||
|
||||
Player* kd_ref = ll_search(ll, find_player, "Kevin Durant");
|
||||
|
||||
assert(strcmp(kd_ref->team, "Bucks") == 0);
|
||||
|
||||
puts("Deleting data from linked list...");
|
||||
|
||||
ll_delete(ll, find_player, "Lebron James");
|
||||
|
||||
assert(ll_search(ll, find_player, "Lebron James") == NULL);
|
||||
|
||||
puts("Tests complete!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue