fxlibc/src/libc/stdio/printf/format_usual.c

189 lines
5.3 KiB
C

#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <fxlibc/printf.h>
/* Character formatter (%c)
(-) Move spaces to the right
{len} Specifies numbers of (whitespace-padded) characters to print */
void __printf_format_c(
struct __printf_output * restrict out,
struct __printf_format * restrict opt,
va_list * restrict args)
{
int c = va_arg(*args, int);
struct __printf_geometry g = {
.prefix = 0, .sign = 0, .content = 1,
};
__printf_compute_geometry(opt, &g);
__printf_outn(out, ' ', g.left_spaces);
__printf_out(out, c);
__printf_outn(out, ' ', g.right_spaces);
}
/* String formatter (%s)
(-) Move spaces to the right
{len} Minimal numbers of characters to output
{pre} Maximal numbers of bytes to read from argument */
void __printf_format_s(
struct __printf_output * restrict out,
struct __printf_format * restrict opt,
va_list * restrict args)
{
char const *s = va_arg(*args, char const *);
/* Compute content length, which is the smallest of two sizes: the
length set as precision and the actual length of the string */
size_t len = 0;
uint32_t precision = opt->precision ? opt->precision : (-1);
while(s[len] && len < precision) len++;
struct __printf_geometry g = {
.prefix = 0, .sign = 0, .content = len,
};
__printf_compute_geometry(opt, &g);
__printf_outn(out, ' ', g.left_spaces);
for(size_t i = 0; i < len; i++) __printf_out(out, s[i]);
__printf_outn(out, ' ', g.right_spaces);
}
/*Integer formatter (%d, %i)
(0) Pad with zeros, rather than spaces, on the left
(-) Move spaces to the right (overrides '0', extends {pre})
( ) Force a blank sign before nonnegative numbers
(+) Force a sign before every number (overrides ' ')
{len} Minimal number of characters to print
{pre} Forces a minimal number of digits, creating 0s (overrides '0') */
void __printf_format_di(
struct __printf_output * restrict out,
struct __printf_format * restrict opt,
va_list * restrict args)
{
int64_t n = __printf_load_i(opt->size, args);
/* Compute the sign and the absolute value */
struct __printf_geometry g = {
.sign = (n < 0) ? '-' : '+',
.prefix = 0,
.style = _PRINTF_INTEGER,
};
if(n < 0) n = -n;
/* Get the digit string */
char digits[32];
int pure, total;
pure = __printf_digits10(digits, n);
if(opt->precision == 0 && !n) pure = 0;
total = (pure > opt->precision ? pure : opt->precision);
g.content = total;
__printf_compute_geometry(opt, &g);
/* Print the result */
__printf_outn(out, ' ', g.left_spaces);
if(g.sign) __printf_out(out, g.sign);
__printf_outn(out, '0', g.zeros);
__printf_outn(out, '0', total - pure);
for(int i = pure - 1; i >= 0; i--) __printf_out(out, digits[i]);
__printf_outn(out, ' ', g.right_spaces);
}
/* Unsigned integer formatter in various bases (%u, %o, %x)
(#) Enable base prefixes ("0" in octal, "0x" in hexadecimal)
(0) Pad with zeros, rather than spaces, on the left
(-) Move spaces to the right (overrides '0', extends {pre})
{len} Minimal number of characters to print
{pre} Forces a minimal number of digits, creating 0s (overrides '0') */
void __printf_format_ouxX(
struct __printf_output * restrict out,
struct __printf_format * restrict opt,
va_list * restrict args)
{
uint64_t n = __printf_load_u(opt->size, args);
char digits[48];
int pure = 0, total;
int specl = opt->spec | 0x20;
if(specl == 'u') pure = __printf_digits10(digits, n);
if(specl == 'o') pure = __printf_digits8(digits, n);
if(specl == 'x') pure = __printf_digits16(digits, opt->spec == 'X', n);
if(opt->precision == 0 && !n) pure = 0;
total = (pure > opt->precision ? pure : opt->precision);
/* Prefix length */
size_t prefix = 0;
if(opt->alternative) prefix = (specl != 'u') + (specl == 'x');
struct __printf_geometry g = {
.sign = 0, .prefix = prefix, .content = total,
.style = _PRINTF_INTEGER,
};
__printf_compute_geometry(opt, &g);
/* Output */
__printf_outn(out, ' ', g.left_spaces);
if(opt->alternative)
{
if(specl != 'u') __printf_out(out, '0');
if(specl == 'x') __printf_out(out, opt->spec);
}
__printf_outn(out, '0', g.zeros);
__printf_outn(out, '0', total - pure);
for(int i = pure - 1; i >= 0; i--) __printf_out(out, digits[i]);
__printf_outn(out, ' ', g.right_spaces);
}
/* Pointer formatter (%p) */
void __printf_format_p(
struct __printf_output * restrict out,
struct __printf_format * restrict opt,
va_list * restrict args)
{
(void)opt;
void *p = va_arg(*args, void *);
char digits[] = "00000000";
__printf_digits16(digits, 0, (uint32_t)p);
__printf_out(out, '0');
__printf_out(out, 'x');
for(int i = 7; i >= 0; i--) __printf_out(out, digits[i]);
}
/* errno message formatter (%m) */
void __printf_format_m(
struct __printf_output * restrict out,
struct __printf_format * restrict opt,
va_list * restrict args)
{
(void)opt;
(void)args;
char const *message = strerror(errno);
__printf_outstr(out, message, strlen(message));
}
/* Number of characters written so far (%n) */
void __printf_format_n(
struct __printf_output * restrict out,
struct __printf_format * restrict opt,
va_list * restrict args)
{
void *p = va_arg(*args, void *);
if(opt->size == 0) *(char *)p = out->count;
if(opt->size == 1) *(short *)p = out->count;
if(opt->size == 2) *(int *)p = out->count;
if(opt->size == 3) *(long *)p = out->count;
if(opt->size == 4) *(long long *)p = out->count;
}