#include "utils.h" #include #include #include #include #define SEPARATOR_CHAR '-' #define SEPARATOR_WIDTH 50 #define NEWLINE_CHAR '\n' #define INPUT_BUFFER_SIZE 16 #define TIME_FORMAT_STRING "%Y-%m-%d %H:%M:%S" #define ASK_YES_NO_PROMPT "Please enter 'y' or 'n': " /** Clear leftover input from stdin */ static void flush_stdin(void) { int input_char; do input_char = getchar(); while (input_char != NEWLINE_CHAR && input_char != EOF); } /** Print a horizontal separator line for the quiz UI */ static void print_separator_line(void) { for (size_t current_column = 0; current_column < SEPARATOR_WIDTH; ++current_column) putchar(SEPARATOR_CHAR); putchar(NEWLINE_CHAR); } /** Print a horizontal separator line */ void print_line(void) { print_separator_line(); } /** * Pause until the user presses ENTER * * @param prompt Optional message to display before waiting */ void wait_for_enter(const char* prompt) { if (prompt != NULL) fputs(prompt, stdout); flush_stdin(); } /** * Ask a yes/no question and return a boolean answer * * @param prompt Question message to display * @return true if user answered 'y' or 'Y', false if 'n', default false */ bool ask_yes_no(const char* prompt) { char input_line[INPUT_BUFFER_SIZE]; while (1) { if (prompt != NULL) fputs(prompt, stdout); if (fgets(input_line, sizeof(input_line), stdin) == NULL) return false; const char first_char = input_line[0]; if (first_char == 'y' || first_char == 'Y') return true; if (first_char == 'n' || first_char == 'N') return false; fputs(ASK_YES_NO_PROMPT, stdout); } } /** * Get the current timestamp for recording when a question was answered * * @param answer_time_buffer Buffer to store the formatted timestamp * @param buffer_capacity Size of the buffer in bytes */ void get_answer_timestamp(char* answer_time_buffer, const size_t buffer_capacity) { if (answer_time_buffer == NULL || buffer_capacity == 0) return; const time_t current_time = time(NULL); const struct tm* local_time = localtime(¤t_time); if (local_time != NULL) strftime(answer_time_buffer, buffer_capacity, TIME_FORMAT_STRING, local_time); } /** * Get a random question index in the quiz (thread-safe) * * @param seed Pointer to an unsigned int seed (per-thread) * @param total_questions Number of questions in the current quiz session * @return Random index in the range [0, total_questions-1] */ size_t get_random_question_index(unsigned int* seed, const size_t total_questions) { if (total_questions == 0 || seed == NULL) return 0; const unsigned long random_value = (unsigned long)rand_r(seed); return random_value % total_questions; }