diff --git a/src/message_logger.c b/src/message_logger.c
index a37b22c..cb9da4e 100644
--- a/src/message_logger.c
+++ b/src/message_logger.c
@@ -2,6 +2,13 @@
// MIT License
// Message logger module - Source code.
+//! \file message_logger.c
+//! \author André Filipe Caldas Laranjeira
+//! \brief Message logger module - Source code.
+//!
+//! The Message Logger module source file contains the implementation of all
+//! the functions provided by the Message Logger module and private state
+//! variables.
// Includes:
#include "message_logger.h"
@@ -33,6 +40,34 @@ static void print_context(const char*);
static void print_formatted_text(const char*, va_list);
// Public function implementations:
+
+//! \fn int configure_log_file(const char *file_name, LogFileMode file_mode)
+//! \brief Configure a log file to store the Message Logger's messages.
+//! Allocates resources, requiring a call to logger_module_clean_up()
+//! afterwards.
+//! \param file_name Name of the file used to log messages.
+//! \param file_mode Mode used for opening the log file.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function configures the Message Logger module to write any messages to
+//! a log file, in adition to priting them on the screen. Each message written
+//! on the log file has the message's contents and information on the message's
+//! datetime.
+//!
+//! If an error occurs when configuring the log file, this function will return
+//! -1 and the Message Logger will print an error message explaining what went
+//! wrong.
+//!
+//! \b Important: After the Message Logger module is no longer used, the
+//! function logger_module_clean_up() must be called to close the log file
+//! created.
+//!
+//! Usage example:
+//! \code
+//! configure_log_file("logger-test.log", WRITE);
+//! // Use the Message Logger normally...
+//! logger_module_clean_up();
+//! \endcode
int configure_log_file(const char *file_name , LogFileMode file_mode) {
// Acquire logger recursive lock if thread safety is enabled:
@@ -83,6 +118,37 @@ int configure_log_file(const char *file_name , LogFileMode file_mode) {
}
+//! \fn int enable_thread_safety()
+//! \brief Enable thread safety for the Message Logger's operations. Allocates
+//! resources, requiring a call to logger_module_clean_up() afterwards.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function configures the Message Logger module to enable thread safety
+//! when logging messages or executing other logger operations. This allows the
+//! logger to be utilized in a multi-threaded environment with the pthreads
+//! library without the nuissance of race conditions or other problems.
+//!
+//! If an error occurs when enabling thread safety, this function will return
+//! -1 and the Message Logger will print an error message explaining what went
+//! wrong.
+//!
+//! \b Important: After the Message Logger module is no longer used, the
+//! function logger_module_clean_up() must be called to release the memory
+//! allocated for the thread-safety data structures utilized.
+//!
+//! Usage example:
+//! \code
+//! // In the main thread, before creating other threads, enable thread safety.
+//! enable_thread_safety();
+//!
+//! // ...
+//! // Create multiple threads to use the Message Logger...
+//!
+//! // ...
+//! // In the main thread, after other threads have been joined (and the
+//! // logger is no longer used), call the clean up function.
+//! logger_module_clean_up();
+//! \endcode
int enable_thread_safety() {
pthread_mutexattr_t logger_mutex_attributes;
@@ -108,6 +174,35 @@ int enable_thread_safety() {
}
+//! \fn int get_logger_msg_colors(
+//! DisplayColors* display_colors_destination,
+//! MessageCategory requested_category
+//! )
+//! \brief Get the display colors in the Message Logger for a message category.
+//! \param display_colors_destination Pointer to where the requested display
+//! colors are copied to. Must NOT be NULL.
+//! \param requested_category Category of message whose display colors will be
+//! copied.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function returns the DisplayColors currently assigned to a
+//! #MessageCategory in the Message Logger. The DisplayColors information is
+//! copied from the logger's LoggerColorPallet to the pointer provided by the
+//! user.
+//!
+//! If an error occurs when getting the display colors, this function will
+//! return -1 and the Message Logger will print an error message explaining
+//! what went wrong.
+//!
+//! \b Important: This function MUST receive a non-NULL DisplayColors pointer
+//! to copy the information to. This function does NOT allocate memory on the
+//! pointer provided by the user.
+//!
+//! Usage example:
+//! \code
+//! DisplayColors current_success_message_colors;
+//! get_logger_msg_colors(¤t_success_message_colors, SUCCESS_MSG);
+//! \endcode
int get_logger_msg_colors(
DisplayColors* display_colors_destination,
MessageCategory requested_category
@@ -139,6 +234,34 @@ int get_logger_msg_colors(
}
+//! \fn int get_logger_tag_colors(
+//! DisplayColors* display_colors_destination,
+//! TagCategory requested_category
+//! )
+//! \brief Get the display colors in the Message Logger for a tag category.
+//! \param display_colors_destination Pointer to where the requested display
+//! colors are copied to. Must NOT be NULL.
+//! \param requested_category Category of tag whose display colors will be
+//! copied.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function returns the DisplayColors currently assigned to a
+//! #TagCategory in the Message Logger. The DisplayColors information is copied
+//! from the logger's LoggerColorPallet to the pointer provided by the user.
+//!
+//! If an error occurs when getting the display colors, this function will
+//! return -1 and the Message Logger will print an error message explaining
+//! what went wrong.
+//!
+//! \b Important: This function MUST receive a non-NULL DisplayColors pointer
+//! to copy the information to. This function does NOT allocate memory on the
+//! pointer provided by the user.
+//!
+//! Usage example:
+//! \code
+//! DisplayColors current_success_tag_colors;
+//! get_logger_tag_colors(¤t_success_tag_colors, SUCCESS_TAG);
+//! \endcode
int get_logger_tag_colors(
DisplayColors* display_colors_destination,
TagCategory requested_category
@@ -170,6 +293,30 @@ int get_logger_tag_colors(
}
+//! \fn int get_time_format(TimeFormat *time_format_destination)
+//! \brief Get the time format used by the Message Logger in log files.
+//! \param time_format_destination Pointer to where the requested time format
+//! is copied to. Must NOT be NULL.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function returns the TimeFormat currently used by the Message Logger
+//! to determine how to format the time information written to log files. The
+//! TimeFormat information is copied from the logger's internal variables to
+//! the pointer provided by the user.
+//!
+//! If an error occurs when getting the time format, this function will return
+//! -1 and the Message Logger will print an error message explaining what went
+//! wrong.
+//!
+//! \b Important: This function MUST receive a non-NULL TimeFormat pointer
+//! to copy the information to. This function does NOT allocate memory on the
+//! pointer provided by the user.
+//!
+//! Usage example:
+//! \code
+//! TimeFormat logger_time_format;
+//! get_time_format(&logger_time_format);
+//! \endcode
int get_time_format(TimeFormat *time_format_destination) {
if(time_format_destination == NULL) {
@@ -200,6 +347,36 @@ int get_time_format(TimeFormat *time_format_destination) {
}
+//! \fn int set_logger_msg_colors(
+//! MessageCategory message_category,
+//! const DisplayColors *assigned_colors
+//! )
+//! \brief Set the display colors used by the Message Logger for a message
+//! category.
+//! \param message_category Category of message whose display colors are being
+//! set.
+//! \param assigned_colors Pointer to the display colors being copied to a
+//! message category of the Message Logger's LoggerColorPallet.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function sets the display colors for a given #MessageCategory in the
+//! Message Logger's LoggerColorPallet. This is done by copying the information
+//! from a valid, non-NULL DisplayColors pointer provided by the user to an
+//! index of the \link LoggerColorPallet::message_colors message_colors
+//! \endlink array.
+//!
+//! If an error occurs when setting the display colors, this function will
+//! return -1 and the Message Logger will print an error message explaining
+//! what went wrong.
+//!
+//! Usage example:
+//! \code
+//! DisplayColors custom_info_msg_colors = {
+//! .text_color = B_WHT,
+//! .background_color = CYN
+//! };
+//! set_logger_msg_colors(INFO_MSG, &custom_info_msg_colors);
+//! \endcode
int set_logger_msg_colors(
MessageCategory message_category,
const DisplayColors *assigned_colors
@@ -231,6 +408,34 @@ int set_logger_msg_colors(
}
+//! \fn int set_logger_tag_colors(
+//! TagCategory tag_category,
+//! const DisplayColors *assigned_colors
+//! )
+//! \brief Set the display colors used by the Message Logger for a tag
+//! category.
+//! \param tag_category Category of tag whose display colors are being set.
+//! \param assigned_colors Pointer to the display colors being copied to a tag
+//! category of the Message Logger's LoggerColorPallet.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function sets the display colors for a given #TagCategory in the
+//! Message Logger's LoggerColorPallet. This is done by copying the information
+//! from a valid, non-NULL DisplayColors pointer provided by the user to an
+//! index of the \link LoggerColorPallet::tag_colors tag_colors \endlink array.
+//!
+//! If an error occurs when setting the display colors, this function will
+//! return -1 and the Message Logger will print an error message explaining
+//! what went wrong.
+//!
+//! Usage example:
+//! \code
+//! DisplayColors custom_info_tag_colors = {
+//! .text_color = B_BLA,
+//! .background_color = CYN
+//! };
+//! set_logger_tag_colors(INFO_TAG, &custom_info_tag_colors);
+//! \endcode
int set_logger_tag_colors(
TagCategory tag_category,
const DisplayColors *assigned_colors
@@ -262,6 +467,26 @@ int set_logger_tag_colors(
}
+//! \fn int set_time_format(const char *new_format)
+//! \brief Set the time format used by the Message Logger in log files.
+//! \param new_format String representation of the time format to be used. Size
+//! must be smaller or equal to #TIME_FMT_SIZE.
+//! \return Returns 0 when successfully executed and -1 if an error occurs.
+//!
+//! This function sets the \link TimeFormat::string_representation
+//! string_representation \endlink in the Message Logger's TimeFormat, which is
+//! used when saving messages to a log file if one is configured. The time
+//! format information is copied from a valid, non-NULL pointer provided by the
+//! user.
+//!
+//! If an error occurs when setting the time format, this function will return
+//! -1 and the Message Logger will print an error message explaining what went
+//! wrong.
+//!
+//! Usage example:
+//! \code
+//! set_time_format("%c");
+//! \endcode
int set_time_format(const char *new_format) {
if(new_format == NULL) {
@@ -298,6 +523,20 @@ int set_time_format(const char *new_format) {
}
+//! \fn void color_background(Color p_color)
+//! \brief Changes the terminal text's background color to a specific #Color.
+//! \param p_color Color to be applied to the terminal text's background.
+//!
+//! This function changes the terminal text's background color to a #Color
+//! provided by the user. When line breaks occur, the entire line's background
+//! is colored, not just the portion with text. If this function is called in
+//! the middle of a text line, any existing background color will be cleared
+//! after the cursor's position.
+//!
+//! Usage example:
+//! \code
+//! color_background(B_GRN);
+//! \endcode
void color_background(Color p_color) {
// Acquire logger recursive lock if thread safety is enabled:
@@ -384,6 +623,18 @@ void color_background(Color p_color) {
}
+//! \fn void color_text(Color p_color)
+//! \brief Changes the terminal text's font color to a specific #Color.
+//! \param p_color Color to be applied to the terminal text's font.
+//!
+//! This function changes the terminal text's font color to a #Color provided by
+//! the user. Bright colors are accompanied by a bold font weight, while the
+//! other font colors are accompanied by a regular font weight.
+//!
+//! Usage example:
+//! \code
+//! color_text(BLU);
+//! \endcode
void color_text(Color p_color) {
// Acquire logger recursive lock if thread safety is enabled:
@@ -468,6 +719,27 @@ void color_text(Color p_color) {
}
+//! \fn void error(const char *context, const char *format, ...)
+//! \brief Log an error message using the Message Logger.
+//! \param context Caller context where message originated. Pass a NULL pointer
+//! for an empty context.
+//! \param format String formatting for the message's contents before argument
+//! substitution takes place.
+//! \param ... Arguments used to substitute placeholders in the message's
+//! contents.
+//!
+//! This function logs an error message to the terminal and configured log
+//! file. The message contains the caller context that originated the error, a
+//! tag that identifies the message as an error and the message's contents. If
+//! a log file is configured, the message will also have the timestamp
+//! information when written to the log file.
+//!
+//! Usage example:
+//! \code
+//! int arg = 0;
+//! error("Example", "%d: This is an error message with a context.\n", arg);
+//! error(NULL, "%d: This is also an error message.\n", arg+1);
+//! \endcode
void error(const char *context, const char *format, ...) {
const char msg_type[8] = "(Error)";
@@ -512,6 +784,27 @@ void error(const char *context, const char *format, ...) {
}
+//! \fn void info(const char *context, const char *format, ...)
+//! \brief Log an info message using the Message Logger.
+//! \param context Caller context where message originated. Pass a NULL pointer
+//! for an empty context.
+//! \param format String formatting for the message's contents before argument
+//! substitution takes place.
+//! \param ... Arguments used to substitute placeholders in the message's
+//! contents.
+//!
+//! This function logs an info message to the terminal and configured log file.
+//! The message contains the caller context that originated the info message, a
+//! tag that identifies the message as an info message and the message's
+//! contents. If a log file is configured, the message will also have the
+//! timestamp information when written to the log file.
+//!
+//! Usage example:
+//! \code
+//! int arg = 0;
+//! info("Example", "%d: This is an info message with a context.\n", arg);
+//! info(NULL, "%d: This is also an info message.\n", arg+1);
+//! \endcode
void info(const char *context, const char *format, ...) {
const char msg_type[7] = "(Info)";
@@ -556,6 +849,46 @@ void info(const char *context, const char *format, ...) {
}
+//! \fn void lock_logger_recursive_mutex()
+//! \brief Lock the Message Logger's recursive mutex lock, preventing any
+//! other thread from using the Message Logger. Thread safety MUST be enabled.
+//!
+//! This function locks the recursive mutex lock utilized by the Message Logger
+//! to ensure thread safety. When the recursive mutex is locked by a thread,
+//! the other threads will not be able to lock it as well and will be suspended
+//! until the mutex is unlocked. This ensures that no race conditions take
+//! place. The recursive nature of the mutex lock allows a thread to lock it
+//! more than once without being suspended.
+//!
+//! Since most of the Message Logger's functions already handle the recursive
+//! mutex lock when thread safety is enabled, the main purpose of this function
+//! is to allow the user's code to avoid race conditions with the logger. For
+//! example, if the user wishes to print information on the terminal without
+//! using the Message Logger, this function will guarantee that the logger
+//! doesn't try to do the same from another thread while the user's code is
+//! running.
+//!
+//! \b Important: For this function to work properly, the function
+//! enable_thread_safety() must have been called to configure the recursive
+//! mutex lock. Otherwise, this function will emit a warning and will have NO
+//! EFFECT.
+//!
+//! Usage example:
+//! \code
+//! // In the main thread, before creating other threads, enable thread safety.
+//! enable_thread_safety();
+//!
+//! // ...
+//! // After creating multiple threads, in one of the threads.
+//! lock_logger_recursive_mutex();
+//! printf("This message will NOT interfere with the logger's operations!\n");
+//! unlock_logger_recursive_mutex();
+//!
+//! // ...
+//! // In the main thread, after other threads have been joined (and the
+//! // logger is no longer used), call the clean up function.
+//! logger_module_clean_up();
+//! \endcode
void lock_logger_recursive_mutex() {
if(logger_recursive_mutex != NULL)
pthread_mutex_lock(logger_recursive_mutex);
@@ -567,6 +900,24 @@ void lock_logger_recursive_mutex() {
);
}
+//! \fn void logger_module_clean_up()
+//! \brief Clean up the resources allocated by the Message Logger.
+//!
+//! This function cleans up any memory or other resources utilized by the
+//! Message Logger. Ideally, it should always be called after the logger is not
+//! longer utilized. If this function is called and the logger is utilized
+//! afterwards, some configurations such as the log file and thread safety will
+//! NOT work.
+//!
+//! \b Important: This function NEEDS to be called when a log file is
+//! configured or when thread safety is enabled. Failure to do so might result
+//! in an incomplete log file or memory leaks.
+//!
+//! Usage example:
+//! \code
+//! // Use the logger normally...
+//! logger_module_clean_up();
+//! \endcode
void logger_module_clean_up() {
// Clean up the log file:
@@ -584,6 +935,27 @@ void logger_module_clean_up() {
}
+//! \fn void message(const char *context, const char *format, ...)
+//! \brief Log a regular message using the Message Logger.
+//! \param context Caller context where message originated. Pass a NULL pointer
+//! for an empty context.
+//! \param format String formatting for the message's contents before argument
+//! substitution takes place.
+//! \param ... Arguments used to substitute placeholders in the message's
+//! contents.
+//!
+//! This function logs a regular message to the terminal and configured log
+//! file. The message contains the caller context that originated the regular
+//! message and the message's contents. If a log file is configured, the
+//! message will also have the timestamp information when written to the log
+//! file.
+//!
+//! Usage example:
+//! \code
+//! int arg = 0;
+//! message("Example", "%d: This is a normal message with a context.\n", arg);
+//! message(NULL, "%d: This is also a normal message.\n", arg+1);
+//! \endcode
void message(const char *context, const char *format, ...) {
va_list arg_list;
@@ -622,10 +994,38 @@ void message(const char *context, const char *format, ...) {
}
+//! \fn void reset_background_color()
+//! \brief Reset the terminal's text background color to the default color.
+//!
+//! Deprecation warning: This function will be removed in the next major
+//! release. Use color_background(DFLT) instead.
+//!
+//! This function resets the terminal's text background color to the default
+//! color specified in the terminal's configuration.
+//!
+//! Usage example:
+//! \code
+//! // Change the text background color in some way.
+//! reset_background_color();
+//! \endcode
void reset_background_color() {
color_background(DFLT);
}
+//! \fn void reset_colors()
+//! \brief Reset all the terminal's colors and text attributes to their
+//! defaults.
+//!
+//! This function resets all of the terminal's colors and text attributes to
+//! the default configurations specified for the terminal. This includes the
+//! colors used for text font and text background, the font weight and any
+//! other characteristics configured using ANSI escape codes.
+//!
+//! Usage example:
+//! \code
+//! // Change various text configurations.
+//! reset_colors();
+//! \endcode
void reset_colors() {
// Acquire logger recursive lock if thread safety is enabled:
if(logger_recursive_mutex != NULL)
@@ -639,6 +1039,23 @@ void reset_colors() {
pthread_mutex_unlock(logger_recursive_mutex);
}
+//! \fn void reset_logger_colors()
+//! \brief Reset the Message Logger's colors to their defaults.
+//!
+//! This function resets the Message Logger's LoggerColorPallet by setting it's
+//! \link LoggerColorPallet::message_colors message_colors \endlink and \link
+//! LoggerColorPallet::tag_colors tag_colors \endlink to the default values
+//! specifed in the macros #DEFAULT_LOGGER_MESSAGE_COLORS and
+//! #DEFAULT_LOGGER_TAG_COLORS. ALL the values are reset, so any changes made
+//! with calls to the functions \link set_logger_msg_colors()
+//! set_logger_msg_colors \endlink and \link set_logger_tag_colors()
+//! set_logger_tag_colors \endlink will be lost after this function is called.
+//!
+//! Usage example:
+//! \code
+//! // Change various logger pallet colors.
+//! reset_logger_colors();
+//! \endcode
void reset_logger_colors() {
int i;
@@ -666,10 +1083,45 @@ void reset_logger_colors() {
pthread_mutex_unlock(logger_recursive_mutex);
}
+//! \fn void reset_text_color()
+//! \brief Reset the terminal's text font color to the default color.
+//!
+//! Deprecation warning: This function will be removed in the next major
+//! release. Use color_text(DFLT) instead.
+//!
+//! This function resets the terminal's text font color to the default color
+//! specified in the terminal's configuration.
+//!
+//! Usage example:
+//! \code
+//! // Change the text font color in some way.
+//! reset_text_color();
+//! \endcode
void reset_text_color() {
color_text(DFLT);
}
+//! \fn void success(const char *context, const char *format, ...)
+//! \brief Log a success message using the Message Logger.
+//! \param context Caller context where message originated. Pass a NULL pointer
+//! for an empty context.
+//! \param format String formatting for the message's contents before argument
+//! substitution takes place.
+//! \param ... Arguments used to substitute placeholders in the message's
+//! contents.
+//!
+//! This function logs a success message to the terminal and configured log
+//! file. The message contains the caller context that originated the success
+//! message, a tag that identifies the message as a success message and the
+//! message's contents. If a log file is configured, the message will also have
+//! the timestamp information when written to the log file.
+//!
+//! Usage example:
+//! \code
+//! int arg = 0;
+//! success("Example", "%d: This is a success message with a context.\n", arg);
+//! success(NULL, "%d: This is also a success message.\n", arg+1);
+//! \endcode
void success(const char *context, const char *format, ...) {
const char msg_type[10] = "(Success)";
@@ -716,6 +1168,47 @@ void success(const char *context, const char *format, ...) {
}
+//! \fn void unlock_logger_recursive_mutex()
+//! \brief Unlock the Message Logger's recursive mutex lock, allowing other
+//! threads to use the Message Logger if no recursive locks remain. Thread
+//! safety MUST be enabled.
+//!
+//! This function unlocks the recursive mutex lock utilized by the Message
+//! Logger to ensure thread safety. When the recursive mutex is locked by a
+//! thread, the other threads will not be able to lock it as well and will be
+//! suspended until the mutex is unlocked. This ensures that no race conditions
+//! take place. The recursive nature of the mutex lock allows a thread to lock
+//! it more than once without being suspended.
+//!
+//! Since most of the Message Logger's functions already handle the recursive
+//! mutex lock when thread safety is enabled, the main purpose of this function
+//! is to allow the user's code to avoid race conditions with the logger. For
+//! example, if the user wishes to print information on the terminal without
+//! using the Message Logger, this function will allow the logger to resume
+//! it's operations in a thread safe manner after the user prints all
+//! information to the screen.
+//!
+//! \b Important: For this function to work properly, the function
+//! enable_thread_safety() must have been called to configure the recursive
+//! mutex lock. Otherwise, this function will emit a warning and will have NO
+//! EFFECT.
+//!
+//! Usage example:
+//! \code
+//! // In the main thread, before creating other threads, enable thread safety.
+//! enable_thread_safety();
+//!
+//! // ...
+//! // After creating multiple threads, in one of the threads.
+//! lock_logger_recursive_mutex();
+//! printf("This message will NOT interfere with the logger's operations!\n");
+//! unlock_logger_recursive_mutex();
+//!
+//! // ...
+//! // In the main thread, after other threads have been joined (and the
+//! // logger is no longer used), call the clean up function.
+//! logger_module_clean_up();
+//! \endcode
void unlock_logger_recursive_mutex() {
if(logger_recursive_mutex != NULL)
pthread_mutex_unlock(logger_recursive_mutex);
@@ -727,6 +1220,27 @@ void unlock_logger_recursive_mutex() {
);
}
+//! \fn void warning(const char *context, const char *format, ...)
+//! \brief Log a warning message using the Message Logger.
+//! \param context Caller context where message originated. Pass a NULL pointer
+//! for an empty context.
+//! \param format String formatting for the message's contents before argument
+//! substitution takes place.
+//! \param ... Arguments used to substitute placeholders in the message's
+//! contents.
+//!
+//! This function logs a warning message to the terminal and configured log
+//! file. The message contains the caller context that originated the warning,
+//! a tag that identifies the message as a warning and the message's contents.
+//! If a log file is configured, the message will also have the timestamp
+//! information when written to the log file.
+//!
+//! Usage example:
+//! \code
+//! int arg = 0;
+//! warning("Example", "%d: This is a warning message with a context.\n", arg);
+//! warning(NULL, "%d: This is also a warning message.\n", arg+1);
+//! \endcode
void warning(const char *context, const char *format, ...) {
const char msg_type[10] = "(Warning)";