Полная реализация s21_sscanf — форматированный ввод из строки (Part 4).
int s21_sscanf(const char *str, const char *format, ...);
Возвращает количество успешно присвоенных аргументов, либо EOF при ошибке до первого присваивания.
suppress (*), width, length, specifierd, i, o, u, x, Xf, e, E, g, Gc, spn, %c, d, i, e, E, f, g, G, o, s, u, x, X, p, n, %* — подавление присваивания (поле читается, но не записывается, не учитывается в return)h, l, L%i — детектит основание автоматически (0x → hex, 0 → oct, иначе dec)%s — читает до whitespace, не включая%c — читает ровно width (по умолчанию 1) символов, без пропуска whitespace%n — сохраняет количество прочитанных байт, не считается в returnEOFСравнение со стандартным sscanf:
int a1, a2; double d1; char s1[64];
int r_my = s21_sscanf(input, fmt, &a1, &d1, s1);
int r_std = sscanf(input, fmt, &a2, &d2, s2);
ck_assert_int_eq(r_my, r_std);
// ...сравнить все значения
Не забыть про:
"abc" для %d)%*d посреди формата\n, \t%[...] НЕ требуется (не входит в задание), но проверь что не падаетПарсер формата реализован в отдельном модуле s21_scan_format и состоит из:
Структура FormatInfo, содержащая:
suppress — флаг подавления (*)width — ширина поля (максимальное количество символов для чтения)length — модификатор длины (h, l, L или 0)specifier — символ спецификатора (d, i, u, o, x, X, c, s, p, n, f, e, E, g, G, %)Функция parse_format, которая:
%)FormatInfoАлгоритм работы парсера:
%* (подавление)h, l, L)Поддерживаются все целочисленные спецификаторы: %d, %i, %u, %o, %x, %X.
Особенности реализации:
%d — читает знаковое десятичное число.%i — автоматически определяет основание:
0x или 0X → шестнадцатеричное0 → восьмеричное%u — беззнаковое десятичное число.%o — восьмеричное число (цифры 0–7).%x / %X — шестнадцатеричное число (цифры 0–9, буквы A–F или a–f).Вспомогательные функции:
read_int — чтение знакового десятичного числаread_unsigned — чтение беззнакового десятичного числаread_unsigned_base — универсальная функция для чтения чисел в любой системе счисления (используется для %o и %x)read_int_i — для %i с автоопределением основанияУчёт модификаторов длины:
h — short / unsigned shortl — long / unsigned longint / unsigned intПоддерживаются все вещественные спецификаторы: %f, %e, %E, %g, %G.
Особенности реализации:
strtod.1.23e-4).Модификаторы длины для вещественных чисел:
L — long double (через преобразование из double)l — double (используется по умолчанию для %lf)floatВспомогательные функции:
read_double — чтение double с учётом шириныread_long_double — чтение long double (через double с последующим преобразованием)%s — читает строку до первого пробельного символа (' ', '\t', '\n'):
\0width символов)%c — читает один или несколько символов:
%s)width == 0), читает 1 символ%3c), читает width символов в массив char*Вспомогательные функции:
read_string — для %sread_char — для %c (с поддержкой ширины)%n:
count* на %n не влияет)%p:
0x или без него)void*read_ptr, которая поддерживает буквы A–F (в любом регистре)%%:
% во входной строке*)Флаг * означает, что поле читается, но не сохраняется и не учитывается в возвращаемом значении.
Реализация:
parse_format устанавливает info.suppress = 1 при встрече *s21_sscanf при suppress == 1:
va_arg не вызывается (указатель ptr = NULL)count не увеличиваетсяПример:
int a;
s21_sscanf("123 456", "%*d %d", &a); // a = 456, возвращает 1
Ширина — это максимальное количество символов, которое может быть прочитано для данного поля.
Реализация:
parse_format считывает число после % и сохраняет его в info.widthread_int, read_unsigned, read_string, read_char, read_double, read_ptr, read_unsigned_base) добавлен параметр width(width == 0 || count < width)Пример:
int a;
s21_sscanf("12345", "%3d", &a); // a = 123