cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

sprintf.c (3400B)


      1#include <types.h>
      2#include <stdio.h>
      3#include <stdarg.h>
      4#include <stdlib.h>
      5#include <stdint.h>
      6
      7typedef void (*emitter_t)(char, char **) OLDCALL;
      8
      9static const char _hex[] = "0123456789ABCDEF";
     10
     11inline void _printhex(uint16_t u, emitter_t emitter, char ** pData)
     12{
     13    (*emitter)(_hex[(uint8_t)(u >> 8) >> 4], pData);
     14    (*emitter)(_hex[(uint8_t)(u >> 8) & 0x0fu], pData);
     15    (*emitter)(_hex[((uint8_t)u >> 4) & 0x0fu], pData);
     16    (*emitter)(_hex[(uint8_t)u & 0x0fu], pData);
     17}
     18
     19inline void _printhexbyte(uint8_t u, emitter_t emitter, char ** pData)
     20{
     21    (*emitter)(_hex[u >> 4], pData);
     22    (*emitter)(_hex[u & 0x0fu], pData);
     23}
     24
     25static void _printbuf(char * buf, emitter_t emitter, char ** pData) {
     26    for (char *s = buf; *s; s++) (*emitter)(*s, pData);
     27}
     28
     29void __printf(const char *format, emitter_t emitter, char **pData, va_list va)
     30{
     31    char buf[16];
     32    while ((uint8_t)(*format)) {
     33        if ((uint8_t)(*format) == '%') {
     34            format++;
     35
     36            // 0 Padding is not supported, ignore
     37            if ((uint8_t)(*format) == '0') format++;
     38
     39            // Width Specifier is not supported, ignore 1 digit worth
     40            if ((uint8_t)((uint8_t)(*format) - '1') < 9u) format++;
     41
     42            switch ((uint8_t)(*format)) {
     43                case 'h': {
     44                    switch ((uint8_t)(*++format)) {
     45                        case 'X' :
     46                        case 'x' : {
     47                            _printhexbyte(va_arg(va, char), emitter, pData);
     48                            break;
     49                        }
     50                        case 'u':
     51                        {
     52                            uitoa((unsigned char)va_arg(va, char), buf, 10);
     53                            _printbuf(buf, emitter, pData);
     54                            break;
     55                        }
     56                        case 'd':
     57                        {
     58                            itoa((signed char)va_arg(va, char), buf, 10);
     59                            _printbuf(buf, emitter, pData);
     60                            break;
     61                        }
     62                    }
     63                    break;
     64                }
     65                case 'c': {
     66                    char c = va_arg(va, char);
     67                    (*emitter)(c, pData);
     68                    break;
     69                }
     70                case 'u':
     71                {
     72                    uitoa(va_arg(va, int), buf, 10);
     73                    _printbuf(buf, emitter, pData);
     74                    break;
     75                }
     76                case 'd':
     77                {
     78                    itoa(va_arg(va, int), buf, 10);
     79                    _printbuf(buf, emitter, pData);
     80                    break;
     81                }
     82                case 'X':
     83                case 'x':
     84                {
     85                    _printhex(va_arg(va, int), emitter, pData);
     86                    break;
     87                }
     88                case 's': 
     89                {
     90                    _printbuf(va_arg(va, char *), emitter, pData);
     91                    break;
     92                }
     93            }
     94        } else {
     95            (*emitter)(*format, pData);
     96        }
     97        format++;
     98    }
     99}
    100
    101static void _sprintf_emitter(char c, char ** pData) OLDCALL {
    102    **pData = c;
    103    (*pData)++;
    104}
    105
    106void sprintf(char *into, const char *format, ...) OLDCALL {
    107    va_list va;
    108    va_start(va, format);
    109
    110    __printf(format, _sprintf_emitter, &into, va);
    111    _sprintf_emitter('\0', &into);
    112}