14#include "sw/device/lib/base/status.h"
28 kUnsignedHexLow =
'x',
29 kUnsignedHexHigh =
'X',
47OT_NONSTRING static const char kDigitsLow[16] =
"0123456789abcdef";
48OT_NONSTRING static const char kDigitsHigh[16] =
"0123456789ABCDEF";
50OT_NONSTRING static const char kErrorNul[17] =
"%<unexpected nul>";
51OT_NONSTRING static const char kUnknownSpec[15] =
"%<unknown spec>";
52OT_NONSTRING static const char kErrorTooWide[12] =
"%<bad width>";
54static size_t base_dev_null(
void *data,
const char *buf,
size_t len) {
65 if (out.sink == NULL) {
66 out.sink = &base_dev_null;
71static size_t base_dev_uart(
void *data,
const char *buf,
size_t len) {
73 for (
size_t i = 0; i < len; ++i) {
74 if (dif_uart_byte_send_polled(uart, (uint8_t)buf[i]) !=
kDifOk) {
83 (
buffer_sink_t){.data = (
void *)uart, .sink = &base_dev_uart});
86size_t base_printf(
const char *format, ...) {
88 va_start(args, format);
89 size_t bytes_left = base_vprintf(format, args);
94size_t base_vprintf(
const char *format, va_list args) {
95 return base_vfprintf(base_stdout, format, args);
103static size_t snprintf_sink(
void *data,
const char *buf,
size_t len) {
105 if (captures->bytes_left == 0) {
109 if (len > captures->bytes_left) {
110 len = captures->bytes_left;
112 memcpy(captures->buf, buf, len);
113 captures->buf += len;
114 captures->bytes_left -= len;
118size_t base_snprintf(
char *buf,
size_t len,
const char *format, ...) {
120 va_start(args, format);
128 .sink = &snprintf_sink,
130 size_t bytes_left = base_vfprintf(out, format, args);
137 va_start(args, format);
138 size_t bytes_left = base_vfprintf(out, format, args);
152static bool consume_until_percent(
buffer_sink_t out,
const char **format,
153 size_t *bytes_written) {
156 char c = (*format)[text_len];
157 if (c ==
'\0' || c == kPercent) {
159 *bytes_written += out.sink(out.data, *format, text_len);
187static bool consume_format_specifier(
buffer_sink_t out,
const char **format,
188 size_t *bytes_written,
189 format_specifier_t *spec) {
190 *spec = (format_specifier_t){0};
197 if ((*format)[0] ==
'!') {
198 spec->is_nonstd =
true;
210 char c = (*format)[spec_len];
212 *bytes_written += out.sink(out.data, kErrorNul,
sizeof(kErrorNul));
215 if (c <
'0' || c >
'9') {
218 if (spec->padding == 0) {
227 spec->width += (c -
'0');
231 if ((spec->width == 0 && spec->padding != 0) || spec->width > 32) {
232 *bytes_written += out.sink(out.data, kErrorTooWide,
sizeof(kErrorTooWide));
236 spec->type = (*format)[spec_len];
237 *format += spec_len + 1;
253static size_t write_digits(
buffer_sink_t out, uint32_t value, uint32_t width,
254 char padding, uint32_t base,
const char *glyphs) {
257 static const int kWordBits =
sizeof(uint32_t) * 8;
258 char buffer[kWordBits];
262 buffer[kWordBits - 1] = glyphs[0];
266 uint32_t digit = value % base;
268 buffer[kWordBits - 1 - len] = glyphs[digit];
271 width = width == 0 ? 1 : width;
272 width = width > kWordBits ? kWordBits : width;
273 while (len < width) {
274 buffer[kWordBits - len - 1] = padding;
277 return out.sink(out.data, buffer + (kWordBits - len), len);
280static size_t write_status(
buffer_sink_t out, status_t value,
bool as_json) {
282 char mod[] = {0, 0, 0};
285 bool err = status_extract(value, &start, &arg, mod);
288 const char *end = start;
293 len += out.sink(out.data,
"{\"", as_json ? 2 : 0);
294 len += out.sink(out.data, start, (
size_t)(end - start));
295 len += out.sink(out.data,
"\"", as_json ? 1 : 0);
297 len += out.sink(out.data,
":", 1);
300 len += out.sink(out.data,
"[\"", 2);
301 for (
size_t i = 0; i < 3; i++) {
302 if (mod[i] ==
'\\') {
303 len += out.sink(out.data,
"\\\\", 2);
305 len += out.sink(out.data, &mod[i], 1);
308 len += out.sink(out.data,
"\",", 2);
309 len += write_digits(out, (uint32_t)arg, 0, 0, 10, kDigitsLow);
310 len += out.sink(out.data,
"]", 1);
313 len += write_digits(out, (uint32_t)arg, 0, 0, 10, kDigitsLow);
315 len += out.sink(out.data,
"}", as_json ? 1 : 0);
333static size_t hex_dump(
buffer_sink_t out,
const char *bytes,
size_t len,
334 uint32_t width,
char padding,
bool big_endian,
335 const char *glyphs) {
336 size_t bytes_written = 0;
341 memset(buf, padding,
sizeof(buf));
343 size_t to_write = width >
ARRAYSIZE(buf) ? 32 : width;
344 bytes_written += out.sink(out.data, buf, to_write);
349 for (
size_t i = 0; i < len; ++i) {
350 size_t idx = big_endian ? len - i - 1 : i;
351 buf[buffered] = glyphs[(bytes[idx] >> 4) & 0xf];
352 buf[buffered + 1] = glyphs[bytes[idx] & 0xf];
356 bytes_written += out.sink(out.data, buf, buffered);
362 bytes_written += out.sink(out.data, buf, buffered);
364 return bytes_written;
378static void process_specifier(
buffer_sink_t out, format_specifier_t spec,
379 size_t *bytes_written, va_list *args) {
385 if (spec.is_nonstd) {
388 *bytes_written += out.sink(out.data,
"%", 1);
392 if (spec.is_nonstd) {
395 char value = (char)va_arg(*args, uint32_t);
396 *bytes_written += out.sink(out.data, &value, 1);
400 uint32_t value = va_arg(*args, uint32_t);
401 for (
size_t i = 0; i <
sizeof(uint32_t); ++i, value >>= 8) {
402 uint8_t ch = (uint8_t)value;
403 if (ch >= 32 && ch < 127) {
404 *bytes_written += out.sink(out.data, (
const char *)&ch, 1);
406 *bytes_written += out.sink(out.data,
"\\x", 2);
407 *bytes_written += out.sink(out.data, &kDigitsLow[ch >> 4], 1);
408 *bytes_written += out.sink(out.data, &kDigitsLow[ch & 15], 1);
415 if (spec.is_nonstd) {
417 len = va_arg(*args,
size_t);
420 char *value = va_arg(*args,
char *);
421 while (!spec.is_nonstd && value[len] !=
'\0') {
426 *bytes_written += out.sink(out.data, value, len);
431 if (spec.is_nonstd) {
434 uint32_t value = va_arg(*args, uint32_t);
435 if (((int32_t)value) < 0) {
436 *bytes_written += out.sink(out.data,
"-", 1);
440 write_digits(out, value, spec.width, spec.padding, 10, kDigitsLow);
444 if (spec.is_nonstd) {
447 uint32_t value = va_arg(*args, uint32_t);
449 write_digits(out, value, spec.width, spec.padding, 8, kDigitsLow);
453 if (spec.is_nonstd) {
462 *bytes_written += out.sink(out.data,
"0x", 2);
463 uintptr_t value = va_arg(*args, uintptr_t);
465 write_digits(out, value,
sizeof(uintptr_t) * 2,
'0', 16, kDigitsLow);
468 case kUnsignedHexLow:
469 if (spec.is_nonstd) {
470 size_t len = va_arg(*args,
size_t);
471 char *value = va_arg(*args,
char *);
472 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
478 uint32_t value = va_arg(*args, uint32_t);
480 write_digits(out, value, spec.width, spec.padding, 16, kDigitsLow);
483 case kUnsignedHexHigh:
484 if (spec.is_nonstd) {
485 size_t len = va_arg(*args,
size_t);
486 char *value = va_arg(*args,
char *);
487 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
493 uint32_t value = va_arg(*args, uint32_t);
495 write_digits(out, value, spec.width, spec.padding, 16, kDigitsHigh);
499 if (!spec.is_nonstd) {
502 size_t len = va_arg(*args,
size_t);
503 char *value = va_arg(*args,
char *);
504 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
509 if (!spec.is_nonstd) {
512 size_t len = va_arg(*args,
size_t);
513 char *value = va_arg(*args,
char *);
514 *bytes_written += hex_dump(out, value, len, spec.width, spec.padding,
519 if (spec.is_nonstd) {
522 uint32_t value = va_arg(*args, uint32_t);
524 write_digits(out, value, spec.width, spec.padding, 10, kDigitsLow);
528 if (spec.is_nonstd) {
531 if (va_arg(*args,
int) != 0) {
532 *bytes_written += out.sink(out.data,
"true", 4);
534 *bytes_written += out.sink(out.data,
"false", 5);
538 uint32_t value = va_arg(*args, uint32_t);
540 write_digits(out, value, spec.width, spec.padding, 2, kDigitsLow);
543 case kStatusResult: {
544 status_t value = va_arg(*args, status_t);
545 *bytes_written += write_status(out, value, spec.is_nonstd);
550 *bytes_written += out.sink(out.data, kUnknownSpec,
sizeof(kUnknownSpec));
556 if (out.sink == NULL) {
557 out.sink = &base_dev_null;
565 va_copy(args_copy, args);
567 size_t bytes_written = 0;
568 while (format[0] !=
'\0') {
569 if (!consume_until_percent(out, &format, &bytes_written)) {
572 format_specifier_t spec;
573 if (!consume_format_specifier(out, &format, &bytes_written, &spec)) {
577 process_specifier(out, spec, &bytes_written, &args_copy);
581 return bytes_written;
587 "................................"
589 " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
591 "................................................................"
592 "................................................................"
599 .alphabet = &kBaseHexdumpDefaultFmtAlphabet,
602size_t base_hexdump(
const char *buf,
size_t len) {
603 return base_hexdump_with(kBaseHexdumpDefaultFmt, buf, len);
606size_t base_snhexdump(
char *out,
size_t out_len,
const char *buf,
size_t len) {
607 return base_snhexdump_with(out, out_len, kBaseHexdumpDefaultFmt, buf, len);
611 return base_fhexdump_with(out, kBaseHexdumpDefaultFmt, buf, len);
615 return base_fhexdump_with(base_stdout, fmt, buf, len);
619 const char *buf,
size_t len) {
622 .bytes_left = out_len,
626 .sink = &snprintf_sink,
628 return base_fhexdump_with(sink, fmt, buf, len);
632 const char *buf,
size_t len) {
633 if (out.sink == NULL) {
634 out.sink = &base_dev_null;
637 size_t bytes_written = 0;
640 for (
size_t line = 0; line < len; line += bytes_per_line) {
641 bytes_written += base_fprintf(out,
"%08x:", line);
644 size_t line_bytes_written = 0;
645 for (
size_t word = 0; word < bytes_per_line; word += fmt.
bytes_per_word) {
646 if (len < line + word) {
648 while (line_bytes_written < chars_per_line) {
649 size_t to_print = chars_per_line - line_bytes_written;
650 if (to_print >
sizeof(spaces)) {
651 to_print =
sizeof(spaces);
653 line_bytes_written += base_fprintf(out,
"%!s", to_print, spaces);
658 size_t bytes_left = len - line - word;
662 line_bytes_written += base_fprintf(out,
" ");
663 line_bytes_written +=
664 hex_dump(out, buf + line + word, bytes_left, bytes_left,
'0',
667 bytes_written += line_bytes_written;
669 bytes_written += base_fprintf(out,
" ");
671 char glyph_buffer[16];
672 for (
size_t byte = 0;
byte < bytes_per_line; ++byte) {
673 if (buffered ==
sizeof(glyph_buffer)) {
674 bytes_written += base_fprintf(out,
"%!s", buffered, glyph_buffer);
677 if (line +
byte >= len) {
680 glyph_buffer[buffered++] =
681 (*fmt.
alphabet)[(
size_t)(uint8_t)buf[line +
byte]];
684 bytes_written += base_fprintf(out,
"%!s", buffered, glyph_buffer);
686 bytes_written += base_fprintf(out,
"\n");
689 return bytes_written;