GCC Code Coverage Report


Directory: ./
File: s21_sprintf_handlers.c
Date: 2025-07-13 17:59:14
Exec Total Coverage
Lines: 210 214 98.1%
Branches: 134 166 80.7%

Line Branch Exec Source
1 #include <locale.h>
2 #include <math.h>
3 #include <stdlib.h>
4
5 #include "s21_sprintf.h"
6
7 53 void handle_specifier_c(char **str, const FormatSpecifier *fs, va_list args) {
8 char arg[16];
9
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 42 times.
53 if (fs->length == 'l') {
10 11 wchar_to_str(va_arg(args, wchar_t), arg);
11 } else {
12 42 char_to_str(va_arg(args, int), arg);
13 }
14 53 apply_padding(str, fs, arg);
15 53 }
16
17 1972 void handle_specifier_d(char **str, FormatSpecifier *fs, va_list args) {
18 char arg[256];
19 1972 int_to_str(get_signed_arg(fs, args), arg, fs);
20 1972 apply_padding_with_zero(str, fs, arg);
21 1972 }
22
23 22 void handle_specifiers_eE(char **str, FormatSpecifier *fs, va_list args) {
24 char arg[256];
25 22 long double num =
26
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19 times.
22 fs->length == 'L' ? va_arg(args, long double) : va_arg(args, double);
27 22 int exponent = 0;
28
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 1 times.
22 if (num) {
29
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 21 times.
75 while (fabsl(num) >= 10.0) {
30 54 num /= 10.0;
31 54 exponent++;
32 }
33
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 21 times.
30 while (fabsl(num) < 1.0) {
34 9 num *= 10.0;
35 9 exponent--;
36 }
37 }
38 char mantissa[256];
39 22 FormatSpecifier mantissa_fs = *fs;
40
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 13 times.
22 mantissa_fs.precision = fs->precision == -1 ? 6 : fs->precision;
41 ;
42 22 float_to_str(num, mantissa, &mantissa_fs);
43
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 13 times.
22 s21_sprintf(arg, "%s%c%+03d", mantissa, fs->specifier == 'E' ? 'E' : 'e',
44 exponent);
45 22 apply_padding_with_zero(str, fs, arg);
46 22 }
47
48 22 void handle_specifier_f(char **str, FormatSpecifier *fs, va_list args) {
49 char arg[256];
50
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19 times.
41 float_to_str(fs->length == 'L' ? va_arg(args, long double)
51 19 : (long double)va_arg(args, double),
52 arg, fs);
53 22 apply_padding_with_zero(str, fs, arg);
54 22 }
55
56 28 void handle_specifiers_gG(char **str, FormatSpecifier *fs, va_list args) {
57 28 long double num =
58
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
28 (fs->length == 'L') ? va_arg(args, long double) : va_arg(args, double);
59
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 18 times.
28 int precision = (fs->precision == -1) ? 6 : fs->precision;
60
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 27 times.
28 if (precision == 0) {
61 1 precision = 1;
62 }
63
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
28 if (num == 0.0) {
64 char zero_buf[128];
65 4 FormatSpecifier fs_f = *fs;
66 4 fs_f.precision = precision - 1;
67
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 fs_f.specifier = (fs->specifier == 'G') ? 'F' : 'f';
68 4 float_to_str(num, zero_buf, &fs_f);
69
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (!fs->alternate_form) {
70 3 char *dot = s21_strchr(zero_buf, '.');
71
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (dot) {
72 2 char *end = zero_buf + s21_strlen(zero_buf) - 1;
73
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
12 while (end > dot && *end == '0') *end-- = '\0';
74
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (end == dot) *end = '\0';
75 }
76 }
77 4 apply_padding(str, fs, zero_buf);
78 } else {
79 24 pick_and_apply_notation(num, precision, str, fs);
80 }
81 28 }
82
83 24 void pick_and_apply_notation(long double num, int precision, char **str,
84 FormatSpecifier *fs) {
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 long double abs_num = (num < 0) ? -num : num;
86 24 int exponent = 0;
87
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (abs_num != 0.0) {
88 24 exponent = (int)floorl(log10l(abs_num));
89 }
90 24 long double rounding_factor = powl(10.0L, exponent - precision + 1);
91 24 long double rounded_num = roundl(num / rounding_factor) * rounding_factor;
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 long double abs_rounded = (rounded_num < 0) ? -rounded_num : rounded_num;
93 24 int rounded_exp = 0;
94
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (abs_rounded != 0.0) {
95 24 rounded_exp = (int)floorl(log10l(abs_rounded));
96 }
97
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 5 times.
24 int use_fixed = (rounded_exp >= -4 && rounded_exp < precision);
98 char buf[256];
99
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 5 times.
24 if (use_fixed) {
100 19 int f_prec = precision - (rounded_exp + 1);
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (f_prec < 0) f_prec = 0;
102 19 FormatSpecifier fs_f = *fs;
103 19 fs_f.precision = f_prec;
104
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 10 times.
19 fs_f.specifier = (fs->specifier == 'G') ? 'F' : 'f';
105 19 float_to_str(rounded_num, buf, &fs_f);
106 } else {
107 5 convert_to_scientific_notation(rounded_num, precision, buf, fs);
108 }
109
4/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 3 times.
24 if (use_fixed && !fs->alternate_form) {
110 16 char *dot = s21_strchr(buf, '.');
111
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 if (dot) {
112 14 char *end = buf + s21_strlen(buf) - 1;
113
3/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 14 times.
16 while (end > dot && *end == '0') *end-- = '\0';
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (end == dot) *end = '\0';
115 }
116 }
117 24 apply_padding_with_zero(str, fs, buf);
118 24 }
119
120 5 void convert_to_scientific_notation(long double rounded_num, int precision,
121 char *buf, FormatSpecifier *fs) {
122 5 int e_prec = precision - 1;
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (e_prec < 0) e_prec = 0;
124 5 long double mantissa = rounded_num;
125 5 int exp = 0;
126
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (mantissa != 0.0) {
127 5 exp = (int)floorl(log10l(fabsl(mantissa)));
128 5 mantissa = mantissa / powl(10.0L, exp);
129 }
130 char mantissa_buf[128];
131 5 FormatSpecifier fs_m = *fs;
132 5 fs_m.precision = e_prec;
133
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 fs_m.specifier = (fs->specifier == 'G') ? 'F' : 'f';
134 5 float_to_str(mantissa, mantissa_buf, &fs_m);
135
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (!fs->alternate_form) {
136 4 char *dot = s21_strchr(mantissa_buf, '.');
137
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (dot) {
138 4 char *end = mantissa_buf + s21_strlen(mantissa_buf) - 1;
139
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 while (end > dot && *end == '0') *end-- = '\0';
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (end == dot) *end = '\0';
141 }
142 }
143 5 s21_sprintf(buf, "%s%c%+03d", mantissa_buf,
144
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 (fs->specifier == 'G') ? 'E' : 'e', exp);
145 5 }
146
147 19 void handle_specifier_o(char **str, const FormatSpecifier *fs, va_list args) {
148 char arg[256];
149 19 unsigned long num = get_unsigned_arg(fs, args);
150
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
19 if (num == 0 && fs->precision == 0) {
151 1 arg[0] = '\0';
152 } else {
153 18 uint_to_base(num, arg, 8, "01234567");
154 }
155 19 int num_len = s21_strlen(arg);
156
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 11 times.
19 if (fs->precision > num_len) {
157 8 int zeros_to_pad = fs->precision - num_len;
158
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 for (int i = num_len; i >= 0; i--) {
159 24 arg[i + zeros_to_pad] = arg[i];
160 }
161
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 8 times.
47 for (int i = 0; i < zeros_to_pad; i++) {
162 39 arg[i] = '0';
163 }
164 }
165
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
19 if (fs->alternate_form && num) {
166
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 4 times.
36 for (int i = s21_strlen(arg); i >= 0; i--) {
167 32 arg[i + 1] = arg[i];
168 }
169 4 arg[0] = '0';
170 }
171 19 apply_padding(str, fs, arg);
172 19 }
173
174 17 void handle_specifier_u(char **str, const FormatSpecifier *fs, va_list args) {
175 char arg[256];
176 17 uint_to_str(get_unsigned_arg(fs, args), arg, fs);
177 17 apply_padding(str, fs, arg);
178 17 }
179
180 23 void handle_specifiers_xX(char **str, FormatSpecifier *fs, va_list args) {
181 char arg[256];
182 23 unsigned long num = va_arg(args, unsigned long);
183 char num_str[256];
184
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
23 if (num == 0 && fs->precision == 0) {
185 1 num_str[0] = '\0';
186 } else {
187 22 uint_to_base(
188 num, num_str, 16,
189
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 15 times.
22 fs->specifier == 'X' ? "0123456789ABCDEF" : "0123456789abcdef");
190 }
191 23 s21_size_t num_len = s21_strlen(num_str);
192 char prec_str[256];
193 23 size_t zeros_to_pad =
194
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
23 fs->precision > (int)num_len ? fs->precision - num_len : 0;
195
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 23 times.
31 for (size_t i = 0; i < zeros_to_pad; i++) {
196 8 prec_str[i] = '0';
197 }
198 23 s21_strncpy(prec_str + zeros_to_pad, num_str, s21_strlen(num_str) + 1);
199 23 arg[0] = '\0';
200
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
23 if (fs->alternate_form && num) {
201
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 s21_strncpy(arg, fs->specifier == 'X' ? "0X" : "0x", 3);
202 }
203 23 s21_strncat(arg, prec_str, s21_strlen(prec_str) + 1);
204
6/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
23 if (fs->zero_padding && !fs->left_justify && fs->alternate_form && num) {
205 2 *(*str)++ = arg[0];
206 2 *(*str)++ = arg[1];
207 2 fs->width -= 2;
208 2 apply_padding(str, fs, arg + 2);
209 } else {
210 21 apply_padding(str, fs, arg);
211 }
212 23 }
213
214 43 void handle_specifier_s(char **str, FormatSpecifier *fs, va_list args) {
215
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 36 times.
43 if (fs->length == 'l') {
216 7 setlocale(LC_ALL, "");
217 7 handle_wide_str(str, fs, args);
218 } else {
219 36 char *str_arg = va_arg(args, char *);
220 36 char *arg = str_arg;
221
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 32 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
36 if (fs->precision != -1 && (s21_size_t)fs->precision < s21_strlen(arg)) {
222 4 arg = malloc(fs->precision + 1);
223 4 s21_strncpy(arg, str_arg, fs->precision);
224 4 arg[fs->precision] = '\0';
225 }
226 36 apply_padding(str, fs, arg);
227
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 32 times.
36 if (arg != str_arg) {
228 4 free(arg);
229 }
230 }
231 43 }
232
233 7 void handle_wide_str(char **str, FormatSpecifier *fs, va_list args) {
234 7 const wchar_t *wstr_arg = va_arg(args, wchar_t *);
235 7 char *full_str = NULL;
236 7 int error_occurred = 0;
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!wstr_arg) {
238 full_str = "(null)";
239 } else {
240 7 size_t buf_len = wcstombs(NULL, wstr_arg, 0);
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (buf_len == (size_t)-1) {
242 error_occurred = 1;
243 } else {
244 7 full_str = malloc(buf_len + 1);
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!full_str) {
246 error_occurred = 1;
247 } else {
248 7 wcstombs(full_str, wstr_arg, buf_len + 1);
249 7 process_wide_string(full_str, buf_len, fs);
250 }
251 }
252 }
253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (error_occurred) {
254 full_str = "(null)";
255 }
256 7 apply_padding(str, fs, full_str);
257
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (wstr_arg && !error_occurred) {
258 7 free(full_str);
259 }
260 7 }
261
262 7 void process_wide_string(char *full_str, size_t buf_len, FormatSpecifier *fs) {
263
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
7 if (fs->precision != -1 && (size_t)fs->precision < buf_len) {
264 4 size_t trunc_len = 0;
265 mbstate_t state;
266 4 s21_memset(&state, 0, sizeof(mbstate_t));
267 4 const char *p = full_str;
268 4 size_t bytes_processed = 0;
269 4 int done = 0;
270
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1 times.
15 while (!done && bytes_processed < (size_t)fs->precision) {
271 size_t char_len =
272 11 mbrlen(p, (size_t)(fs->precision - bytes_processed), &state);
273
4/6
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
11 if (char_len == (size_t)-1 || char_len == (size_t)-2 || char_len == 0) {
274 3 done = 1;
275 } else {
276 8 p += char_len;
277 8 bytes_processed += char_len;
278 8 trunc_len = bytes_processed;
279 }
280 }
281 4 full_str[trunc_len] = '\0';
282 }
283 7 }
284
285 6 void handle_specifier_p(char **str, const FormatSpecifier *fs, va_list args) {
286 char num_str[256];
287 6 uint_to_base((unsigned long)va_arg(args, void *), num_str, 16,
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 fs->specifier == 'X' ? "0123456789ABCDEF" : "0123456789abcdef");
289 char arg[256];
290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 s21_strncpy(arg, fs->specifier == 'X' ? "0X" : "0x", 3);
291 6 s21_strncat(arg, num_str, s21_strlen(num_str) + 1);
292 6 apply_padding(str, fs, arg);
293 6 }
294
295 3 void handle_specifier_n(const char **str, const FormatSpecifier *fs,
296 va_list args, const char *str_start) {
297 3 int chars_written = (int)(*str - str_start);
298
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (fs->length == 'l') {
299 1 long *ptr = va_arg(args, long *);
300 1 *ptr = (long)chars_written;
301
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (fs->length == 'h') {
302 1 short *ptr = va_arg(args, short *);
303 1 *ptr = (short)chars_written;
304 } else {
305 1 int *ptr = va_arg(args, int *);
306 1 *ptr = chars_written;
307 }
308 3 }
309