192 lines
4.5 KiB
D
192 lines
4.5 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 ch_out Character output function.
|
|
* @param s Format string.
|
|
* @param args Variable arguments structure.
|
|
*
|
|
* @return Number of characters written.
|
|
*/
|
|
size_t writefv(ch_out_fn ch_out, string s, va_list args)
|
|
{
|
|
size_t length_written;
|
|
bool escape = false;
|
|
char pad = ' ';
|
|
size_t width;
|
|
foreach (char c; s)
|
|
{
|
|
if (escape)
|
|
{
|
|
if (c == 'c')
|
|
{
|
|
ulong ch;
|
|
va_arg(args, ch);
|
|
ch_out(cast(ubyte)ch);
|
|
length_written++;
|
|
escape = false;
|
|
}
|
|
else if (c == 'p')
|
|
{
|
|
ulong v;
|
|
va_arg(args, v);
|
|
length_written += write_hex(v, true, true, pad, width, ch_out);
|
|
escape = false;
|
|
}
|
|
else if (c == 'x')
|
|
{
|
|
ulong v;
|
|
va_arg(args, v);
|
|
length_written += write_hex(v, false, false, pad, width, ch_out);
|
|
escape = false;
|
|
}
|
|
else if (c == 'X')
|
|
{
|
|
ulong v;
|
|
va_arg(args, v);
|
|
length_written += write_hex(v, true, false, 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 string and write characters to the given output function.
|
|
*
|
|
* @param ch_out Character output function.
|
|
* @param s Format string.
|
|
*
|
|
* @return Number of characters written.
|
|
*/
|
|
extern(C) size_t writef(ch_out_fn ch_out, string s, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, s);
|
|
size_t rv = writefv(ch_out, s, args);
|
|
va_end(args);
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* Format a value in hexadecimal to the given output function.
|
|
*
|
|
* @param v Value to format.
|
|
* @param upper Whether to use uppercase letters.
|
|
* @param pointer Whether to format as a pointer.
|
|
* @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, bool pointer, char pad, size_t width, ch_out_fn ch_out)
|
|
{
|
|
static __gshared const(char)[16] hex_chars_lower = "0123456789abcdef";
|
|
static __gshared const(char)[16] hex_chars_upper = "0123456789ABCDEF";
|
|
char[19] buf;
|
|
size_t digit;
|
|
size_t buf_idx;
|
|
do
|
|
{
|
|
ulong n = v & 0xFu;
|
|
buf[buf_idx] = upper ? hex_chars_upper[n] : hex_chars_lower[n];
|
|
v >>= 4u;
|
|
buf_idx++;
|
|
digit++;
|
|
if (pointer && ((digit % 4) == 0) && (v != 0u))
|
|
{
|
|
buf[buf_idx] = '_';
|
|
buf_idx++;
|
|
}
|
|
} while (v != 0u);
|
|
size_t length_written = buf_idx;
|
|
while (width > buf_idx)
|
|
{
|
|
ch_out(pad);
|
|
width--;
|
|
length_written++;
|
|
}
|
|
do
|
|
{
|
|
buf_idx--;
|
|
ch_out(buf[buf_idx]);
|
|
} while (buf_idx != 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)
|
|
{
|
|
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;
|
|
}
|