hos/src/hulk/writef.d

152 lines
3.4 KiB
D

/**
* HULK Formatted stream writing support.
*/
module hulk.writef;
import core.stdc.stdarg;
alias ch_out_fn = void function(ubyte);
/**
* Format a string and write characters to the given output function.
*
* @param s Format string.
* @param args Variable arguments structure.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
size_t writef(string s, va_list args, ch_out_fn ch_out)
{
size_t length_written;
bool escape = false;
char pad = ' ';
size_t width;
foreach (char c; s)
{
if (escape)
{
if (c == 'x')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, false, pad, width, ch_out);
escape = false;
}
else if (c == 'X')
{
ulong v;
va_arg(args, v);
length_written += write_hex(v, true, pad, width, ch_out);
escape = false;
}
else if (c == 'u')
{
ulong v;
va_arg(args, v);
length_written += write_udec(v, pad, width, ch_out);
escape = false;
}
else if ((c == '0') && (width == 0u))
{
pad = '0';
}
else if (('0' <= c) && (c <= '9'))
{
width = (width * 10u) + (c - '0');
}
else
{
ch_out(c);
escape = false;
}
}
else if (c == '%')
{
escape = true;
pad = ' ';
width = 0u;
}
else
{
ch_out(c);
}
}
return length_written;
}
/**
* Format a value in hexadecimal to the given output function.
*
* @param v Value to format.
* @param upper Whether to use uppercase letters.
* @param pad Pad character to use.
* @param width Field width.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
private size_t write_hex(ulong v, bool upper, char pad, size_t width, ch_out_fn ch_out)
{
static __gshared string hex_chars_lower = "0123456789abcdef";
static __gshared string hex_chars_upper = "0123456789ABCDEF";
static __gshared char[16] buf;
size_t i;
do
{
ulong n = v & 0xFu;
buf[i] = upper ? hex_chars_upper[n] : hex_chars_lower[n];
v >>= 4u;
i++;
} while (v != 0u);
size_t length_written = i;
while (width > i)
{
ch_out(pad);
width--;
length_written++;
}
do
{
i--;
ch_out(buf[i]);
} while (i != 0u);
return length_written;
}
/**
* Format a value in decimal to the given output function.
*
* @param v Value to format.
* @param pad Pad character to use.
* @param width Field width.
* @param ch_out Character output function.
*
* @return Number of characters written.
*/
private size_t write_udec(ulong v, char pad, size_t width, ch_out_fn ch_out)
{
static __gshared char[20] buf;
size_t i;
do
{
ulong d = v % 10u;
buf[i] = cast(char)(d + '0');
v /= 10u;
i++;
} while (v != 0u);
size_t length_written = i;
while (width > i)
{
ch_out(pad);
width--;
length_written++;
}
do
{
i--;
ch_out(buf[i]);
} while (i != 0u);
return length_written;
}