2020-09-17 19:27:01 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2020-10-14 12:07:29 +02:00
|
|
|
// internal depency
|
|
|
|
// TODO: update path detection
|
|
|
|
#include "../src/stdio/internal/printf.h"
|
|
|
|
|
2020-09-17 19:27:01 +02:00
|
|
|
// Define all actions
|
|
|
|
static void action_str(struct printf_opt *op, char n);
|
|
|
|
static void action_ptr(struct printf_opt *op, char n);
|
|
|
|
static void action_int(struct printf_opt *op, char n);
|
|
|
|
static void action_uint(struct printf_opt *op, char n);
|
|
|
|
static void action_char(struct printf_opt *op, char n);
|
|
|
|
|
|
|
|
// Define all actions which can be used
|
|
|
|
void (*action[26])(struct printf_opt *opt, char n) = {
|
|
|
|
NULL, NULL, action_char, action_int,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
action_int, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, action_uint, action_ptr,
|
|
|
|
NULL, NULL, action_str, NULL,
|
|
|
|
action_uint, NULL, NULL, action_uint,
|
|
|
|
NULL, NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Disp part
|
|
|
|
//---
|
|
|
|
static void base_to_str(struct printf_opt *opt, uint32_t num, int base, int digits)
|
|
|
|
{
|
|
|
|
char *hexa = (opt->uppercase == 1) ? "0123456789ABCDEF" : "0123456789abcdef";
|
2020-10-14 12:07:29 +02:00
|
|
|
|
2020-09-17 19:27:01 +02:00
|
|
|
opt->digits = 0;
|
|
|
|
while (num != 0 || opt->digits < digits)
|
|
|
|
{
|
|
|
|
opt->format[opt->digits++] = hexa[num % base];
|
|
|
|
num = num / base;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_format(struct printf_opt *opt)
|
|
|
|
{
|
|
|
|
// display pre symbols
|
|
|
|
if (opt->sign != '\0')
|
|
|
|
(*opt->disp_char)(opt, opt->sign);
|
|
|
|
if (opt->base[0] != '\0')
|
|
|
|
(*opt->disp_char)(opt, opt->base[0]);
|
|
|
|
if (opt->base[1] != '\0')
|
|
|
|
(*opt->disp_char)(opt, opt->base[1]);
|
|
|
|
|
|
|
|
// padding
|
|
|
|
if (opt->flags.minus == 1 && opt->width > opt->digits)
|
|
|
|
{
|
|
|
|
int total = opt->digits + (opt->sign != '\0') +
|
|
|
|
(opt->base[0] != '\0') + (opt->base[1] != '\0');
|
|
|
|
total = opt->width - total;
|
|
|
|
while (--total >= 0)
|
|
|
|
(*opt->disp_char)(opt, (opt->flags.zero == 1) ? '0' : ' ');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display number
|
|
|
|
int saved_digits = opt->digits;
|
|
|
|
while (--opt->digits >= 0)
|
|
|
|
(*opt->disp_char)(opt, opt->format[opt->digits]);
|
|
|
|
|
|
|
|
// padding
|
|
|
|
if (opt->flags.minus == 0 && opt->width > saved_digits)
|
|
|
|
{
|
|
|
|
int total = saved_digits + (opt->sign != '\0') +
|
|
|
|
(opt->base[0] != '\0') + (opt->base[1] != '\0');
|
|
|
|
total = opt->width - total;
|
|
|
|
while (--total >= 0)
|
|
|
|
(*opt->disp_char)(opt, ' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Args part
|
|
|
|
//---
|
|
|
|
static uint32_t get_arg_i(struct printf_opt *opt)
|
|
|
|
{
|
|
|
|
switch (opt->lenght)
|
|
|
|
{
|
|
|
|
case 0: return ((signed char)va_arg(opt->ap, int));
|
|
|
|
case 1: return ((short int)va_arg(opt->ap, int));
|
|
|
|
case 2: return (va_arg(opt->ap, long int));
|
|
|
|
case 3: return (va_arg(opt->ap, long long int));
|
|
|
|
case 4: return (va_arg(opt->ap, intmax_t));
|
|
|
|
case 5: return (va_arg(opt->ap, size_t));
|
|
|
|
case 6: return (va_arg(opt->ap, ptrdiff_t));
|
|
|
|
}
|
|
|
|
return (va_arg(opt->ap, int));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t get_arg_u(struct printf_opt *opt)
|
|
|
|
{
|
|
|
|
switch (opt->lenght)
|
|
|
|
{
|
|
|
|
case 0: return ((unsigned char)va_arg(opt->ap, int));
|
|
|
|
case 1: return ((unsigned short int)va_arg(opt->ap, int));
|
|
|
|
case 2: return (va_arg(opt->ap, unsigned long int));
|
|
|
|
case 3: return (va_arg(opt->ap, unsigned long long int));
|
|
|
|
case 4: return (va_arg(opt->ap, intmax_t));
|
|
|
|
case 5: return (va_arg(opt->ap, size_t));
|
|
|
|
case 6: return (va_arg(opt->ap, ptrdiff_t));
|
|
|
|
}
|
|
|
|
return (va_arg(opt->ap, unsigned int));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Actions part.
|
|
|
|
//---
|
|
|
|
static void action_str(struct printf_opt *opt, char n)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
(void)n;
|
|
|
|
str = va_arg(opt->ap, const char *);
|
|
|
|
while (*str != '\0')
|
|
|
|
(*opt->disp_char)(opt, *(str++));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void action_char(struct printf_opt *opt, char n)
|
|
|
|
{
|
|
|
|
n = (char)va_arg(opt->ap, int);
|
|
|
|
(*opt->disp_char)(opt, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void action_ptr(struct printf_opt *opt, char n)
|
|
|
|
{
|
|
|
|
(void)n;
|
|
|
|
opt->sign = '@';
|
|
|
|
opt->base[0] = '0';
|
|
|
|
opt->base[1] = 'x';
|
2020-10-14 12:07:29 +02:00
|
|
|
base_to_str(opt, (uintptr_t)va_arg(opt->ap, void*), 16, 8);
|
2020-09-17 19:27:01 +02:00
|
|
|
disp_format(opt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void action_int(struct printf_opt *opt, char n)
|
|
|
|
{
|
|
|
|
int64_t num;
|
|
|
|
|
|
|
|
// Get data and check negative value
|
|
|
|
// FIXME: max negative value can not be reversed
|
|
|
|
(void)n;
|
|
|
|
num = get_arg_i(opt);
|
|
|
|
if (num < 0) {
|
|
|
|
opt->sign = '-';
|
|
|
|
num = -num;
|
|
|
|
} else if (opt->flags.space == 1 || opt->flags.plus == 1) {
|
|
|
|
opt->sign = (opt->flags.plus == 1) ? '+' : ' ';
|
|
|
|
}
|
|
|
|
|
2020-10-14 12:07:29 +02:00
|
|
|
// Generate / display number
|
2020-09-17 19:27:01 +02:00
|
|
|
base_to_str(opt, num, 10, 1);
|
|
|
|
disp_format(opt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void action_uint(struct printf_opt *opt, char n)
|
|
|
|
{
|
|
|
|
uint32_t num;
|
|
|
|
int base;
|
|
|
|
|
|
|
|
// Get appropriate base
|
|
|
|
switch (n)
|
|
|
|
{
|
|
|
|
case 'o': base = 8; break;
|
|
|
|
case 'x': base = 16; break;
|
|
|
|
default: base = 10; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display extra symbols if needed
|
2020-10-14 12:07:29 +02:00
|
|
|
if (opt->flags.diez == 1) {
|
2020-09-17 19:27:01 +02:00
|
|
|
if (n == 'o') {
|
|
|
|
opt->base[0] = '0';
|
|
|
|
} else if (n == 'x') {
|
|
|
|
opt->base[0] = '0';
|
|
|
|
opt->base[1] = (opt->uppercase == 1) ? 'X' : 'x';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get number
|
|
|
|
num = get_arg_u(opt);
|
|
|
|
|
|
|
|
// Generate / display number
|
|
|
|
base_to_str(opt, num, base, 1);
|
|
|
|
disp_format(opt);
|
|
|
|
}
|