void sb_efunc(const char *color, const char *hilight, const char *format, ...) { save_errno(); int fd = STDERR_FILENO; if (!init_color) { nocolor = is_env_on(ENV_NOCOLOR); init_color = true; } if (!nocolor) sb_fdprintf(fd, "%s%s%s", color, hilight, COLOR_NORMAL); else sb_fdprintf(fd, "%s", hilight); va_list args; va_start(args, format); sb_vfdprintf(fd, format, args); va_end(args); restore_errno(); }
void sb_vfdprintf(int fd, const char *format, va_list args) { const char *fmt = format; const char *format_end = format + strlen(format); const char *conv = fmt; while (fmt < format_end) { conv = memchr(fmt, '%', format_end - fmt); if (conv != fmt) { size_t out_bytes = (conv ? conv : format_end) - fmt; sb_write(fd, fmt, out_bytes); if (!conv) return; } char buf[50]; size_t idx; unsigned int u, x; char hex_base; size_t padding = 0; unsigned int modifiers = 0; eat_more: switch (conv[1]) { default: sb_fdprintf(fd, "{invalid conversion specifier in string: %s}", format); break; case '%': if (modifiers) { inv_modifier: sb_fdprintf(fd, "{invalid modifier in string: %s}", format); } sb_write(fd, conv, 1); break; case 'z': ++conv; if (modifiers & MOD_SIZE_T) goto inv_modifier; modifiers |= MOD_SIZE_T; goto eat_more; case '*': ++conv; if (modifiers & MOD_STAR) goto inv_modifier; modifiers |= MOD_STAR; padding = va_arg(args, int); goto eat_more; case 'c': { char c = va_arg(args, int); sb_write(fd, &c, 1); break; } case 's': { char *s = va_arg(args, char *); if (!s) s = "(null)"; size_t len = strlen(s); while (len < padding--) sb_write(fd, " ", 1); sb_write(fd, s, len); break; } case 'd': case 'i': { long i; if (modifiers & MOD_SIZE_T) i = va_arg(args, ssize_t); else i = va_arg(args, int); u = i; if (i < 0) { sb_write(fd, "-", 1); u = i * -1; } out_uint: idx = 0; do { buf[idx++] = '0' + (u % 10); } while (u /= 10); while (idx--) sb_write(fd, buf+idx, 1); break; } case 'u': { u = va_arg(args, unsigned int); goto out_uint; break; } case 'X': { hex_base = 'A'; goto out_hex; } case 'x': { hex_base = 'a'; out_hex: if (modifiers & MOD_SIZE_T) x = va_arg(args, size_t); else x = va_arg(args, unsigned int); out_ptr: idx = 0; do { u = x % 16; buf[idx++] = (u < 10 ? '0' + u : hex_base + u - 10); } while (x /= 16); while (idx < padding) buf[idx++] = '0'; buf[idx++] = 'x'; buf[idx++] = '0'; while (idx--) sb_write(fd, buf+idx, 1); break; } case 'p': { void *p = va_arg(args, void *); hex_base = 'a'; padding = sizeof(p) * 2; x = (unsigned long)p; goto out_ptr; } } fmt = conv + 2; } }
void sb_vfdprintf(int fd, const char *format, va_list args) { const char *fmt = format; const char *format_end = format + strlen(format); const char *conv = fmt; while (fmt < format_end) { conv = memchr(fmt, '%', format_end - fmt); if (conv != fmt) { size_t out_bytes = (conv ? conv : format_end) - fmt; sb_write(fd, fmt, out_bytes); if (!conv) return; } char buf[50]; size_t idx; unsigned long long int u, x; char hex_base; size_t padding = 0; unsigned int modifiers = 0; eat_more: switch (conv[1]) { default: sb_fdprintf(fd, "{invalid conversion specifier in string: %s}", format); break; case '%': if (modifiers) { inv_modifier: sb_fdprintf(fd, "{invalid modifier in string: %s}", format); } sb_write(fd, conv, 1); break; case 'l': ++conv; if (modifiers & MOD_LONG_T) { if (modifiers & MOD_LONG_LONG_T) goto inv_modifier; modifiers = (modifiers & ~MOD_LONG_T) | MOD_LONG_LONG_T; } else modifiers |= MOD_LONG_T; goto eat_more; case 'z': ++conv; if (modifiers & MOD_SIZE_T) goto inv_modifier; modifiers |= MOD_SIZE_T; goto eat_more; case '*': ++conv; if (modifiers & MOD_STAR) goto inv_modifier; modifiers |= MOD_STAR; padding = va_arg(args, int); goto eat_more; case '#': /* ignore */ ++conv; goto eat_more; case 'c': { char c = va_arg(args, int); sb_write(fd, &c, 1); break; } case 's': { char *s = va_arg(args, char *); if (!s) s = "(null)"; size_t len = strlen(s); while (len < padding--) sb_write(fd, " ", 1); sb_write(fd, s, len); break; } case 'd': case 'i': { long long i; if (modifiers & MOD_SIZE_T) i = va_arg(args, ssize_t); else if (modifiers & MOD_LONG_T) i = va_arg(args, long); else if (modifiers & MOD_LONG_LONG_T) i = va_arg(args, long long); else i = va_arg(args, int); u = i; if (i < 0) { sb_write(fd, "-", 1); u = i * -1; } out_uint: idx = 0; do { buf[idx++] = '0' + (u % 10); } while (u /= 10); while (idx--) sb_write(fd, buf+idx, 1); break; } case 'u': { if (modifiers & MOD_SIZE_T) u = va_arg(args, size_t); else if (modifiers & MOD_LONG_T) u = va_arg(args, unsigned long); else if (modifiers & MOD_LONG_LONG_T) u = va_arg(args, unsigned long long); else