summaryrefslogtreecommitdiffstats
path: root/src/utils.c
diff options
context:
space:
mode:
authorFilip Wandzio <contact@philw.dev>2026-03-01 17:45:00 +0100
committerFilip Wandzio <contact@philw.dev>2026-03-01 17:45:00 +0100
commit9e9c1b21569faeabd33716e4153a881e2eed7134 (patch)
treef3a7ad21aed4b1c4f51c3ee308ffef88430deafc /src/utils.c
parent57b077a4788b7fb5ed6add1df4ba3f15c9e6349b (diff)
downloadysnp-9e9c1b21569faeabd33716e4153a881e2eed7134.tar.gz
ysnp-9e9c1b21569faeabd33716e4153a881e2eed7134.zip
Separate quiz logic from main function fo dedicated moduleHEADmaster
Signed-off-by: Filip Wandzio <contact@philw.dev>
Diffstat (limited to '')
-rw-r--r--src/utils.c125
1 files changed, 104 insertions, 21 deletions
diff --git a/src/utils.c b/src/utils.c
index c139929..2e26e8e 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,34 +1,117 @@
1#include "utils.h" 1#include "utils.h"
2#include <stdbool.h>
2#include <stdio.h> 3#include <stdio.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <time.h> 5#include <time.h>
5 6
6void print_line(void) { 7#define SEPARATOR_CHAR '-'
7 printf("--------------------------------------------------\n"); 8#define SEPARATOR_WIDTH 50
9#define NEWLINE_CHAR '\n'
10#define INPUT_BUFFER_SIZE 16
11#define TIME_FORMAT_STRING "%Y-%m-%d %H:%M:%S"
12#define ASK_YES_NO_PROMPT "Please enter 'y' or 'n': "
13
14/** Clear leftover input from stdin */
15static void flush_stdin(void)
16{
17 int input_char;
18 do
19 input_char = getchar();
20 while (input_char != NEWLINE_CHAR && input_char != EOF);
21}
22
23/** Print a horizontal separator line for the quiz UI */
24static void print_separator_line(void)
25{
26 for (size_t current_column = 0; current_column < SEPARATOR_WIDTH;
27 ++current_column)
28 putchar(SEPARATOR_CHAR);
29
30 putchar(NEWLINE_CHAR);
8} 31}
9 32
10void wait_enter(const char *msg) { 33/** Print a horizontal separator line */
11 if (msg) 34void print_line(void)
12 printf("%s", msg); 35{
13 int c; 36 print_separator_line();
14 while ((c = getchar()) != '\n' && c != EOF)
15 ;
16} 37}
17 38
18char ask_yes_no(const char *msg) { 39/**
19 char c = 'n'; 40 * Pause until the user presses ENTER
20 printf("%s", msg); 41 *
21 if (scanf(" %c", &c) != 1) 42 * @param prompt Optional message to display before waiting
22 c = 'n'; 43 */
23 int flush; 44void wait_for_enter(const char* prompt)
24 while ((flush = getchar()) != '\n' && flush != EOF) 45{
25 ; 46 if (prompt != NULL)
26 return c; 47 fputs(prompt, stdout);
48
49 flush_stdin();
50}
51
52/**
53 * Ask a yes/no question and return a boolean answer
54 *
55 * @param prompt Question message to display
56 * @return true if user answered 'y' or 'Y', false if 'n', default false
57 */
58bool ask_yes_no(const char* prompt)
59{
60 char input_line[INPUT_BUFFER_SIZE];
61
62 while (1) {
63 if (prompt != NULL)
64 fputs(prompt, stdout);
65
66 if (fgets(input_line, sizeof(input_line), stdin) == NULL)
67 return false;
68
69 const char first_char = input_line[0];
70
71 if (first_char == 'y' || first_char == 'Y')
72 return true;
73
74 if (first_char == 'n' || first_char == 'N')
75 return false;
76
77 fputs(ASK_YES_NO_PROMPT, stdout);
78 }
27} 79}
28 80
29void now_str(char *buf, size_t size) { 81/**
30 time_t t = time(NULL); 82 * Get the current timestamp for recording when a question was answered
31 strftime(buf, size, "%Y-%m-%d %H:%M:%S", localtime(&t)); 83 *
84 * @param answer_time_buffer Buffer to store the formatted timestamp
85 * @param buffer_capacity Size of the buffer in bytes
86 */
87void get_answer_timestamp(char* answer_time_buffer,
88 const size_t buffer_capacity)
89{
90 if (answer_time_buffer == NULL || buffer_capacity == 0)
91 return;
92
93 const time_t current_time = time(NULL);
94 const struct tm* local_time = localtime(&current_time);
95 if (local_time != NULL)
96 strftime(answer_time_buffer,
97 buffer_capacity,
98 TIME_FORMAT_STRING,
99 local_time);
32} 100}
33 101
34size_t rand_index(size_t max) { return max ? (size_t)(rand() % max) : 0; } 102/**
103 * Get a random question index in the quiz (thread-safe)
104 *
105 * @param seed Pointer to an unsigned int seed (per-thread)
106 * @param total_questions Number of questions in the current quiz session
107 * @return Random index in the range [0, total_questions-1]
108 */
109size_t get_random_question_index(unsigned int* seed,
110 const size_t total_questions)
111{
112 if (total_questions == 0 || seed == NULL)
113 return 0;
114
115 const unsigned long random_value = (unsigned long)rand_r(seed);
116 return random_value % total_questions;
117}