Picklock_RCM/source/utils/sprintf.c

121 lines
3.0 KiB
C
Raw Normal View History

/*
* Copyright (c) 2019 shchmue
*
* 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 "types.h"
#include <stdarg.h>
static void _putc(char *buffer, const char c) {
*buffer = c;
}
static u32 _puts(char *buffer, const char *s) {
u32 count = 0;
for (; *s; s++, count++)
_putc(buffer + count, *s);
return count;
}
static u32 _putn(char *buffer, u32 v, int base, char fill, int fcnt) {
char buf[0x121];
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
char *p;
int c = fcnt;
if (base > 36)
return 0;
p = buf + 0x120;
*p = 0;
do {
c--;
*--p = digits[v % base];
v /= base;
} while (v);
if (fill != 0) {
while (c > 0) {
*--p = fill;
c--;
}
}
return _puts(buffer, p);
}
u32 sprintf(char *buffer, const char *fmt, ...) {
va_list ap;
int fill, fcnt;
u32 count = 0;
va_start(ap, fmt);
while(*fmt) {
if (*fmt == '%') {
fmt++;
fill = 0;
fcnt = 0;
if ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ') {
fcnt = *fmt;
fmt++;
if (*fmt >= '0' && *fmt <= '9') {
fill = fcnt;
fcnt = *fmt - '0';
fmt++;
} else {
fill = ' ';
fcnt -= '0';
}
}
switch (*fmt) {
case 'c':
_putc(buffer + count, va_arg(ap, u32));
count++;
break;
case 's':
count += _puts(buffer + count, va_arg(ap, char *));
break;
case 'd':
count += _putn(buffer + count, va_arg(ap, u32), 10, fill, fcnt);
break;
case 'p':
case 'P':
case 'x':
case 'X':
count += _putn(buffer + count, va_arg(ap, u32), 16, fill, fcnt);
break;
case '%':
_putc(buffer + count, '%');
count++;
break;
case '\0':
goto out;
default:
_putc(buffer + count, '%');
_putc(buffer + count, *fmt);
count += 2;
break;
}
} else {
_putc(buffer + count, *fmt);
count++;
}
fmt++;
}
out:
va_end(ap);
return count;
}