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:
Barry Kane 2022-12-18 21:07:10 +00:00
parent 2ab873b40b
commit 8ae3eaf2b8
9 changed files with 410 additions and 8 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -47,9 +47,9 @@ typedef struct list
listNode * tail;
} list;
// ==================
// ========================
// -=[ Functions ]=-:
// ==================
// ========================
// Allocates and instantiates a list of the specified type:
list * createList(listDataType type);

206
src/queue.c Normal file
View File

@ -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;
}

62
src/queue.h Normal file
View File

@ -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

View File

@ -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)

View File

@ -33,4 +33,5 @@ char * logostring =
" # # ### ##### ##### ### # # # # #### ### /\n";
void wrapString(char * stringToWrap, int stringLength, int screenWidth);
#endif

132
tests/queue-test.c Normal file
View File

@ -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);
}