generated from AfonsoCMSousa/CPP-Template
230 lines
6.2 KiB
C++
230 lines
6.2 KiB
C++
#include "logger.h"
|
|
#include <sys/stat.h> // For mkdir
|
|
#include <errno.h> // For errno
|
|
|
|
// By declaring this function here, we make it private. you cant access it outside of this file
|
|
void get_executable_path(char *buffer, size_t size)
|
|
{
|
|
#ifdef _WIN32
|
|
// On Windows, we use GetModuleFileName
|
|
GetModuleFileName(NULL, buffer, (DWORD)size);
|
|
// Strip the filename from the path
|
|
char *last_slash = strrchr(buffer, '\\');
|
|
if (last_slash)
|
|
*last_slash = '\0';
|
|
#else
|
|
// On Linux, we can just do "./"
|
|
// or use readlink("/proc/self/exe", buffer, size) to get the full path
|
|
// but for simplicity, we just use "./"
|
|
|
|
if (size > 2)
|
|
{
|
|
strncpy(buffer, "./", size - 1);
|
|
buffer[size - 1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Buffer size is too small\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/** \brief A simple print funcion to help easely print to the screen
|
|
*
|
|
* \param unsigned short flags
|
|
* \param const char *Format
|
|
* \param ...
|
|
* \return unsigned int (number of printed chars)
|
|
*
|
|
*/
|
|
unsigned int flogf(unsigned short flags, const char *Format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, Format);
|
|
|
|
unsigned int char_counter = 0;
|
|
|
|
static unsigned char isFileDeclared = 0; // false
|
|
char filepath[256];
|
|
|
|
FILE *selected_std = stdout;
|
|
|
|
if (isFileDeclared)
|
|
{
|
|
selected_std = fopen(filepath, "a");
|
|
}
|
|
|
|
time_t RAW_TIME = time(NULL);
|
|
struct tm *time_info;
|
|
|
|
time_info = localtime(&RAW_TIME);
|
|
|
|
if ((flags & LOG_FILE) && !isFileDeclared)
|
|
{
|
|
char exe_path[512];
|
|
get_executable_path(exe_path, sizeof(exe_path));
|
|
|
|
#if defined(_WIN32)
|
|
sprintf(filepath, "%s\\logs\\log_%02d-%02d-%4d.txt",
|
|
exe_path,
|
|
time_info->tm_mday,
|
|
time_info->tm_mon + 1, // months start at 0
|
|
time_info->tm_year + 1900);
|
|
#else
|
|
sprintf(filepath, "%slogs/log_%02d-%02d-%4d.txt",
|
|
exe_path,
|
|
time_info->tm_mday,
|
|
time_info->tm_mon + 1, // months start at 0
|
|
time_info->tm_year + 1900);
|
|
#endif
|
|
|
|
// Ensure the logs directory exists
|
|
char logs_dir[512];
|
|
#if defined(_WIN32)
|
|
sprintf(logs_dir, "%s\\logs", exe_path);
|
|
_mkdir(logs_dir); // Windows-specific mkdir
|
|
#else
|
|
sprintf(logs_dir, "%s/logs", exe_path);
|
|
if (mkdir(logs_dir, 0755) == -1 && errno != EEXIST)
|
|
{
|
|
perror("Error creating logs directory");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// Create file if it doesn't exist
|
|
selected_std = fopen(filepath, "a");
|
|
|
|
if (!selected_std)
|
|
{
|
|
fprintf(stdout, "ERROR OPENING LOG FILE\n");
|
|
selected_std = stdout;
|
|
return 0;
|
|
}
|
|
|
|
printf("Loging to file: \"%s\"\n", filepath);
|
|
|
|
fprintf(selected_std, "\n%02d:%02d:%02d - NEW ENTRY \n-------------------------------------------------\n",
|
|
time_info->tm_hour,
|
|
time_info->tm_min,
|
|
time_info->tm_sec);
|
|
|
|
isFileDeclared = 1;
|
|
}
|
|
|
|
if ((flags & LOG_TIME_STAMP))
|
|
{
|
|
fprintf(selected_std, "%02d:%02d:%02d - ",
|
|
time_info->tm_hour,
|
|
time_info->tm_min,
|
|
time_info->tm_sec);
|
|
}
|
|
else
|
|
{
|
|
fprintf(selected_std, " ");
|
|
}
|
|
|
|
if (flags & LOG_LEVEL_WARN)
|
|
{
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_YELLOW);
|
|
}
|
|
fprintf(selected_std, "[WARNING]: \t");
|
|
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_RESET);
|
|
}
|
|
}
|
|
else if (flags & LOG_LEVEL_ERROR)
|
|
{
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_RED);
|
|
}
|
|
fprintf(selected_std, "[ERROR]: \t");
|
|
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_RESET);
|
|
}
|
|
}
|
|
else if (flags & LOG_LEVEL_INFO)
|
|
{
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_BLUE);
|
|
}
|
|
|
|
fprintf(selected_std, "[INFO]: \t");
|
|
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_RESET);
|
|
}
|
|
}
|
|
else if (flags & LOG_LEVEL_SUCCESS)
|
|
{
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_GREEN);
|
|
}
|
|
|
|
fprintf(selected_std, "[SUCCESS]: \t");
|
|
|
|
if (flags & LOG_COLOR_OUT)
|
|
{
|
|
fprintf(selected_std, COLOR_RESET);
|
|
}
|
|
}
|
|
|
|
while (*Format)
|
|
{
|
|
if (*Format == '%')
|
|
{
|
|
*Format++; // find out if its a d, s, f, etc.
|
|
switch (*Format)
|
|
{
|
|
case 'd': // Integer
|
|
fprintf(selected_std, "%d", va_arg(args, int));
|
|
break;
|
|
case 'f': // Floating-point
|
|
fprintf(selected_std, "%f", va_arg(args, double));
|
|
break;
|
|
case 's': // String
|
|
fprintf(selected_std, "%s", va_arg(args, char *));
|
|
break;
|
|
case 'c': // Character
|
|
fprintf(selected_std, "%c", va_arg(args, int));
|
|
break;
|
|
case 'x': // Hexadecimal
|
|
fprintf(selected_std, "%x", va_arg(args, unsigned int));
|
|
break;
|
|
case 'p': // Pointer
|
|
fprintf(selected_std, "%p", va_arg(args, void *));
|
|
break;
|
|
case '%': // Literal '%'
|
|
fprintf(selected_std, "%%");
|
|
break;
|
|
default: // Unknown specifier
|
|
fprintf(selected_std, "%%");
|
|
fprintf(selected_std, "%c", *Format);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(selected_std, "%c", *Format);
|
|
}
|
|
*Format++; // iterate over the format text
|
|
char_counter++;
|
|
}
|
|
|
|
if (flags & LOG_FILE)
|
|
fclose(selected_std);
|
|
va_end(args);
|
|
return char_counter;
|
|
} // wrapper (global)
|