Files
gbdk-2020/gbdk-lib/libc/sprintf.c

110 lines
3.3 KiB
C

#include <types.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>
#if defined(__PORT_mos6502)
typedef void (*emitter_t)(char, char **) REENTRANT;
#else
typedef void (*emitter_t)(char, char **) OLDCALL;
#endif
static const char _hex[] = "0123456789ABCDEF";
inline void _printhex(uint16_t u, emitter_t emitter, char ** pData)
{
(*emitter)(_hex[(uint8_t)(u >> 8) >> 4], pData);
(*emitter)(_hex[(uint8_t)(u >> 8) & 0x0fu], pData);
(*emitter)(_hex[((uint8_t)u >> 4) & 0x0fu], pData);
(*emitter)(_hex[(uint8_t)u & 0x0fu], pData);
}
inline void _printhexbyte(uint8_t u, emitter_t emitter, char ** pData)
{
(*emitter)(_hex[u >> 4], pData);
(*emitter)(_hex[u & 0x0fu], pData);
}
static void _printbuf(char * buf, emitter_t emitter, char ** pData) {
for (char *s = buf; *s; s++) (*emitter)(*s, pData);
}
void __printf(const char *format, emitter_t emitter, char **pData, va_list va)
{
char buf[16];
while ((uint8_t)(*format)) {
if ((uint8_t)(*format) == '%') {
format++;
// 0 Padding is not supported, ignore
if ((uint8_t)(*format) == '0') format++;
// Width Specifier is not supported, ignore 1 digit worth
if ((uint8_t)((uint8_t)(*format) - '1') < 9u) format++;
switch ((uint8_t)(*format)) {
case 'h':
switch ((uint8_t)(*++format)) {
case 'X' :
case 'x' :
_printhexbyte(va_arg(va, char), emitter, pData);
break;
case 'u':
uitoa((unsigned char)va_arg(va, char), buf, 10);
_printbuf(buf, emitter, pData);
break;
case 'd':
itoa((signed char)va_arg(va, char), buf, 10);
_printbuf(buf, emitter, pData);
break;
}
break;
case 'u':
uitoa(va_arg(va, int), buf, 10);
_printbuf(buf, emitter, pData);
break;
case 'd':
itoa(va_arg(va, int), buf, 10);
_printbuf(buf, emitter, pData);
break;
case 's':
_printbuf(va_arg(va, char *), emitter, pData);
break;
case 'c':
char c = va_arg(va, char);
(*emitter)(c, pData);
break;
case 'X':
case 'x':
_printhex(va_arg(va, int), emitter, pData);
break;
default:
(*emitter)(*format, pData);
break;
}
} else {
(*emitter)(*format, pData);
}
format++;
}
}
#if defined(__PORT_mos6502)
static void _sprintf_emitter(char c, char ** pData) REENTRANT
#else
static void _sprintf_emitter(char c, char ** pData) OLDCALL
#endif
{
**pData = c;
(*pData)++;
}
void sprintf(char *into, const char *format, ...) {
va_list va;
va_start(va, format);
__printf(format, _sprintf_emitter, &into, va);
_sprintf_emitter('\0', &into);
}