/*1* Copyright (c) 2018 naehrwert2* Copyright (c) 2019-2024 CTCaer3*4* This program is free software; you can redistribute it and/or modify it5* under the terms and conditions of the GNU General Public License,6* version 2, as published by the Free Software Foundation.7*8* This program is distributed in the hope it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for11* more details.12*13* You should have received a copy of the GNU General Public License14* along with this program. If not, see <http://www.gnu.org/licenses/>.15*/1617#include <stdarg.h>18#include <string.h>1920#include <utils/types.h>2122char **sout_buf;2324static void _s_putc(char c)25{26**sout_buf = c;27*sout_buf += 1;28}2930static void _s_putspace(int fcnt)31{32if (fcnt <= 0)33return;3435for (int i = 0; i < fcnt; i++)36_s_putc(' ');37}3839static void _s_puts(char *s, char fill, int fcnt)40{41if (fcnt)42{43fcnt = fcnt - strlen(s);4445// Left padding. Check if padding is not space based (dot counts as such).46if (fill != '.')47_s_putspace(fcnt);48}4950for (; *s; s++)51_s_putc(*s);5253// Right padding. Check if padding is space based (dot counts as such).54if (fill == '.')55_s_putspace(fcnt);56}5758static void _s_putn(u32 v, int base, char fill, int fcnt)59{60static const char digits[] = "0123456789ABCDEF";6162char *p;63char buf[65]; // Number char size + leftover for padding.64int c = fcnt;65bool negative = false;6667if (base != 10 && base != 16)68return;6970// Account for negative numbers.71if (base == 10 && v & 0x80000000)72{73negative = true;74v = (int)v * -1;75c--;76}7778p = buf + 64;79*p = 0;80do81{82c--;83*--p = digits[v % base];84v /= base;85} while (v);8687if (negative)88*--p = '-';8990if (fill != 0)91{92while (c > 0 && p > buf)93{94*--p = fill;95c--;96}97}9899_s_puts(p, 0, 0);100}101102/*103* Padding:104* Numbers:105* %3d: Fill: ' ', Count: 3.106* % 3d: Fill: ' ', Count: 3.107* %.3d: Fill: '.', Count: 3.108* %23d: Fill: '2', Count: 3.109* % 23d: Fill: ' ', Count: 23.110* %223d: Fill: '2', Count: 23.111*112* Strings, Fill: ' ':113* %3s: Count: 5, Left.114* %23s: Count: 5, Left.115* %223s: Count: 25, Left.116* %.3s: Count: 5, Right.117* %.23s: Count: 25, Right.118* %.223s: Count: 225, Right.119*/120121void s_printf(char *out_buf, const char *fmt, ...)122{123va_list ap;124int fill, fcnt;125126sout_buf = &out_buf;127128va_start(ap, fmt);129while (*fmt)130{131if (*fmt == '%')132{133fmt++;134fill = 0;135fcnt = 0;136137// Check for padding. Number or space based (dot count as space for string).138if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ' || *fmt == '.')139{140fcnt = *fmt; // Padding size or padding type.141fmt++;142143if (*fmt >= '0' && *fmt <= '9')144{145// Padding size exists. Previous char was type.146fill = fcnt;147fcnt = *fmt - '0';148fmt++;149parse_padding_dec:150// Parse padding size extra digits.151if (*fmt >= '0' && *fmt <= '9')152{153fcnt = fcnt * 10 + *fmt - '0';154fmt++;155goto parse_padding_dec;156}157}158else159{160// No padding type, use space. (Max padding size is 9).161fill = ' ';162fcnt -= '0';163}164}165166switch (*fmt)167{168case 'c':169char c = va_arg(ap, u32);170if (c != '\0')171_s_putc(c);172break;173174case 'd':175_s_putn(va_arg(ap, u32), 10, fill, fcnt);176break;177178case 's':179_s_puts(va_arg(ap, char *), fill, fcnt);180break;181182case 'p':183case 'P':184case 'x':185case 'X':186_s_putn(va_arg(ap, u32), 16, fill, fcnt);187break;188189case '%':190_s_putc('%');191break;192193case '\0':194goto out;195196default:197_s_putc('%');198_s_putc(*fmt);199break;200}201}202else203_s_putc(*fmt);204fmt++;205}206207out:208**sout_buf = '\0';209va_end(ap);210}211212void s_vprintf(char *out_buf, const char *fmt, va_list ap)213{214int fill, fcnt;215216sout_buf = &out_buf;217218while (*fmt)219{220if (*fmt == '%')221{222fmt++;223fill = 0;224fcnt = 0;225226// Check for padding. Number or space based.227if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')228{229fcnt = *fmt; // Padding size or padding type.230fmt++;231232if (*fmt >= '0' && *fmt <= '9')233{234// Padding size exists. Previous char was type.235fill = fcnt;236fcnt = *fmt - '0';237fmt++;238parse_padding_dec:239// Parse padding size extra digits.240if (*fmt >= '0' && *fmt <= '9')241{242fcnt = fcnt * 10 + *fmt - '0';243fmt++;244goto parse_padding_dec;245}246}247else248{249// No padding type, use space. (Max padding size is 9).250fill = ' ';251fcnt -= '0';252}253}254255switch (*fmt)256{257case 'c':258char c = va_arg(ap, u32);259if (c != '\0')260_s_putc(c);261break;262263case 'd':264_s_putn(va_arg(ap, u32), 10, fill, fcnt);265break;266267case 's':268_s_puts(va_arg(ap, char *), fill, fcnt);269break;270271case 'p':272case 'P':273case 'x':274case 'X':275_s_putn(va_arg(ap, u32), 16, fill, fcnt);276break;277278case '%':279_s_putc('%');280break;281282case '\0':283goto out;284285default:286_s_putc('%');287_s_putc(*fmt);288break;289}290}291else292_s_putc(*fmt);293fmt++;294}295296out:297**sout_buf = '\0';298}299300301