hekate/bdk/utils/sprintf.c

259 lines
4.2 KiB
C
Raw Permalink Normal View History

/*
* Copyright (c) 2018 naehrwert
2024-01-07 10:38:10 +00:00
* Copyright (c) 2019-2024 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <string.h>
#include <utils/types.h>
char **sout_buf;
static void _s_putc(char c)
{
**sout_buf = c;
*sout_buf += 1;
}
static void _s_puts(char *s)
{
for (; *s; s++)
_s_putc(*s);
}
static void _s_putn(u32 v, int base, char fill, int fcnt)
{
static const char digits[] = "0123456789ABCDEF";
char *p;
2024-02-16 14:01:54 +00:00
char buf[65]; // Number char size + leftover for padding.
int c = fcnt;
bool negative = false;
if (base != 10 && base != 16)
return;
// Account for negative numbers.
if (base == 10 && v & 0x80000000)
{
negative = true;
v = (int)v * -1;
c--;
}
p = buf + 64;
*p = 0;
do
{
c--;
*--p = digits[v % base];
v /= base;
} while (v);
if (negative)
*--p = '-';
if (fill != 0)
{
while (c > 0 && p > buf)
{
*--p = fill;
c--;
}
}
_s_puts(p);
}
void s_printf(char *out_buf, const char *fmt, ...)
{
va_list ap;
int fill, fcnt;
sout_buf = &out_buf;
va_start(ap, fmt);
while (*fmt)
{
if (*fmt == '%')
{
fmt++;
fill = 0;
fcnt = 0;
2024-02-16 14:01:54 +00:00
// Check for padding. Number or space based.
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')
{
2024-02-16 14:01:54 +00:00
fcnt = *fmt; // Padding size or padding type.
fmt++;
2024-02-16 14:01:54 +00:00
if (*fmt >= '0' && *fmt <= '9')
{
2024-02-16 14:01:54 +00:00
// Padding size exists. Previous char was type.
fill = fcnt;
fcnt = *fmt - '0';
fmt++;
2024-02-16 14:01:54 +00:00
parse_padding_dec:
// Parse padding size extra digits.
if (*fmt >= '0' && *fmt <= '9')
{
fcnt = fcnt * 10 + *fmt - '0';
fmt++;
goto parse_padding_dec;
}
}
else
{
2024-02-16 14:01:54 +00:00
// No padding type, use space. (Max padding size is 9).
fill = ' ';
fcnt -= '0';
}
}
2024-02-16 14:01:54 +00:00
switch (*fmt)
{
case 'c':
char c = va_arg(ap, u32);
if (c != '\0')
_s_putc(c);
break;
2024-02-16 14:01:54 +00:00
case 's':
_s_puts(va_arg(ap, char *));
break;
2024-02-16 14:01:54 +00:00
case 'd':
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
break;
2024-02-16 14:01:54 +00:00
case 'p':
case 'P':
case 'x':
case 'X':
_s_putn(va_arg(ap, u32), 16, fill, fcnt);
break;
2024-02-16 14:01:54 +00:00
case '%':
_s_putc('%');
break;
2024-02-16 14:01:54 +00:00
case '\0':
goto out;
2024-02-16 14:01:54 +00:00
default:
_s_putc('%');
_s_putc(*fmt);
break;
}
}
else
_s_putc(*fmt);
fmt++;
}
out:
**sout_buf = '\0';
va_end(ap);
2022-01-20 10:37:41 +00:00
}
void s_vprintf(char *out_buf, const char *fmt, va_list ap)
{
int fill, fcnt;
sout_buf = &out_buf;
while (*fmt)
2022-01-20 10:37:41 +00:00
{
if (*fmt == '%')
2022-01-20 10:37:41 +00:00
{
fmt++;
fill = 0;
fcnt = 0;
2024-02-16 14:01:54 +00:00
// Check for padding. Number or space based.
2022-01-20 10:37:41 +00:00
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')
{
2024-02-16 14:01:54 +00:00
fcnt = *fmt; // Padding size or padding type.
2022-01-20 10:37:41 +00:00
fmt++;
2024-02-16 14:01:54 +00:00
2022-01-20 10:37:41 +00:00
if (*fmt >= '0' && *fmt <= '9')
{
2024-02-16 14:01:54 +00:00
// Padding size exists. Previous char was type.
2022-01-20 10:37:41 +00:00
fill = fcnt;
fcnt = *fmt - '0';
fmt++;
2024-02-16 14:01:54 +00:00
parse_padding_dec:
// Parse padding size extra digits.
if (*fmt >= '0' && *fmt <= '9')
{
fcnt = fcnt * 10 + *fmt - '0';
fmt++;
goto parse_padding_dec;
}
2022-01-20 10:37:41 +00:00
}
else
{
2024-02-16 14:01:54 +00:00
// No padding type, use space. (Max padding size is 9).
2022-01-20 10:37:41 +00:00
fill = ' ';
fcnt -= '0';
}
}
2024-02-16 14:01:54 +00:00
switch (*fmt)
2022-01-20 10:37:41 +00:00
{
case 'c':
2024-02-16 14:01:54 +00:00
char c = va_arg(ap, u32);
if (c != '\0')
_s_putc(c);
2022-01-20 10:37:41 +00:00
break;
2024-02-16 14:01:54 +00:00
2022-01-20 10:37:41 +00:00
case 's':
_s_puts(va_arg(ap, char *));
break;
2024-02-16 14:01:54 +00:00
2022-01-20 10:37:41 +00:00
case 'd':
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
break;
2024-02-16 14:01:54 +00:00
2022-01-20 10:37:41 +00:00
case 'p':
case 'P':
case 'x':
case 'X':
_s_putn(va_arg(ap, u32), 16, fill, fcnt);
break;
2024-02-16 14:01:54 +00:00
2022-01-20 10:37:41 +00:00
case '%':
_s_putc('%');
break;
2024-02-16 14:01:54 +00:00
2022-01-20 10:37:41 +00:00
case '\0':
goto out;
2024-02-16 14:01:54 +00:00
2022-01-20 10:37:41 +00:00
default:
_s_putc('%');
_s_putc(*fmt);
break;
}
}
else
_s_putc(*fmt);
fmt++;
}
out:
**sout_buf = '\0';
}