/
solidbase
/
C3_s21_stringplus
Обзор
Документация
Войти
/
solidbase
/
C3_s21_stringplus
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
src/s21_sprintf.c
1 180 строк
34 KB
Andrey
Change to earliema %g/%G
06 фев 2026, 08:22
06 фев 2026, 08:22
22e7896
Код
Авторство
О чём код?
#include "s21_sprintf.h" int s21_sprintf(char* str, const char* format, ...) { int succes_output = 0, index_format = 0, index_str = 0; char sim = format[index_format]; va_list ap; bool sp = false; va_start(ap, format); while (sim != '\0') { if (sim == '%') { index_format++; succes_output += format_change(str, format, &index_format, &index_str, &ap); sp = true; } else { str[index_str] = sim; index_str++; succes_output++; sp = false; } index_format++; sim = format[index_format]; } if (sp) ++index_str; str[index_str] = '\0'; va_end(ap); return succes_output; } int format_change(char* str, const char* format, int* index_format, int* index_str, va_list* ap) { form change = {false, false, false, false, false, -1, -1, false, false, false, false, false, '\0'}; int succes_output = 0; int start_index_format = *index_format; if (template_sp(format, index_format, ap, &change) != -1) { succes_output = allocate_sp(str, index_str, ap, &change); } else { for (int i = start_index_format - 1; i <= *index_format; i++) { // вывод для неправильного формата char sim = format[i]; str[*index_str] = sim; (*index_str)++; succes_output++; } } return succes_output; } int template_sp(const char* format, int* index_format, va_list* ap, form* change) { int start_index_format = *index_format; int error = 0; while (change->sp == '\0' && format[*index_format] != '\0') { if (format[*index_format] == 'd' || format[*index_format] == 'i' || format[*index_format] == 'o' || format[*index_format] == 'x' || format[*index_format] == 'X' || format[*index_format] == 'u' || format[*index_format] == 'f' || format[*index_format] == 'e' || format[*index_format] == 'E' || format[*index_format] == 'g' || format[*index_format] == 'G' || format[*index_format] == 'p' || // format[*index_format] == 'n' || format[*index_format] == '%' || format[*index_format] == '%' || format[*index_format] == 'c' || format[*index_format] == 's') { change->sp = format[*index_format]; } // ищем спецификатор else (*index_format)++; } if (format[*index_format] != '\0') { if (change->sp != '\0') { // если спецификатор есть if (template_betwsp(format, *index_format, ap, start_index_format, change) != 0) { error = -1; } } } else { error = -1; } return error; // если формат правильный выводит 0, иначе -1 } int template_betwsp(const char* format, int index_format, va_list* ap, int start_index_format, form* change) { bool switch_num = false; // переключатель ширины на точность int error = 0; for (int i = start_index_format; i < index_format; i++) { if (format[i] == '.') { if (switch_num == true) { // если больше одной точки error = -1; } switch_num = true; } else if (format[i] >= 49 && format[i] <= 57) { if (switch_num) { // если числа после точки if (change->accuracy != -1) change->accuracy = change->accuracy * 10 + format[i] - 48; else // для первой цифры change->accuracy = format[i] - 48; } else { // если точки ещё не было if (change->width != -1) change->width = change->width * 10 + format[i] - 48; else // для первой цифры change->width = format[i] - 48; } } else if (format[i] == '0') { if (change->width == -1 && switch_num == false) { change->fl_nu = 1; // флаг 0 } else if (switch_num) { // точность if (change->accuracy != -1) change->accuracy *= 10; else change->accuracy = 0; } else { // ширина if (change->width != -1) change->width *= 10; else change->width = 0; } } else if (format[i] == '*') { if (acc_wid_arg(format, i, ap, change) == -1) { error = -1; } } else if ((format[i] == 'h' || format[i] == 'L' || format[i] == 'l')) { error = length_sp(format, i, change); } else if (change->accuracy == -1 && change->width == -1) { if (format[i] == '+') { change->fl_pl = true; } else if (format[i] == '-') { change->fl_mi = true; } else if (format[i] == ' ') { change->fl_sp = true; } else if (format[i] == '#') { change->fl_gr = true; } else error = -1; } else error = -1; } return error; } int acc_wid_arg(const char* format, int index_star, va_list* ap, form* change) { int error = 0; if (change->width == -1 && change->accuracy == -1 && format[index_star - 1] != '.') { change->width = va_arg(*ap, int); } else if (change->accuracy == -1 && format[index_star - 1] == '.') { change->accuracy = va_arg(*ap, int); } else error = -1; return error; } int length_sp(const char* format, int index_len, form* change) { int error = 0; if (format[index_len] == 'h') { if (change->h == true) { change->hh = true; change->h = false; } else if (change->L || change->hh || change->l || change->ll) error = -1; else change->h = true; } if (format[index_len] == 'l') { if (change->l == true) { change->ll = true; change->l = false; } else if (change->L || change->ll || change->h || change->hh) error = -1; else change->l = true; } if (format[index_len] == 'L') { if (change->l || change->ll || change->h || change->hh || change->L) error = -1; else change->L = true; } return error; } int allocate_sp(char* str, int* index_str, va_list* ap, form* change) { int succes_output = 0; switch (change->sp) { case 'd': succes_output = num_sp(str, index_str, ap, change); break; case 'i': succes_output = num_sp(str, index_str, ap, change); break; case 'o': succes_output = unum_sp(str, index_str, ap, change); break; case 'x': succes_output = unum_sp(str, index_str, ap, change); break; case 'X': succes_output = unum_sp(str, index_str, ap, change); break; case 'u': succes_output = unum_sp(str, index_str, ap, change); break; case 'c': succes_output = c_sp(str, index_str, ap, change); break; case 's': succes_output = s_sp(str, index_str, ap, change); break; case 'f': succes_output = f_sp(str, index_str, ap, change); break; case 'e': succes_output = e_sp(str, index_str, ap, change); break; case 'E': succes_output = e_sp(str, index_str, ap, change); break; case 'g': succes_output = g_sp(str, index_str, ap, change); break; case 'G': succes_output = g_sp(str, index_str, ap, change); break; case 'p': succes_output = p_sp(str, index_str, ap, change); break; // case 'n': /* code */ // break; case '%': str[(*index_str)++] = '%'; succes_output++; break; } return succes_output; } long long lenaddnum(form change, va_list* ap) { long long num; if (change.h == true) num = (short int)va_arg(*ap, int); else if (change.l == true) num = va_arg(*ap, long int); else if (change.ll == true) num = va_arg(*ap, long long); else if (change.hh) num = (char)va_arg(*ap, int); else num = va_arg(*ap, int); return num; } bool signum(char* str, int* index_str, form change, int* lenchange, long long num, bool count) { bool out = false; if (num < 0ll) { if (!count) { str[*index_str] = '-'; (*index_str)++; } (*lenchange)++; out = true; } else if (change.fl_pl) { if (!count) { str[*index_str] = '+'; (*index_str)++; } (*lenchange)++; out = true; } else if (change.fl_sp) { if (!count) { str[*index_str] = ' '; (*index_str)++; } (*lenchange)++; out = true; } return out; } long double lenadddouble(form change, va_list* ap) { long double num = 0L; if (change.l == true) num = va_arg(*ap, double); else if (change.L == true) num = va_arg(*ap, long double); else num = va_arg(*ap, double); return num; } bool sigdouble(char* str, int* index_str, form change, int* lenchange, long double num, bool cout) { bool out = false; if (num < 0L) { if (!cout) { str[*index_str] = '-'; (*index_str)++; } (*lenchange)++; out = true; } else if (change.fl_pl) { if (!cout) { str[*index_str] = '+'; (*index_str)++; } (*lenchange)++; out = true; } else if (change.fl_sp) { if (!cout) { str[*index_str] = ' '; (*index_str)++; } (*lenchange)++; out = true; } return out; } int f_sp(char* str, int* index_str, va_list* ap, form* change) { int lenchange = 0, lenspace = 0, start_index_str = *index_str; bool sig; if (change->accuracy == -1) { change->accuracy = 6; } long double num = lenadddouble(*change, ap); sig = sigdouble(str, index_str, *change, &lenchange, num, false); if (num < 0) num *= -1.L; lenchange += insert_double(str, index_str, *change, num); if (change->width > lenchange) { lenspace = change->width - lenchange; if (change->fl_mi) { for (int i = 0; i < lenspace; i++) { str[*index_str] = ' '; (*index_str)++; } } else { --(*index_str); for (int i = start_index_str; i < start_index_str + lenspace; i++) { shift_rigth_str(str, i, index_str, *change); } } } lenchange += lenspace; point_change(str, index_str, &lenchange, *change, sig); return lenchange; } int rounding(char* str, int* index_str, long double frac, int start_index_str) { // frac - дробная часть числа long long var = 0ll, lenchange = 0; bool switchokr = true; while (switchokr) { // округление long long okr1 = (long long)(frac * 10); frac = frac * 10 - (long double)okr1; if (okr1 > 5) { var++; switchokr = false; } if (okr1 < 5) { switchokr = false; } } for (int i = *index_str - 1; i > start_index_str; i--) { // переносим едининыцы на порядок выше if (var == 0) { break; } if (str[i] != '.') { str[i] += (int)var; if (str[i] == ':') { str[i] = '0'; } else var = 0; } } if (var == 1) { str[start_index_str] = '1'; lenchange++; } else { (*index_str)--; shift_left_str(str, start_index_str, *index_str); } return lenchange; } int insert_double(char* str, int* index_str, form change, long double num) { // frac - дробная часть числа, dig - целая часть long long dig, lendig = 0, lenchange = 0; int start_index_str = *index_str; long double frac, var; dig = (long long)num; frac = num - (long double)dig; var = num; do { // считаем кол-во целый цифр var /= 10.L; lendig++; } while (var >= 1.L); lenchange += lendig; (*index_str)++; // оставляем место на случай нового порядка при округления for (int i = (*index_str) + lendig - 1; i >= (*index_str); i--) { // целая часть str[i] = (int)(dig % 10) + 48; dig /= 10; } (*index_str) += (lendig); str[*index_str] = '.'; lenchange++; ++(*index_str); if (!change.fl_gr && change.accuracy == 0) ; // если 0 и нет # else { for (int i = (*index_str); i < (*index_str) + change.accuracy; i++) { // дробная часть dig = (int)(frac * 10); str[i] = dig + 48; frac = frac * 10 - (long double)dig; lenchange++; } (*index_str) += (change.accuracy); } lenchange += rounding(str, index_str, frac, start_index_str); return lenchange; } void shift_left_str( char* str, int start_index_str, int index_str) { // смещает символы влево, в конце добавляет \0 // // start_index_str - индекс , где будет находится первый // символ // смещённой строки, *index_str - индекс последнего символа // смещяемой строки for (int i = start_index_str; i < index_str; i++) { char sim = str[i + 1]; str[i] = sim; } str[index_str] = '\0'; } void shift_rigth_str(char* str, int start_index_str, int* index_str, form change) { // смещает символы вправо, и добавляет 0 // или ' ' // start_index_str - это индекс // который должен заполнится пробелом // или нулём, *index_str - это последний символ в строке // Пропускаем знак только если он реально есть if (change.fl_nu && (str[start_index_str] == '-' || str[start_index_str] == '+' || str[start_index_str] == ' ')) start_index_str++; for (int i = *index_str; i >= start_index_str; i--) { char sim = str[i]; str[i + 1] = sim; } if (change.fl_nu) str[start_index_str] = '0'; else str[start_index_str] = ' '; (*index_str)++; } int c_sp(char* str, int* index_str, va_list* ap, form* change) { int lenchange = 0; if (!change->l) { char sim = (char)va_arg(*ap, int); if (!change->fl_mi) { for (int i = 0; i < change->width - 1; i++) { str[(*index_str)] = ' '; (*index_str)++; lenchange++; } str[(*index_str)++] = sim; lenchange++; } else { str[(*index_str)++] = sim; lenchange++; for (int i = 0; i < change->width - 1; i++) { str[(*index_str)] = ' '; (*index_str)++; lenchange++; } } (*index_str)--; } else { lenchange += lc_sp(str, index_str, ap, change); } return lenchange; } int lc_sp(char* str, int* index_str, va_list* ap, form* change) { int lenchange = 0, start_index_str = *index_str; int sim = va_arg(*ap, int); lenchange += unicod_char(sim, str, index_str); if (change->fl_mi) { for (int i = 0; i < change->width - lenchange; i++) { str[(*index_str)] = ' '; (*index_str)++; } lenchange += change->width - lenchange; } else { change->fl_nu = 0; (*index_str)--; for (int i = 0; i < change->width - lenchange; i++) { shift_rigth_str(str, start_index_str, index_str, *change); } (*index_str)++; if ((change->width - lenchange) > 0) lenchange += change->width - lenchange; } return lenchange; } int unicod_char(int sim, char* str, int* index_str) { int lenchange = 0; // if (sim>=0 && sim<128){ // str[(*index_str)++] = (char)sim; // lenchange += 1; // } if (sim <= 0x7F) { str[(*index_str)++] = (sim & 0x7F); lenchange += 1; } else if (sim <= 0x7FF) { str[(*index_str)++] = 0xC0 | ((sim >> 6) & 0x1F); str[(*index_str)++] = 0x80 | (sim & 0x3F); lenchange += 2; } else if (sim <= 0xFFFF) { str[(*index_str)++] = 0xE0 | ((sim >> 12) & 0x3F); str[(*index_str)++] = 0x80 | ((sim >> 6) & 0x3F); str[(*index_str)++] = 0x80 | (sim & 0x3F); lenchange += 3; } else if (sim <= 0x10FFFF) { str[(*index_str)++] = 0xF0 | ((sim >> 18) & 0x07); str[(*index_str)++] = 0x80 | ((sim >> 12) & 0x3F); str[(*index_str)++] = 0x80 | ((sim >> 6) & 0x3F); str[(*index_str)++] = 0x80 | (sim & 0x3F); lenchange += 4; } return lenchange; } int ls_sp(char* str, int* index_str, va_list* ap, form* change) { // широкие строки int lenchange = 0, start_index_str = *index_str; int* sim_str = va_arg(*ap, int*); if (change->accuracy > 0) { for (int i = 0; i < change->accuracy / 4; i++) { lenchange += unicod_char(*sim_str, str, index_str); sim_str++; } } else { while ((*sim_str) != 0) { lenchange += unicod_char(*sim_str, str, index_str); sim_str++; } } if (change->fl_mi && change->width > lenchange) { for (int i = 0; i < change->width - lenchange; i++) { str[(*index_str)] = ' '; (*index_str)++; } lenchange += change->width - lenchange; } else if (!change->fl_mi && change->width > lenchange) { change->fl_nu = 0; (*index_str)--; for (int i = 0; i < change->width - lenchange; i++) { shift_rigth_str(str, start_index_str, index_str, *change); } (*index_str)++; lenchange += change->width - lenchange; } return lenchange; } int s_sp(char* str, int* index_str, va_list* ap, form* change) { int lenchange = 0, start_index_str = *index_str; if (!change->l) { char* sim_str = va_arg(*ap, char*); while ((*sim_str) != '\0') { str[(*index_str)++] = (*sim_str); sim_str++; lenchange++; if (change->accuracy == lenchange) break; } if (change->fl_mi && change->width > lenchange) { for (int i = 0; i < change->width - lenchange; i++) { str[(*index_str)] = ' '; (*index_str)++; } lenchange += change->width - lenchange; } else if (!change->fl_mi && change->width > lenchange) { change->fl_nu = 0; (*index_str)--; for (int i = 0; i < change->width - lenchange; i++) { shift_rigth_str(str, start_index_str, index_str, *change); } (*index_str)++; lenchange += change->width - lenchange; } } else { lenchange = ls_sp(str, index_str, ap, change); } return lenchange; } int unum_sp(char* str, int* index_str, va_list* ap, form* change) { int lenchange = 0, lennum = 0, start_index_str = *index_str, start_index_strspace = start_index_str, del; long long unsigned num, var; num = lenaddunum(*change, ap); if (sigunum(str, index_str, *change, &lenchange, false)) start_index_str++; var = num; lenchange += prefix_num(str, index_str, *change, &start_index_str, &del, num); do { // считаем цифры lennum++; var /= del; } while (var >= 1); for (int i = lennum - 1; i >= 0; i--) { // записываем цифры str[(*index_str) + i] = change_sim(num % del, *change); num /= del; lenchange++; } (*index_str) += lennum; if (change->accuracy > lennum) { // добавляем нули для точности change->fl_nu = true; if (change->sp == 'o' && change->fl_gr) change->accuracy--; --(*index_str); for (int i = 0; i < change->accuracy - lennum; i++) { shift_rigth_str(str, start_index_str, index_str, *change); lenchange++; } change->fl_nu = false; ++(*index_str); } if (change->fl_mi && change->width > lenchange) { // добавляем справа ' ' for (int i = 0; i < change->width - lenchange; i++) { str[(*index_str) + i] = ' '; } (*index_str) += change->width - lenchange; lenchange += change->width - lenchange; } else { if (change->width > lenchange) { (*index_str)--; // добавляем слева ' ' for (int i = 0; i < change->width - lenchange; i++) { shift_rigth_str(str, start_index_strspace, index_str, *change); } lenchange += change->width - lenchange; (*index_str)++; } } return lenchange; } long long unsigned lenaddunum(form change, va_list* ap) { long long unsigned num; if (change.h == true) num = (short unsigned int)va_arg(*ap, unsigned int); else if (change.l == true) num = va_arg(*ap, long unsigned int); else if (change.ll == true) num = va_arg(*ap, long long unsigned); else if (change.hh) num = (unsigned char)va_arg(*ap, unsigned int); else num = va_arg(*ap, unsigned int); return num; } bool sigunum(char* str, int* index_str, form change, int* lenchange, bool count) { bool out = false; if (change.fl_pl) { if (!count) { str[*index_str] = '+'; (*index_str)++; } (*lenchange)++; out = true; } else if (change.fl_sp) { if (!count) { str[*index_str] = ' '; (*index_str)++; } (*lenchange)++; out = true; } return out; } int num_sp(char* str, int* index_str, va_list* ap, form* change) { int lenchange = 0, lennum = 0, start_index_str = *index_str - 1, start_index_strspace = *index_str, del; long long num, var; num = lenaddnum(*change, ap); if (signum(str, index_str, *change, &lenchange, num, false)) start_index_str++; if (num < 0) num *= -1ll; var = num; lenchange += prefix_num(str, index_str, *change, &start_index_str, &del, num); do { // считаем цифры lennum++; var /= del; } while (var >= 1); for (int i = lennum - 1; i >= 0; i--) { // записываем цифры str[(*index_str) + i] = change_sim(num % del, *change); num /= del; lenchange++; } (*index_str) += lennum; if (change->accuracy > lennum) { // добавляем нули для точности change->fl_nu = true; if (change->sp == 'o' && change->fl_gr) change->accuracy--; --(*index_str); for (int i = 0; i < change->accuracy - lennum; i++) { shift_rigth_str(str, start_index_str, index_str, *change); lenchange++; } change->fl_nu = false; ++(*index_str); } if (change->fl_mi && change->width > lenchange) { // добавляем справа ' ' for (int i = 0; i < change->width - lenchange; i++) { str[(*index_str) + i] = ' '; } (*index_str) += change->width - lenchange; lenchange += change->width - lenchange; } else { if (change->width > lenchange) { (*index_str)--; // добавляем слева ' ' for (int i = 0; i < change->width - lenchange; i++) { shift_rigth_str(str, start_index_strspace, index_str, *change); } lenchange += change->width - lenchange; (*index_str)++; } } return lenchange; } int change_sim(int sim, form change) { if (sim < 10) { sim += 48; } else if (change.sp == 'x') { sim += 87; } else if (change.sp == 'X') { sim += 55; } return sim; } // === Функции для %e/%E (от Макса) === int prefix_num(char* str, int* index_str, form change, int* start_index_str, int* del, long long unsigned num) { int lenchange = 0; if (change.sp == 'x' || change.sp == 'X') { *del = 16; if (change.fl_gr) { str[(*index_str)++] = '0'; if (change.sp == 'x') str[(*index_str)++] = 'x'; else if (change.sp == 'X') str[(*index_str)++] = 'X'; lenchange += 2; (*start_index_str) += 2; } } else if (change.sp == 'o') { *del = 8; if (change.fl_gr && num != 0llu) { str[(*index_str)++] = '0'; (*start_index_str)++; lenchange++; } } else if (change.sp == 'd' || change.sp == 'i' || change.sp == 'u') { *del = 10; } return lenchange; } int e_num_change(long double* num, int* exp) { int lenexp = 0; // количество цифр,которуе нужно записать после e int var = 0; // промежуточная переменная if ((*num) >= 10.L) { while ((roundl(*num) >= 10.L)) { (*num) /= 10; (*exp)++; } var = (*exp); } else if ((*num) < 1.L && (*num) != 0) { while ((roundl(*num) < 1.L)) { (*num) *= 10; (*exp)--; } var = (*exp) * -1; } while (var > 0) { var /= 10; lenexp++; } return lenexp; } void point_change(char* str, int* index_str, int* lenchange, form change, bool sign) { int i = *index_str - 1; while (str[i] != '.' && i > -(*lenchange) + *index_str - 1) i--; bool noalter = (!change.fl_gr && change.accuracy == 0); if (noalter && change.fl_mi) { if (i == *index_str - 1) { if (change.width > (*lenchange) - 1) { str[i] = ' '; } else { str[i] = '\0'; (*lenchange)--; (*index_str)--; } } else { --(*index_str); shift_left_str(str, i, *index_str); if (change.width > *lenchange - 1) { str[(*index_str)] = ' '; ++(*index_str); } else (*lenchange)--; } } else if (noalter) { if (sign) { int index_sig = (*index_str) - (*lenchange); if (change.fl_nu && change.width > *lenchange - 1) { i--; shift_rigth_str(str, index_sig + 1, &i, change); } else if (!change.fl_nu && change.width > *lenchange - 1) { i--; shift_rigth_str(str, index_sig, &i, change); } else { (*index_str)--; shift_left_str(str, i, *index_str); (*lenchange)--; } } else { if (change.width > *lenchange - 1) { i--; shift_rigth_str(str, *index_str - *lenchange, &i, change); } else { (*index_str)--; shift_left_str(str, i, *index_str); (*lenchange)--; } } } } int e_sp(char* str, int* index_str, va_list* ap, form* change) { int lenchange = 0, lenspace = 0, start_index_str = *index_str - 1, lenexp = 0, exp = 0; bool sign = false; if (change->accuracy == -1) { change->accuracy = 6; } long double num = lenadddouble(*change, ap); sign = sigdouble(str, index_str, *change, &lenchange, num, false); if (sign && change->fl_nu) start_index_str++; // при смещении вправо знак не будет смещаться if (num < 0) num *= -1.L; lenexp = e_num_change(&num, &exp); lenchange += insert_double(str, index_str, *change, num); if (change->sp == 'e') str[(*index_str)++] = 'e'; if (change->sp == 'E') str[(*index_str)++] = 'E'; if (exp < 0) { str[(*index_str)++] = '-'; exp *= -1; } else str[(*index_str)++] = '+'; if (lenexp <= 2) { str[(*index_str)++] = 48 + exp / 10; str[(*index_str)++] = 48 + (exp % 10); lenchange += 2; } else { for (int i = (*index_str) + lenexp - 1; i >= (*index_str); i--) { str[i] = 48 + exp % 10; exp /= 10; lenchange++; } (*index_str) += lenexp; } lenchange += 2; if (change->fl_mi) { if (change->width > lenchange) { lenspace = change->width - lenchange; for (int i = 0; i < lenspace; i++) { str[*index_str] = ' '; (*index_str)++; } } } else if (change->width > lenchange) { lenspace = change->width - lenchange; --(*index_str); for (int i = start_index_str + 1; i < start_index_str + 1 + lenspace; i++) { shift_rigth_str(str, i, index_str, *change); } ++(*index_str); } lenchange += lenspace; point_change(str, index_str, &lenchange, *change, sign); return lenchange; } // === Функции для %g/%G === // Вычисляет экспоненту числа (порядок) int get_exponent(long double num) { int exp = 0; if (num < 0) num = -num; if (num == 0.0L) return 0; if (num >= 1.0L) { while (num >= 10.0L) { num /= 10.0L; exp++; } } else { while (num < 1.0L) { num *= 10.0L; exp--; } } return exp; } // Убирает trailing zeros и точку (если нет #) void remove_trailing_zeros(char* str, int* index_str, form* change) { if (change->fl_gr) return; // с флагом # не убираем int i = *index_str - 1; // Убираем нули с конца while (i > 0 && str[i] == '0') { i--; } // Убираем точку, если после неё ничего не осталось if (i > 0 && str[i] == '.') { i--; } *index_str = i + 1; str[*index_str] = '\0'; } // Записывает экспоненту в формате e+XX или e-XX int write_exponent(char* str, int* index_str, int exp, char e_char) { int lenchange = 0; str[(*index_str)++] = e_char; lenchange++; if (exp >= 0) { str[(*index_str)++] = '+'; } else { str[(*index_str)++] = '-'; exp = -exp; } lenchange++; // Экспонента минимум 2 цифры if (exp < 10) { str[(*index_str)++] = '0'; str[(*index_str)++] = '0' + exp; lenchange += 2; } else if (exp < 100) { str[(*index_str)++] = '0' + (exp / 10); str[(*index_str)++] = '0' + (exp % 10); lenchange += 2; } else { str[(*index_str)++] = '0' + (exp / 100); str[(*index_str)++] = '0' + ((exp / 10) % 10); str[(*index_str)++] = '0' + (exp % 10); lenchange += 3; } return lenchange; } // Записывает знак числа для %g, возвращает 1 если записан int g_write_sign(char* str, int* index_str, long double num, form* change) { int result = 0; if (num < 0) { str[(*index_str)++] = '-'; result = 1; } else if (change->fl_pl) { str[(*index_str)++] = '+'; result = 1; } else if (change->fl_sp) { str[(*index_str)++] = ' '; result = 1; } return result; } // Округление для %g, обрабатывает перенос void g_round_result(char* str, const int* index_str, long double frac, int start_index_str) { if (frac * 10.0L < 5.0L) return; int j = *index_str - 1; int carry = 1; while (j >= start_index_str && carry != 0) { if (str[j] == '.') { j--; } else if (str[j] >= '0' && str[j] <= '8') { str[j]++; carry = 0; } else if (str[j] == '9') { str[j] = '0'; j--; } else { carry = 0; } } } // Экспоненциальный формат для %g int g_exp_format(char* str, int* index_str, long double abs_num, int precision, form* change) { long double normalized = abs_num; if (abs_num != 0.0L) { while (normalized >= 10.0L) normalized /= 10.0L; while (normalized < 1.0L) normalized *= 10.0L; } int mantissa_prec = (precision - 1 > 0) ? precision - 1 : 0; int digit = (int)normalized; str[(*index_str)++] = '0' + digit; normalized = normalized - digit; if (mantissa_prec > 0 || change->fl_gr) { str[(*index_str)++] = '.'; for (int i = 0; i < mantissa_prec; i++) { normalized *= 10.0L; digit = (int)normalized; str[(*index_str)++] = '0' + digit; normalized = normalized - digit; } } return (int)(normalized * 10.0L); } // Фиксированный формат для %g int g_fixed_format(char* str, int* index_str, long double abs_num, int frac_digits, form* change) { long long int_part = (long long)abs_num; long double frac_part = abs_num - (long double)int_part; if (int_part == 0) { str[(*index_str)++] = '0'; } else { char temp[64]; int temp_len = 0; long long tmp = int_part; while (tmp > 0) { temp[temp_len++] = '0' + (tmp % 10); tmp /= 10; } for (int i = temp_len - 1; i >= 0; i--) { str[(*index_str)++] = temp[i]; } } if (frac_digits > 0 || change->fl_gr) { str[(*index_str)++] = '.'; for (int i = 0; i < frac_digits; i++) { frac_part *= 10.0L; int digit = (int)frac_part; str[(*index_str)++] = '0' + digit; frac_part = frac_part - digit; } } return (int)(frac_part * 10.0L); } // Применяет padding ширины для %g void g_apply_width(char* str, int* index_str, int start_index_str, form* change) { int content_len = *index_str - start_index_str; if (change->width <= content_len) return; int padding = change->width - content_len; if (change->fl_mi) { for (int i = 0; i < padding; i++) { str[(*index_str)++] = ' '; } } else { char pad_char = change->fl_nu ? '0' : ' '; for (int i = *index_str - 1; i >= start_index_str; i--) { str[i + padding] = str[i]; } for (int i = 0; i < padding; i++) { str[start_index_str + i] = pad_char; } *index_str += padding; } } // Спецификатор %g и %G int g_sp(char* str, int* index_str, va_list* ap, form* change) { int start_index_str = *index_str; int precision = (change->accuracy == -1) ? 6 : change->accuracy; if (precision == 0) precision = 1; long double num = lenadddouble(*change, ap); long double abs_num = (num < 0) ? -num : num; int exp = get_exponent(abs_num); bool use_exp = (exp < -4 || exp >= precision); g_write_sign(str, index_str, num, change); int round_digit = 0; if (use_exp) { round_digit = g_exp_format(str, index_str, abs_num, precision, change); g_round_result(str, index_str, round_digit / 10.0L, start_index_str); remove_trailing_zeros(str, index_str, change); char e_char = (change->sp == 'G') ? 'E' : 'e'; write_exponent(str, index_str, exp, e_char); } else { int frac_digits = precision - exp - 1; if (frac_digits < 0) frac_digits = 0; round_digit = g_fixed_format(str, index_str, abs_num, frac_digits, change); g_round_result(str, index_str, round_digit / 10.0L, start_index_str); remove_trailing_zeros(str, index_str, change); } str[*index_str] = '\0'; g_apply_width(str, index_str, start_index_str, change); str[*index_str] = '\0'; return *index_str - start_index_str; } // Записывает hex-адрес для %p int p_write_addr(char* str, int* index_str, uintptr_t addr) { int lenchange = 0; str[(*index_str)++] = '0'; str[(*index_str)++] = 'x'; lenchange += 2; int num_digits = 0; uintptr_t temp = addr; do { num_digits++; temp >>= 4; } while (temp != 0); for (int i = num_digits - 1; i >= 0; i--) { int shift = i * 4; int digit = (addr >> shift) & 0xF; char c = (digit < 10) ? ('0' + digit) : ('a' + digit - 10); str[(*index_str)++] = c; lenchange++; } return lenchange; } // Применяет ширину для %p void p_apply_width(char* str, int* index_str, int start_index, int* lenchange, form* change) { int total_len = *index_str - start_index; if (change->width <= total_len) return; int padding = change->width - total_len; if (change->fl_mi) { for (int i = 0; i < padding; i++) { str[(*index_str)++] = ' '; } } else { for (int i = *index_str - 1; i >= start_index; i--) { str[i + padding] = str[i]; } for (int i = 0; i < padding; i++) { str[start_index + i] = ' '; } *index_str += padding; } *lenchange += padding; } // Спецификатор %p int p_sp(char* str, int* index_str, va_list* ap, form* change) { void* ptr = va_arg(*ap, void*); int start_index = *index_str; int lenchange = 0; if (ptr == NULL) { const char nil_str[] = "(nil)"; for (int i = 0; nil_str[i] != '\0'; ++i) { str[(*index_str)++] = nil_str[i]; ++lenchange; } } else { lenchange = p_write_addr(str, index_str, (uintptr_t)ptr); } p_apply_width(str, index_str, start_index, &lenchange, change); return lenchange; }