#include "logger.h" #include // For mkdir #include // 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)