Added queue.c and queue.h.
- Added a singular queue type for input/output messages and commands. - Added a test of the queue type in tests. - Made some edits to the Makefile to enable the addition of debug code using the preprocessor. - Minor styling and spelling updates in gamelogic.c/h and text effects .h. - Ready to integrate the new queue type in place of the previous ones.
This commit is contained in:
parent
2ab873b40b
commit
8ae3eaf2b8
2
Makefile
2
Makefile
|
@ -25,5 +25,5 @@ clean:
|
|||
|
||||
all: clean SilverMUDClient SilverMUDServer
|
||||
all: CFLAGS += -Wall -Wextra -Ofast
|
||||
debug: CFLAGS += -Wall -Wextra -pg -ggdb -Og
|
||||
debug: CFLAGS += -Wall -Wextra -pg -ggdb -Og -D debug
|
||||
debug: clean SilverMUDClientDebug SilverMUDServerDebug
|
||||
|
|
|
@ -136,6 +136,8 @@ int queueMessagedCommand(commandQueue * queue, inputMessage * messageToQueue)
|
|||
// Check that we're not overflowing the queue:
|
||||
if ((queue->currentLength + 1) > MAXQUEUELENGTH)
|
||||
{
|
||||
// Free the new command, it's getting dumped:
|
||||
free(newCommand);
|
||||
// Unlock the queue:
|
||||
queue->lock = false;
|
||||
return -1;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// gamelogic.h: Header file contatning function prototypes and datastructures
|
||||
// for dealing with the game's logic.
|
||||
// gamelogic.h: Function prototypes and data-structures for dealing with game logic.
|
||||
// Barry Kane, 2022.
|
||||
#ifndef GAMELOGIC_H
|
||||
#define GAMELOGIC_H
|
||||
|
@ -12,7 +11,7 @@
|
|||
// -=[ Main Game Loop ]=-:
|
||||
// =======================
|
||||
|
||||
// A datastructure containing the needed parameters for a main game loop:
|
||||
// A data-structure containing the needed parameters for a main game loop:
|
||||
typedef struct gameLogicParameters
|
||||
{
|
||||
int * playerCount;
|
||||
|
|
|
@ -47,9 +47,9 @@ typedef struct list
|
|||
listNode * tail;
|
||||
} list;
|
||||
|
||||
// ==================
|
||||
// -=[ Functions ]=-:
|
||||
// ==================
|
||||
// ========================
|
||||
// -=[ Functions ]=-:
|
||||
// ========================
|
||||
|
||||
// Allocates and instantiates a list of the specified type:
|
||||
list * createList(listDataType type);
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
// queue.c: Implements the queue data type and associated functions for SilverMUD.
|
||||
// Barry Kane, 2022
|
||||
#include "queue.h"
|
||||
|
||||
// Allocates and instantiates a queue:
|
||||
queue * createQueue(void)
|
||||
{
|
||||
// Allocate the memory for the queue:
|
||||
queue * newQueue = malloc(sizeof(queue));
|
||||
|
||||
// Instantiate the variables in the data-structure:
|
||||
newQueue->itemCount = 0;
|
||||
newQueue->front = NULL;
|
||||
newQueue->back = NULL;
|
||||
|
||||
// Return the pointer to the new queue:
|
||||
return newQueue;
|
||||
}
|
||||
|
||||
// Destroys a queue and all of it's members:
|
||||
void destroyQueue(queue ** queue)
|
||||
{
|
||||
// Pop everything off of the queue:
|
||||
while ((*queue)->itemCount > 0)
|
||||
{
|
||||
popQueue(*queue);
|
||||
}
|
||||
|
||||
// Deallocate the queue:
|
||||
free(*queue);
|
||||
}
|
||||
|
||||
// Returns the data at the front of the given queue:
|
||||
queueNode * peekQueue(queue * queue)
|
||||
{
|
||||
return queue->front;
|
||||
}
|
||||
|
||||
// Removes the current data from the front of the queue:
|
||||
void popQueue(queue * queue)
|
||||
{
|
||||
// Check if the queue is locked, and wait:
|
||||
while (queue->lock);
|
||||
|
||||
// Lock the queue:
|
||||
queue->lock = true;
|
||||
|
||||
// Check there is actually anything to remove:
|
||||
if (queue->itemCount == 0)
|
||||
{
|
||||
queue->lock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the special case of being the last item in the queue:
|
||||
else if (queue->itemCount == 1)
|
||||
{
|
||||
// Deallocate the correct data:
|
||||
switch (queue->front->type)
|
||||
{
|
||||
case EVENT:
|
||||
{
|
||||
// TODO: Implement events.
|
||||
}
|
||||
case COMMAND:
|
||||
{
|
||||
free(queue->front->data.command->command);
|
||||
free(queue->front->data.command->arguments);
|
||||
free(queue->front->data.command);
|
||||
break;
|
||||
}
|
||||
case INPUT_MESSAGE:
|
||||
{
|
||||
free(queue->front->data.inputMessage->content);
|
||||
free(queue->front->data.inputMessage);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_MESSAGE:
|
||||
{
|
||||
free(queue->front->data.outputMessage->content);
|
||||
free(queue->front->data.outputMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Deallocate the node:
|
||||
free(queue->front);
|
||||
|
||||
// Set the correct variables for the queue:
|
||||
queue->front = NULL;
|
||||
queue->back = NULL;
|
||||
queue->itemCount = 0;
|
||||
|
||||
// Unlock the queue:
|
||||
queue->lock = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the current front of the queue:
|
||||
else
|
||||
{
|
||||
// Deallocate the correct data:
|
||||
switch (queue->front->type)
|
||||
{
|
||||
case EVENT:
|
||||
{
|
||||
// TODO: Implement events.
|
||||
break;
|
||||
}
|
||||
case COMMAND:
|
||||
{
|
||||
free(queue->front->data.command->command);
|
||||
free(queue->front->data.command->arguments);
|
||||
free(queue->front->data.command);
|
||||
break;
|
||||
}
|
||||
case INPUT_MESSAGE:
|
||||
{
|
||||
free(queue->front->data.inputMessage->content);
|
||||
free(queue->front->data.inputMessage);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_MESSAGE:
|
||||
{
|
||||
free(queue->front->data.outputMessage->content);
|
||||
free(queue->front->data.outputMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Save a pointer to the current node so we don't leak it:
|
||||
queueNode * nodeToDelete = queue->front;
|
||||
|
||||
// Advance the queue:
|
||||
queue->front = queue->front->next;
|
||||
queue->itemCount--;
|
||||
|
||||
// Deallocate the old node:
|
||||
free(nodeToDelete);
|
||||
|
||||
// Unlock the queue:
|
||||
queue->lock = false;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Adds data to the back of a queue:
|
||||
void pushQueue(queue * queue, void * data, queueDataType type)
|
||||
{
|
||||
// Create a new node:
|
||||
queueNode * newNode = malloc(sizeof(queueNode));
|
||||
|
||||
// Copy the data into the correct slot for the type:
|
||||
switch (type)
|
||||
{
|
||||
case EVENT:
|
||||
{
|
||||
// TODO: Implement events.
|
||||
break;
|
||||
}
|
||||
case COMMAND:
|
||||
{
|
||||
newNode->data.command = data;
|
||||
break;
|
||||
}
|
||||
case INPUT_MESSAGE:
|
||||
{
|
||||
newNode->data.inputMessage = data;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_MESSAGE:
|
||||
{
|
||||
newNode->data.outputMessage = data;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check if the queue is locked:
|
||||
while (queue->lock);
|
||||
|
||||
// Lock the queue:
|
||||
queue->lock = true;
|
||||
|
||||
// Set the correct pointers:
|
||||
newNode->next = NULL;
|
||||
|
||||
if (queue->itemCount == 0)
|
||||
{
|
||||
queue->front = newNode;
|
||||
queue->back = newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->back->next = newNode;
|
||||
queue->back = newNode;
|
||||
}
|
||||
|
||||
// Increase the queue item count:
|
||||
queue->itemCount++;
|
||||
|
||||
// Unlock the queue:
|
||||
queue->lock = false;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// queue.h: Defines the queue data type and associated function prototypes for SilverMUD.
|
||||
// Barry Kane, 2022
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
#include "gamelogic.h"
|
||||
#include "inputoutput.h"
|
||||
|
||||
// ========================
|
||||
// -=[ Data Structures ]=-:
|
||||
// ========================
|
||||
|
||||
typedef enum queueDataType
|
||||
{
|
||||
EVENT,
|
||||
COMMAND,
|
||||
INPUT_MESSAGE,
|
||||
OUTPUT_MESSAGE
|
||||
} queueDataType;
|
||||
|
||||
typedef union queueData
|
||||
{
|
||||
outputMessage * outputMessage;
|
||||
inputMessage * inputMessage;
|
||||
commandEvent * command;
|
||||
} queueData;
|
||||
|
||||
typedef struct queueNode queueNode;
|
||||
typedef struct queueNode
|
||||
{
|
||||
queueDataType type;
|
||||
queueData data;
|
||||
queueNode * next;
|
||||
} queueNode;
|
||||
|
||||
typedef struct queue
|
||||
{
|
||||
bool lock;
|
||||
size_t itemCount;
|
||||
queueNode * front;
|
||||
queueNode * back;
|
||||
} queue;
|
||||
|
||||
// ========================
|
||||
// -=[ Functions ]=-:
|
||||
// ========================
|
||||
|
||||
// Allocates and instantiates a queue:
|
||||
queue * createQueue(void);
|
||||
|
||||
// Destroys a queue and all of it's members:
|
||||
void destroyQueue(queue ** queue);
|
||||
|
||||
// Returns the node at the front of the given queue:
|
||||
queueNode * peekQueue(queue * queue);
|
||||
|
||||
// Removes the current node from the front of the queue:
|
||||
void popQueue(queue * queue);
|
||||
|
||||
// Adds data to the back of a queue:
|
||||
void pushQueue(queue * queue, void * data, queueDataType type);
|
||||
|
||||
#endif
|
|
@ -29,7 +29,7 @@ typedef struct sockaddr sockaddr;
|
|||
void sigintHandler(int signal)
|
||||
{
|
||||
printf("Caught signal %d.\n", signal);
|
||||
exit(EXIT_SUCCESS);
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
|
|
|
@ -33,4 +33,5 @@ char * logostring =
|
|||
" # # ### ##### ##### ### # # # # #### ### /\n";
|
||||
|
||||
void wrapString(char * stringToWrap, int stringLength, int screenWidth);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// Test for the queue type in SilverMUD:
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "../src/queue.h"
|
||||
|
||||
#define formatBoolean(b) ((b) ? "true" : "false")
|
||||
#define formatEquality(b) ((b) ? "equal" : "not equal")
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Create a queue:
|
||||
printf("-=[ Creating queue ]=-:\n");
|
||||
queue * testQueue = createQueue();
|
||||
|
||||
// Check that the queue has the correct values:
|
||||
printf("-=[ Checking initial values ]=-:\n");
|
||||
|
||||
printf("- Item count should be 0:\n");
|
||||
assert(testQueue->itemCount == 0);
|
||||
printf("Item count is %d.\n\n", testQueue->itemCount);
|
||||
|
||||
printf("- Lock should be false:\n");
|
||||
assert(testQueue->lock == false);
|
||||
printf("Lock is %s.\n\n", formatBoolean(testQueue->lock));
|
||||
|
||||
printf("- Front should be (nil):\n");
|
||||
assert(testQueue->front == NULL);
|
||||
printf("Front is %p.\n\n", testQueue->front);
|
||||
|
||||
printf("- Back should be (nil):\n");
|
||||
assert(testQueue->back == NULL);
|
||||
printf("Back is %p.\n\n", testQueue->front);
|
||||
|
||||
// Create some items for the queue:
|
||||
inputMessage * testInputMessage = malloc(sizeof(inputMessage));
|
||||
testInputMessage->sender = NULL;
|
||||
testInputMessage->next = NULL;
|
||||
testInputMessage->content = malloc(sizeof(userMessage));
|
||||
strcpy(testInputMessage->content->senderName,"Queue Test Input Sender");
|
||||
strcpy(testInputMessage->content->messageContent, "Queue Test Input Content - Hello!");
|
||||
|
||||
outputMessage * testOutputMessage = malloc(sizeof(outputMessage));
|
||||
for(int index = 0; index < PLAYERCOUNT; index++)
|
||||
{
|
||||
testOutputMessage->targets[index] = NULL;
|
||||
}
|
||||
testOutputMessage->next = NULL;
|
||||
testOutputMessage->content = malloc(sizeof(userMessage));
|
||||
strcpy(testOutputMessage->content->senderName, "Queue Test Output Sender");
|
||||
strcpy(testOutputMessage->content->messageContent, "Queue Test Output Content - World!");
|
||||
|
||||
commandEvent * testCommandEvent = malloc(sizeof(commandEvent));
|
||||
testCommandEvent->next = NULL;
|
||||
testCommandEvent->caller = NULL;
|
||||
testCommandEvent->command = malloc(5 * sizeof(char));
|
||||
testCommandEvent->arguments = malloc(15 * sizeof(char));
|
||||
strcpy(testCommandEvent->command, "Test");
|
||||
strcpy(testCommandEvent->arguments, "Test Arguments");
|
||||
|
||||
// Add them to the queue:
|
||||
printf("-=[ Adding items to the queue ]=-:\n");
|
||||
printf("- First item, Item count should be 1. Front and Back should be equal.\n");
|
||||
pushQueue(testQueue, testInputMessage, INPUT_MESSAGE);
|
||||
assert(testQueue->itemCount == 1);
|
||||
assert(testQueue->front == testQueue->back);
|
||||
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||
formatEquality(testQueue->front == testQueue->back));
|
||||
|
||||
printf("- Second item, Item count should be 2. Front and Back should be not equal.\n");
|
||||
pushQueue(testQueue, testOutputMessage, OUTPUT_MESSAGE);
|
||||
assert(testQueue->itemCount == 2);
|
||||
assert(testQueue->front != testQueue->back);
|
||||
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||
formatEquality(testQueue->front == testQueue->back));
|
||||
|
||||
printf("- Third item, Item count should be 3. Front and Back should be not equal.\n");
|
||||
pushQueue(testQueue, testCommandEvent, COMMAND);
|
||||
assert(testQueue->itemCount == 3);
|
||||
assert(testQueue->front != testQueue->back);
|
||||
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||
formatEquality(testQueue->front == testQueue->back));
|
||||
|
||||
printf("-=[ Checking items and popping from queue ]=-:\n");
|
||||
printf("- First item peeked should point to testInputMessage.\n");
|
||||
assert(peekQueue(testQueue)->data.inputMessage == testInputMessage);
|
||||
printf("Peeked data is located at: %p, testInputMessage is located at: %p.\n\n",
|
||||
peekQueue(testQueue)->data.inputMessage, testInputMessage);
|
||||
|
||||
printf("- Popping first item, Item count should be 2, Front and Back should not be equal.\n");
|
||||
popQueue(testQueue);
|
||||
assert(testQueue->itemCount == 2);
|
||||
assert(testQueue->front != testQueue->back);
|
||||
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||
formatEquality(testQueue->front == testQueue->back));
|
||||
|
||||
printf("- Second item peeked should point to testOutputMessage.\n");
|
||||
assert(peekQueue(testQueue)->data.outputMessage == testOutputMessage);
|
||||
printf("Peeked data is located at: %p, testOutputMessage is located at: %p.\n\n",
|
||||
peekQueue(testQueue)->data.outputMessage, testOutputMessage);
|
||||
|
||||
printf("- Popping second item, Item count should be 1, Front and Back should be equal.\n");
|
||||
popQueue(testQueue);
|
||||
assert(testQueue->itemCount == 1);
|
||||
assert(testQueue->front == testQueue->back);
|
||||
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||
formatEquality(testQueue->front == testQueue->back));
|
||||
|
||||
printf("- Third item peeked should point to testCommandEvent.\n");
|
||||
assert(peekQueue(testQueue)->data.command == testCommandEvent);
|
||||
printf("Peeked data is located at: %p, testCommandEvent is located at: %p.\n\n",
|
||||
peekQueue(testQueue)->data.command, testCommandEvent);
|
||||
|
||||
printf("- Popping third item:\n");
|
||||
popQueue(testQueue);
|
||||
|
||||
printf("- Item count should be 0:\n");
|
||||
assert(testQueue->itemCount == 0);
|
||||
printf("Item count is %d.\n\n", testQueue->itemCount);
|
||||
|
||||
printf("- Lock should be false:\n");
|
||||
assert(testQueue->lock == false);
|
||||
printf("Lock is %s.\n\n", formatBoolean(testQueue->lock));
|
||||
|
||||
printf("- Front should be (nil):\n");
|
||||
assert(testQueue->front == NULL);
|
||||
printf("Front is %p.\n\n", testQueue->front);
|
||||
|
||||
printf("- Back should be (nil):\n");
|
||||
assert(testQueue->back == NULL);
|
||||
printf("Back is %p.\n\n", testQueue->front);
|
||||
}
|
Loading…
Reference in New Issue