/** * 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; }