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